關(guān)于Android的.so文件你所需要知道的

原文鏈接

早期的Android系統(tǒng)幾乎只支持ARMv5的CPU架構(gòu)菠发,你知道現(xiàn)在它支持多少種嗎瓮床?7種志鹃!
Android系統(tǒng)目前支持以下七種不同的CPU架構(gòu):ARMv5,ARMv7 (從2010年起)烛卧,x86 (從2011年起),MIPS (從2012年起)妓局,ARMv8总放,MIPS64和x86_64 (從2014年起),每一種都關(guān)聯(lián)著一個(gè)相應(yīng)的ABI好爬。
應(yīng)用程序二進(jìn)制接口(Application Binary Interface)定義了二進(jìn)制文件(尤其是.so文件)如何運(yùn)行在相應(yīng)的系統(tǒng)平臺(tái)上局雄,從使用的指令集,內(nèi)存對(duì)齊到可用的系統(tǒng)函數(shù)庫(kù)存炮。在Android 系統(tǒng)上炬搭,每一個(gè)CPU架構(gòu)對(duì)應(yīng)一個(gè)ABI:armeabi蜈漓,armeabi-v7a,x86宫盔,mips融虽,arm64- v8a,mips64灼芭,x86_64有额。

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

如果項(xiàng)目中使用到了NDK,它將會(huì)生成.so文件姿鸿,因此顯然你已經(jīng)在關(guān)注它了谆吴。如果只是使用Java語(yǔ)言進(jìn)行編碼,你可能在想不需要關(guān)注.so文 件了吧苛预,因?yàn)镴ava是跨平臺(tái)的句狼。但事實(shí)上,即使你在項(xiàng)目中只是使用Java語(yǔ)言热某,很多情況下腻菇,你可能并沒(méi)有意識(shí)到項(xiàng)目中依賴的函數(shù)庫(kù)或者引擎庫(kù)里面已經(jīng) 嵌入了.so文件,并依賴于不同的ABI昔馋。
例如筹吐,項(xiàng)目中使用RenderScript支持庫(kù),OpenCV秘遏,Unity丘薛,android-gif-drawable,SQLCipher等邦危,你都已經(jīng)在生成的APK文件中包含.so文件了洋侨,而你需要關(guān)注.so文件。
Android應(yīng)用支持的ABI取決于APK中位于lib/ABI目錄中的.so文件倦蚪,其中ABI可能是上面說(shuō)過(guò)的七種ABI中的一種希坚。

關(guān)于Android的.so文件你所需要知道的

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

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

App中可能出錯(cuò)的地方

處理.so文件時(shí)有一條簡(jiǎn)單卻并不知名的重要法則蒜鸡。
你應(yīng)該盡可能的提供專為每個(gè)ABI優(yōu)化過(guò)的.so文件,但要么全部支持牢裳,要么都不支持:你不應(yīng)該混合著使用逢防。你應(yīng)該為###每個(gè)ABI目錄提供對(duì)應(yīng)的.so文件。
當(dāng)一個(gè)應(yīng)用安裝在設(shè)備上蒲讯,只有該設(shè)備支持的CPU架構(gòu)對(duì)應(yīng)的.so文件會(huì)被安裝忘朝。在x86設(shè)備上,libs/x86目錄中如果存在.so文件的 話判帮,會(huì)被安裝局嘁,如果不存在,則會(huì)選擇armeabi-v7a中的.so文件晦墙,如果也不存在悦昵,則選擇armeabi目錄中的.so文件(因?yàn)閤86設(shè)備也支 持armeabi-v7a和armeabi)。

其他地方也可能出錯(cuò)

當(dāng)你引入一個(gè).so文件時(shí)晌畅,不止影響到CPU架構(gòu)但指。我從其他開(kāi)發(fā)者那里可以看到一系列常見(jiàn)的錯(cuò)誤,其中最多的是"UnsatisfiedLinkError"抗楔,"dlopen: failed"以及其他類型的crash或者低下的性能:
使用android-21平臺(tái)版本編譯的.so文件運(yùn)行在android-15的設(shè)備上
使用NDK時(shí)棋凳,你可能會(huì)傾向于使用最新的編譯平臺(tái),但事實(shí)上這是錯(cuò)誤的谓谦,因?yàn)镹DK平臺(tái)不是后向兼容的,而是前向兼容的贪婉。推薦使用app的minSdkVersion對(duì)應(yīng)的編譯平臺(tái)反粥。
這也意味著當(dāng)你引入一個(gè)預(yù)編譯好的.so文件時(shí),你需要檢查它被編譯所用的平臺(tái)版本疲迂。

