實作虛擬 A/B 版本

如要在新裝置上導入虛擬 A/B 測試,或在已發布的裝置上進行改造,您必須變更裝置專屬的程式碼。

建構旗標

使用虛擬 A/B 的裝置必須設定為 A/B 裝置,且必須使用動態分割區啟動

如要使用虛擬 A/B 功能啟動裝置,請將裝置設為繼承虛擬 A/B 裝置基本設定:

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

使用虛擬 A/B 啟動的裝置只需要一半的電路板大小,即可容納 BOARD_SUPER_PARTITION_SIZE,因為 B 插槽不再位於超級插槽中。也就是說,BOARD_SUPER_PARTITION_SIZE 必須大於或等於 sum(更新群組大小) + 額外負荷,而這又必須大於或等於 sum(分割區大小) + 額外負荷

如要使用 Virtual A/B 啟用壓縮快照 (適用於 Android 13 以上版本),請沿用下列基本設定:

$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_ramdisk.mk)
$(call inherit-product, \
    $(SRC_TARGET_DIR)/product/virtual_ab_ota/vabc_features.mk)

這樣一來,使用者就能搭配 Virtual A/B 使用使用者空間快照,同時採用無運算壓縮方法。然後將壓縮方法設定為其中一種支援的方法,zstdlz4。在 Android 15 中,壓縮作業可進一步自訂,以符合裝置需求。詳情請參閱「微調壓縮」。

PRODUCT_VIRTUAL_AB_COMPRESSION_METHOD := lz4
PRODUCT_VIRTUAL_AB_COMPRESSION_FACTOR := 65536

如果是 Android 12,如要透過 Virtual A/B 啟用壓縮快照,請沿用下列基本設定:

$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_ramdisk.mk)
$(call inherit-product, \
    $(SRC_TARGET_DIR)/product/virtual_ab_ota/compression.mk)

XOR 壓縮

如果裝置升級至 Android 13 以上版本,XOR 壓縮功能不會預設啟用。如要啟用 XOR 壓縮,請在裝置的 .mk 檔案中新增以下內容。

PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.compression.xor.enabled=true

對於從 android_t_baseline.mk 繼承的裝置,XOR 壓縮功能預設為啟用。

使用者空間合併

在 Virtual A/B 的新版 (Android T 以上版本) 中,快照合併程序完全在使用者空間中進行。這項變更是由 snapuserd 和 dm-user 促成。搭載 Android 13 以上版本的裝置預設會啟用使用者空間合併功能,而升級的舊版裝置則可透過下列方式設定這項屬性:

PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.userspace.snapshots.enabled=true

啟動控制 HAL

開機控制 HAL 提供介面,供 OTA 用戶端控制開機插槽。虛擬 A/B 需要升級啟動控制 HAL 的次要版本,因為需要額外的 API,才能確保在刷機或恢復原廠設定期間保護啟動載入程式。如要查看最新版 HAL 定義,請參閱 IBootControl.haltypes.hal

// hardware/interfaces/boot/1.1/types.hal
enum MergeStatus : uint8_t {
    NONE, UNKNOWN, SNAPSHOTTED, MERGING, CANCELLED };

// hardware/interfaces/boot/1.1/IBootControl.hal
package android.hardware.boot@1.1;
interface IBootControl extends @1.0::IBootControl {
    setSnapshotMergeStatus(MergeStatus status)
        generates (bool success);
    getSnapshotMergeStatus()
        generates (MergeStatus status);
}
// Recommended implementation

Return<bool> BootControl::setSnapshotMergeStatus(MergeStatus v) {
    // Write value to persistent storage
    // e.g. misc partition (using libbootloader_message)
    // bootloader rejects wipe when status is SNAPSHOTTED
    // or MERGING
}

Fstab 變更

中繼資料分割區的完整性對啟動程序至關重要,尤其是在套用 OTA 更新後。因此,中繼資料分割區必須先經過檢查,first_stage_init 才能掛接。如要確保發生這種情況,請將 check fs_mgr 標記新增至 /metadata 的項目。以下提供範例:

/dev/block/by-name/metadata /metadata ext4 noatime,nosuid,nodev,discard,sync wait,formattable,first_stage_mount,check

核心需求

如要啟用快照功能,請將 CONFIG_DM_SNAPSHOT 設為 true

如果裝置使用 F2FS,請加入 f2fs:將 FS_NOCOW_FL 旗標匯出至使用者核心修補程式,修正檔案釘選問題。請一併納入 f2fs:支援對齊的釘選檔案核心修補程式。

