Android 共用系統映像檔

本頁介紹 Android 裝置 OEM 可使用的幾種機制,在產品線中採用自己的共用系統映像檔 (SSI)。此外,本文也建議程序,讓原始設備製造商 (OEM) 能夠以 AOSP 建構的一般系統映像檔 (GSI) 為基礎,建立自有 SSI。

背景

Project Treble 將單一的 Android 分成兩部分:硬體專屬部分 (供應商實作) 和一般 OS 部分 (Android OS 架構)。每個軟體都安裝在不同的分區:供應商分區用於硬體專屬軟體,系統分區則用於一般 OS 軟體。系統會定義並強制執行兩個分區的介面版本,稱為供應商介面 (VINTF)。使用這個分割系統時,您可以修改系統分割區,而不必修改供應商分割區,反之亦然。

動機

Android 開放原始碼計畫 (AOSP) 發布的架構程式碼一直都符合 Treble 架構,並維持與舊版供應商實作項目的回溯相容性。舉例來說,從 Android 10 AOSP 來源建構的通用系統映像檔,可在任何執行 Android 8 以上版本的 Treble 相容裝置上執行。消費者裝置搭載的 Android 版本是由 SoC 供應商和 OEM 修改。(請參閱「Android 版本生命週期」。)這些對架構進行的變更和擴充功能並非為了維持回溯相容性而編寫,因此 OS 升級的複雜度增加,成本也隨之提高。裝置專屬的變更和修改會增加 Android OS 版本升級的成本和複雜度。

在 Android 11 之前,合作夥伴無法透過明確的架構,為 Android OS 架構建構模組化擴充功能。本文說明 SoC 供應商和 OEM 建立 SSI 的步驟。也就是說,只要一個映像檔,就能從 Android 作業系統架構來源建構,在多部裝置上重複使用,維持與供應商實作的回溯相容性,並大幅降低 Android 作業系統升級的複雜度和成本。如需建立 SSI 的具體步驟,請參閱「建議的 GSI 型 SSI 步驟」一節,並注意您不一定要完成所有四個步驟。選擇哪些步驟 (例如僅步驟 1) 取決於您的實作方式。

SSI 總覽

使用 SSI 時,產品專屬的軟體元件和 OEM 擴充功能會放在新的 /product 分割區。/product 分區中的元件會使用明確定義的穩定介面,與 /system 分區中的元件互動。OEM 可以選擇建構一個 SSI,也可以選擇少量 SSI,供多個裝置 SKU 使用。Android 作業系統發布新版本時,原始設備製造商 (OEM) 只需一次投入資源,即可將 SSI 更新至最新 Android 版本。他們可以重複使用 SSI,在更新 /product 分區的情況下,更新多部裝置。

請注意,原始設備製造商 (OEM) 和 SoC 供應商會建構 SSI,其中包含 OEM 需要的所有自訂功能和修改項目。本頁面提供的機制和最佳做法,可協助原始設備製造商達成下列主要目標:

  • 在多個裝置 SKU 中重複使用 SSI。
  • 使用模組化擴充功能更新 Android 系統,讓作業系統升級更輕鬆。

將產品專屬元件劃分為產品分割區的核心概念,與 Treble 將 SoC 專屬元件劃分為供應商分割區的概念類似。產品介面 (類似於 VINTF) 可讓 SSI 與產品分割區通訊。請注意,就 SSI 而言,「元件」一詞是指安裝到映像檔的所有資源、二進位檔、文字、程式庫等,這些資源基本上會成為分割區。

SSI 周圍的分區

圖 1 顯示 SSI 周圍的分區,以及分區和介面上各個介面和政策的版本。本節將詳細說明每個分割區和介面。

SSI 區塊圖周圍的分割區和介面

圖 1. SSI 周圍的分區和介面

圖片和分割區

本節資訊會區分「映像檔」和「磁碟分割」這兩個詞彙。

  • 映像檔是概念上的軟體,可獨立更新。
  • 分割區是可獨立更新的實體儲存位置。

