Issue
Android cmake project with sub-directories "dlopen failed: cannot locate symbol" on api < 23
same code works fine on api >= 23
this test program will print a log if success
project structure:
src/main/cpp
+foo
CMakeLists.txt
foo.cpp
+utils
CMakeLists.txt
log-utils.h
log-utils.cpp
CMakeLists.txt
CMakeLists.txt(foo)
project(foo)
add_library(foo SHARED foo.cpp)
target_link_libraries(foo PUBLIC utils)
foo.cpp
#include <jni.h>
#include <utils/log-utils.h>
#include <cstring>
jint JNI_OnLoad(JavaVM* vm, void * reserved) {
const char * test = "test message";
printByte("JNI_OnLoad", test, strlen(test));
JNIEnv *env;
if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK) {
return -1;
}
return JNI_VERSION_1_6;
}
CMakeLists.txt(utils)
project(utils)
find_library(log-lib log)
add_library(utils SHARED log-utils.cpp)
target_link_libraries(utils ${log-lib})
log-utils.h
#ifndef LOG_UTILS_H
#define LOG_UTILS_H
void printByte(const char*tag, const char* content, unsigned int len);
#endif //LOG_UTILS_H
log-utils.cpp
#include "log-utils.h"
#include <cstring>
#include <cstdio>
#include <android/log.h>
static const char * TAG = "LOG_UTILS";
void printByte(const char*tag, const char* content, unsigned int len) {
char buff[len*2+1];
memset(buff, '\0', len*2+1);
for (int i = 0; i<len; ++i) {
sprintf(buff+i*2, "%02x", content[i] & 0xff);
}
__android_log_print(ANDROID_LOG_DEBUG, TAG, "%-12s%04d: %s\n", tag, len, buff);
}
CMakeLists.txt(root)
cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-omit-frame-pointer")
include_directories(./)
add_subdirectory(utils)
add_subdirectory(foo)
MainActivity.kt
class MainActivity : AppCompatActivity() {
companion object {
init {
System.loadLibrary("utils")
System.loadLibrary("foo")
}
}
// ...
}
two library: libfoo.so, libutils.so, libfoo.so depends on libutils.so. on Android 4.4 and 5.0, it just crash, and the system log:
09-10 17:36:33.388 10908-10908/? E/art: dlopen("/data/app/com.example.nativefoo-2/lib/x86/libfoo.so", RTLD_LAZY) failed: dlopen failed: cannot locate symbol "_Z9printBytePKcS0_j" referenced by "libfoo.so"...
09-10 17:36:33.388 10908-10908/? D/AndroidRuntime: Shutting down VM
09-10 17:36:33.389 10908-10908/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.nativefoo, PID: 10908
java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "_Z9printBytePKcS0_j" referenced by "libfoo.so"...
at java.lang.Runtime.loadLibrary(Runtime.java:371)
at java.lang.System.loadLibrary(System.java:989)
at com.example.nativefoo.MainActivity.<clinit>(MainActivity.kt:18)
at java.lang.reflect.Constructor.newInstance(Native Method)
at java.lang.Class.newInstance(Class.java:1572)
at android.app.Instrumentation.newActivity(Instrumentation.java:1065)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2199)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2360)
at android.app.ActivityThread.access$800(ActivityThread.java:144)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1278)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
Update1 2019.09.11 07:23 UTC Time
app/build.gradle
compileSdkVersion 29
buildToolsVersion "29.0.2"
defaultConfig {
applicationId "com.example.nativefoo"
minSdkVersion 18
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
cppFlags ""
abiFilters "armeabi-v7a", "x86"
}
}
}
I think libutils.so is loaded correct, see the logcat
09-11 15:27:29.622 D/dalvikvm: Not late-enabling CheckJNI (already on)
09-11 15:27:29.672 D/dalvikvm: Trying to load lib /data/app-lib/com.example.nativefoo-1/libutils.so 0x9d061440
09-11 15:27:29.672 D/dalvikvm: Added shared lib /data/app-lib/com.example.nativefoo-1/libutils.so 0x9d061440
09-11 15:27:29.672 D/dalvikvm: No JNI_OnLoad found in /data/app-lib/com.example.nativefoo-1/libutils.so 0x9d061440, skipping init
09-11 15:27:29.672 D/dalvikvm: Trying to load lib /data/app-lib/com.example.nativefoo-1/libfoo.so 0x9d061440
09-11 15:27:29.672 E/dalvikvm: dlopen("/data/app-lib/com.example.nativefoo-1/libfoo.so") failed: dlopen failed: cannot locate symbol "_Z9printBytePKcS0_j" referenced by "libfoo.so"...
You can see the whole Project at github NativeFoo
Solution
This was a very stupid mistake, my library name is libutils.so, but Android system also has a inner library called libutils.so. So, when I try to load libutils.so, it load the system library first, not mine! Because of that, my app never works as expected.
Answered By - wzjing
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.