實作虛擬 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(size of update groups) + overhead,而 sum(size of partitions) + overhead 也必須大於或等於 sum(size of partitions) + overhead

針對 Android 13 以上版本,如要啟用 Virtual A/B 的壓縮快照,請繼承下列基本設定:

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

這可在使用無操作壓縮法時,透過虛擬 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 壓縮功能。

使用者空間合併

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

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

啟動控制 HAL

boot control HAL 提供介面,讓 OTA 用戶端控制啟動槽。虛擬 A/B 需要升級 boot control 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: export FS_NOCOW_FL flag to user 核心修補程式,以修正檔案固定功能。請一併納入 f2fs: support aligned pinned file 核心修補程式。

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

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

BOARD_GENERIC_RAMDISK_KERNEL_MODULES_LOAD := dm-user.ko

Fastboot 工具異動

Android 11 會對 Fastboot 通訊協定進行以下變更:

  • getvar snapshot-update-status:傳回啟動控制 HAL 傳送至啟動載入程式的值:
    • 如果狀態為 MERGING,則系統啟動載入程式必須傳回 merging
    • 如果狀態為 SNAPSHOTTED,則啟動載入程式必須傳回 snapshotted
    • 否則,Bootloader 必須傳回 none
  • snapshot-update merge:完成合併作業,並視需要啟動至復原/快速啟動模式。只有在 snapshot-update-statusmerging 時,此指令才有效,且僅支援在 fastbootd 中執行。
  • snapshot-update cancel:將開機控制 HAL 的合併狀態設為 CANCELLED。裝置鎖定時,這個指令無效。
  • erasewipemetadatauserdata 或分區的 erasewipe 應檢查快照合併狀態,以便保留啟動控制 HAL 的合併狀態。如果狀態為 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 空間使用量、啟動時間和快照合併時間之間取得平衡。透過壓縮功能啟用虛擬 ADB 的預設選項為 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 秒