圖 1 中的各節定義如下:

  • SSI:SSI 是 OEM 裝置通用的映像檔,可存在於多部裝置中。不含任何硬體或產品專屬元件。根據定義,特定 SSI 中的所有內容都會在所有使用該 SSI 的裝置間共用。SSI 由單一 /system 圖片,或 /system/system_ext 分區組成,如圖 1 所示。

    • /system 分區包含以 Android 開放原始碼計畫為基礎的元件,而 /system_ext (如果已實作) 則包含 OEM 和 SoC 廠商的擴充功能,以及與 Android 開放原始碼計畫元件緊密結合的元件。舉例來說,如果 OEM Java 架構程式庫為 OEM 自己的應用程式提供自訂 API,就比較適合放在 /system_ext 分割區,而不是 /system 分割區。/system/system_ext 分割區的內容都是以 OEM 修改的 Android 來源建構而成。

    • /system_ext 分區為選用項目,但建議用於與 AOSP 型元件緊密結合的任何自訂功能和擴充功能。這項區別有助於您找出需要進行的變更,以便在一段時間內將這類元件從 /system_ext 分區移至 /product 分區。

  • 產品:一組產品或裝置專屬元件,代表 OEM 對 Android OS 的自訂和擴充功能。將 SoC 專屬元件放在 /vendor 分割區。SoC 供應商也可以使用 /product 分區,存放適當的元件,例如獨立於 SoC 的元件。舉例來說,如果 SoC 供應商向 OEM 客戶提供獨立於 SoC 的元件 (可選擇是否隨產品出貨),SoC 供應商可以在產品圖片中放置該元件。元件的位置並非由擁有權決定,而是由用途決定。

  • 供應商:SoC 專屬元件的集合。

  • ODM:SoC 未提供的特定主機板元件集合。通常供應商映像檔由 SoC 供應商擁有,而 ODM 映像檔則由裝置製造商擁有。如果沒有個別的 /odm 分區,SoC 供應商和 ODM 映像檔會合併到 /vendor 分區。

圖片之間的介面

SSI 有兩個主要介面,分別用於供應商和產品圖片:

  • 供應商介面 (VINTF):VINTF 是供應商和 ODM 映像檔中元件的介面。產品和系統映像檔中的元件只能透過這個介面與供應商和 ODM 映像檔互動。舉例來說,供應商映像檔不能依附於系統映像檔的私人部分,反之亦然。這項功能最初是在 Project Treble 中定義,可將映像檔分割為系統和供應商分區。介面說明方式如下:

    • HIDL (Passthrough HAL 僅適用於 systemsystem_ext 模組)
    • 穩定 AIDL
    • 設定
      • 系統屬性 API
      • 設定檔結構定義 API
    • VNDK
    • Android SDK API
    • Java SDK 程式庫
  • 產品介面:產品介面是 SSI 與產品圖片之間的介面。定義穩定介面可將產品元件與 SSI 中的系統元件分離。產品介面必須與 VINTF 採用相同的穩定介面。不過,對於搭載 Android 11 以上版本推出的裝置,系統只會強制執行 VNDK 和 Android SDK API。

在 Android 11 中啟用 SSI

本節說明如何使用新功能,在 Android 11 中支援 SSI。

/system_ext 分區

Android 11 推出 /system_ext 分區,做為選用分區。(這是指與 /system 分區中 AOSP 定義的元件緊密耦合的非 AOSP 元件。)/system_ext 分區應是 /system 分區的 OEM 專用擴充功能,且這兩個分區之間沒有定義介面。/system_ext 分割區中的元件可以對 /system 分割區發出私有 API 呼叫,/system 分割區中的元件也可以對 /system_ext 分割區發出私有 API 呼叫。

由於這兩個磁碟分割區緊密結合,因此在發布新版 Android 時,這兩個磁碟分割區會一併升級。為先前 Android 版本建立的 /system_ext 分區,不必與下一個 Android 版本的 /system 分區相容。

如要將模組安裝至 /system_ext 分區,請在 Android.bp 檔案中新增 system_ext_specific: true。如果裝置沒有 /system_ext 分區,請將這類模組安裝至 /system 分區的 ./system_ext 子目錄。

記錄

以下是 /system_ext 分區的相關歷史記錄。設計目標是將所有 OEM 專屬元件 (無論是否為通用元件) 放置在 /product 分割區中。不過,一次移動所有元件並不可行,尤其是某些元件與 /system 分區緊密耦合時。如要將緊密耦合的元件移至 /product 分區,必須擴充產品介面。這通常需要大量重構元件本身,耗費大量時間和精力。/system_ext 分區最初是暫時存放這些元件的地方,這些元件尚未準備好移至 /product 分區。SSI 的目標是最終淘汰 /system_ext 分區。

不過,/system_ext 分區有助於盡可能讓 /system 分區接近 AOSP。使用 SSI 時,大部分的升級工作都花在 /system/system_ext 分區的元件上。如果系統映像檔是從與 AOSP 盡可能相似的來源建構而成,您就可以專注於升級 system_ext 映像檔。

將元件從 /system 和 /system_ext 分區解除綁定,並移至 /product 分區

Android 9 導入了與 /system 分區配對的 /product 分區/product 分割區中的模組可不受限制地使用系統資源,反之亦然。為在 Android 10 中啟用 SSI,產品元件會分割到 /system_ext/product 分區。/system_ext 分區不必遵守 Android 9 中 /product 分區對使用系統元件的限制。從 Android 10 開始,/product 分區必須從 /system 分區取消組合,且必須使用 /system/system_ext 分區的穩定介面。

