Android Studio下Ndk開發踩過的坑以及解辦法決
Android studio在2.2之後是開始相容ndk的開發,嚐鮮用來本地開發,各種坑,不相容。之前用得好好的,一個升級AS或者NDK版本都會一不小心導致了編譯失敗,或者成功之後,載入不成功。故隨手筆記記錄下自己踩過的坑,也方便其他人查詢。
Trap One :
Causedby: java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "__aeabi_memcpy" referenced by **
原因:
情景一、AS配置Builde.grade來編譯生成so檔案。
升級AS之後,到2.3版本,新建的module預設配置builde.grade中Android sdk編譯版本,以及目標目標都會自動配置到最新版 本,這個時候就會容易沒有注意到新版本的sdk(version>23),這是24版本之後出現的bug,但不能低於9。
解決方式:把目標版本降低到23以及以下即可
詳細說明:http://stackoverflow.com/questions/39541599/error-loading-package-jni-cannot-locate-symbol-aeabi-memcpy
情景二、使用Ndk-build命令
修改Application.mk檔案中APP_PLATFORM所配置的版本要高於8以上,但不能高於23
Trap Two:
這個是STL配置錯誤導致的,檢視發現APP_STL := gnustl_shared 配置成共享型了。
APP_STL 可用值
stlport_static - 使用STLport作為靜態庫
stlport_shared - 使用STLport 作為共享庫
gnustl_static - 使用GNU libstdc++ 作為靜態庫
gnustl_shared - 使用GNU libstdc++ 作為共享庫
其中STLport和libstdc的區別詳見https://www.zhihu.com/question/20845153。建議配置成stlport_static
Trap Three: DeleteLocalRef error
在jni.h中定義void DeleteLocalRef(jobject localRef)函式刪除引用時,是針對嘗試jobject以及子類,如jstring,jclass,jobject
但是一些基本型別的 jboolean 、jmethodId 、jfieldId 缺不可以,否則會報編譯失敗。
Trap Three: local reference table overflow
JNI ERROR (app bug): local reference table overflow (max=512)05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] local reference table dump:
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] Last 10 entries (of 512):
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 511: 0x70473f60 java.lang.Class<java.io.BufferedWriter>
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 510: 0x70473f60 java.lang.Class<java.io.BufferedWriter>
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 509: 0x70473f60 java.lang.Class<java.io.BufferedWriter>
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 508: 0x70473f60 java.lang.Class<java.io.BufferedWriter>
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 507: 0x70473f60 java.lang.Class<java.io.BufferedWriter>
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 506: 0x70473f60 java.lang.Class<java.io.BufferedWriter>
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 505: 0x70473f60 java.lang.Class<java.io.BufferedWriter>
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 504: 0x70473f60 java.lang.Class<java.io.BufferedWriter>
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 503: 0x70473f60 java.lang.Class<java.io.BufferedWriter>
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 502: 0x70473f60 java.lang.Class<java.io.BufferedWriter>
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] Summary:
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 1 of cn.egame.terminal.paysdk.EgamePay$1
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 2 of dalvik.system.DexClassLoader (1 unique instances)
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 455 of java.lang.Class (14 unique instances)
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 39 of java.lang.String (39 unique instances)
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 1 of java.lang.Exception
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 1 of java.io.BufferedWriter
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 1 of java.io.FileInputStream
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 1 of java.security.MessageDigest$MessageDigestImpl
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 1 of java.util.TreeMap$KeySet$1
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 1 of java.util.TreeMap
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 3 of byte[] (162 elements) (3 unique instances)
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 1 of byte[] (4096 elements)
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 5 of java.io.File (5 unique instances)
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115]
05-19 12:53:40.564 32571-32667/com.sanguo.cdws A/art: art/runtime/runtime.cc:368] Runtime aborting...
在android nativie開發中jni區域性引用限制了512個LocalRef,如果建立了局部引用,如上述的 jclass、jstring、jobject等通過FindClass /NewString/ NewStringUTF/NewObject來產生了localRef。如果用完了(已經傳遞賦值了或者不再使用了),必須呼叫env->DeleteLocalRef來刪除,否則引用計數超過512就會導致執行終止,local reference table overflow。
同時有個不好習慣導致沒有刪除,習慣性直接FindClass /NewString/ NewStringUTF/NewObject來給函式直接賦值,沒有直接使用引用,並刪除,依然會被計數,如下程式碼:
這種方式直接導致區域性應用沒有被回收,迴圈中從而超過512個。必須直接寫出來,並刪除:
所以不能再偷懶了。
Trap four
dynamic section has invalid link(0) sh_type: 0 (expected SHT_STRTAB)
多見於載入so失敗,上層報UnsatisfiedLinkError 異常,由於google在Android 7.0 以後對so做了更加嚴格的限制,對於非標準so,比如section header缺失或者dynamic table中資料項不對,會直接崩潰,對於這類問題,可以過濾linker的log檢視logcat-s linker。
----結頭表裡面dynamic section 對應的sh_link欄位非法,這裡正常應該是字串表,如果不是字串表,就會報錯。
相關錯誤資訊:
xxx.so has invalid e_phnum
-----程式頭項數不對
xxx.so has no section headers
-----結頭丟失
xxx.so .dynamic section header was not found
-----動態結區丟失
xxx.so .dynamic section has invalid link(%d) sh_type: %d (expected SHT_STRTAB)
-----結頭表裡面dynamic section 對應的sh_link欄位非法,這裡正常應該是字串表,如果不是字串表,就會報錯。
xxx.so has invalid offset/size of .dynamic section
-----動態結區offset 校驗失敗
xxx.so: has text relocations
-----so有text 重定位section,對於targetSDK>22 會報錯。
Trap Five
error:only
position independent executables (PIE) are supported.
PIE這個安全機制從4.1引入,但是Android L之前的系統版本並不會去檢驗可執行檔案是否基於PIE編譯出的。因此不會報錯。
但是Android L已經開啟驗證,如果呼叫的可執行檔案不是基於PIE方式編譯的,則無法執行。解決辦法非常簡單,在Android.mk中加入如下flag就行。
LOCAL_CFLAGS +=-pie -fPIE
LOCAL_LDFLAGS +=-pie -fPIE
Trap six
make: *** No rule to make target
問題在Android.mk沒有配置好,之前配置多了字元
LOCAL_PATH:= $(call my-dir)