APEX 文件格式

Android Pony EXpress (APEX) 容器格式是在 Android 10 中引入的,它用於較低層級系統模組的安裝流程。這種格式有利於不適合標準 Android 應用程式模型的系統元件的更新。一些範例元件包括本機服務和函式庫、硬體抽象層 ( HAL )、執行時間 ( ART ) 和類別庫。

術語“APEX”也可以指 APEX 檔。

背景

儘管 Android 支援透過軟體包安裝程式應用程式(例如 Google Play 商店應用程式)更新適合標準應用程式模型(例如服務、活動)的模組,但對較低級別的作業系統元件使用類似的模型具有以下缺點:

  • 基於 APK 的模組不能在啟動順序的早期使用。套件管理器是有關應用程式資訊的中央儲存庫,只能從活動管理器啟動,活動管理器在啟動過程的後期階段準備就緒。
  • APK 格式(尤其是清單)是為 Android 應用程式設計的,系統模組並不總是合適。

設計

本節介紹 APEX 檔案格式和 APEX 管理員(管理 APEX 檔案的服務)的進階設計。

有關為什麼選擇 APEX 的這種設計的更多信息,請參閱開發 APEX 時考慮的替代方案

頂點格式

這是 APEX 檔案的格式。

APEX 檔案格式

圖 1. APEX 檔案格式

在頂層,APEX 檔案是一個 zip 文件,其中文件以未壓縮的方式存儲,並且位於 4 KB 邊界處。

APEX 檔案中的四個檔案是:

  • apex_manifest.json
  • AndroidManifest.xml
  • apex_payload.img
  • apex_pubkey

apex_manifest.json檔案包含套件名稱和版本,用於識別 APEX 檔案。這是 JSON 格式的ApexManifest協定緩衝區。

