Google繼Project Treble後的大動作:Android Q系統元件更新機制APEX
一直以來,與iOS相比,Android在效能、安全、功耗、碎片化(相容性)問題上一直被詬病。知恥而後勇,知弱而圖強。自Android 4.0以來,Google一直致力於解決效能(Project Butter/OpenGLRenderer/RenderThread/ART)、安全(SELinux/FDE/FBE/VerifiedBoot)、功耗問題(Project Volta/Doze/App Standby/Background Execution Limits)。到了Android8.0,提出了Treble架構,致力於解決碎片化問題,在Android發展史上留下濃重的一筆。


到了P版本,Android似乎停止了演進,在架構上沒有出現可圈可點的變化。然而並沒有,Google正在醞釀下一個版本(Q)的大招——APEX。
APEX與Treble有著千絲萬縷的關係,它們同為解決碎片化(相容性)問題而生。Treble使得使用者快速地更新系統版本。簡單來說,Android系統由廠商程式碼(QCOM/MTK)以及AOSP程式碼兩部分組成。廠商程式碼主要是硬體相關的,AOSP則代表Android系統版本。在沒有Treble之前,這兩部分程式碼是耦合在一起的,導致升級AOSP程式碼的同時,也需要同步升級廠商程式碼。

由於這兩部分程式碼是不同的公司維護的,同時升級是一件不容易的事情,需要花費大量的精力,導致Android的最新版本遲遲不能推送到使用者手上。
Treble通過HIDL和VNDK兩個技術實現了廠商程式碼和AOSP程式碼的解耦。解耦後,就可以實現各自獨立升級,極大地降低手機廠商升級Android版本的難度。對使用者來說,甚至可以不用等待手機廠商最新的定製版Android系統,而直接刷入最新的原生Android系統。

Treble似乎很完美,但是仔細觀察,升級流程還是太重了。上一個版本的某一個系統模組出現了問題(安全、相容性等),需要等到下一個OTA版本才能解決。通過OTA升級版本是一個很重的流程,而且它是以整個Android系統為目標進行升級的。因此,如果只是針對特定的模組,通過OTA的方式來解決顯然是不合適的,殺雞焉用牛刀!
APEX呼之欲出,它的目標比Treble更進一步,要能夠獨立升級特定的系統模組,就像獨立升級APK一樣。事實上,APEX檔案與APK檔案的結構基本上是一樣的,而且都是zip壓縮格式。

APEX包內部包含兩個配置檔案AndroidManifest.xml和manifest.json,兩者的內容是一樣的。
AndroidManifest.xml

manifest.json

從配置檔案的內容可以看到,APEX模組具有包名和版本號。目前從公開的Android Q程式碼可以看到,系統中存在以下這些APEX模組:
- com.android.runtime: ART and bionic runtime (binaries and libraries)
- com.android.tzdata: TimeZone and ICU data (libraries and configuration data)
- com.android.resolv: Library used by Android to resolve network related requests (libraries)
- com.android.conscrypt: A Java Security Provider (Java framework)
這些APEX檔案儲存在/system/apex或者/data/apex目錄中。其中,儲存在/data/apex目錄中的APEX檔案就是動態更新下載的,用來更新原來的APEX模組。
APEX包的主角是image.img檔案,這是一個EXT2格式的Image檔案:

它的內容由content和vbmeta兩部分組成:

vbmeta包含content的簽名信息。APEX模組啟用後,content的內容受到dm-verity完整性保護,防止持久化攻擊。dm-verity就是通過vbmeta的資訊對content的內容進行完整性保護的。這與system分割槽受到的完整性保護機制是一致的。
下面我們主要介紹content中的內容。其中,manifest.json是配置檔案,和APEX包根目錄下的manifest.json內容是一樣的。file1和file2是要更新的系統檔案。
file_contexts檔案用來指定file1和file2檔案的SELinux上下文:

fs_config檔案用來指定file1和file2檔案的UID/GID:

如果APEX模組包含bin檔案,那麼可以在Image檔案中指定ld.config.txt檔案,用來描述該bin檔案的LinkerNamespace。LinkerNamespace也是Treble引進的技術,用來隔離VNDK中不同Linker Namespace中的共享庫,以確保具有相同庫名稱和不同符號的庫不會發生衝突。
ld.config.txt的部分內容如下所示:

