close
1. 背景

本文整理了JNI開發中常見的問題和解決方案。

2. 編譯時指定SDK版本問題

智能語音交互SDK工程模塊編譯時指定的ANDROID_PLATFORM統一是23:-DANDROID_PLATFORM=23,ndk使用的是版本是17,在手上現有設備跑的都沒問題,但是在一個新採購的temi移動機器人上跑不起來,定位到問題是信號處理庫報了下面問題:

java.lang.UnsatisfiedLinkError:dlopenfailed:cannotlocatesymbol"__aeabi_memclr4"referencedby"/data/app/com.xxx.xxxx.robot-2/lib/arm/libkeos_signal_processing.so"...

最開始以為是信號處理庫中用到了什麼不兼容方法,把庫的實現都改為空實現後仍報該錯誤,網上查詢到是target version和目標設備不對應會報該錯,機器人的系統版本是6.0,信號處理庫編譯時Application.mk中設置的APP_PLATFORM := android-26,修改完後就果然解決。

https://github.com/android/ndk/issues/126

https://github.com/android/ndk/issues/1188

官網中對該問題有介紹:

當嘗試加載原生庫時,這些錯誤會顯示在日誌中。此符號可以是 __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 級別搭配使用,會導致可用函數減少。

r16 博文和 bionic 文檔對該問題作了詳細解釋。

問題: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(NativeMethod)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:

