要在新設備上實現虛擬 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(更新組的大小) + 開銷,而後者必須大於或等於sum(分區的大小) + 開銷。
對於 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/android_t_baseline.mk)
這使得用戶空間快照能夠在使用無操作壓縮方法的同時使用 Virtual A/B。然後,您可以將壓縮方法配置為受支持的方法之一: gz
和brotli
。
PRODUCT_VIRTUAL_AB_COMPRESSION_METHOD := gz
對於 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)
異或壓縮
對於升級到 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.hal和types.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:也支持對齊固定文件內核補丁。
Virtual A/B 依賴於內核版本 4.3 中添加的功能: snapshot
和snapshot-merge
目標中的溢出狀態位。所有搭載 Android 9 及更高版本的設備都應該已經具有內核版本 4.4 或更高版本。
要啟用壓縮快照,支持的最低內核版本為 4.19。設置CONFIG_DM_USER=m
或CONFIG_DM_USER=y
。如果使用前者(模塊),則該模塊必須加載到第一階段 ramdisk 中。這可以通過將以下行添加到設備 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_OTA
和PRODUCT_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(更新組的大小) + 開銷,而開銷又大於或等於2 * sum(分區的大小) + 開銷。
引導加載程序更改
在更新的合併步驟中, /data
保存 Android 操作系統的唯一完整實例。遷移開始後,本機system
、 vendor
和product
分區在復製完成之前都是不完整的。如果在此過程中通過恢復或通過系統設置對話框將設備重置為出廠設置,則設備將無法啟動。
在擦除/data
之前,根據設備狀態完成恢復或回滾中的合併:
- 如果新版本之前已成功啟動,請完成遷移。
- 否則,回滾到舊槽:
- 對於動態分區,回滾到之前的狀態。
- 對於靜態分區,將活動插槽設置為舊插槽。
如果設備解鎖,引導加載程序和fastbootd
都可以擦除/data
分區。雖然fastbootd
可以強制遷移完成,但引導加載程序卻不能。引導加載程序不知道合併是否正在進行,也不知道/data
中的哪些塊構成操作系統分區。設備必須通過執行以下操作來防止用戶在不知不覺中使設備無法運行(變磚):
- 實現引導控制HAL,以便引導加載程序可以讀取
setSnapshotMergeStatus()
方法設置的值。 - 如果合併狀態為
MERGING
,或者合併狀態為SNAPSHOTTED
並且插槽已更改為新更新的插槽,則必須在引導加載程序中拒絕擦除userdata
、metadata
或存儲合併狀態的分區的請求。 - 實施
fastboot snapshot-update cancel
命令,以便用戶可以向引導加載程序發出信號,表明他們想要繞過此保護機制。 - 修改自定義刷新工具或腳本,以在刷新整個設備時發出
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-status
為merging
時有效,並且僅在 fastbootd 中受支持。 -
snapshot-update cancel
— 將啟動控制 HAL 的合併狀態設置為CANCELLED
。當設備鎖定時,該命令無效。 -
erase
或wipe
—erase
或wipe
metadata
、userdata
或保存啟動控制 HAL 合併狀態的分區應檢查快照合併狀態。如果狀態為MERGING
或SNAPSHOTTED
,設備應中止操作。 -
set_active
— 更改活動插槽的set_active
命令應檢查快照合併狀態。如果狀態為MERGING
,設備應中止操作。可以在SNAPSHOTTED
狀態下安全地更改插槽。
這些更改旨在防止意外導致設備無法啟動,但它們可能會對自動化工具造成破壞。當命令用作刷新所有分區的組件時,例如運行fastboot flashall
,建議使用以下流程:
- 查詢
getvar snapshot-update-status
。 - 如果
merging
或snapshotted
,請發出snapshot-update cancel
。 - 繼續執行閃爍步驟。
減少存儲需求
強烈建議未在 super 中分配完整 A/B 存儲並希望根據需要使用/data
設備使用塊映射工具。塊映射工具使構建之間的塊分配保持一致,從而減少對快照的不必要寫入。這記錄在“減少 OTA 大小”下。
OTA壓縮方法
Ota 包可以針對不同的性能指標進行調整。 Android 目前提供了一些受支持的壓縮方法( gz
、 lz4
和none
),這些方法在安裝時間、COW 空間使用、啟動時間和快照合併時間之間進行權衡。為帶有壓縮功能的虛擬 ab 啟用的默認選項是gz compression method
。 (注意:壓縮方法之間的相對性能因 CPU 速度和存儲吞吐量而異,而這可能會根據設備而變化。下面生成的所有 OTA 包均禁用 PostInstall,這會稍微減慢啟動時間。完整 OTA 的動態分區總大小未壓縮時為4.81 GB )。
Pixel 6 Pro 上的增量 OTA
安裝時間(不含安裝後階段) | COW空間使用情況 | OTA 後啟動時間 | 快照合併時間 | |
---|---|---|---|---|
廣州 | 24分鐘 | 1.18GB | 40.2秒 | 45.5秒 |
lz4 | 13分鐘 | 1.49GB | 37.4秒 | 37.1秒 |
沒有任何 | 13分鐘 | 2.90GB | 37.6秒 | 40.7秒 |
Pixel 6 Pro 上的完整 OTA
安裝時間(不含安裝後階段) | COW 空間使用情況 | OTA 後啟動時間 | 快照合併時間 | |
---|---|---|---|---|
廣州 | 23分鐘 | 2.79GB | 24.9秒 | 41.7秒 |
lz4 | 12分鐘 | 3.46GB | 20.0秒 | 25.3秒 |
沒有任何 | 10分鐘 | 4.85GB | 20.6秒 | 29.8秒 |