混合使用不同C++運(yùn)行時(shí)編譯的.so文件

.so文件可以依賴于不同的C++運(yùn)行時(shí)才顿,靜態(tài)編譯或者動(dòng)態(tài)加載∮容铮混合使用不同版本的C++運(yùn)行時(shí)可能導(dǎo)致很多奇怪的crash郑气,是應(yīng)該避免的。 作為一個(gè)經(jīng)驗(yàn)法則腰池,當(dāng)只有一個(gè).so文件時(shí)尾组,靜態(tài)編譯C++運(yùn)行時(shí)是沒(méi)問(wèn)題的忙芒,否則當(dāng)存在多個(gè).so文件時(shí),應(yīng)該讓所有的.so文件都動(dòng)態(tài)鏈接相同的 C++運(yùn)行時(shí)讳侨。
這意味著當(dāng)引入一個(gè)新的預(yù)編譯.so文件呵萨,而且項(xiàng)目中還存在其他的.so文件時(shí),我們需要首先確認(rèn)新引入的.so文件使用的C++運(yùn)行時(shí)是否和已經(jīng)存在的.so文件一致跨跨。
沒(méi)有為每個(gè)支持的CPU架構(gòu)提供對(duì)應(yīng)的.so文件
這一點(diǎn)在前文已經(jīng)說(shuō)到了潮峦,但你應(yīng)該真的特別注意它,因?yàn)樗赡馨l(fā)生在根本沒(méi)有意識(shí)到的情況下勇婴。
例如:你的app支持armeabi-v7a和x86架構(gòu)忱嘹,然后使用Android Studio新增了一個(gè)函數(shù)庫(kù)依賴,這個(gè)函數(shù)庫(kù)包含.so文件并支持更多的CPU架構(gòu)耕渴,例如新增android-gif-drawable函數(shù)庫(kù):

compile ‘pl.droidsonroids.gif:android-gif-drawable:1.1.+’

發(fā)布我們的app后拘悦,會(huì)發(fā)現(xiàn)它在某些設(shè)備上會(huì)發(fā)生Crash,例如Galaxy S6萨螺,最終可以發(fā)現(xiàn)只有64位目錄下的.so文件被安裝進(jìn)手機(jī)窄做。
解決方案:重新編譯我們的.so文件使其支持缺失的ABIs,或者設(shè)置

ndk.abiFilters

顯示指定支持的ABIs慰技。
最后一點(diǎn): 如果你是一個(gè)SDK提供者椭盏,但提供的函數(shù)庫(kù)不支持所有的ABIs,那你將會(huì)搞砸你的用戶吻商,因?yàn)樗麄兡苤С值腁BIs必將只能少于你提供的掏颊。

將.so文件放在錯(cuò)誤的地方

我們往往很容易對(duì).so文件應(yīng)該放在或者生成到哪里感到困惑,下面是一個(gè)總結(jié):
Android Studio工程放在jniLibs/ABI目錄中(當(dāng)然也可以通過(guò)在build.gradle文件中的設(shè)置jniLibs.srcDir屬性自己指定)
Eclipse工程放在libs/ABI目錄中(這也是ndk-build命令默認(rèn)生成.so文件的目錄)
AAR壓縮包中位于jni/ABI目錄中(.so文件會(huì)自動(dòng)包含到引用AAR壓縮包的APK中)
最終APK文件中的lib/ABI目錄中
通過(guò)PackageManager安裝后艾帐,在小于Android 5.0的系統(tǒng)中乌叶,.so文件位于app的nativeLibraryPath目錄中;在大于等于Android 5.0的系統(tǒng)中柒爸,.so文件位于app的nativeLibraryRootDir/CPU_ARCH目錄中准浴。

只提供armeabi架構(gòu)的.so文件而忽略其他ABIs的