staticjobjectgClassLoader;staticjmethodIDgFindClassMethod;JNIEXPORTjintJNICALLJNI_OnLoad(JavaVM*pjvm,void*reserved){gJvm=pjvm;//cachetheJavaVMpointerautoenv=getEnv();//replacewithoneofyourclassesinthelinebelowautorandomClass=env->FindClass("com/example/RandomClass");jclassclassClass=env->GetObjectClass(randomClass);autoclassLoaderClass=env->FindClass("java/lang/ClassLoader");autogetClassLoaderMethod=env->GetMethodID(classClass,"getClassLoader","()Ljava/lang/ClassLoader;");gClassLoader=env->CallObjectMethod(randomClass,getClassLoaderMethod);gFindClassMethod=env->GetMethodID(classLoaderClass,"findClass","(Ljava/lang/String;)Ljava/lang/Class;");returnJNI_VERSION_1_6;}jclassfindClass(constchar*name){returnstatic_cast<jclass>(getEnv()->CallObjectMethod(gClassLoader,gFindClassMethod,getEnv()->NewStringUTF(name)));}JNIEnv*getEnv(){JNIEnv*env;intstatus=gJvm->GetEnv((void**)&env,JNI_VERSION_1_6);if(status<0){status=gJvm->AttachCurrentThread(&env,NULL);if(status<0){returnnullptr;}}returnenv;}Nopendingexceptionexpected:java.lang.ClassNotFoundException:Didn'tfindclass"com.qingkouwei.foundclassdemo.TestClass"onpath:DexPathList[[directory"."],nativeLibraryDirectories=[/system/lib64,

stackoverflow.com/questions/1…

5. 返回值錯誤問題

我們在其他平台,比如linux中聲明了返回值類型為int,實際函數體沒有return可能沒有問題,但是Android平台會直接崩潰。

2022-03-0715:09:01.15216695-16695/com.qingkouwei.foundclassdemoA/libc:Fatalsignal5(SIGTRAP),code1(TRAP_BRKPT),faultaddr0x7656c5c5e4intid16695(.foundclassdemo),pid16695(.foundclassdemo)2022-03-0715:09:01.15716639-16881/?E/SecurityComp10105306:EncryptUtil:exception:Failedresolutionof:Lorg/bouncycastle/crypto/engines/AESEngine;,youshouldimplementationbcprov-jdk15onlibrary2022-03-0715:09:01.22216908-16908/?A/DEBUG:************************************************2022-03-0715:09:01.22216908-16908/?A/DEBUG:Buildfingerprint:'HONOR/YAL-AL00/HWYAL:10/HUAWEIYAL-AL00/10.1.0.162C00:user/release-keys'2022-03-0715:09:01.22216908-16908/?A/DEBUG:Revision:'0'2022-03-0715:09:01.22216908-16908/?A/DEBUG:ABI:'arm64'2022-03-0715:09:01.22616908-16908/?A/DEBUG:SYSVMTYPE:MapleAPPVMTYPE:Art2022-03-0715:09:01.22616908-16908/?A/DEBUG:Timestamp:2022-03-0715:09:01+08002022-03-0715:09:01.22616908-16908/?A/DEBUG:pid:16695,tid:16695,name:.foundclassdemo>>>com.qingkouwei.foundclassdemo<<<2022-03-0715:09:01.22616908-16908/?A/DEBUG:uid:106162022-03-0715:09:01.22616908-16908/?A/DEBUG:signal5(SIGTRAP),code1(TRAP_BRKPT),faultaddr0x7656c5c5e42022-03-0715:09:01.22616908-16908/?A/DEBUG:x0000000000000006ax10000007fd6d0b8e0x20000000000000004x300000000000000052022-03-0715:09:01.22616908-16908/?A/DEBUG:x40000000000000000x54008000000000000x60000000000000000x77f7f7f7f7f7f7f7f2022-03-0715:09:01.22616908-16908/?A/DEBUG:x8cefdb6c250ecaf4ax9cefdb6c250ecaf4ax1000000076f406305cx11000000000000003b2022-03-0715:09:01.22616908-16908/?A/DEBUG:x120000000000000018x13ffffffffffffffffx14ffffffffff000000x15ffffffffffffffff2022-03-0715:09:01.22616908-16908/?A/DEBUG:x1600000076f406a8f8x1700000076f5a4d560x1800000076f8cbe000x1900000076722108002022-03-0715:09:01.22616908-16908/?A/DEBUG:x200000000000000000x210000007672210800x220000007fd6d0c450x23000000766176c9cb2022-03-0715:09:01.22616908-16908/?A/DEBUG:x240000000000000008x2500000076f7e51020x2600000076722108b0x2700000000000000022022-03-0715:09:01.22616908-16908/?A/DEBUG:x280000007fd6d0c1e0x290000007fd6d0c1602022-03-0715:09:01.22616908-16908/?A/DEBUG:sp0000007fd6d0c0b0lr0000007656c5c5e4pc0000007656c5c5e42022-03-0715:09:01.37516908-16908/?A/DEBUG:backtrace:2022-03-0715:09:01.37516908-16908/?A/DEBUG:#00pc00000000000025e4/data/app/com.qingkouwei.foundclassdemo-9j6a3XxFGTn9Cw9oVWDDpg==/lib/arm64/libnative-lib.so(myFindClass+344)(BuildId:c9adfab317deb3b439ef1646bc9b03951ef68837)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#01pc0000000000002c30/data/app/com.qingkouwei.foundclassdemo-9j6a3XxFGTn9Cw9oVWDDpg==/lib/arm64/libnative-lib.so(BuildId:c9adfab317deb3b439ef1646bc9b03951ef68837)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#02pc0000000000150350/apex/com.android.runtime/lib64/libart.so(art_quick_generic_jni_trampoline+144)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#03pc0000000000147334/apex/com.android.runtime/lib64/libart.so(art_quick_invoke_stub+548)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#04pc00000000001561b4/apex/com.android.runtime/lib64/libart.so(art::ArtMethod::Invoke(art::Thread*,unsignedint*,unsignedint,art::JValue*,charconst*)+252)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#05pc00000000002fd900/apex/com.android.runtime/lib64/libart.so(art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*,art::ArtMethod*,art::ShadowFrame*,unsignedshort,art::JValue*)+384)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#06pc00000000002f8bd0/apex/com.android.runtime/lib64/libart.so(boolart::interpreter::DoCall<false,false>(art::ArtMethod*,art::Thread*,art::ShadowFrame&,art::Instructionconst*,unsignedshort,art::JValue*)+912)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#07pc00000000005cb550/apex/com.android.runtime/lib64/libart.so(MterpInvokeVirtual+648)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#08pc0000000000141814/apex/com.android.runtime/lib64/libart.so(mterp_op_invoke_virtual+20)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#09pc0000000000123f60[anon:dalvik-classes.dexextractedinmemoryfrom/data/app/com.qingkouwei.foundclassdemo-9j6a3XxFGTn9Cw9oVWDDpg==/base.apk](com.qingkouwei.foundclassdemo.MainActivity$1.onClick+12)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#10pc00000000005cd060/apex/com.android.runtime/lib64/libart.so(MterpInvokeInterface+1752)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#11pc0000000000141a14/apex/com.android.runtime/lib64/libart.so(mterp_op_invoke_interface+20)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#12pc000000000023af0c/system/framework/framework.jar(android.view.View.performClick+40)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#13pc00000000005cb860/apex/com.android.runtime/lib64/libart.so(MterpInvokeVirtual+1432)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#14pc0000000000141814/apex/com.android.runtime/lib64/libart.so(mterp_op_invoke_virtual+20)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#15pc000000000023af56/system/framework/framework.jar(android.view.View.performClickInternal+6)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#16pc00000000005cdbfc/apex/com.android.runtime/lib64/libart.so(MterpInvokeDirect+1168)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#17pc0000000000141914/apex/com.android.runtime/lib64/libart.so(mterp_op_invoke_direct+20)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#18pc00000000002363fc/system/framework/framework.jar(android.view.View.access$3600)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#19pc00000000005ce408/apex/com.android.runtime/lib64/libart.so(MterpInvokeStatic+1136)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#20pc0000000000141994/apex/com.android.runtime/lib64/libart.so(mterp_op_invoke_static+20)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#21pc000000000021320c/system/framework/framework.jar(android.view.View$PerformClick.run+56)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#22pc00000000005cd060/apex/com.android.runtime/lib64/libart.so(MterpInvokeInterface+1752)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#23pc0000000000141a14/apex/com.android.runtime/lib64/libart.so(mterp_op_invoke_interface+20)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#24pc000000000030cc4c/system/framework/framework.jar(android.os.Handler.handleCallback+4)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#25pc00000000005ce408/apex/com.android.runtime/lib64/libart.so(MterpInvokeStatic+1136)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#26pc0000000000141994/apex/com.android.runtime/lib64/libart.so(mterp_op_invoke_static+20)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#27pc000000000030cab8/system/framework/framework.jar(android.os.Handler.dispatchMessage+8)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#28pc00000000005cb860/apex/com.android.runtime/lib64/libart.so(MterpInvokeVirtual+1432)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#29pc0000000000141814/apex/com.android.runtime/lib64/libart.so(mterp_op_invoke_virtual+20)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#30pc0000000000337c30/system/framework/framework.jar(android.os.Looper.loop+480)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#31pc00000000005ce408/apex/com.android.runtime/lib64/libart.so(MterpInvokeStatic+1136)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#32pc0000000000141994/apex/com.android.runtime/lib64/libart.so(mterp_op_invoke_static+20)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#33pc00000000001abfe0/system/framework/framework.jar(android.app.ActivityThread.main+1372)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#34pc00000000002ce22c/apex/com.android.runtime/lib64/libart.so(_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEbb.llvm.10887373532384510885+320)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#35pc00000000005bc090/apex/com.android.runtime/lib64/libart.so(artQuickToInterpreterBridge+1012)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#36pc0000000000150468/apex/com.android.runtime/lib64/libart.so(art_quick_to_interpreter_bridge+88)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#37pc00000000001475b8/apex/com.android.runtime/lib64/libart.so(art_quick_invoke_static_stub+568)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#38pc00000000001561d4/apex/com.android.runtime/lib64/libart.so(art::ArtMethod::Invoke(art::Thread*,unsignedint*,unsignedint,art::JValue*,charconst*)+284)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#39pc00000000004d8820/apex/com.android.runtime/lib64/libart.so(art::(anonymousnamespace)::InvokeWithArgArray(art::ScopedObjectAccessAlreadyRunnableconst&,art::ArtMethod*,art::(anonymousnamespace)::ArgArray*,art::JValue*,charconst*)+104)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#40pc00000000004da248/apex/com.android.runtime/lib64/libart.so(art::InvokeMethod(art::ScopedObjectAccessAlreadyRunnableconst&,_jobject*,_jobject*,_jobject*,unsignedlong)+1476)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#41pc000000000046412c/apex/com.android.runtime/lib64/libart.so(art::Method_invoke(_JNIEnv*,_jobject*,_jobject*,_jobjectArray*)+52)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#42pc00000000000f8c34/system/framework/arm64/boot.oat(art_jni_trampoline+180)(BuildId:8fb9eb57b3ea725573d56f165d17f78dd54965d7)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#43pc0000000000147334/apex/com.android.runtime/lib64/libart.so(art_quick_invoke_stub+548)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#44pc00000000001561b4/apex/com.android.runtime/lib64/libart.so(art::ArtMethod::Invoke(art::Thread*,unsignedint*,unsignedint,art::JValue*,charconst*)+252)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#45pc00000000002fd900/apex/com.android.runtime/lib64/libart.so(art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*,art::ArtMethod*,art::ShadowFrame*,unsignedshort,art::JValue*)+384)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#46pc00000000002f8bd0/apex/com.android.runtime/lib64/libart.so(boolart::interpreter::DoCall<false,false>(art::ArtMethod*,art::Thread*,art::ShadowFrame&,art::Instructionconst*,unsignedshort,art::JValue*)+912)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#47pc00000000005cb550/apex/com.android.runtime/lib64/libart.so(MterpInvokeVirtual+648)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#48pc0000000000141814/apex/com.android.runtime/lib64/libart.so(mterp_op_invoke_virtual+20)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#49pc000000000040010e/system/framework/framework.jar(com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run+22)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#50pc00000000002ce22c/apex/com.android.runtime/lib64/libart.so(_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEbb.llvm.10887373532384510885+320)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#51pc00000000005bc090/apex/com.android.runtime/lib64/libart.so(artQuickToInterpreterBridge+1012)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#52pc0000000000150468/apex/com.android.runtime/lib64/libart.so(art_quick_to_interpreter_bridge+88)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#53pc0000000000b253bc/system/framework/arm64/boot-framework.oat(com.android.internal.os.ZygoteInit.main+3660)(BuildId:839677a7635b67b1b883c48b6ed1ea5c4a581790)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#54pc00000000001475b8/apex/com.android.runtime/lib64/libart.so(art_quick_invoke_static_stub+568)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#55pc00000000001561d4/apex/com.android.runtime/lib64/libart.so(art::ArtMethod::Invoke(art::Thread*,unsignedint*,unsignedint,art::JValue*,charconst*)+284)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#56pc00000000004d8820/apex/com.android.runtime/lib64/libart.so(art::(anonymousnamespace)::InvokeWithArgArray(art::ScopedObjectAccessAlreadyRunnableconst&,art::ArtMethod*,art::(anonymousnamespace)::ArgArray*,art::JValue*,charconst*)+104)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#57pc00000000004d848c/apex/com.android.runtime/lib64/libart.so(art::InvokeWithVarArgs(art::ScopedObjectAccessAlreadyRunnableconst&,_jobject*,_jmethodID*,std::__va_list)+408)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#58pc00000000003d7cf8/apex/com.android.runtime/lib64/libart.so(art::JNI::CallStaticVoidMethodV(_JNIEnv*,_jclass*,_jmethodID*,std::__va_list)+660)(BuildId:08543716770b195bd10fafbe11bb5052)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#59pc00000000001015c4/system/lib64/libandroid_runtime.so(_JNIEnv::CallStaticVoidMethod(_jclass*,_jmethodID*,...)+116)(BuildId:034c759a360c29cae9a101b25604f692)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#60pc0000000000104c48/system/lib64/libandroid_runtime.so(android::AndroidRuntime::start(charconst*,android::Vector<android::String8>const&,bool)+1248)(BuildId:034c759a360c29cae9a101b25604f692)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#61pc00000000000034e0/system/bin/app_process64(main+1168)(BuildId:e844be217eb39b34490d3798328d1f12)2022-03-0715:09:01.37516908-16908/?A/DEBUG:#62pc000000000006b108/apex/com.android.runtime/lib64/bionic/libc.so(__libc_init+108)(BuildId:b91c775ccc9b0556e91bc575a2511cd0)2022-03-0715:09:01.40517145-17756/?E/X509CertUtil:cannotopencbgrootcer6. 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:dlopenfailed:cannotlocatesymbol"rand"6.3 未定義對 `_atomic*` 的引用

問題:某些 ABI 需要 libatomic 才能為原子操作提供一些實現。

解決方案:在鏈接時添加 -latomic。

對於以下錯誤消息:

error:undefinedreferenceto'__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開發過程中常見的問題,比如版本問題,定位符號失敗問題以及不同平台函數實現的差異等。後續可以持續維護迭代本文檔。

原文鏈接: https://juejin.cn/post/7083127329156759559


-- END --

進技術交流群,掃碼添加我的微信:Byte-Flow

獲取相關資料和源碼


推薦閱讀:

建議收藏 | Android JNI 相關文章匯總

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 鑽石舞台 的頭像
    鑽石舞台

    鑽石舞台

    鑽石舞台 發表在 痞客邦 留言(0) 人氣()