Android 應(yīng)用開發(fā)者應(yīng)該對 UnsatisfiedLinkError 這種類型的錯(cuò)誤比較熟悉了,這個(gè)問題一直困擾著廣大的開發(fā)者,,那么有沒有想過有可能你什么都沒做錯(cuò),也會(huì)出現(xiàn)這個(gè)問題呢,? 我們在 Android 應(yīng)用開發(fā)測試過程中曾經(jīng)碰到過這樣的案例,,apk 在某機(jī)型上安裝完成之后運(yùn)行即崩潰,報(bào)錯(cuò) UnsatisfiedLinkError,。 java.lang.UnsatisfiedLinkError: Couldn’t load mobsec from loader dalvik.system.PathClassLoader.....findLibrary returned null 首先懷疑是在 apk 中相應(yīng)的 libs\abi 目錄下沒有放置 libmobsec.so,,然而檢查發(fā)現(xiàn)這個(gè) so 在所有的 libs\abi 下都有放置過,,繼續(xù)排查; 然后的想法是放置的 so 不是對應(yīng) abi 的,,比如由于粗心在 armeabi 目錄下放置了 x86 指令集的 so,,導(dǎo)致在 armeabi 指令集手機(jī)上加載出錯(cuò),,這個(gè)也被排除掉; 就在沒有頭緒的時(shí)候,想到 System.loadLibrary 函數(shù)加載 so 時(shí),,系統(tǒng)是從指定的路徑下加載的,那么這個(gè)路徑下 so 是否存在呢? 我們知道應(yīng)用的私有 Native library 目錄 /data/data/packagename/lib 是一個(gè)符號鏈接,,鏈接到 /data/app-lib/<package name> 目錄,System.loadLibrary 是到這個(gè)目錄去嘗試加載 so 的,。 adb shell 到這個(gè)路徑下,使用命令 ls 查看,,果然這個(gè) libmobsec.so 是不存在的,。那么是什么原因?qū)е碌哪兀?/p> 分析 Android 系統(tǒng)源碼的實(shí)現(xiàn),,發(fā)現(xiàn) /data/app-lib/<package name> 這個(gè)目錄下的 so ,是在系統(tǒng)安裝 apk 時(shí)從 apk 的 lib 目錄下去抽取的,。 在安裝 app 時(shí),Android package manager 代碼需要分析當(dāng)前手機(jī)支持的指令集并拷貝相關(guān)指令集的 so,。從 Android2.X 到 Android6.0 系統(tǒng),由于相繼加入了 x86,、64位等指令集的支持,這一部分代碼處理邏輯有不少變動(dòng),,然而這個(gè)代碼是存在邏輯缺陷的,,存在遺漏拷貝的可能,導(dǎo)致在一些機(jī)型上并不一定保證所有的 so 都能被正確抽取到 /data/app-lib/<package name> 目錄下,,從而導(dǎo)致應(yīng)用在加載 so 的時(shí)候出現(xiàn) UnsatisfiedLinkError 這樣的錯(cuò)誤。 已經(jīng)有開發(fā)者意識到這個(gè) bug,,比如在 Chromium 的源代碼的一段注釋,說明了 Android package manager 中的問題:
“在 Android 平臺上加載本地庫的危險(xiǎn)性”這篇文章中提到了作者遇到同樣的問題,,并基于 Chromium 給出的一種權(quán)宜的解決辦法:封裝 System.loadLibrary 接口為 ReLinker 接口,,如果發(fā)現(xiàn)無法正常加載 so,,則獲取 apk 路徑并解壓相應(yīng)指令集的 so,,然后嘗試去加載。這種方案經(jīng)過驗(yàn)證是可以顯著減少 UnsatisfiedLinkError 錯(cuò)誤的出現(xiàn),,下圖為作者使用了 ReLinker 接口后的日上報(bào) UnsatisfiedLinkError 錯(cuò)誤數(shù)的變化趨勢圖。 ReLinker 接口現(xiàn)在已經(jīng)集成到網(wǎng)易云捕的SDK中,,使用方法如下: 用
來代替
|
|