適用於沒有動態分區的 A/B 裝置 OTA

Android 10 支援動態分區,這是一種使用者空間分區系統,可在無線 (OTA) 更新期間建立、調整大小及刪除分區。

本頁說明 OTA 用戶端如何在更新期間為未支援動態分區的 A/B 裝置調整動態分區大小,以及 OTA 用戶端如何升級至 Android 10。

背景

在更新 A/B 裝置以支援動態分區時,裝置上的 GUID 分區表 (GPT) 會保留,因此裝置上不會有 super 分區。中繼資料會儲存在 system_asystem_b,但您可以變更 BOARD_SUPER_PARTITION_METADATA_DEVICE 來自訂中繼資料。

每個區塊裝置都有兩個中繼資料插槽。只會使用每個區塊裝置中單一的中繼資料插槽。舉例來說,system_a 的中繼資料 0 和 system_b 的中繼資料 1 分別對應 A 運算單元和 B 運算單元的分區。在執行階段,無論哪個時段正在更新,都沒有關係。

在這個頁面中,中繼資料版位稱為「中繼資料 S」(來源) 和「中繼資料 T」(目標)。同樣地,分區會稱為 system_svendor_t 等。

如要進一步瞭解建構系統設定,請參閱「升級裝置」。

如要進一步瞭解分區如何屬於更新群組,請參閱新裝置的板卡設定變更

裝置上的中繼資料範例:

  • 實體區塊裝置 system_a
    • 中繼資料 0
      • 群組 foo_a
        • 邏輯 (動態) 分割區 system_a
        • 邏輯 (動態) 區隔 product_services_a
        • 由 Foo 更新的其他分區
      • 群組 bar_a
        • 邏輯 (動態) 分割區 vendor_a
        • 邏輯 (動態) 分區 product_a
        • 由 Bar 更新的其他分區
    • 中繼資料 1 (未使用)
  • 實體區塊裝置 system_b
    • 中繼資料 0 (未使用)
    • 中繼資料 1
      • 群組 foo_b
        • 邏輯 (動態) 區隔 system_b
        • 邏輯 (動態) 區隔 product_services_b
        • 由 Foo 更新的其他分區
      • 群組 bar_b
        • 邏輯 (動態) 區隔 vendor_b
        • 邏輯 (動態) 區隔 product_b
        • 已透過長條更新其他分區

您可以使用 system/extras/partition_tools 底下的 lpdump 工具轉儲裝置上的中繼資料。例如:

lpdump --slot 0 /dev/block/by-name/system_a
lpdump --slot 1 /dev/block/by-name/system_b

翻新更新

在搭載 Android 9 以下版本的裝置上,裝置的 OTA 用戶端不支援更新前對應動態分區。系統會建立另一組修補程式,以便將對應關係直接套用至現有的實體分區。

OTA 產生器會建構最終的 super.img 檔案,其中包含所有動態分割區的內容,然後將映像檔分割成多個映像檔,以符合系統、供應商等對應實體區塊裝置的大小。這些圖片的名稱為 super_system.imgsuper_vendor.img 等。OTA 用戶端會將這些映像檔套用至實體分區,而非套用邏輯 (動態) 分區。

由於 OTA 用戶端不知道如何對應動態分區,因此在產生更新套件時,系統會自動為這些分區停用所有安裝後步驟。詳情請參閱「設定安裝後程序」。

更新流程與 Android 9 相同。

更新前:

ro.boot.dynamic_partitions=
ro.boot.dynamic_partitions_retrofit=

更新後:

ro.boot.dynamic_partitions=true
ro.boot.dynamic_partitions_retrofit=true

日後的修舊更新

在進行復舊更新後,OTA 用戶端會更新為搭配動態分區運作。來源分區的範圍絕不會跨越目標實體分區。

使用一般更新套件進行更新流程

  1. 初始化 super 分區中繼資料。
    1. 從中繼資料 S (來源中繼資料) 建構新的中繼資料 M。舉例來說,如果中繼資料 S 使用 [system_svendor_sproduct_s] 做為區塊裝置,那麼新的中繼資料 M 就會使用 [system_tvendor_tproduct_t] 做為區塊裝置。所有群組和分區都會在 M 中遭到捨棄。
    2. 根據更新資訊清單中的 dynamic_partition_metadata 欄位新增目標群組和分區。您可以在 new_partition_info 中找到每個分區的大小。
    3. 將 M 寫入中繼資料 T。
    4. 將裝置對應工具新增的分區對應至可寫入的分區。
  2. 在區塊裝置上套用更新。
    1. 視需要將裝置對應器上的來源分區設為唯讀。這是側載作業的必要步驟,因為更新前並未對來源分區進行對應。
    2. 將完整或差異更新套用至目標時段的所有區塊裝置。
    3. 接著掛接分區以執行安裝後指令碼,然後卸載分區。
  3. 取消對應目標分區。

