適用於沒有動態分區的 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」與「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 更新的其他分區
      • 群組列_b
        • 邏輯 (動態) 區隔 vendor_b
        • 邏輯 (動態) 分區 product_b
        • 由 Bar 更新的其他分區

您可以使用 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

為 Retrofit 裝置產生漸進式 OTA 時, 取決於基礎版本是否定義 「PRODUCT_USE_DYNAMIC_PARTITIONS」和 PRODUCT_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 做為安裝後步驟, 拒絕更新。