自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

在安卓項目里部署so文件你需要知道的知識

移動開發(fā) Android
Android系統(tǒng)目前支持以下七種不同的CPU架構(gòu):ARMv5,ARMv7 (從2010年起),x86 (從2011年起),MIPS (從2012年起),ARMv8,MIPS64和x86_64 (從2014年起),每一種都關(guān)聯(lián)著一個相應(yīng)的ABI。

在安卓項目里部署so文件你需要知道的知識

1. 什么是CPU架構(gòu)及ABI

Android系統(tǒng)目前支持以下七種不同的CPU架構(gòu):ARMv***RMv7 (從2010年起),x86 (從2011年起),MIPS (從2012年起),ARMv8,MIPS64和x86_64 (從2014年起),每一種都關(guān)聯(lián)著一個相應(yīng)的ABI。

應(yīng)用程序二進(jìn)制接口(Application Binary Interface)定義了二進(jìn)制文件(尤其是.so文件)如何運行在相應(yīng)的系統(tǒng)平臺上,從使用的指令集、內(nèi)存對齊到可用的系統(tǒng)函數(shù)庫。在Android系統(tǒng)上,每一個CPU架構(gòu)對應(yīng)一個ABI:armeabi,armeabi-v7a,x86,mips,arm64-v8a,mips64,x86_64。

2. 為什么需要重點關(guān)注.so文件

如果項目中使用到了NDK,它將會生成.so文件,因此顯然你已經(jīng)在關(guān)注它了。如果只是使用Java語言進(jìn)行編碼,你可能在想不需要關(guān)注.so文件了吧,因為Java是跨平臺的。但事實上,即使你在項目中只是使用Java語言,很多情況下,你可能并沒有意識到項目中依賴的函數(shù)庫或者引擎庫里面已經(jīng)嵌入了.so文件,并依賴于不同的ABI。例如,項目中使用RenderScript支持庫,OpenCV,Unity,android-gif-drawable,SQLCipher等,你都已經(jīng)在生成的APK文件中包含.so文件了,而你需要關(guān)注.so文件。

Android應(yīng)用支持的ABI取決于APK中位于lib/ABI目錄中的.so文件,其中ABI可能是上面說過的七種ABI中的一種。

Native Libs Monitor這個應(yīng)用可以幫助我們理解手機(jī)上安裝的APK用到了哪些.so文件,以及.so文件來源于哪些函數(shù)庫或者框架。當(dāng)然,我們也可以自己對APP反編譯來獲取這些信息,不過相對麻煩一些。

很多設(shè)備都支持多于一種的ABI,例如ARM64和x86設(shè)備也可以同時運行armeabi-v7a和armeabi的二進(jìn)制包。但***是針對特定平臺提供相應(yīng)平臺的二進(jìn)制包,這種情況下運行時就少了一個模擬層(例如x86設(shè)備上模擬arm的虛擬層),從而得到更好的性能(歸功于最近的架構(gòu)更新,例如硬件fpu,更多的寄存器,更好的向量化等)。我們可以通過Build.SUPPORTED_ABIS得到根據(jù)偏好排序的設(shè)備支持的ABI列表。但你不應(yīng)該從你的應(yīng)用程序中讀取它,因為Android包管理器安裝APK時,會自動選擇APK包中為對應(yīng)系統(tǒng)ABI預(yù)編譯好的.so文件,如果在對應(yīng)的lib/ABI目錄中存在.so文件的話。

3. .so文件應(yīng)該放在什么地方

我們往往很容易對.so文件應(yīng)該放在或者生成到哪里感到困惑,下面是一個總結(jié):

  • Android Studio工程放在main/jniLibs/ABI目錄中(當(dāng)然也可以通過在build.gradle文件中的設(shè)置jniLibs.srcDir屬性自己指定)
  • Eclipse工程放在libs/ABI目錄中(這也是ndk-build命令默認(rèn)生成.so文件的目錄)
  • AAR壓縮包中位于jni/ABI目錄中(.so文件會自動包含到引用AAR壓縮包的APK中)
  • 最終APK文件中的lib/ABI目錄中
  • 通過PackageManager安裝后,在小于Android 5.0的系統(tǒng)中,.so文件位于app的nativeLibraryPath目錄中;在大于等于Android 5.0的系統(tǒng)中,.so文件位于app的nativeLibraryRootDir/CPU_ARCH目錄中。

4. 安裝Apk時PackageManagerService選擇解壓so文件的策略

在Android系統(tǒng)中,當(dāng)我們安裝Apk文件的時候,lib目錄下的so文件會被解壓App的原生庫目錄,一般來說是放到/data/data/package-name/lib目錄下,而根據(jù)系統(tǒng)和CPU架構(gòu)的不同,其拷貝策略也是不一樣的,不正確地配置so文件,比如某些App使用第三方的so時,只配置了其中某一種CPU架構(gòu)的so,可能會造成App在某些機(jī)型上的適配問題。