使用 Retrofit 更新套件更新流程

如果 Retrofit 更新套件套用至已啟用動態分區的裝置,OTA 用戶端會直接將分割的 super.img 檔案套用至區塊裝置。更新流程與 Retrofit 更新流程類似。詳情請參閱「翻新更新」。

舉例來說,假設:

  • 插槽 A 是有效插槽。
  • system_a 會在 0 個插槽中包含有效的中繼資料。
  • system_avendor_aproduct_a 會用做區塊裝置。

當 OTA 用戶端收到復古更新套件時,會在實體 system_b 上套用 super_system.img,在實體 vendor_b 上套用 super_vendor.img,以及在實體 product_b 上套用 super_product.img。實體區塊裝置 system_b 包含正確的中繼資料,可在開機時對應邏輯 system_bvendor_bproduct_b

產生更新套件

增量 OTA

為改裝裝置產生增量 OTA 時,更新內容取決於基本版本是否定義 PRODUCT_USE_DYNAMIC_PARTITIONSPRODUCT_RETROFIT_DYNAMIC_PARTITIONS

  • 如果基本版本定義變數,則為回溯更新。更新套件包含分割的 super.img 檔案,並停用安裝後步驟。
  • 如果基礎版本確實定義變數,這就與動態分區的一般更新相同。更新套件包含邏輯 (動態) 分區的映像檔。可以啟用安裝後步驟。

完整 OTA

系統會為復古裝置產生兩個完整的 OTA 套件。

  • $(PRODUCT)-ota-retrofit-$(TAG).zip 一律包含分割的 super.img,並停用安裝後步驟,以便回溯更新。
    • 系統會在 ota_from_target_files 指令碼中加入額外參數 --retrofit_dynamic_partitions 來產生此指令碼。
    • 此設定可套用至所有版本。
  • $(PRODUCT)-ota-$(TAG).zip 包含日後更新的邏輯圖片。
    • 僅將這項設定套用至已啟用動態分區的建構作業。請參閱下文,瞭解如何強制執行這項規定。

拒絕舊版本的非 Retrofit 更新

請只將一般完整 OTA 套件套用至已啟用動態分區的版本。如果 OTA 伺服器設定有誤,並將這些套件推送至搭載 Android 9 以下版本的裝置,裝置將無法啟動。Android 9 以下版本的 OTA 用戶端無法區分復古 OTA 套件和一般完整 OTA 套件,因此用戶端不會拒絕完整套件。

為避免裝置接受完整的 OTA 套件,您可以要求在安裝後執行步驟,以便檢查現有的裝置設定。例如:

device/device_name/dynamic_partitions/check_dynamic_partitions

#!/system/bin/sh
DP_PROPERTY_NAME="ro.boot.dynamic_partitions"
DP_RETROFIT_PROPERTY_NAME="ro.boot.dynamic_partitions_retrofit"

DP_PROPERTY=$(getprop ${DP_PROPERTY_NAME})
DP_RETROFIT_PROPERTY=$(getprop ${DP_RETROFIT_PROPERTY_NAME})

if [ "${DP_PROPERTY}" != "true" ] || [ "${DP_RETROFIT_PROPERTY}" != "true" ] ; then
    echo "Error: applied non-retrofit update on build without dynamic" \
         "partitions."
    echo "${DP_PROPERTY_NAME}=${DP_PROPERTY}"
    echo "${DP_RETROFIT_PROPERTY_NAME}=${DP_RETROFIT_PROPERTY}"
    exit 1
fi

device/device_name/dynamic_partitions/Android.mk

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE:= check_dynamic_partitions
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_SRC_FILES := check_dynamic_partitions
LOCAL_PRODUCT_MODULE := true
include $(BUILD_PREBUILT)

device/device_name/device.mk

PRODUCT_PACKAGES += check_dynamic_partitions

# OPTIONAL=false so that the error in check_dynamic_partitions will be
# propagated to OTA client.
AB_OTA_POSTINSTALL_CONFIG += \
    RUN_POSTINSTALL_product=true \
    POSTINSTALL_PATH_product=bin/check_dynamic_partitions \
    FILESYSTEM_TYPE_product=ext4 \
    POSTINSTALL_OPTIONAL_product=false \

當一般 OTA 套件套用至未啟用動態分區的裝置時,OTA 用戶端會將 check_dynamic_partitions 當做安裝後步驟執行,並拒絕更新。