虛擬 A/B 測試依賴核心 4.3 版新增的功能:snapshotsnapshot-merge 目標中的溢位狀態位元。所有搭載 Android 9 以上版本的裝置,都應已採用 4.4 以上版本的核心。

如要啟用壓縮快照,支援的最低核心版本為 4.19。 將 CONFIG_DM_USER=mCONFIG_DM_USER=y 設為 如果使用前者 (模組),模組必須載入第一階段的 RAM 磁碟。如要達成此目的,請在裝置 Makefile 中加入下列程式行:

BOARD_GENERIC_RAMDISK_KERNEL_MODULES_LOAD := dm-user.ko

Fastboot 工具異動

Android 11 對 fastboot 通訊協定進行了下列變更:

  • getvar snapshot-update-status - 傳回開機控制 HAL 傳達給啟動載入程式的值:
    • 如果狀態為 MERGING,啟動載入程式必須傳回 merging
    • 如果狀態為 SNAPSHOTTED,啟動載入程式必須傳回 snapshotted
    • 否則,開機載入程式必須傳回 none
  • snapshot-update merge:完成合併作業,並視需要啟動至復原/fastbootd。只有在 snapshot-update-statusmerging 時,這項指令才有效,且僅支援 fastbootd。
  • snapshot-update cancel:將開機控制 HAL 的合併狀態設為 CANCELLED。裝置鎖定時,這個指令無效。
  • erasewipe - metadatauserdata 或保存啟動控制 HAL 合併狀態的分區,應檢查快照合併狀態。erasewipe如果狀態為 MERGINGSNAPSHOTTED,裝置應中止作業。
  • set_active - 變更有效時段的 set_active 指令應檢查快照合併狀態。如果狀態為 MERGING,裝置應中止作業。在 SNAPSHOTTED 狀態中,可以安全地變更時段。

這些異動旨在防止裝置意外無法開機,但可能會中斷自動化工具。如果將這些指令當做刷寫所有分區的元件 (例如執行 fastboot flashall),建議使用下列流程:

  1. 查詢 getvar snapshot-update-status
  2. 如果是 mergingsnapshotted,請發出 snapshot-update cancel
  3. 繼續執行刷機步驟。

降低儲存空間需求

如果裝置在 super 中未分配完整的 A/B 儲存空間,且預期會視需要使用 /data,強烈建議使用區塊對應工具。區塊對應工具可確保建構作業之間的區塊分配一致,減少不必要的快照寫入作業。相關說明請參閱「縮減 OTA 大小」。

OTA 壓縮演算法

您可以針對不同的效能指標調整 OTA 封裝。Android 提供多種支援的壓縮方法 (lz4zstdnone),這些方法在安裝時間、COW 空間用量、啟動時間和快照合併時間之間有所取捨。啟用壓縮功能的虛擬 AB 測試預設選項為 lz4 compression method

微調壓縮

您可以透過兩種方法進一步自訂壓縮演算法:(壓縮層級) (以速度為代價達成的壓縮量) 和 (壓縮係數) (可壓縮的最大視窗大小)。壓縮層級適用於特定演算法 (例如 zstd),變更層級時,速度和壓縮率會有所取捨。壓縮係數說明 OTA 安裝期間使用的最大壓縮視窗大小。預設值為 64k,但您可以自訂建構參數 PRODUCT_VIRTUAL_AB_COMPRESSION_FACTOR 來覆寫預設值。支援的壓縮係數:4k、8k、16k、32k、64k、128k 和 256k。

PRODUCT_VIRTUAL_AB_COMPRESSION_FACTOR := 65536

Pixel 8 Pro 的增量 OTA

不含安裝後階段的安裝時間 COW 空間用量 OTA 更新後啟動時間 快照合併時間
lz4 18 分 15 秒 2.5 GB 32.7 秒 98.6 秒
zstd 24 分 49 秒 2.05 GB 36.3 秒 133.2 秒
16 分 42 秒 4.76 GB 28.7 秒 76.6 秒

Pixel 8 Pro 的完整 OTA

不含安裝後階段的安裝時間 COW 空間用量 OTA 更新後啟動時間 快照合併時間
lz4 15 分 11 秒 4.16 GB 17.6 秒 82.2 秒
zstd 16 分 19 秒 3.46 GB 21.0 秒 106.3 秒
13 分 33 秒 6.39 GB 18.5 秒 92.5 秒