Android 共用系統映像檔

本頁說明 Android 裝置原始設備製造商 (OEM) 可用於在各產品線建立自己的共用系統映像檔 (SSI) 的幾種機制。這份文件也提出了相關程序,說明如何在 AOSP 建構的通用系統映像檔 (GSI) 上,建立原始設備製造商 (OEM) 擁有的 SSI。

背景

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

動機

Android 開放原始碼計畫中發布的架構程式碼符合 Treble 架構,並與舊版供應商實作項目維持回溯相容性。舉例來說,從 Android 10 AOSP 來源建構的通用系統映像檔,可在任何搭載 Android 8 以上版本且符合 Treble 規範的裝置上執行。消費者裝置出貨時搭載的 Android 版本,會由 SoC 供應商和原始設備製造商修改。(請參閱「Android 版本的生命週期」)。這些對架構所做的變更和擴充功能並非為了維持回溯相容性而編寫,因此導致 OS 升級作業變得更複雜且成本更高。針對特定裝置進行的變更和修改,會導致 Android OS 版本升級的成本和複雜性增加。

在 Android 11 之前,沒有任何明確架構可讓合作夥伴針對 Android OS 架構建構模組化擴充功能。本文件說明 SoC 供應商和原始設備製造商可採取的步驟,以建立 SSI。也就是說,這會是從 Android 作業系統架構來源建立的單一映像檔,可在多個裝置上重複使用,以便維持與供應商實作項目的回溯相容性,並大幅降低 Android 作業系統升級的複雜度和成本。如需建立 SSI 的具體步驟,請參閱「建議的 GSI 準則 SSI 步驟」一節,請注意,您不必使用所有四個步驟。您選擇的步驟 (例如僅限步驟 1) 取決於您的實作方式。

SSI 總覽

透過 SSI,產品專屬軟體元件和 OEM 擴充功能會放置在新的 /product 分區。/product 分區中的元件會使用明確且穩定的介面,與 /system 分區中的元件互動。原始設備製造商 (OEM) 可以選擇建構一組 SSI,或是在多個裝置 SKU 中使用少量的 SS。當新版 Android 作業系統推出時,原始設備製造商 (OEM) 只需一次更新 SSI 至最新版 Android 版本。他們可以重複使用 SSI 來更新多部裝置,而無須更新 /product 分割區。

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

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

將產品專屬元件分割至產品分區的核心概念,與將 SoC 專屬元件分割至供應商分區的 Treble 概念相似。產品介面 (類似於 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 分區。

  • 產品:產品或裝置專屬元件集合,代表 Android OS 的原始設備製造商 (OEM) 自訂選項和擴充功能。將 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 (直通 HAL 僅適用於 systemsystem_ext 模組)
    • 穩定版 AIDL
    • 設定
      • 系統屬性 API
      • 設定檔結構定義 API
    • VNDK
    • Android SDK API
    • Java SDK 程式庫
  • 產品介面:產品介面是 SSI 和產品圖片之間的介面。定義穩定的介面可將產品元件與 SSI 中的系統元件分離。產品介面需要使用與 VINTF 相同的穩定介面。不過,只有 VNDK 和 Android SDK API 適用於搭載 Android 11 以上版本的裝置。

在 Android 11 中啟用 SSI

本節說明如何使用現有新功能支援 Android 11 中的 SSI。

/system_ext 分區

/system_ext 分區是在 Android 11 中推出,做為選用分區。(這是非 AOSP 元件與 /system 區段中 AOSP 定義元件緊密結合的地方)。系統會假設 /system_ext 分區是 /system 分區的 OEM 專屬擴充功能,且兩個分區之間沒有定義介面。/system_ext 區隔中的元件可以對 /system 區隔發出私人 API 呼叫,而 /system 區隔中的元件則可以對 /system_ext 區隔發出私人 API 呼叫。

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

如要將模組安裝至 /system_ext 分割區,請將 system_ext_specific: true 新增至 Android.bp 檔案。若裝置沒有 /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 分割區的主要目的是擴充系統功能,而非安裝內含的產品模組,如 /system_ext partition 一節所述。如要這麼做,請解除包裝產品專屬的模組,並將其移至 /product 分區。將產品專屬模組拆分後,裝置就會使用 /system_ext。(詳情請參閱將 /system_ext 分區設為通用)。

如要取消 /product 分區與系統元件組合,/product 分區的強制執行政策必須與已從 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) 是直接從 AOSP 建構的系統映像檔。用於進行 Treble 法規遵循測試 (例如 CTS-on-GSI) 的測試,也會做為參考平台,讓應用程式開發人員在沒有執行所需 Android 版本的實際裝置時,用來測試應用程式的相容性。

