實施虛擬 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 插槽不再處於 super 中。也就是說, BOARD_SUPER_PARTITION_SIZE必須大於或等於sum(size of update groups) + overhead ,而 sum(size of partitions) + overhead 又必須大於或等於sum(size of partitions) + overhead

對於 Android 13 及更高版本,要使用虛擬 A/B 啟用壓縮快照,請繼承以下基本配置:

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

這在使用無操作壓縮方法時啟用了具有虛擬 A/B 的用戶空間快照。然後,您可以將壓縮方法配置為受支持的方法之一, gzbrotli

PRODUCT_VIRTUAL_AB_COMPRESSION_METHOD := gz

對於 Android 12,要使用虛擬 A/B 啟用壓縮快照,請繼承以下基本配置:

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

異或壓縮

對於升級到 Android 13 及更高版本的設備,默認情況下不啟用XOR 壓縮功能。要啟用 XOR 壓縮,請將以下內容添加到設備的.mk文件中。

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

對於繼承自android_t_baseline.mk的設備,XOR 壓縮默認啟用。

用戶空間合併

對於升級到 Android 13 及更高版本的設備,默認情況下不啟用設備映射器分層中所述的用戶空間合併過程。要啟用用戶空間合併,請將以下行添加到設備的.mk文件中:

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

用戶空間合併在使用 13 及更高版本啟動的設備上默認啟用。

引導控制 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: export FS_NOCOW_FL 標誌到用戶內核補丁以修復文件固定。包括f2fs:也支持對齊固定文件內核補丁。

虛擬 A/B 依賴於內核版本 4.3 中添加的功能: snapshotsnapshot-merge目標中的溢出狀態位。所有搭載 Android 9 及更高版本的設備都應該已經擁有 4.4 或更高版本的內核。

要啟用壓縮快照,支持的最低內核版本為 4.19。設置CONFIG_DM_USER=mCONFIG_DM_USER=y 。如果使用前者(模塊),模塊必須加載到第一階段的虛擬磁盤中。這可以通過將以下行添加到設備 Makefile 來實現:

BOARD_GENERIC_RAMDISK_KERNEL_MODULES_LOAD := dm-user.ko

在升級到 Android 11 的設備上進行改造

升級到 Android 11 時,使用動態分區啟動的設備可以選擇性地改造虛擬 A/B。更新過程與使用虛擬 A/B 啟動的設備基本相同,但有一些細微差別:

  • COW 文件的位置——對於啟動設備,OTA 客戶端在使用/data中的空間之前使用超級分區中所有可用的空白空間。對於改裝設備,超級分區中始終有足夠的空間,因此永遠不會在/data上創建 COW 文件。

  • 構建時功能標誌——對於改裝虛擬 A/B 的設備, PRODUCT_VIRTUAL_AB_OTAPRODUCT_VIRTUAL_AB_OTA_RETROFIT均設置為true ,如下所示:

    (call inherit-product, \
        (SRC_TARGET_DIR)/product/virtual_ab_ota_retrofit.mk)
    
  • 超級分區大小——使用虛擬 A/B 啟動的設備可以將BOARD_SUPER_PARTITION_SIZE減半,因為 B 插槽不在超級分區中。改造虛擬 A/B 的設備保持舊的超級分區大小,因此BOARD_SUPER_PARTITION_SIZE大於或等於2 * sum(size of update groups) + overhead ,這又大於或等於2 * sum(size of partitions) + 開銷

引導加載程序更改

在更新的合併步驟中, /data包含 Android 操作系統的唯一完整實例。遷移開始後,本機systemvendorproduct分區在復製完成之前是不完整的。如果設備在此過程中通過恢復或通過系統設置對話框恢復出廠設置,則設備將無法啟動。

在擦除/data之前,根據設備狀態在恢復或回滾中完成合併:

  • 如果之前新構建成功啟動,則完成遷移。
  • 否則,回滾到舊插槽:
    • 對於動態分區,回滾到以前的狀態。
    • 對於靜態分區,將活動插槽設置為舊插槽。

如果設備解鎖,引導加載程序和fastbootd都可以擦除/data分區。雖然fastbootd可以強製完成遷移,但引導加載程序不能。引導加載程序不知道合併是否正在進行,或者/data中的哪些塊構成了 OS 分區。設備必須防止用戶通過執行以下操作在不知不覺中使設備無法操作(變磚):

  1. 實現引導控制 HAL,以便引導加載程序可以讀取setSnapshotMergeStatus()方法設置的值。
  2. 如果合併狀態為MERGING ,或者如果合併狀態為SNAPSHOTTED並且插槽已更改為新更新的插槽,則必須在引導加載程序中拒絕擦除userdatametadata或存儲合併狀態的分區的請求。
  3. 實施fastboot snapshot-update cancel命令,以便用戶可以向引導加載程序發出他們想要繞過此保護機制的信號。
  4. 修改自定義刷機工具或腳本以在刷機整個設備時發出fastboot snapshot-update cancel 。這是可以安全發布的,因為刷寫整個設備會刪除 OTA。工具可以通過實施fastboot getvar snapshot-update-status在運行時檢測此命令。此命令有助於區分錯誤情況。

例子

struct VirtualAbState {
    uint8_t StructVersion;
    uint8_t MergeStatus;
    uint8_t SourceSlot;
};

bool ShouldPreventUserdataWipe() {
    VirtualAbState state;
    if (!ReadVirtualAbState(&state)) ...
    return state.MergeStatus == MergeStatus::MERGING ||
           (state.MergeStatus == MergeStatus::SNAPSHOTTED &&
            state.SourceSlot != CurrentSlot()));
}

Fastboot 工具更改

Android 11 對 fastboot 協議做瞭如下改動:

  • getvar snapshot-update-status — 返回引導控制 HAL 與引導加載程序通信的值:
    • 如果狀態為MERGING ,引導加載程序必須返回merging
    • 如果狀態為SNAPSHOTTED ,引導加載程序必須返回snapshotted
    • 否則,引導加載程序必須返回none
  • snapshot-update merge — 完成合併操作,必要時引導至 recovery/fastbootd。此命令僅在snapshot-update-statusmerging時有效,並且僅在 fastbootd 中受支持。
  • snapshot-update cancel — 將引導控制 HAL 的合併狀態設置為CANCELLED 。該命令在設備被鎖定時無效。
  • erasewipe - erasewipe metadatauserdata或保存引導控制 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 目前提供了一些受支持的壓縮方法( gzlz4none ),它們在安裝時間、cow 空間使用、啟動時間和快照合併時間之間進行權衡。為帶壓縮的虛擬 ab 啟用的默認選項是gz compression method 。 (注意:lz4 和無壓縮之間的相對性能取決於 CPU 速度和存儲吞吐量。在某些設備上,無壓縮可能優於lz4

1. Pixel 6 Pro 上的增量 OTA

安裝時間母牛空間使用後 OTA 啟動時間快照合併時間
廣州1416.13 秒1.18GB 47.3 秒48023 毫秒
lz4 733.12 秒1.49GB 45.0 秒37021 毫秒
沒有任何777.70 秒2.90 GB 40.8 秒43442 毫秒

2. Pixel 6 Pro 上的完整 OTA

安裝時間母牛空間使用後 OTA 啟動時間快照合併時間
廣州1220.37 秒2.79GB 90.0 秒37385 毫秒
lz4 630.49 秒3.46GB 44.4 秒31573 毫秒
沒有任何663.75 秒4.85GB 44.2 秒31669 毫秒