所有的x86/x86_64/armeabi-v7a/arm64-v8a設(shè)備都支持armeabi架構(gòu)的.so文件,因此似乎移除其他ABIs的.so文件是一個(gè)減少APK大小的好技巧捎稚。但事實(shí)上并不是:這不只影響到函數(shù)庫(kù)的性能和兼容性乐横。
x86設(shè)備能夠很好的運(yùn)行ARM類型函數(shù)庫(kù),但并不保證100%不發(fā)生crash今野,特別是對(duì)舊設(shè)備葡公。64位設(shè)備(arm64-v8a, x86_64, mips64)能夠運(yùn)行32位的函數(shù)庫(kù),但是以32位模式運(yùn)行条霜,在64位平臺(tái)上運(yùn)行32位版本的ART和Android組件催什,將丟失專為64位優(yōu)化過(guò)的性 能(ART,webview宰睡,media等等)蒲凶。
以減少APK包大小為由是一個(gè)錯(cuò)誤的借口气筋,因?yàn)槟阋部梢赃x擇在應(yīng)用市場(chǎng)上傳指定ABI版本的APK,生成不同ABI版本的APK可以在build.gradle中如下配置:

android {
   ... 
   splits {
     abi {
       enable true
       reset()
       include 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a' //select ABIs to build APKs for
       universalApk true //generate an additional APK that contains all the ABIs
     }
   }
   // map for the version code
   project.ext.versionCodes = ['armeabi': 1, 'armeabi-v7a': 2, 'arm64-v8a': 3, 'mips': 5, 'mips64': 6, 'x86': 8, 'x86_64': 9]
   android.applicationVariants.all { variant ->
     // assign different version code for each output
     variant.outputs.each { output ->
       output.versionCodeOverride =
           project.ext.versionCodes.get(output.getFilter(com.android.build.OutputFile.ABI), 0) * 1000000 + android.defaultConfig.versionCode
     }
   }
}

原文 http://www.open-open.com/lib/view/open1440421271716.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末豹爹,一起剝皮案震驚了整個(gè)濱河市裆悄,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌臂聋,老刑警劉巖光稼,帶你破解...
    沈念sama閱讀 217,406評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異孩等,居然都是意外死亡艾君,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門肄方,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)冰垄,“玉大人,你說(shuō)我怎么就攤上這事权她『绮瑁” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,711評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵隅要,是天一觀的道長(zhǎng)蝴罪。 經(jīng)常有香客問(wèn)我,道長(zhǎng)步清,這世上最難降的妖魔是什么要门? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,380評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮廓啊,結(jié)果婚禮上欢搜,老公的妹妹穿的比我還像新娘。我一直安慰自己谴轮,他們只是感情好炒瘟,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著第步,像睡著了一般疮装。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上雌续,一...
    開(kāi)封第一講書(shū)人閱讀 51,301評(píng)論 1 301
  • 那天斩个,我揣著相機(jī)與錄音胯杭,去河邊找鬼驯杜。 笑死,一個(gè)胖子當(dāng)著我的面吹牛做个,可吹牛的內(nèi)容都是我干的鸽心。 我是一名探鬼主播滚局,決...
    沈念sama閱讀 40,145評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼顽频!你這毒婦竟也來(lái)了藤肢?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,008評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤糯景,失蹤者是張志新(化名)和其女友劉穎嘁圈,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體蟀淮,經(jīng)...
    沈念sama閱讀 45,443評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡最住,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了怠惶。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片涨缚。...
    茶點(diǎn)故事閱讀 39,795評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖策治,靈堂內(nèi)的尸體忽然破棺而出脓魏,到底是詐尸還是另有隱情,我是刑警寧澤通惫,帶...
    沈念sama閱讀 35,501評(píng)論 5 345
  • 正文 年R本政府宣布茂翔,位于F島的核電站,受9級(jí)特大地震影響讽膏,放射性物質(zhì)發(fā)生泄漏檩电。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評(píng)論 3 328
  • 文/蒙蒙 一府树、第九天 我趴在偏房一處隱蔽的房頂上張望俐末。 院中可真熱鬧,春花似錦奄侠、人聲如沸卓箫。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,731評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)烹卒。三九已至,卻和暖如春弯洗,著一層夾襖步出監(jiān)牢的瞬間旅急,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,865評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工牡整, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留藐吮,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,899評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像谣辞,于是被迫代替她去往敵國(guó)和親迫摔。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容