原始設備製造商 (OEM) 也可以使用 GSI 製作 SSI。如映像檔和分區所述,SSI 是由 Android 開放原始碼計畫定義元件的系統映像檔,以及 OEM 定義元件的 system_ext 映像檔。如果 GSI 用於 system 映像檔,OEM 可以專注於升級的 system_ext 映像檔。

本節提供指南,供 OEM 廠商在使用 AOSP 或接近 AOSP 的系統映像檔時,將自訂項目模組化為 /system_ext/product 分區。如果原始設備製造商 (OEM) 從 Android 開放原始碼計畫來源建構系統映像檔,則可使用 Android 開放原始碼計畫提供的 GSI 取代所建構的系統映像檔。不過,原始設備製造商 (OEM) 不需要同時完成最後一個步驟 (以 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) 可以修改這些檔案,讓原始設備製造商 GSI 除了包含 Android 開放原始碼計畫 GSI 檔案外,還能包含原始設備製造商專屬檔案。不過,OEM 不得修改 generic_system.mk 檔案本身。

為原始設備製造商 (OEM) 系統映像檔繼承 `generic_system.mk`

圖 3. 為原始設備製造商 (OEM) 的系統映像檔繼承 generic_system.mk

步驟 2:讓原始設備製造商 (OEM) GSI 與 Android 開放原始碼計畫 GSI 的檔案清單相同

OEM GSI 目前無法有其他檔案。原始設備製造商 (OEM) 的專屬檔案必須移至 system_extproduct 分區。

將新增的檔案移出原始設備製造商 (OEM) GSI

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

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

原始設備製造商 (OEM) 可使用 compare_images 工具檢查已修改的檔案,並將 AOSP GSI 與 OEM GSI 進行比較。向 Android 開放原始碼計畫午餐目標 generic_system_* 取得 Android 開放原始碼計畫 GSI。

只要定期使用 allowlist 參數執行 compare_images 工具,您就可以監控允許清單以外的差異。這樣可避免需要對原始設備製造商 (OEM) GSI 進行額外修改。

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

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

步驟 4:讓原始設備製造商 (OEM) GSI 的二進位檔與 Android 開放原始碼計畫 (AOSP) GSI 相同

清除許可清單後,原始設備製造商 (OEM) 就能將 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,與 Android 開放原始碼計畫 GSI 的步驟無關。

強制執行產品介面

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

讓 /system_ext 分區成為常見分區

/system_ext 分割區可能會因裝置而異,因為它可能包含裝置專屬的系統內建模組。由於 SSI 包含 /system/system_ext 分區,/system_ext 分區的差異會妨礙原始設備製造商定義 SSI。原始設備製造商 (OEM) 可以有自己的 SSI,只要移除任何差異並將 /system_ext 分區設為通用,即可在多部裝置上分享該 SSI。

本節提供將 /system_ext 分區設為共通的建議。

在系統分區中公開隱藏的 API

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

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

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

加入所有 APK 的超集合,並略過針對每部裝置安裝的部分套件

某些系統內建的套件在不同裝置上並不常見。將這些 APK 模組解除綁定,並移至產品或供應商分區,可能會相當困難。作為暫時性解決方案,原始設備製造商 (OEM) 可以讓 SSI 納入所有模組,然後使用 SKU 屬性 (ro.boot.hardware.sku) 篩除不需要的模組。如要使用篩選器,OEM 應重疊架構資源 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)」一文。OEM 廠商也可以使用 android:requiredSystemPropertyNameandroid:requiredSystemPropertyValue 屬性,定義依系統屬性而定的條件式 RRO。

常見問題 (FAQ)

我可以定義多個 SSI 嗎?

這取決於裝置 (或裝置群組) 的共通性和特性。OEM 可以嘗試讓 system_ext 分區通用,詳情請參閱「讓 system_ext 分區通用」。如果裝置群組有許多差異,建議您定義多個 SSI。

我可以修改原始設備製造商 (OEM) GSI 的 generic_system.mk (mainline_system.mk) 嗎?

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

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

否。GSI 包含一組可啟動和測試的模組。如果您認為某個模組不是必要的,請提出錯誤報告,以便更新 AOSP 中的 generic_system.mk 檔案。