Android版本

so拷貝策略

策略問題

 

在安卓項目里部署so文件你需要知道的知識在安卓項目里部署so文件你需要知道的知識

5. 配置so的建議

針對Android 系統(tǒng)的這些拷貝策略的問題,我們給出了一些配置so的建議:

5.1 針對armeabi和armeabi-v7a兩種ABI

  • 方法1:由于armeabi-v7a指令集兼容armeabi指令集,所以如果損失一些應(yīng)用的性能是可以接受的,同時不希望保留庫的兩份拷貝,可以移除armeabi-v7a目錄和其下的庫文件,只保留armeabi目錄;比如Apk使用第三方的so只有armeabi這一種ABI時,可以考慮去掉Apk中l(wèi)ib目錄下armeabi-v7a目錄。
  • 方法2:在armeabi和armeabi-v7a目錄下各放入一份so。

5.2 針對x86

目前市面上的x86機(jī)型,為了兼容arm指令,基本都內(nèi)置libhoudini模塊,即二進(jìn)制轉(zhuǎn)碼支持,該模塊負(fù)責(zé)把ARM指令轉(zhuǎn)換為x86指令,所以如果是出于Apk包大小的考慮,并且可以接受一些性能損失,可以選擇刪掉x86庫目錄,x86下配置的armeabi目錄的so庫一樣可以正常加載使用。

5.3 針對64位ABI

如果App開發(fā)者打算支持64位,那么64位的so要放全,否則可以選擇不單獨編譯64位的so,全部使用32位的so,64位機(jī)型默認(rèn)支持32位so的加載。比如Apk使用第三方的so只有32位ABI的so,可以考慮去掉Apk中l(wèi)ib目錄下的64位ABI子目錄,保證Apk安裝后正常使用。

5. Android Studio配置abiFilters

 

  1. android {  
  2. defaultConfig {  
  3. ndk {  
  4. abiFilters 'armeabi-v7a' //, 'armeabi''arm64-v8a''x86''x86_64''mips''mips64'  
  5.  
  6.  

這句話的意思就是指定NDK需要兼容的架構(gòu),把除了armeabi-v7a以外的兼容包都過濾掉,只剩下一個armeabi-v7a的文件夾。

即使我們沒有指定其他的兼容框架,也需要一個過濾。當(dāng)我們接入多個第三方庫時,很可能第三方庫做了多個平臺的兼容。譬如fresco就做了各個平臺的兼容,所以它創(chuàng)建了各個兼容平臺的目錄。因為只要出現(xiàn)了這個目錄,系統(tǒng)就只會在這個目錄里找.so文件而不會遍歷其他的目錄,所以就出現(xiàn)了找不到.so文件的情況。

6. java.lang.UnsatisfiedLinkError

該錯誤類型較多,以下進(jìn)行分類:

 

  1. java.lang.UnsatisfiedLinkError : dlopen failed: library //dlopen打開失敗  
  2. java.lang.UnsatisfiedLinkError :findLibrary returned null //找不到library  
  3. java.lang.UnsatisfiedLinkError : Native method not found //找不到對應(yīng)函數(shù) 
  4.  java.lang.UnsatisfiedLinkError :Cannot load library: load_library //無法load library 

出現(xiàn)原因:

顯然出現(xiàn)上述崩潰的根本原因是:

  • (1)so無法加載,可能是so不存在等原因
  • (2)so正常加載,但是沒有找到相應(yīng)的函數(shù)

針對第二個原因,顯然相對來說很容易排查,而且在開發(fā)中,這樣的函數(shù)調(diào)用必然會在編譯時和debug模式下進(jìn)行測試,所以這種原因產(chǎn)生的概率很小。

那么下面主要總結(jié)幾類“so無法加載”而導(dǎo)致上述崩潰的幾種原因:

6.1 生成的so本身缺陷

一個簡單的例子:

crash堆棧:

 

  1. java.lang.UnsatisfiedLinkError: Cannot load library: find_library(linker.cpp:889): "/data/data/com.netease.nis.apptestunit/app_lib/libdemo.so" failed to load previously 
  2. at java.lang.Runtime.load(Runtime.java:340)  
  3. at java.lang.System.load(System.java:521)  
  4. at com.netease.nis.bugrpt.ReLinker.loadLibrary(ReLinker.java:76)  
  5. at com.example.crash.MainActivity.onCreate(MainActivity.java:272)  
  6. at android.app.Activity.performCreate(Activity.java:5220)  
  7. at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1086)  
  8. at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2193)  
  9. at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2279)  
  10. at android.app.ActivityThread.access$600(ActivityThread.java:142)  
  11. at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1272)  
  12. at android.os.Handler.dispatchMessage(Handler.java:99)  
  13. at android.os.Looper.loop(Looper.java:137)  
  14. at android.app.ActivityThread.main(ActivityThread.java:5105)  
  15. at java.lang.reflect.Method.invokeNative(Native Method)  
  16. at java.lang.reflect.Method.invoke(Method.java:511)  
  17. at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)  
  18. at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)  
  19. at dalvik.system.NativeStart.main(Native Method) 