其中,第1行和第6行表示,當執行/apex/com.android.apex.text/bin目錄下的bin檔案時,將/apex/com.android.apex.test/${LIB}增加到它的動態庫搜尋路徑中去。這樣更新後的bin可以使用自帶的so庫代替原系統中的so庫。
APEX模組是由系統服務ApexService管理的,它主要提供的功能有:
- stagePackage:將APEX檔案拷貝到/data/apex目錄,並且命名為<package>@<version>.apex的形式
- activatePackage:將APEX檔案中的image.img掛載到/apex/<package>@<version>
- deactivatePackage:取消/apex/<package>@<version>的掛載,並刪除資料夾
在系統正常執行期間,系統將APEX檔案拷貝到/data/apex目錄下。等到下次開機時,ApexService就會自動通過activatePackage啟用APEX模組,實現替換系統原有的APEX模組的功能。
以com.android.apex.test為例,APEX模組的啟用過程如下所示:

Step 1:從/data/apex/[email protected]中提取image.img檔案。
Step 2:為image.img檔案建立一個Loop Device。
Step 3:使用預置在系統中的/system/etc/security/apex/apex.key檢驗image.img的vbmeata簽名。
Step 4:為Step 2中的Loop Device建立Verity Deivce,以便可以通過dm-verity保護image.img內容的完整性,防止持久化攻擊。
Step 5:將VerityDeivce掛載在/apex/com.android.apex.test@1中。
Step 6:為/apex/com.android.apex.test@1建立符號連結/apex/com.android.apex.test。
從這個APEX模組的啟用流程可以看到,一方面APEX模組受到dm-verity完整性保護,另一方面APEX模組通過版本號管理。其中,/apex/<package id>總是連結到最新版本的APEX模組。
APEX模組啟用之後,它是如何替換系統中原來的模組的呢?被替換的模組可能是:
- 配置檔案(com.android.tzdata)
- ELF可執行檔案(com.android.runtime)
- SO庫檔案(com.android.runtime/com.android.resolv)
- JAR庫檔案(com.android.conscrypt)
不同型別的檔案使用的替換方式是不一樣的,我們分別介紹。
首先是配置檔案,以com.android.tzdata為例,TimeZone資訊是由libc負責讀取的,它在讀取的過程中,會優先檢查/apex/com.android.tzdata下是否存在tzdata。如果存在,就會優先使用它:

*https://android.googlesource.com/platform/bionic/+/master/libc/tzcode/bionic.cpp
其次是ELF可執行檔案,它所在的目錄會被新增PATH環境變數中,以com.android.runtime為例,/apex/com.android.runtime/bin目錄將會新增到PATH環境變數中:

*https://android.googlesource.com/platform/bionic/+/master/libc/include/paths.h
SO庫檔案和JAR庫檔案與ELF可執行檔案型別,分別會被新增到各自的搜尋路徑中。
其中,將APEX模組中的SO庫檔案新增到搜尋路徑是在system/etc/ld.config.txt中配置的,以com.android.runtime為例:

*https://android.googlesource.com/platform/system/core/+/master/rootdir/etc/ld.config.txt
JAR庫檔案會被新增到BOOTCLASSPATH環境變數中,以com.android.conscrypt為例:

*https://android.googlesource.com/platform/build/+/master/target/product/base_system.mk
以上就是Android Q系統元件更新機制APEX。通過APEX,可以像更新APK一樣更新系統元件,以快速解決Android系統的碎片化(相容性)問題。我們也可以將APEX看作是Android系統的熱更新機制。不過,從目前的熱更新方式來看,只有預先指定的模組才可以進行熱更新,不可以進行任意檔案的更新。這是一個比較大的限制,不知道Google是否會考慮更靈活的方式,做到任意檔案都可以進行熱更新(使用Magisk的Magic Mount技術,或者overlayfs技術)。
轉載自微信公眾號:OPPO新技術
原文連結:https://mp.weixin.qq.com/s/9crfHyAiNUoLa6di9aQA3g