【教程】Android x86的arm兼容庫移植--初步分析及嘗試手動移植houdini/ndk翻譯庫

適用于x86架構(gòu)的安卓5.0以上需要root,或者離線改文件,但并非全部適用;本文僅為個人經(jīng)驗,未涵蓋的地方需要自行探索。

簡略版以及移植演示,請參考視頻。需要了解一些東西的初步概念以理解本文再謹(jǐn)慎動手實踐,若不了解,請先在模擬環(huán)境測試環(huán)境下嘗試,備份資料。
Houdini兼容庫(Intel)與NDK_Translation兼容庫(Google)是目前x86處理器運(yùn)行安卓時兼容arm應(yīng)用的兩種方案。本篇文章參考安卓x86各處的源碼,Android-x86項目與Bliss-x86項目的一些文件,還有bliss os開發(fā)人員寫的兼容庫配置腳本(https://github.com/casualsnek/waydroid_script/blob/main/waydroid_extras.py)以嘗試實現(xiàn)手動移植這些兼容庫。(若要在編譯x86安卓時包含兼容庫,請移步其他教程)
網(wǎng)上已經(jīng)存在Android-x86項目的arm兼容啟用教程,特別對于在sfs格式的只讀system系統(tǒng)目錄情況,本篇文章將不適用,請移步網(wǎng)上教程。
其中有些網(wǎng)上的教程還會配置L3級別的widevine,這里不講。
簡述waydroid的腳本的配置過程(install_houdini()與install_ndk()部分):
掛載系統(tǒng)鏡像,下載壓縮包驗證解壓,擴(kuò)容鏡像(waydroid部分不詳述)
設(shè)置兼容庫文件權(quán)限為可執(zhí)行
復(fù)制文件到系統(tǒng)鏡像 ①
添加內(nèi)容到build.prop ③
添加內(nèi)容到init.rc ②
卸載鏡像
針對以上三個序號①②③分別展開

①兼容庫文件構(gòu)成
(不同安卓版本的文件可能稍不同,不同的來源也可能目錄結(jié)構(gòu)均有不同,因此可有多種,但目錄結(jié)構(gòu)是由相關(guān)配置或者是動態(tài)庫的預(yù)設(shè)位置關(guān)聯(lián)的,因此應(yīng)盡量與移植來源一致)
兼容庫文件權(quán)限設(shè)置
其中l(wèi)ib和etc目錄下,相關(guān)的文件夾權(quán)限均為drwxr-xr-x (755),相關(guān)的文件權(quán)限為-rw-r--r-- (644),bin目錄下的相關(guān)可執(zhí)行文件權(quán)限為-rwxr-xr-x (755)
預(yù)先說明:部分目錄結(jié)構(gòu)含有以下文件不會列出,會在后邊詳細(xì)說明

以下為兼容庫文件如何構(gòu)成的一些例子,移植時可以盡量參考。同時,部分兼容庫可能會存放于vendor中,甚至是各種軟鏈接,需要弄清楚它們關(guān)聯(lián)
圖例顏色說明:

一、Houdini(經(jīng)典目錄結(jié)構(gòu)):

二、Houdini(waydroid目錄結(jié)構(gòu),linker在bin的arm文件夾中)

三、Houdini (remix os 5.1版本目錄結(jié)構(gòu),houdini可執(zhí)行文件以及l(fā)ibhoudini.so動態(tài)庫在/lib/arm/下;類似的,許多安卓模擬器的houdini均在此文件夾,但libhoudini.so在原位置)

Ndk_Translation,9.0及以上,9.0目前有32位版本,9.0與11.0以上有所不同
四、Ndk_Translation(waydroid目錄結(jié)構(gòu),與11.0類似)

五、Ndk_Translation(9.0版本32位目錄結(jié)構(gòu))


②binfmt_misc注冊arm二進(jìn)制執(zhí)行文件
關(guān)于這個模塊,可以閱讀https://blog.csdn.net/whatday/article/details/88299482/ 以了解更多。
上邊已提前說明部分目錄結(jié)構(gòu)包含binfmt_misc,在不同的設(shè)備/系統(tǒng)上,這部分的支持可以在超級多的地方,但主要是一個工作:在系統(tǒng)初始化時,將binfmt_misc目錄下的那些內(nèi)容拷貝到/proc/sys/fs/binfmt_misc/register 下進(jìn)行注冊。以下舉多種例子:
一、Waydroid配置腳本的內(nèi)容過程解釋:
先找到init.rc(在舊版本中init.rc位于根目錄/ramdisk,在新版本中init.rc位于/system/etc/init/hw/),然后將以下內(nèi)容拷貝進(jìn)去:

解釋以上配置文本:在初始化早期,掛載binfmt_misc;檢測具有“啟用兼容庫的執(zhí)行=√”這個屬性時,注冊內(nèi)容
二、谷歌AS模擬器,安卓9 x86的32位:
system\etc\init\ndk_translation.rc的內(nèi)容:(與waydroid有些類似)

三、chrome os (部分機(jī)型,此內(nèi)容查看于guybrush機(jī)型)
安卓容器根目錄中的init.bertha.rc 部分內(nèi)容:

四、Android-x86項目和Bliss OS等系統(tǒng),部分安卓模擬器:


可以看到Android-x86項目在系統(tǒng)初始化時將腳本文件enable_nativebridge設(shè)置成了一個服務(wù),引入了一個屬性persist.sys.nativebridge來控制服務(wù)的運(yùn)行與終止。同時enable_nativebridge中也是關(guān)于binfmt_misc的配置。一些模擬器則會改動很多,注冊的內(nèi)容可能還會在其他地方
參考其中一種arm_dyn和arm_exe及其文本內(nèi)容,
由名字可猜測分別對應(yīng)動態(tài)庫和可執(zhí)行程序,而里邊的注冊內(nèi)容尾部也標(biāo)定了arm代碼由哪個文件執(zhí)行。對于houdini,則指定houdini文件的存放位置;對于ndk翻譯庫,則指定ndk_translation_program_runner_binfmt_misc文件的存放位置。其余部分詳解網(wǎng)上有,移植時基本上照搬即可。在移植翻譯庫時除了復(fù)制這些文件,也應(yīng)考慮如何適配這個binfmt_misc的注冊。

③build.prop, default.prop等系統(tǒng)屬性內(nèi)容配置
1.參考waydroid配置腳本內(nèi)容:

2.參考Android-x86配置內(nèi)容:

3.參考谷歌AS模擬器9.0 x86 32位:

4.參考chrome os,安卓11子系統(tǒng),ndk翻譯器:


總結(jié)以上例子:這些屬性中,部分屬性是可選的,而部分屬性是必選,但其位置很可能在各種地方,如default.prop或vendor下的build.prop,以下為這些屬性總結(jié):
1.abi列表:根據(jù)需要,增加或刪除abi,以及調(diào)整abi順序
上邊中,第一行包含全部abi及優(yōu)先級(arm64優(yōu)先級最低),第二第三行分別對應(yīng)32位abi和64位abi。這幾行abi屬性影響應(yīng)用安裝與運(yùn)行,大多數(shù)情況,應(yīng)用安裝包根據(jù)此處判斷是否支持的abi以及優(yōu)先使用的abi。
2. ro.dalvik.vm.isa.arm64=x86_64和ro.dalvik.vm.isa.arm=x86
這兩個,如果含有64位或32位arm翻譯庫,則prop應(yīng)包含對應(yīng)的那行屬性,具體作用網(wǎng)上有介紹
3. ro.enable.native.bridge.exec=1
這一行屬性是安卓系統(tǒng)啟用兼容庫的標(biāo)志,也可能與binfmt_misc在rc文件的的注冊代碼有關(guān);部分包含64位翻譯庫的系統(tǒng)包含ro.enable.native.bridge.exec64=1,這應(yīng)該由系統(tǒng)配置,或者init.rc相關(guān)的內(nèi)容決定其作用,依情況添加
4. ro.dalvik.vm.native.bridge
這一個屬性很重要,其后參數(shù)代表使用的翻譯庫名稱,指向system的lib或lib64目錄下的對應(yīng)文件。同時這一行屬性一般可能在根目錄的default.prop,部分系統(tǒng)則在build.prop
其后在目前有三種可能:
????①libhoudini.so,使用houdini兼容庫
????②libndk_translation.so,使用ndk_translation兼容庫
????③libnb.so,使用Android-x86項目特有的中間層,其動態(tài)庫位置由源代碼指定(詳細(xì)后講)
5. persist.sys.nativebridge
Android-x86項目特有的屬性,控制enable_nativebridge服務(wù)的運(yùn)行與終止,以及決定libnb是否起作用。在系統(tǒng)設(shè)置中有其對應(yīng)的開關(guān)。
6. dalvik.vm.isa.{abi}.variant;dalvik.vm.isa.{abi}.features
一般原系統(tǒng)已定義,不同設(shè)備(比如atom處理器的平板)可能會有不同的特殊的參數(shù),模擬器和Android-x86一般都是默認(rèn);其中AS模擬器額外添加了arm的屬性
7.其他可選
一些尚未知曉其作用的屬性,如ro.ndk_translation.version,參考兼容庫的移植來源。

額外說明?
1. houdini 兼容庫存在x,y,z這三種版本,同時具有基本對應(yīng)的安卓版本,可執(zhí)行的houdini和libhoudini.so中均可獲取版本號。版本號形式舉個例子:
Houdini 9.0.5c_y.51331
9.0.5c為大版本號,9對應(yīng)安卓9;51331為小版本號,可作為區(qū)分更細(xì)版本。中間的y即代表y版本。含義——
????x:32位系統(tǒng)內(nèi)核的arm32翻譯庫(x86→arm),
????y:64位系統(tǒng)內(nèi)核的arm32翻譯庫(x86_64→arm),
????z:64位系統(tǒng)內(nèi)核的arm64翻譯庫(x86_64→arm64)。
NDK翻譯庫應(yīng)該也是這么區(qū)分兩種32位模式,但是難以辨別,要從移植來源確認(rèn)是32位還是64位linux內(nèi)核。
?
最前邊的數(shù)字存在特例,安卓7的x版本使用的是houdini 6.1.2d_x,但部分模擬器用的libhoudini.so是7.1.1b_x(安卓9.0也能用houdini8)。此外安卓5存在houdini5.0.*和houdni5.2.*,部分使用houdini5.0.*的英特爾cpu的安卓5設(shè)備不能使用houdini5.2.*,原因是那些設(shè)備的安卓系統(tǒng)缺少部分源代碼,以致不兼容新的houdini5.2.*。改動內(nèi)容可以參考https://github.com/iConsole/Console-OS_art/commits/consoleos-lollipop
2.?部分包含houdini兼容庫的Android-x86系統(tǒng)存在/system/vendor/etc/misc/目錄,包含三個文件:
?????? .OEMBlackList
?????? .OEMWhiteList
?????? .ThirdPartySO
其作用在Android-x86源碼可查(https://osdn.net/projects/android-x86/scm/git/frameworks-base/commits/280957b03c2c36535975d43ef5c0b0a1b8ad2c87?)需要系統(tǒng)代碼支持,
功能簡述:含有這些文件的系統(tǒng),開啟了“國產(chǎn)app兼容性檢查”。這個檢查會將那些有x86庫但缺斤少兩,或者用arm庫以次充好的那些app,均安裝arm的版本而不是x86版本。
?????? .OEMWhiteList:對這個名單的app關(guān)閉這個檢查功能,有x86庫就裝x86
?????? .OEMBlackList:對這個名單的app強(qiáng)制安裝arm版本
?????? .ThirdPartySO:包含第三方庫的列表,以供檢查
另外,adb調(diào)試可以用 adb install --abi {abi名稱} {apk路徑} 命令以指定abi來安裝應(yīng)用;而Android系統(tǒng)在shell可以用 pm install --abi {abi名稱} {apk路徑} 命令以指定abi安裝應(yīng)用(pm需要root權(quán)限,且低版本安卓的pm沒有指定abi的功能)
3.?libnb.so庫:這是屬于Android-x86特有的一個中間層,可以找到其源碼。其內(nèi)容標(biāo)定了libhoudini.so的存放位置(因此remix os等可以將這個庫挪到其他地方);同時源碼中含有讀取persist.sys.nativebridge屬性,以決定是否啟用兼容;源碼中還含有其他調(diào)用兼容庫的中間層函數(shù),但目前僅針對houdini優(yōu)化,因此,若移植ndk_translation則不應(yīng)使用libnb。
Remix OS的libnb源碼:https://github.com/JideTechnology/remixos-device-generic-common/blob/jide_x86_lollipop/nativebridge/src/libnb.cpp
4.?翻譯庫移植來源:鑒于目前可用的翻譯庫均是閉源產(chǎn)品,使用應(yīng)該低調(diào)些,在以下地方等等可以提取
Houdini:
①Android-x86項目的下載鏈接,比如若要下載houdini5_z,則從這個網(wǎng)址以5_z為版本下載
http://dl.android-x86/houdini.php?v=5_z
http://dl.android-x86.org/houdini/5_z/houdini.sfs
②各種市面的安卓模擬器(夜神、雷電、逍遙等等)
③Win11的安卓子系統(tǒng)
④一些Android x86系統(tǒng),如bliss os,prime os,以前的remix os,鳳凰os等等
⑤Intel處理器的chrome os刷機(jī)包內(nèi)的安卓子系統(tǒng)可能含有
⑥寨板、zenfone2手機(jī)等intel處理器的安卓設(shè)備(Android IA)的刷機(jī)包含有
注:houdini自8.0開始就沒有發(fā)布x版本,8.0僅發(fā)布了y版本,10.0則完全沒有發(fā)布
?
NDK_Translation:
①谷歌Android Studio模擬器,含有g(shù)oogle api的鏡像,其中安卓9的x86,安卓11的x86和x86_64,安卓12 x86_64會含有
②部分AMD處理器的chrome os設(shè)備的刷機(jī)包的安卓子系統(tǒng)會含有
③部分bliss os鏡像,waydroid的GitHub資源等等也含有移植過來的翻譯庫
移植過程大致總結(jié):
1. 獲取/提取兼容庫,參考兼容庫目錄文件構(gòu)成,將文件復(fù)制過去,需要注意兼容庫版本,目標(biāo)系統(tǒng)空間剩余
2. 對復(fù)制后的兼容庫文件/文件夾進(jìn)行權(quán)限設(shè)置
3. 配置binfmt_misc,參考上邊的過程類似;
?????? 常見的有:
?????? ①根目錄下的init.rc或init.{機(jī)型相關(guān)}.rc中包含部分注冊內(nèi)容,這些內(nèi)容將/system/etc/binfmt_misc/下的配置進(jìn)行注冊;
?????? ②/system/etc/init/,或/vendor/etc/等附近與init有關(guān)的rc文件,也與①類似;
?????? ③Android-x86項目已通過init.rc相關(guān)的地方將腳本文件/system/bin/enable_nativebridge設(shè)置為服務(wù),注冊/配置內(nèi)容均在此腳本文件中實現(xiàn)。(不同的模擬器改動較大,自行探索)
4. 配置屬性(default.prop或build.prop等),參考上邊內(nèi)容