如「/system_ext partition」一節所述,/system_ext 分區的主要用途是擴充系統功能,而非安裝隨附的產品模組。如要這麼做,請取消產品專屬模組的組合,並將其移至 /product 分區。將產品專屬模組解除綁定後,/system_ext 就能在裝置間共用。(詳情請參閱「將 /system_ext 分區設為通用」。)

如要從系統元件取消綁定 /product 分區,/product 分區必須與已透過 Project Treble 取消綁定的 /vendor 分區採用相同的強制執行政策。

從 Android 11 開始,系統會強制執行 /product 分區的原生和 Java 介面,詳情如下。詳情請參閱「強制執行產品分割介面」。

  • 原生介面:/product 分區中的原生模組必須與其他分區解除繫結。產品模組中唯一允許的依附元件,是 /system 分割區中的部分 VNDK 程式庫 (包括 LLNDK)。產品應用程式所依附的 JNI 程式庫必須是 NDK 程式庫。
  • Java 介面:/product 分區中的 Java (應用程式) 模組無法使用隱藏版 API,因為這些 API 不穩定。這些模組只能使用 /system 分區的公開 API 和系統 API,以及 /system/system_ext 分區的 Java SDK 程式庫。您可以為自訂 API 定義 Java SDK 程式庫。

以 GSI 為基礎的 SSI 建議步驟

以 GSI 為基礎的 SSI 建議分割區

圖 2. 以 GSI 為基礎的 SSI 建議分割區

通用系統映像檔 (GSI) 是直接從 Android 開放原始碼計畫建構的系統映像檔。GSI 可用於 Treble 相容性測試 (例如 CTS-on-GSI),以及做為參考平台,供應用程式開發人員在沒有搭載所需 Android 版本的實體裝置時,測試應用程式的相容性。

原始設備製造商也可以使用 GSI 製作 SSI。如「映像檔和分割區」一文所述,SSI 包含 AOSP 定義元件的系統映像檔,以及 OEM 定義元件的 system_ext 映像檔。使用 GSI 做為 system 映像檔時,原始設備製造商可以專注於升級 system_ext 映像檔。

本節提供指南,協助 OEM 廠商在使用 AOSP 或近乎 AOSP 的系統映像檔時,將自訂項目模組化至 /system_ext/product 分割區。如果原始設備製造商從 Android 開放原始碼計畫來源建構系統映像檔,則可將建構的系統映像檔替換為 Android 開放原始碼計畫提供的 GSI。不過,原始設備製造商不需要一次完成最後一個步驟 (直接使用 GSI)。

步驟 1:為 OEM 的系統映像檔 (OEM GSI) 繼承 generic_system.mk

透過繼承 generic_system.mk (在 Android 11 中名為 mainline_system.mk,並在 Android 開放原始碼計畫中重新命名為 generic_system.mk),系統映像檔 (OEM GSI) 會包含 Android 開放原始碼計畫 GSI 的所有檔案。原始設備製造商 (OEM) 可以修改這些檔案,因此除了 AOSP GSI 檔案外,OEM GSI 也可以包含 OEM 專有檔案。不過,OEM 不得修改 generic_system.mk 檔案本身。

為 OEM 系統映像檔繼承 `generic_system.mk`

圖 3. 為 OEM 的系統映像檔繼承 generic_system.mk

步驟 2:讓 OEM GSI 擁有與 AOSP GSI 相同的檔案清單

現階段 OEM GSI 無法包含其他檔案。原始設備製造商的專有檔案必須移至 system_extproduct 分區。

將新增的檔案移出 OEM GSI

圖 4. 將新增的檔案移出 OEM GSI

步驟 3:定義允許清單,限制 OEM GSI 中修改的檔案

如要檢查修改後的檔案,原始設備製造商 (OEM) 可以使用 compare_images 工具,並比較 AOSP GSI 與 OEM GSI。從 AOSP lunch 目標 generic_system_* 取得 AOSP GSI。

定期使用 allowlist 參數執行 compare_images 工具,即可監控允許清單以外的差異。這樣可避免對 OEM GSI 進行額外修改。

定義允許清單,減少 OEM GSI 中修改的檔案清單

圖 5. 定義允許清單,減少 OEM GSI 中修改的檔案清單

步驟 4:讓 OEM GSI 與 AOSP GSI 具有相同的二進位檔

清理許可清單後,原始設備製造商就能將 AOSP GSI 用於自家產品的系統映像檔。如要清除允許清單,原始設備製造商可以放棄 OEM GSI 中的變更,也可以將變更上傳至 AOSP,讓 AOSP GSI 包含這些變更。

讓 OEM GSI 與 AOSP GSI 具有相同的二進位檔

圖 6. 讓 OEM GSI 與 AOSP GSI 具有相同的二進位檔

為原始設備製造商 (OEM) 定義 SSI

在建構時保護 /system 分割區

