實作虛擬 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(分區大小) + 負擔

在 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 啟用使用者空間快照 。接著,您可以將壓縮方法設為 支援的方法:gzzstdlz4

PRODUCT_VIRTUAL_AB_COMPRESSION_METHOD := lz4

在 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)

XOR 壓縮

如果是升級至 Android 13 以上版本的裝置, XOR 壓縮功能 預設啟用的功能如要啟用 XOR 壓縮,請將下列程式碼新增到裝置的 .mk 檔案。

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

針對以下來源的裝置,系統預設會啟用 XOR 壓縮功能 android_t_baseline.mk

使用者空間合併

如果是升級至 Android 13 以上版本的裝置, 使用者空間合併程序,詳情請見「裝置對應程式」一節 分層並未啟用 預設值。如要啟用使用者空間合併功能,請在裝置的 .mk 中新增以下這一行 檔案:

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

根據預設, 13 以及更高版本。

啟動控制項 HAL

啟動控制項 HAL 可讓 OTA 用戶端控制啟動運算單元。虛擬 A/B 版本 需要升級啟動控制項 HAL 的子版本,因為其他 API 以確保系統啟動載入程式在刷新或恢復原廠設定時受到保護。詳情請見 IBootControl.haltypes.hal 取得最新版本的 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。如果使用舊版 (模組), 模組必須在第一階段 ramdisk 中載入。這可以藉由 在裝置 Makefile 中新增下列指令行:

BOARD_GENERIC_RAMDISK_KERNEL_MODULES_LOAD := dm-user.ko

升級至 Android 11 的裝置可享受 Retrofit

升級至 Android 11 時,搭載動態分區啟動的裝置可以 可視需要翻新虛擬 A/B更新程序與 以虛擬 A/B 版本啟動的裝置,但有些微差異:

  • COW 檔案的位置 — 對於推出的裝置,OTA 用戶端會使用 必須先讓超級分區中的所有可用空間 /data。對懷舊裝置來說,超級系列中有足夠的空間 ,確保 COW 檔案不會在 /data 中建立。

  • 建構時間功能旗標 - 針對翻新的虛擬 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 * 總和(更新群組的大小) + 負荷,而該數字會大於或等於 2 * 總和(分區大小) +

系統啟動載入程式變更

在更新合併步驟中,/data 會保留整個更新 Android 作業系統。遷移作業開始後,systemvendor 和 在複製完成前,product 個分區不完整。如果裝置 過程中透過系統還原或重新恢復原廠設定。 設定對話方��,���示裝置無法���動。

���除 /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 - 完成合併作業,啟動以下作業: 必要時復原和快速啟動只有在下列情況中,這個指令才有效 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. 繼續執行刷新步驟。
,瞭解如何調查及移除這項存取權。

降低儲存空間需求

並未分配完整 A/B 儲存空間,且在預期 以便視需要使用 /data,我們強烈建議使用區塊對應 如果偏好在終端機視窗中工作 可使用 Google Cloud CLI gcloud 指令列工具區塊對應工具可讓不同版本之間的區塊配置保持一致, 並減少不必要的寫入快照量這部分已記錄在減少 OTA 大小

OTA 壓縮方法

OTA 套件可依不同的成效指標進行調整。Android 提供 幾種支援的壓縮方法 (gzlz4zstdnone), 在安裝時間、COW 空間用量、開機時間和快照之間取得平衡 合併時間。要用於壓縮的虛擬 ADB,預設選項是 gz compression method。(注意:壓縮方法之間的相對效能) 會因 CPU 速度和儲存空間處理量而異 應用程式。下方產生的所有 OTA 套件都會停用 PostInstall, 也會稍微降低啟動時間陣列的動態分區總大小 未壓縮的完整 ota 即為 4.81 GB)。

Pixel 6 Pro 上的 OTA 增量

安裝後階段的安裝時間 COW 空間用量 OTA 啟動時間 快照合併時間
gz 24 分鐘 1.18 GB 40.2 秒 45.5 秒
lz4 13 分鐘 1.49 GB 37.4 秒 37.1 秒
13 分鐘 2.90 GB 37.6 秒 40.7 秒

Pixel 6 Pro 的完整 OTA

安裝後階段的安裝時間 COW 空間用量 OTA 啟動時間 快照合併時間
gz 23 分鐘 2.79 GB 24.9 秒 41.7 秒
lz4 12 min 3.46 GB 20.0 秒 25.3 秒
10 分鐘 4.85 GB 20.6 秒 29.8 秒