AndroidManifest.xml檔案允許 APEX 檔案使用 APK 相關工具和基礎設施,例如 ADB、PackageManager 和套件安裝程式應用程式(例如 Play Store)。例如,APEX 檔案可以使用現有工具(例如aapt來檢查檔案中的基本元資料。該檔案包含套件名稱和版本資訊。此資訊通常也可以在apex_manifest.json中找到。

對於處理 APEX 的新程式碼和系統,建議使用apex_manifest.json而不是AndroidManifest.xmlAndroidManifest.xml可能包含其他可供現有應用程式發布工具的定位資訊。

apex_payload.img是 dm-verity 支援的 ext4 檔案系統映像。影像在運作時透過環回設備安裝。具體來說,哈希樹和元資料塊是使用libavb庫創建的。不解析檔案系統有效負載(因為映像應該可以就地安裝)。常規檔案包含在apex_payload.img檔案內。

apex_pubkey是用於對檔案系統映像進行簽署的公鑰。在執行時,此金鑰可確保下載的 APEX 與在內建分割區中簽署相同 APEX 的相同實體進行簽署。

APEX 命名指南

為了幫助防止隨著平台的進步,新 APEX 之間發生命名衝突,請使用以下命名準則:

  • com.android.*
    • 為 AOSP APEX 保留。並非任何公司或設備所獨有。
  • com.<companyname>.*
    • 為公司保留。可能被該公司的多個設備使用。
  • com.<companyname>.<devicename>.*
    • 為特定設備(或設備子集)特有的 APEX 保留。

頂點經理

APEX 管理器(或稱apexd )是一個獨立的本機進程,負責驗證、安裝和卸載 APEX 檔案。該進程在啟動序列的早期啟動並準備就緒。 APEX 檔案通常預先安裝在裝置上的/system/apex下。如果沒有可用的更新,APEX 管理器預設使用這些軟體包。

APEX的更新順序使用PackageManager類,如下所示。

  1. APEX 檔案是透過軟體包安裝程式應用程式、ADB 或其他來源下載的。
  2. 套件管理器開始安裝程序。在識別出該檔案是 APEX 後,套件管理器將控制權轉移給 APEX 管理員。
  3. APEX 管理器驗證 APEX 檔案。
  4. 如果 APEX 檔案經過驗證,APEX 管理器的內部資料庫將會更新,以反映 APEX 檔案在下次啟動時被啟動。
  5. 安裝請求者在成功驗證軟體包後會收到廣播。
  6. 若要繼續安裝,必須重新啟動系統。
  7. 下次啟動時,APEX 管理器啟動,讀取內部資料庫,並對列出的每個 APEX 檔案執行以下操作:

    1. 驗證 APEX 檔案。
    2. 從 APEX 檔案建立環回設備。
    3. 在環回設備之上建立設備映射器塊設備。
    4. 將裝置映射器區塊裝置安裝到唯一路徑(例如, /apex/ name @ ver )。

當內部資料庫中列出的所有 APEX 檔案都已安裝時,APEX 管理員會為其他系統元件提供綁定器服務,以查詢已安裝 APEX 檔案的資訊。例如,其他系統元件可以查詢設備中安裝的 APEX 檔案的列表,或查詢安裝特定 APEX 的確切路徑,以便可以存取這些檔案。

APEX檔是APK文件

APEX 檔案是有效的 APK 文件,因為它們是包含AndroidManifest.xml檔案的簽章 zip 檔案(使用 APK 簽章方案)。這允許 APEX 檔案使用 APK 檔案的基礎設施,例如軟體包安裝程式應用程式、簽署實用程式和軟體套件管理器。

APEX 檔案內的AndroidManifest.xml檔案很小,由套件nameversionCode和可選的targetSdkVersionminSdkVersionmaxSdkVersion組成,用於細粒度定位。此資訊允許透過現有管道(例如軟體包安裝程式應用程式和 ADB)傳送 APEX 檔案。

支援的文件類型

APEX 格式支援以下檔案類型:

  • 本機共享庫
  • 本機可執行檔
  • JAR 文件
  • 資料檔案
  • 設定檔

這並不意味著 APEX 可以更新所有這些檔案類型。文件類型是否可以更新取決於平台以及文件類型介面定義的穩定性。

簽名選項

APEX 檔案有兩種簽章方式。首先,使用金鑰對apex_payload.img (具體來說,附加到apex_payload.img的 vbmeta 描述符)檔案進行簽署。然後,使用APK簽章方案v3對整個APEX進行簽章。在此過程中使用兩個不同的密鑰。

在裝置端,安裝了與用於簽署 vbmeta 描述符的私鑰相對應的公鑰。 APEX 管理員使用公鑰來驗證要求安裝的 APEX。每個 APEX 必須使用不同的金鑰進行簽名,並在建置時和執行時強制執行。

內建分割區中的 APEX

APEX 檔案可以位於內建分割區,例如/system 。該分割區已經通過 dm-verity,因此 APEX 檔案直接安裝在環回裝置上。

如果內建分割區中存在 APEX,則可以透過提供具有相同套件名稱且大於或等於版本號碼的 APEX 套件來更新 APEX。新的 APEX 儲存在/data中,與 APK 類似,新安裝的版本會隱藏內建分割區中已存在的版本。但與 APK 不同的是,新安裝的 APEX 版本僅在重新啟動後才會啟動。

內核要求

要在 Android 裝置上支援 APEX 主線模組,需要以下 Linux 核心功能:環回驅動程式和 dm-verity。環回驅動程式將檔案系統映像安裝在 APEX 模組中,並且 dm-verity 驗證 APEX 模組。

使用 APEX 模組時,環回驅動程式和 dm-verity 的效能對於實現良好的系統效能非常重要。

支援的核心版本

使用核心版本 4.4 或更高版本的裝置支援 APEX 主線模組。搭載 Android 10 或更高版本的新裝置必須使用核心版本 4.9 或更高版本才能支援 APEX 模組。

所需的內核補丁

支援 APEX 模組所需的核心補丁包含在 Android 公共樹中。若要取得支援 APEX 的補丁,請使用最新版本的 Android 公共樹。

核心版本4.4

此版本僅支援從 Android 9 升級到 Android 10 並希望支援 APEX 模組的裝置。要取得所需的補丁,強烈建議從android-4.4分支進行向下合併。以下是核心版本 4.4 所需的各個補丁的清單。

  • UPSTREAM:循環:新增 ioctl 來改變邏輯區塊大小( 4.4
  • 後向連接埠:區塊/循環:設定 hw_sectors ( 4.4 )
  • UPSTREAM:循環:在 compat ioctl 中新增 LOOP_SET_BLOCK_SIZE ( 4.4 )
  • ANDROID:mnt:修正 next_descendent ( 4.4 )
  • ANDROID:mnt:重新安裝應該會傳播到從屬的從屬( 4.4
  • ANDROID:mnt:正確傳播重新安裝( 4.4
  • 恢復「ANDROID:dm verity:新增最小預取大小」( 4.4
  • UPSTREAM:循環:如果 offset 或 block_size 更改則刪除快取( 4.4

核心版本4.9/4.14/4.19

若要取得內核版本 4.9/4.14/4.19 所需的補丁,請從android-common分支向下合併。

所需的內核配置選項

以下列表顯示了支援 Android 10 中引入的 APEX 模組的基本配置要求。帶有星號 (*) 的項目是 Android 9 及更低版本的現有要求。

(*) CONFIG_AIO=Y # AIO support (for direct I/O on loop devices)
CONFIG_BLK_DEV_LOOP=Y # for loop device support
CONFIG_BLK_DEV_LOOP_MIN_COUNT=16 # pre-create 16 loop devices
(*) CONFIG_CRYPTO_SHA1=Y # SHA1 hash for DM-verity
(*) CONFIG_CRYPTO_SHA256=Y # SHA256 hash for DM-verity
CONFIG_DM_VERITY=Y # DM-verity support

核心命令列參數要求

為了支援 APEX,請確保核心命令列參數符合以下要求:

  • 不得設定loop.max_loop
  • loop.max_part必須 <= 8

建構一個 APEX

本節介紹如何使用 Android 建置系統建置 APEX。以下是名為apex.test的 APEX 的Android.bp範例。

apex {
    name: "apex.test",
    manifest: "apex_manifest.json",
    file_contexts: "file_contexts",
    // libc.so and libcutils.so are included in the apex
    native_shared_libs: ["libc", "libcutils"],
    binaries: ["vold"],
    java_libs: ["core-all"],
    prebuilts: ["my_prebuilt"],
    compile_multilib: "both",
    key: "apex.test.key",
    certificate: "platform",
}

apex_manifest.json範例:

{
  "name": "com.android.example.apex",
  "version": 1
}

file_contexts範例:

(/.*)?           u:object_r:system_file:s0
/sub(/.*)?       u:object_r:sub_file:s0
/sub/file3       u:object_r:file3_file:s0

APEX 中的檔案類型和位置

文件類型位於 APEX 的位置
共享庫/lib/lib64/lib/arm用於 x86 翻譯後的arm)
執行檔/bin
Java 函式庫/javalib
預製件/etc

傳遞依賴

APEX 檔案自動包含本機共用程式庫或執行檔的傳遞依賴項。例如,如果libFoo依賴libBar ,則當native_shared_libs屬性中僅列出libFoo時,就會包含這兩個函式庫。

處理多個 ABI

為裝置的主要和輔助應用程式二進位介面 (ABI) 安裝native_shared_libs屬性。如果 APEX 面向具有單一 ABI 的裝置(即僅限 32 位元或僅限 64 位元),則僅安裝具有對應 ABI 的程式庫。

僅為設備的主要 ABI 安裝binaries屬性,如下所述:

  • 如果裝置僅為 32 位,則僅安裝二進位檔案的 32 位元變體。
  • 如果裝置僅為 64 位,則僅安裝二進位檔案的 64 位元變體。

若要新增對本機程式庫和二進位檔案的 ABI 的細微控制,請使用multilib.[first|lib32|lib64|prefer32|both].[native_shared_libs|binaries]屬性。

  • first :匹配設備的主要 ABI。這是二進位檔案的預設設定。
  • lib32 :符合裝置的 32 位元 ABI(如果支援)。
  • lib64 :匹配裝置的 64 位元 ABI,它支援。
  • prefer32 :符合裝置的 32 位元 ABI(如果支援)。如果不支援 32 位元 ABI,則符合 64 位元 ABI。
  • both :符合兩個 ABI。這是native_shared_libraries的預設值。

javalibrariesprebuilts屬性與 ABI 無關。

此範例適用於支援 32/64 但不喜歡 32 的裝置:

apex {
    // other properties are omitted
    native_shared_libs: ["libFoo"], // installed for 32 and 64
    binaries: ["exec1"], // installed for 64, but not for 32
    multilib: {
        first: {
            native_shared_libs: ["libBar"], // installed for 64, but not for 32
            binaries: ["exec2"], // same as binaries without multilib.first
        },
        both: {
            native_shared_libs: ["libBaz"], // same as native_shared_libs without multilib
            binaries: ["exec3"], // installed for 32 and 64
        },
        prefer32: {
            native_shared_libs: ["libX"], // installed for 32, but not for 64
        },
        lib64: {
            native_shared_libs: ["libY"], // installed for 64, but not for 32
        },
    },
}

vb元簽名

使用不同的金鑰對每個 APEX 進行簽署。當需要新金鑰時,建立公私金鑰對並建立apex_key模組。使用key屬性來使用金鑰對 APEX 進行簽署。公鑰自動包含在 APEX 中,名稱為avb_pubkey

# create an rsa key pair
openssl genrsa -out foo.pem 4096

# extract the public key from the key pair
avbtool extract_public_key --key foo.pem --output foo.avbpubkey

# in Android.bp
apex_key {
    name: "apex.test.key",
    public_key: "foo.avbpubkey",
    private_key: "foo.pem",
}

在上面的範例中,公鑰 ( foo ) 的名稱成為金鑰的 ID。用於簽署 APEX 的密鑰 ID 寫入 APEX 中。在執行時, apexd使用裝置中具有相同 ID 的公鑰來驗證 APEX。

APEX簽約

簽署 APEX 的方式與簽署 APK 的方式相同。對 APEX 進行兩次簽章;一次用於迷你檔案系統( apex_payload.img檔案),一次用於整個檔案。

若要在檔案層級簽署 APEX,請透過以下三種方式之一設定certificate屬性:

  • 未設定:如果未設定值,則 APEX 使用位於PRODUCT_DEFAULT_DEV_CERTIFICATE的憑證進行簽署。如果未設定標誌,則路徑預設為build/target/product/security/testkey
  • <name> :APEX 使用與PRODUCT_DEFAULT_DEV_CERTIFICATE位於同一目錄中的<name>憑證進行簽章。
  • :<name> :APEX 使用名為<name>的 Soong 模組定義的憑證進行簽署。證書模組可以定義如下。
android_app_certificate {
    name: "my_key_name",
    certificate: "dir/cert",
    // this will use dir/cert.x509.pem (the cert) and dir/cert.pk8 (the private key)
}

安裝 APEX

若要安裝 APEX,請使用 ADB。

adb install apex_file_name
adb reboot

如果在apex_manifest.json中將supportsRebootlessUpdate設為true並且目前安裝的 APEX 未使用(例如,它包含的任何服務已停止),則可以使用--force-non-staged標誌安裝新的 APEX,無需重新啟動。

adb install --force-non-staged apex_file_name

使用 APEX

重新啟動後,APEX 將安裝在/apex/<apex_name>@<version>目錄中。同一 APEX 的多個版本可以同時掛載。掛載路徑中,最新版本對應的掛載路徑為/apex/<apex_name>

客戶端可以使用綁定安裝路徑從 APEX 讀取或執行檔。

APEX 通常如下使用:

  1. 設備出貨時,OEM 或 ODM 會在/system/apex下預先載入 APEX。
  2. APEX 中的檔案可透過/apex/<apex_name>/路徑存取。
  3. 當 APEX 的更新版本安裝在/data/apex中時,路徑在重新啟動後指向新的 APEX。

使用 APEX 更新服務

若要使用 APEX 更新服務:

  1. 將系統分區中的服務標記為可更新。將updatable選項新增至服務定義。

    /system/etc/init/myservice.rc:
    
    service myservice /system/bin/myservice
        class core
        user system
        ...
        updatable
    
  2. 為更新的服務建立新的.rc檔。使用override選項重新定義現有服務。

    /apex/my.apex/etc/init.rc:
    
    service myservice /apex/my.apex/bin/myservice
        class core
        user system
        ...
        override
    

服務定義只能在 APEX 的.rc檔中定義。 APEX 不支援操作觸發器。

如果標記為可更新的服務在 APEX 啟動之前啟動,則啟動會延遲,直到 APEX 啟動完成。

設定係統以支援 APEX 更新

將下列系統屬性設為true以支援 APEX 檔案更新。

<device.mk>:

PRODUCT_PROPERTY_OVERRIDES += ro.apex.updatable=true

BoardConfig.mk:
TARGET_FLATTEN_APEX := false

要不就

<device.mk>:

$(call inherit-product, $(SRC_TARGET_DIR)/product/updatable_apex.mk)

扁平化頂點

對於舊設備,有時不可能或不可行更新舊核心以完全支援 APEX。例如,核心可能是在沒有CONFIG_BLK_DEV_LOOP=Y情況下建構的,這對於在 APEX 內掛載檔案系統映像至關重要。

Flattened APEX 是專門建置的 APEX,可在具有舊核心的裝置上啟動。扁平化APEX中的檔案直接安裝到內建分割區下的目錄。例如,扁平 APEX my.apex中的lib/libFoo.so安裝到/system/apex/my.apex/lib/libFoo.so

啟動扁平 APEX 不涉及循環設備。整個目錄/system/apex/my.apex直接綁定安裝到/apex/name@ver

扁平化的 APEX 無法透過從網路下載 APEX 的更新版本來更新,因為下載的 APEX 無法扁平化。扁平化 APEX 只能透過常規 OTA 進行更新。

扁平 APEX 是預設配置。這表示預設情況下所有 APEX 都是扁平化的,除非您明確將裝置配置為建置非扁平化 APEX 以支援 APEX 更新(如上所述)。

不支援在設備中混合展平和非展平 APEX。設備中的 APEX 必須全部非扁平化或全部扁平化。當為 Mainline 等專案提供預先簽署的 APEX 預先建置時,這一點尤其重要。未預先簽署(即從來源建置)的 APEX 也應該是非扁平化的,並使用正確的金鑰進行簽署。設備應繼承自updatable_apex.mk ,如使用 APEX 更新服務所述。

壓縮 APEX

Android 12 及更高版本具有 APEX 壓縮功能,可減少可更新 APEX 套件的儲存影響。安裝 APEX 更新後,雖然不再使用其預安裝版本,但仍佔用相同的空間量。所佔用的空間仍然不可用。

APEX 壓縮透過在唯讀分割區(例如/system分割區)上使用高度壓縮的 APEX 檔案集來最大限度地減少這種儲存影響。 Android 12 及更高版本使用 DEFLATE zip 壓縮演算法。

壓縮不會對以下內容提供優化:

  • 需要在引導序列的早期安裝的引導 APEX。

  • 不可更新的 APEX。只有當 APEX 的更新版本安裝在/data分割區上時,壓縮才有用。模組化系統元件頁面上提供了可更新 APEX 的完整清單。

  • 動態共享庫 APEX。由於apexd始終啟動此類 APEX 的兩個版本(預先安裝和升級),因此壓縮它們不會增加價值。

壓縮 APEX 檔案格式

這是壓縮 APEX 檔案的格式。

Diagram shows the format of a compressed APEX file

圖 2.壓縮的 APEX 檔案格式

在頂層,壓縮的 APEX 檔案是一個 zip 文件,其中包含壓縮形式的原始 apex 文件,壓縮等級為 9,其他文件未壓縮儲存。

四個檔案組成一個 APEX 檔:

  • original_apex :壓縮等級為 9 的壓縮 這是原始的、未壓縮的APEX 檔
  • apex_manifest.pb :僅存儲
  • AndroidManifest.xml :僅儲存
  • apex_pubkey :僅儲存

apex_manifest.pbAndroidManifest.xmlapex_pubkey檔案是original_apex中對應檔案的副本。

建構壓縮的 APEX

可以使用位於system/apex/toolsapex_compression_tool.py工具建立壓縮 APEX。

建置系統中提供了與 APEX 壓縮相關的多個參數。

Android.bp中,APEX 檔案是否可壓縮由compressible屬性控制:

apex {
    name: "apex.test",
    manifest: "apex_manifest.json",
    file_contexts: "file_contexts",
    compressible: true,
}

PRODUCT_COMPRESSED_APEX產品標誌控制從來源建置的系統映像是否必須包含壓縮的 APEX 檔案。

對於本機實驗,您可以透過將OVERRIDE_PRODUCT_COMPRESSED_APEX=設為true來強制建置壓縮 APEX。

建置系統產生的壓縮 APEX 檔案具有.capex副檔名。此擴充功能使區分 APEX 檔案的壓縮版本和未壓縮版本變得更加容易。

支援的壓縮演算法

Android 12 僅支援 deflate-zip 壓縮。

在啟動期間啟動壓縮的 APEX 文件

在啟動壓縮的 APEX 之前,其中的original_apex檔案將被解壓縮到/data/apex/decompressed目錄中。產生的解壓縮 APEX 檔案硬連結到/data/apex/active目錄。

考慮以下範例來說明上述過程。

/system/apex/com.android.foo.capex視為正在啟動的壓縮 APEX,版本代碼為 37。

  1. /system/apex/com.android.foo.capex中的original_apex檔案被解壓縮到/data/apex/decompressed/com.android.foo@37.apex
  2. 執行restorecon /data/apex/decompressed/com.android.foo@37.apex以驗證它是否具有正確的SELinux標籤。
  3. /data/apex/decompressed/com.android.foo@37.apex執行驗證檢查以確保其有效性: apexd檢查/data/apex/decompressed/com.android.foo@37.apex中捆綁的公鑰驗證它是否等於/system/apex/com.android.foo.capex中捆綁的那個。
  4. /data/apex/decompressed/com.android.foo@37.apex檔案硬連結至/data/apex/active/com.android.foo@37.apex目錄。
  5. 未壓縮 APEX 檔案的常規啟動邏輯在/data/apex/active/com.android.foo@37.apex上執行。

與OTA交互

壓縮的 APEX 檔案會對 OTA 交付和應用產生影響。由於 OTA 更新可能包含版本等級高於裝置上活動文件的壓縮 APEX 文件,因此在重新啟動裝置以套用 OTA 更新之前,必須保留一定量的可用空間。

為了支援 OTA 系統, apexd公開了這兩個 Binder API:

  • calculateSizeForCompressedApex - 計算解壓縮 OTA 套件中的 APEX 檔案所需的大小。這可用於在下載 OTA 之前驗證裝置是否有足夠的空間。
  • reserveSpaceForCompressedApex - 保留磁碟上的空間以供apexd將來用於解壓縮 OTA 套件內的壓縮 APEX 檔案。

對於 A/B OTA 更新, apexd會在背景嘗試解壓縮,作為安裝後 OTA 例程的一部分。如果解壓縮失敗, apexd將在應用 OTA 更新的引導期間執行解壓縮。

開發 APEX 時考慮的替代方案

以下是 AOSP 在設計 APEX 檔案格式時考慮的一些選項,以及包含或排除它們的原因。

常規套件管理系統

Linux 發行版具有dpkgrpm等套件管理系統,它們功能強大、成熟且健壯。但是,它們沒有被 APEX 採用,因為它們無法在安裝後保護軟體包。僅在安裝軟體包時才執行驗證。攻擊者可以在不被注意的情況下破壞已安裝軟體包的完整性。這是 Android 的回歸,其中所有系統元件都儲存在唯讀檔案系統中,其完整性受到每個 I/O 的 dm-verity 保護。對系統組件的任何篡改都必須被禁止,或者是可檢測的,以便設備在受到損害時可以拒絕啟動。

dm-crypt 的完整性

APEX容器中的檔案來自受dm-verity保護的內建分割區(例如/system分割區),即使在掛載分割區後也禁止對檔案進行任何修改。為了給檔案相同等級的安全性,APEX 中的所有檔案都儲存在與雜湊樹和 vbmeta 描述符配對的檔案系統映像中。如果沒有 dm-verity, /data分割區中的 APEX 很容易受到驗證和安裝後的意外修改。

事實上, /data分割區也受到dm-crypt等加密層的保護。儘管這提供了一定程度的防篡改保護,但其主要目的是隱私,而不是完整性。當攻擊者獲得對/data分區的存取權限時,就無法提供進一步的保護,與/system分區中的每個系統元件相比,這又是一種倒退。 APEX 檔案內的哈希樹與 dm-verity 一起提供相同等級的內容保護。

將路徑從 /system 重定向到 /apex

打包在 APEX 中的系統元件檔案可以透過/apex/<name>/lib/libfoo.so等新路徑存取。當檔案是/system分區的一部分時,可以透過/system/lib/libfoo.so等路徑存取它們。 APEX 檔案(其他 APEX 檔案或平台)的用戶端必須使用新路徑。由於路徑更改,您可能需要更新現有程式碼。

儘管避免路徑更改的一種方法是將 APEX 文件中的文件內容覆蓋到/system分區上,但 Android 團隊決定不在/system分區上覆蓋文件,因為這可能會影響效能,因為覆蓋的文件數量會增加(甚至可能一個接一個地堆疊)增加。

另一個選擇是劫持檔案存取函數,例如openstatreadlink ,以便以/system開頭的路徑被重定向到/apex下的對應路徑。 Android 團隊放棄了這個選項,因為更改所有接受路徑的函數是不可行的。例如,一些應用程式靜態連結 Bionic,它實現了功能。在這種情況下,這些應用程式不會被重新導向。