1. 背景
本文整理了JNI开发中常见的问题和解决方案。
2. 编译时指定SDK版本问题
智能语音交互SDK工程模块编译时指定的ANDROID_PLATFORM统一是23:-DANDROID_PLATFORM=23
,ndk使用的是版本是17,在手上现有设备跑的都没问题,但是在一个新采购的temi移动机器人上跑不起来,定位到问题是信号处理库报了下面问题:
java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "__aeabi_memclr4" referenced by "/data/app/com.xxx.xxxx.robot-2/lib/arm/libkeos_signal_processing.so"...
最开始以为是信号处理库中用到了什么不兼容方法,把库的实现都改为空实现后仍报该错误,网上查询到是target version和目标设备不对应会报该错,机器人的系统版本是6.0,信号处理库编译时Application.mk中设置的APP_PLATFORM := android-26
,修改完后就果然解决。
官网中对该问题有介绍:
当尝试加载原生库时,这些错误会显示在日志中。此符号可以是 __aeabi_*
中的任意一个;其中 __aeabi_memcpy
和 __aeabi_memclr
可能是最常见的。此问题已记录在问题 126 中
2. Using _FILE_OFFSET_BITS=64
with older API levels
与上一个类似,也是API版本问题。
在统一头文件之前,NDK 并不支持 _FILE_OFFSET_BITS=64
。如果在构建应用时定义了该选项,系统会静默地忽略它。现在,_FILE_OFFSET_BITS=64
选项受统一头文件的支持,但在旧版本的 Android 中,很少有 off_t
API 可用作 off64_t
变体。因此,如果将该功能与旧版 API 级别搭配使用,会导致可用函数减少。
问题: build 请求获得的 minSdkVersion
中不存在的 API。
解决方案:停用 _FILE_OFFSET_BITS=64
或提高 minSdkVersion
。
3. jni local reference table overflow (max=512)
正常情况我们在方法里面申请的local reference会在方法执行完后自动释放,所以一直没有太在意local reference的释放,结果在一个线程的looper方法中有两个jstring使用完一直没释放,导致交互多轮后泄露崩溃。
4. FindClass
找不到类
常见问题类型:
- 确保类名称字符串的格式正确无误,JNI 类名称以软件包名称开头,并用斜线分隔,例如
java/lang/String
。如果要查找某个数组类,则需要以适当数量的英文方括号开头,并且还必须用“L”和“;”将该类包裹起来,因此String
的一维数组将是[Ljava/lang/String;
。如果要查找内部类,使用“$”而不是“.”,可以在 .class 文件上使用javap
是查找类的内部名称。 - 如果启用代码混淆,请确保查找的类名未被混淆。
- 如果类名称形式正确,可能是遇到了类加载器问题。
FindClass
需要在与代码关联的类加载器的启动类搜索。它会检查调用堆栈,如下所示:
Foo.myfunc(Native Method) Foo.main(Foo.java:10)
最顶层的方法是 Foo.myfunc
。FindClass
会查找与 Foo
类关联的 ClassLoader
对象并使用它。
采用这种方法一般情况可以满足我们的需求。但是如果在native线程(比如通过调用 pthread_create
,然后使用 AttachCurrentThread
进行附加),可能会有问题。因为在这个线程中没有堆栈帧,如果从此线程调用 FindClass
,JavaVM 会在“系统”类加载器(而不是与应用关联的类加载器)中启动,因此尝试查找特定于应用的类将失败。
可以通过以下几种方法来解决此问题:
- 在
JNI_OnLoad
中执行一次FindClass
查找,然后缓存类引用以供日后使用。在执行JNI_OnLoad
过程中发出的任何FindClass
调用都会使用与调用System.loadLibrary
的函数关联的类加载器(这是一条特殊规则,用于更方便地进行库初始化)。如果我们的应用代码要加载库,FindClass
会使用正确的类加载器。 - 通过声明原生方法来获取 Class 参数,然后传入
Foo.class
,从而将类的实例传递给需要它的函数。 - 在某个便捷位置缓存
ClassLoader
对象的引用,然后直接发出loadClass
调用,这个比较麻烦一些,而且缓存classloader可能也会存在一些问题。 - 使用
java/lang/ClassLoader
的getClassLoader
,然后调用findClass
:
static jobject gClassLoader; static jmethodID gFindClassMethod; JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *pjvm, void *reserved) { gJvm = pjvm; // cache the JavaVM pointer auto env = getEnv(); //replace with one of your classes in the line below auto randomClass = env->FindClass("com/example/RandomClass"); jclass classClass = env->GetObjectClass(randomClass); auto classLoaderClass = env->FindClass("java/lang/ClassLoader"); auto getClassLoaderMethod = env->GetMethodID(classClass, "getClassLoader", "()Ljava/lang/ClassLoader;"); gClassLoader = env->CallObjectMethod(randomClass, getClassLoaderMethod); gFindClassMethod = env->GetMethodID(classLoaderClass, "findClass", "(Ljava/lang/String;)Ljava/lang/Class;"); return JNI_VERSION_1_6; } jclass findClass(const char* name) { return static_cast<jclass>(getEnv()->CallObjectMethod(gClassLoader, gFindClassMethod, getEnv()->NewStringUTF(name))); } JNIEnv* getEnv() { JNIEnv *env; int status = gJvm->GetEnv((void**)&env, JNI_VERSION_1_6); if(status < 0) { status = gJvm->AttachCurrentThread(&env, NULL); if(status < 0) { return nullptr; } } return env; }
No pending exception expected: java.lang.ClassNotFoundException: Didn't find class "com.qingkouwei.foundclassdemo.TestClass" on path: DexPathList[[directory "."],nativeLibraryDirectories=[/system/lib64,
stackoverflow.com/questions/1…
5. 返回值错误问题
我们在其他平台,比如linux中声明了返回值类型为int,实际函数体没有return可能没有问题,但是Android平台会直接崩溃。
2022-03-07 15:09:01.152 16695-16695/com.qingkouwei.foundclassdemo A/libc: Fatal signal 5 (SIGTRAP), code 1 (TRAP_BRKPT), fault addr 0x7656c5c5e4 in tid 16695 (.foundclassdemo), pid 16695 (.foundclassdemo) 2022-03-07 15:09:01.157 16639-16881/? E/SecurityComp10105306: EncryptUtil: exception : Failed resolution of: Lorg/bouncycastle/crypto/engines/AESEngine; , you should implementation bcprov-jdk15on library 2022-03-07 15:09:01.222 16908-16908/? A/DEBUG: *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 2022-03-07 15:09:01.222 16908-16908/? A/DEBUG: Build fingerprint: 'HONOR/YAL-AL00/HWYAL:10/HUAWEIYAL-AL00/10.1.0.162C00:user/release-keys' 2022-03-07 15:09:01.222 16908-16908/? A/DEBUG: Revision: '0' 2022-03-07 15:09:01.222 16908-16908/? A/DEBUG: ABI: 'arm64' 2022-03-07 15:09:01.226 16908-16908/? A/DEBUG: SYSVMTYPE: Maple APPVMTYPE: Art 2022-03-07 15:09:01.226 16908-16908/? A/DEBUG: Timestamp: 2022-03-07 15:09:01+0800 2022-03-07 15:09:01.226 16908-16908/? A/DEBUG: pid: 16695, tid: 16695, name: .foundclassdemo >>> com.qingkouwei.foundclassdemo <<< 2022-03-07 15:09:01.226 16908-16908/? A/DEBUG: uid: 10616 2022-03-07 15:09:01.226 16908-16908/? A/DEBUG: signal 5 (SIGTRAP), code 1 (TRAP_BRKPT), fault addr 0x7656c5c5e4 2022-03-07 15:09:01.226 16908-16908/? A/DEBUG: x0 000000000000006a x1 0000007fd6d0b8e0 x2 0000000000000004 x3 0000000000000005 2022-03-07 15:09:01.226 16908-16908/? A/DEBUG: x4 0000000000000000 x5 4008000000000000 x6 0000000000000000 x7 7f7f7f7f7f7f7f7f 2022-03-07 15:09:01.226 16908-16908/? A/DEBUG: x8 cefdb6c250ecaf4a x9 cefdb6c250ecaf4a x10 00000076f406305c x11 000000000000003b 2022-03-07 15:09:01.226 16908-16908/? A/DEBUG: x12 0000000000000018 x13 ffffffffffffffff x14 ffffffffff000000 x15 ffffffffffffffff 2022-03-07 15:09:01.226 16908-16908/? A/DEBUG: x16 00000076f406a8f8 x17 00000076f5a4d560 x18 00000076f8cbe000 x19 0000007672210800 2022-03-07 15:09:01.226 16908-16908/? A/DEBUG: x20 0000000000000000 x21 0000007672210800 x22 0000007fd6d0c450 x23 000000766176c9cb 2022-03-07 15:09:01.226 16908-16908/? A/DEBUG: x24 0000000000000008 x25 00000076f7e51020 x26 00000076722108b0 x27 0000000000000002 2022-03-07 15:09:01.226 16908-16908/? A/DEBUG: x28 0000007fd6d0c1e0 x29 0000007fd6d0c160 2022-03-07 15:09:01.226 16908-16908/? A/DEBUG: sp 0000007fd6d0c0b0 lr 0000007656c5c5e4 pc 0000007656c5c5e4 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: backtrace: 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #00 pc 00000000000025e4 /data/app/com.qingkouwei.foundclassdemo-9j6a3XxFGTn9Cw9oVWDDpg==/lib/arm64/libnative-lib.so (myFindClass+344) (BuildId: c9adfab317deb3b439ef1646bc9b03951ef68837) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #01 pc 0000000000002c30 /data/app/com.qingkouwei.foundclassdemo-9j6a3XxFGTn9Cw9oVWDDpg==/lib/arm64/libnative-lib.so (BuildId: c9adfab317deb3b439ef1646bc9b03951ef68837) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #02 pc 0000000000150350 /apex/com.android.runtime/lib64/libart.so (art_quick_generic_jni_trampoline+144) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #03 pc 0000000000147334 /apex/com.android.runtime/lib64/libart.so (art_quick_invoke_stub+548) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #04 pc 00000000001561b4 /apex/com.android.runtime/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+252) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #05 pc 00000000002fd900 /apex/com.android.runtime/lib64/libart.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+384) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #06 pc 00000000002f8bd0 /apex/com.android.runtime/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+912) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #07 pc 00000000005cb550 /apex/com.android.runtime/lib64/libart.so (MterpInvokeVirtual+648) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #08 pc 0000000000141814 /apex/com.android.runtime/lib64/libart.so (mterp_op_invoke_virtual+20) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #09 pc 0000000000123f60 [anon:dalvik-classes.dex extracted in memory from /data/app/com.qingkouwei.foundclassdemo-9j6a3XxFGTn9Cw9oVWDDpg==/base.apk] (com.qingkouwei.foundclassdemo.MainActivity$1.onClick+12) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #10 pc 00000000005cd060 /apex/com.android.runtime/lib64/libart.so (MterpInvokeInterface+1752) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #11 pc 0000000000141a14 /apex/com.android.runtime/lib64/libart.so (mterp_op_invoke_interface+20) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #12 pc 000000000023af0c /system/framework/framework.jar (android.view.View.performClick+40) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #13 pc 00000000005cb860 /apex/com.android.runtime/lib64/libart.so (MterpInvokeVirtual+1432) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #14 pc 0000000000141814 /apex/com.android.runtime/lib64/libart.so (mterp_op_invoke_virtual+20) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #15 pc 000000000023af56 /system/framework/framework.jar (android.view.View.performClickInternal+6) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #16 pc 00000000005cdbfc /apex/com.android.runtime/lib64/libart.so (MterpInvokeDirect+1168) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #17 pc 0000000000141914 /apex/com.android.runtime/lib64/libart.so (mterp_op_invoke_direct+20) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #18 pc 00000000002363fc /system/framework/framework.jar (android.view.View.access$3600) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #19 pc 00000000005ce408 /apex/com.android.runtime/lib64/libart.so (MterpInvokeStatic+1136) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #20 pc 0000000000141994 /apex/com.android.runtime/lib64/libart.so (mterp_op_invoke_static+20) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #21 pc 000000000021320c /system/framework/framework.jar (android.view.View$PerformClick.run+56) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #22 pc 00000000005cd060 /apex/com.android.runtime/lib64/libart.so (MterpInvokeInterface+1752) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #23 pc 0000000000141a14 /apex/com.android.runtime/lib64/libart.so (mterp_op_invoke_interface+20) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #24 pc 000000000030cc4c /system/framework/framework.jar (android.os.Handler.handleCallback+4) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #25 pc 00000000005ce408 /apex/com.android.runtime/lib64/libart.so (MterpInvokeStatic+1136) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #26 pc 0000000000141994 /apex/com.android.runtime/lib64/libart.so (mterp_op_invoke_static+20) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #27 pc 000000000030cab8 /system/framework/framework.jar (android.os.Handler.dispatchMessage+8) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #28 pc 00000000005cb860 /apex/com.android.runtime/lib64/libart.so (MterpInvokeVirtual+1432) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #29 pc 0000000000141814 /apex/com.android.runtime/lib64/libart.so (mterp_op_invoke_virtual+20) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #30 pc 0000000000337c30 /system/framework/framework.jar (android.os.Looper.loop+480) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #31 pc 00000000005ce408 /apex/com.android.runtime/lib64/libart.so (MterpInvokeStatic+1136) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #32 pc 0000000000141994 /apex/com.android.runtime/lib64/libart.so (mterp_op_invoke_static+20) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #33 pc 00000000001abfe0 /system/framework/framework.jar (android.app.ActivityThread.main+1372) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #34 pc 00000000002ce22c /apex/com.android.runtime/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEbb.llvm.10887373532384510885+320) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #35 pc 00000000005bc090 /apex/com.android.runtime/lib64/libart.so (artQuickToInterpreterBridge+1012) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #36 pc 0000000000150468 /apex/com.android.runtime/lib64/libart.so (art_quick_to_interpreter_bridge+88) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #37 pc 00000000001475b8 /apex/com.android.runtime/lib64/libart.so (art_quick_invoke_static_stub+568) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #38 pc 00000000001561d4 /apex/com.android.runtime/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+284) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #39 pc 00000000004d8820 /apex/com.android.runtime/lib64/libart.so (art::(anonymous namespace)::InvokeWithArgArray(art::ScopedObjectAccessAlreadyRunnable const&, art::ArtMethod*, art::(anonymous namespace)::ArgArray*, art::JValue*, char const*)+104) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #40 pc 00000000004da248 /apex/com.android.runtime/lib64/libart.so (art::InvokeMethod(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jobject*, _jobject*, unsigned long)+1476) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #41 pc 000000000046412c /apex/com.android.runtime/lib64/libart.so (art::Method_invoke(_JNIEnv*, _jobject*, _jobject*, _jobjectArray*)+52) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #42 pc 00000000000f8c34 /system/framework/arm64/boot.oat (art_jni_trampoline+180) (BuildId: 8fb9eb57b3ea725573d56f165d17f78dd54965d7) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #43 pc 0000000000147334 /apex/com.android.runtime/lib64/libart.so (art_quick_invoke_stub+548) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #44 pc 00000000001561b4 /apex/com.android.runtime/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+252) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #45 pc 00000000002fd900 /apex/com.android.runtime/lib64/libart.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+384) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #46 pc 00000000002f8bd0 /apex/com.android.runtime/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+912) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #47 pc 00000000005cb550 /apex/com.android.runtime/lib64/libart.so (MterpInvokeVirtual+648) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #48 pc 0000000000141814 /apex/com.android.runtime/lib64/libart.so (mterp_op_invoke_virtual+20) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #49 pc 000000000040010e /system/framework/framework.jar (com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run+22) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #50 pc 00000000002ce22c /apex/com.android.runtime/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEbb.llvm.10887373532384510885+320) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #51 pc 00000000005bc090 /apex/com.android.runtime/lib64/libart.so (artQuickToInterpreterBridge+1012) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #52 pc 0000000000150468 /apex/com.android.runtime/lib64/libart.so (art_quick_to_interpreter_bridge+88) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #53 pc 0000000000b253bc /system/framework/arm64/boot-framework.oat (com.android.internal.os.ZygoteInit.main+3660) (BuildId: 839677a7635b67b1b883c48b6ed1ea5c4a581790) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #54 pc 00000000001475b8 /apex/com.android.runtime/lib64/libart.so (art_quick_invoke_static_stub+568) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #55 pc 00000000001561d4 /apex/com.android.runtime/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+284) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #56 pc 00000000004d8820 /apex/com.android.runtime/lib64/libart.so (art::(anonymous namespace)::InvokeWithArgArray(art::ScopedObjectAccessAlreadyRunnable const&, art::ArtMethod*, art::(anonymous namespace)::ArgArray*, art::JValue*, char const*)+104) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #57 pc 00000000004d848c /apex/com.android.runtime/lib64/libart.so (art::InvokeWithVarArgs(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jmethodID*, std::__va_list)+408) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #58 pc 00000000003d7cf8 /apex/com.android.runtime/lib64/libart.so (art::JNI::CallStaticVoidMethodV(_JNIEnv*, _jclass*, _jmethodID*, std::__va_list)+660) (BuildId: 08543716770b195bd10fafbe11bb5052) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #59 pc 00000000001015c4 /system/lib64/libandroid_runtime.so (_JNIEnv::CallStaticVoidMethod(_jclass*, _jmethodID*, ...)+116) (BuildId: 034c759a360c29cae9a101b25604f692) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #60 pc 0000000000104c48 /system/lib64/libandroid_runtime.so (android::AndroidRuntime::start(char const*, android::Vector<android::String8> const&, bool)+1248) (BuildId: 034c759a360c29cae9a101b25604f692) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #61 pc 00000000000034e0 /system/bin/app_process64 (main+1168) (BuildId: e844be217eb39b34490d3798328d1f12) 2022-03-07 15:09:01.375 16908-16908/? A/DEBUG: #62 pc 000000000006b108 /apex/com.android.runtime/lib64/bionic/libc.so (__libc_init+108) (BuildId: b91c775ccc9b0556e91bc575a2511cd0) 2022-03-07 15:09:01.405 17145-17756/? E/X509CertUtil: can not open cbg root cer
6. NDK指南中介绍的其他错误
6.1 minSdkVersion
的设置高于设备的 API 级别
使用 NDK 进行构建所依据的 API 级别与 Java 中的 compileSdkVersion
所代表的含义截然不同。NDK API 级别是您的应用支持的最低 API 级别。在 ndk-build 中,这是指 APP_PLATFORM
设置。对于 CMake,这是指 -DANDROID_PLATFORM
。(如果使用的是 externalNativeBuild,系统会自动使用您的 minSdkVersion
。)
系统对函数引用的解析通常发生在库加载时,而不是首次调用时,因此,对于并非始终存在并通过 API 级别检查保护对其的使用的 API,将无法引用。如果 API 被引用,那么此 API 就必须存在。
问题: NDK API 级别高于设备支持的 API 级别。
解决方案:将 NDK API 级别 (APP_PLATFORM
) 设置为应用支持的最低 Android 版本。
6.2 找不到 rand
符号
对于以下错误日志消息,请参阅这条详细的 Stack Overflow 解答。
UnsatisfiedLinkError: dlopen failed: cannot locate symbol "rand"
6.3 未定义对 __atomic_*
的引用
问题:某些 ABI 需要 libatomic
才能为原子操作提供一些实现。
解决方案:在链接时添加 -latomic
。
对于以下错误消息:
error: undefined reference to '__atomic_exchange_4'
此处的实际符号可能是前缀为 __atomic_
的任何符号。(ndk-build 和 CMake 会替我们处理这个问题。对于其他构建系统,我们需要手动处理。)
6.3 RTTI/异常捕获功能无法跨库边界运行
问题:在跨共享库边界抛出异常或 dynamic_cast
失败时,无法捕获异常。
解决方案:为我们的类型添加一个关键函数。关键函数是某个类型的第一个非纯的外联虚拟函数。可参阅关于问题 533 的讨论。
C++ ABI 规定,当且仅当两个对象的 type_info
指针相同时,两者才具有相同的类型。只有当捕获的 type_info
与抛出的异常匹配时,系统才会捕获异常。这项规则同样适用于 dynamic_cast
。
如果某个类型没有关键函数,系统会将其 typeinfo
作为弱符号发出,并在加载库时合并匹配类型信息。如果在可执行文件加载完毕后动态加载库(也就是说通过 dlopen
或 System.loadLibrary
加载),加载器可能无法合并已加载库的类型信息。当出现这种情况时,这两种类型就不会被视为等同。
对于非多态类型,类型不能具有关键函数。对于非多态类型,RTTI 是多余的,因为可使用 std::is_same
在编译时确定类型等同性。
6.4 使用不匹配的预构建库
在我们的应用中使用预构建库(这些库通常是第三方库)时,需要特别注意。一般来说,请注意以下规则:
- 生成的应用的最低 API 级别是应用所有库的最大
minSdkVersion
值。
如果我们的 minSdkVersion
是 16,但使用了依据 21 构建的预构建库,那么生成的应用的最低 API 级别为 21。如果预构建库是静态的,那么对于此规则的违反将会在构建时显示出来,但在预构建共享库运行时才会显示。
- 应使用相同的 NDK 版本生成所有库。
由于违反的情况极少,此规则比大多数规则的灵活性略高,但无法保证使用不同 Major 版本的 NDK 构建的库之间的兼容性。C++ ABI 并非稳定版,在过去有过变化。
- 具有多个共享库的应用必须使用一个共享 STL。
就 STL 不匹配而言,可以通过小心谨慎地操作来避免由此引起的问题,但最好直接避免该问题。为避免该问题,最好避免在您的应用中使用多个共享库。
7. 总结
本文介绍了JNI开发过程中常见的问题,比如版本问题,定位符号失败问题以及不同平台函数实现的差异等。后续可以持续维护迭代本文档。