為避免 /system 分區中出現任何產品專屬變更,並定義 OEM GSI,OEM 可以使用名為 require-artifacts-in-path 的 Makefile 巨集,防止在呼叫巨集後宣告任何系統模組。請參閱建立 Makefile 並啟用構件路徑檢查的範例

OEM 可以定義清單,允許將產品專屬模組暫時安裝在 /system 分區中。不過,如要讓 OEM GSI 適用於所有 OEM 產品,這份清單就必須空白。這個程序是用於定義 OEM GSI,可獨立於 AOSP GSI 的步驟

強制執行產品介面

為確保 /product 分區未綁定,原始設備製造商可以設定 PRODUCT_PRODUCT_VNDK_VERSION:= current (適用於原生模組) 和 PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE:= true (適用於 Java 模組),確保裝置強制執行產品介面。如果裝置的 PRODUCT_SHIPPING_API_LEVEL 大於或等於 30,系統會自動設定這些變數。詳情請參閱「強制執行產品分割介面」。

將 /system_ext 分區設為通用

/system_ext 分區可能因裝置而異,因為當中可能含有裝置專屬的系統隨附模組。由於 SSI 包含 /system/system_ext 分區,/system_ext 分區的差異會阻礙原始設備製造商定義 SSI。原始設備製造商可以擁有自己的 SSI,並移除所有差異,將 /system_ext 分割區設為通用,即可在多部裝置之間共用該 SSI。

本節提供建議,說明如何將 /system_ext 分區設為通用。

公開系統分區中隱藏的 API

許多產品專屬應用程式無法安裝在產品分割區中,因為這些應用程式使用隱藏版 API,而產品分割區禁止使用這類 API。如要將裝置專用應用程式移至產品分割區,請移除隱藏 API 的使用方式。

從應用程式中移除隱藏 API 的最佳方式,是找出替代的公開或系統 API 來取代。如果沒有可取代隱藏 API 的 API,原始設備製造商 (OEM) 可以為 AOSP 貢獻心力,為自家裝置定義新的系統 API。

或者,OEM 可以在 /system_ext 分區中建立自己的 Java SDK 程式庫,定義自訂 API。它可以運用系統分區中的隱藏版 API,並將 API 提供給產品或供應商分區中的應用程式。為確保回溯相容性,原始設備製造商必須凍結面向產品的 API

包含所有 APK 的超集,並略過每個裝置的部分套件安裝作業

系統隨附的某些套件並非所有裝置都有。 將這些 APK 模組解除綁定並移至產品或供應商分割區,可能會有困難。做為暫時解決方案,原始設備製造商可以讓 SSI 包含所有模組,然後使用 SKU 屬性 (ro.boot.hardware.sku) 篩除不需要的模組。如要使用篩選器,原始設備製造商可以疊加架構資源 config_disableApkUnlessMatchedSku_skus_listconfig_disableApksUnlessMatchedSku_apk_list

如要進行更精確的設定,請宣告廣播接收器,停用不必要的套件。廣播接收器會在收到 ACTION_BOOT_COMPLETED 訊息時呼叫 setApplicationEnabledSetting,停用套件。

定義 RRO,而非使用靜態資源疊加

靜態資源疊加層會操控疊加的套件。不過,這可能會阻礙定義 SSI,因此請務必開啟 RRO 的屬性並正確設定。OEM 只要依下列方式設定屬性,就能將所有自動產生的疊加層設為 RRO。

PRODUCT_ENFORCE_RRO_TARGETS := *
PRODUCT_ENFORCE_RRO_EXCLUDED_OVERLAYS := # leave it empty

如需詳細設定,請手動定義 RRO,而非依賴自動產生的 RRO。詳情請參閱「執行階段資源重疊 (RRO)」。原始設備製造商也可以使用 android:requiredSystemPropertyNameandroid:requiredSystemPropertyValue 屬性,定義取決於系統屬性的條件式 RRO。

常見問題 (FAQ)

我可以定義多個 SSI 嗎?

這取決於裝置 (或裝置群組) 的共通性和特徵。 如要讓 OEM 嘗試將 system_ext 分區設為通用,請參閱「將 system_ext 分區設為通用」。如果裝置群組有許多差異,最好定義多個 SSI。

我可以修改 OEM GSI 的 generic_system.mk (mainline_system.mk) 嗎?

不可以。但原始設備製造商 (OEM) 可以為 OEM GSI 定義新的 Makefile,並繼承 generic_system.mk 檔案,然後改用新的 Makefile。如需範例,請參閱「強制執行產品分割介面」。

我可以從 generic_system.mk 中移除與實作項目衝突的模組嗎?

否。GSI 具有可啟動及可測試的最低模組集。如果您認為某個模組並非必要,請提出錯誤報告,更新 AOSP 中的 generic_system.mk 檔案。