解決方法:

查看原項目Application.mk,發(fā)現(xiàn)APP_STL := gnustl_shared。原方案使用的是共享庫,這不一定都支持所有的機(jī)型,改用靜態(tài)庫gnustl_static問題解決。

對應(yīng)的在Android Studio中需要將共享庫改用靜態(tài)庫gnustl_static。這一類關(guān)于so編譯共享庫問題,需要進(jìn)行檢查。

 

  1. APP_STL 可用值  
  2. system 系統(tǒng)默認(rèn)  
  3. stlport_static - 使用STLport作為靜態(tài)庫  
  4. stlport_shared - 使用STLport 作為共享庫  
  5. gnustl_static - 使用GNU libstdc++ 作為靜態(tài)庫  
  6. gnustl_shared - 使用GNU libstdc++ 作為共享庫 

上述例子只是一個簡單的例子,可能在so編譯生成時,由于沒有考慮共享庫的機(jī)型匹配等原因?qū)е耈nsatisfiedLinkError崩潰,其次是64位32位系統(tǒng)架構(gòu)問題,也可能導(dǎo)致UnsatisfiedLinkError崩潰。

6.2 手機(jī)設(shè)備沒有空間

在so正確生成情況下,會根據(jù)設(shè)置的支持so庫框架生成對應(yīng)的庫。在Android系統(tǒng)中,當(dāng)我們安裝Apk文件的時候,lib目錄下的so文件會被解壓到App的原生庫目錄,一般來說是放到/data/data/package-name/lib目錄下,當(dāng)準(zhǔn)備加載native層的so時,雖然在Apk中有對應(yīng)的so文件,但是由于手機(jī)設(shè)備沒有足夠的空間加載該so,導(dǎo)致加載失敗,產(chǎn)生上述崩潰。

6.3 so配置錯誤

倘若so正確生成,且手機(jī)空間充足,那么如上所述,在Android系統(tǒng)中,當(dāng)我們安裝Apk文件的時候,lib目錄下的so文件會被解壓到App的原生庫目錄,一般來說是放到/data/data/package-name/lib目錄下。但是根據(jù)系統(tǒng)和CPU架構(gòu)的不同,其拷貝策略也是不一樣的。倘若不正確地配置了so文件,比如某些App使用第三方的so時,只配置了其中某一種CPU架構(gòu)的so,可能會造成App在某些機(jī)型上的適配問題,產(chǎn)生上述崩潰。

6.4 Android的PackageManager安裝問題

用戶安裝了與手機(jī)CPU架構(gòu)不符的Apk安裝包,或者App升級過程中因各種原因未正確釋放so文件。這種問題可以使用ReLinker解決。

使用ReLinker十分簡單,使用

  1. ReLinker.loadLibrary(context, “mylibrary”) 

代替標(biāo)準(zhǔn)的即可。

  1. System.loadLibrary(“mylibrary”); 
責(zé)任編輯:未麗燕 來源: 程序師
相關(guān)推薦

2022-02-09 16:25:34

區(qū)塊鏈技術(shù)加密貨幣

2011-09-20 10:56:35

云計算PaaS

2018-09-10 09:26:33

2022-04-29 09:00:00

Platform架構(gòu)內(nèi)核線程

2022-08-10 09:03:35

TypeScript前端

2021-07-26 10:48:47

Kafka

2011-12-13 10:16:34

2023-09-08 13:46:12

ArrayList數(shù)據(jù)存儲容器

2024-01-24 11:59:44

Django自定義字段Python

2024-06-04 16:51:11

2018-05-30 15:15:47

混合云公共云私有云

2019-10-23 10:36:46

DevSecOpsDevOps

2014-07-31 17:13:50

編碼程序員

2020-03-27 12:30:39

python開發(fā)代碼

2023-01-30 11:43:04

開源代碼

2018-02-08 08:08:12

2020-09-08 08:27:25

JavaScript模塊ECMAScript

2014-09-01 14:31:11

2012-07-27 09:25:40

2023-01-09 17:23:14

CSS技巧
點贊
收藏

51CTO技術(shù)棧公眾號