1. 程式人生 > >Android Studio下Ndk開發踩過的坑以及解辦法決

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)