To implement virtual A/B on a new device, or to retrofit a launched device, you must make changes to device-specific code.
Build flags
Devices that use virtual A/B must be configured as an A/B device and must launch with dynamic partitions.
For devices launching with virtual A/B, set them to inherit the virtual A/B device base configuration:
$(call inherit-product, \
$(SRC_TARGET_DIR)/product/virtual_ab_ota.mk)
Devices launching with virtual A/B need only half as much board size for
BOARD_SUPER_PARTITION_SIZE
because B slots are no longer in super. That is,
BOARD_SUPER_PARTITION_SIZE
must be greater than or equal to
sum(size of update groups) + overhead, which, in turn, must be greater
than or equal to sum(size of partitions) + overhead.
For Android 13 and higher, to enable compressed snapshots with Virtual A/B, inherit the following base configuration:
$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_ramdisk.mk)
$(call inherit-product, \
$(SRC_TARGET_DIR)/product/virtual_ab_ota/vabc_features.mk)
This enables userspace snapshots with Virtual A/B while using a no-op
compression method. You can then configure the compression method to one of the
supported methods,zstd
and lz4
. For Android 15,
compression can be further customized to match device needs. For further
information, see Fine tuning compression.
PRODUCT_VIRTUAL_AB_COMPRESSION_METHOD := lz4
PRODUCT_VIRTUAL_AB_COMPRESSION_FACTOR := 65536
For Android 12, to enable compressed snapshots with Virtual A/B, inherit the following base configuration:
$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_ramdisk.mk)
$(call inherit-product, \
$(SRC_TARGET_DIR)/product/virtual_ab_ota/compression.mk)
XOR compression
For devices upgrading to Android 13 and higher, the
XOR compression feature isn't
enabled by default. To enable XOR compression, add the following to the device's
.mk
file.
PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.compression.xor.enabled=true
XOR compression is enabled by default for devices that inherit from
android_t_baseline.mk
.
Userspace merge
In the modern version of Virtual A/B (Android T and after), the snapshot merge process happens entirely in userspace. This change is made possible by snapuserd and dm-user. Devices launching with android 13 and higher have userspace merge enabled by default and for older devices upgrading, this property can be set with the following:
PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.userspace.snapshots.enabled=true
Boot control HAL
The boot control HAL provides an interface for OTA clients to control boot slots. Virtual A/B requires a minor version upgrade of the boot control HAL because additional APIs are needed to ensure bootloader is protected during flashing or factory reset. See IBootControl.hal and types.hal for the latest version of the HAL definition.
// 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 changes
The integrity of the metadata partition is essential to the boot process,
especially right after an OTA update is applied. So, the metadata partition must
be checked before first_stage_init
mounts it. To ensure this happens, add the
check
fs_mgr flag to the entry for /metadata
. The following provides an
example:
/dev/block/by-name/metadata /metadata ext4 noatime,nosuid,nodev,discard,sync wait,formattable,first_stage_mount,check
Kernel requirements
To enable snapshotting, set CONFIG_DM_SNAPSHOT
to true
.
For devices using F2FS, include the f2fs: export FS_NOCOW_FL flag to user kernel patch to fix file pinning. Include the f2fs: support aligned pinned file kernel patch as well.
Virtual A/B relies on features added in kernel version 4.3: the overflow
status bit in the snapshot
and snapshot-merge
targets. All devices launching
with Android 9 and later should already have kernel version 4.4 or later.
To enable compressed snapshots, the minimum supported kernel version is 4.19.
Set CONFIG_DM_USER=m
or CONFIG_DM_USER=y
. If using the former (a module),
the module must be loaded in the first-stage ramdisk. This can be achieved by
adding the following line to the device Makefile:
BOARD_GENERIC_RAMDISK_KERNEL_MODULES_LOAD := dm-user.ko
Fastboot tooling changes
Android 11 makes the following changes to the fastboot protocol:
getvar snapshot-update-status
— Returns the value that the boot control HAL communicated to the bootloader:- If the state is
MERGING
, the bootloader must returnmerging
. - If the state is
SNAPSHOTTED
, the bootloader must returnsnapshotted
. - Otherwise, the bootloader must return
none
.
- If the state is
snapshot-update merge
— Completes a merge operation, booting to recovery/fastbootd if necessary. This command is valid only ifsnapshot-update-status
ismerging
, and is only supported in fastbootd.snapshot-update cancel
— Sets the boot control HAL's merge status toCANCELLED
. This command is invalid when the device is locked.erase
orwipe
— Anerase
orwipe
ofmetadata
,userdata
, or a partition holding the merge status for the boot control HAL should check the snapshot merge status. If the status isMERGING
orSNAPSHOTTED
, the device should abort the operation.set_active
— Aset_active
command that changes the active slot should check the snapshot merge status. If the status isMERGING
, the device should abort the operation. The slot can safely be changed in theSNAPSHOTTED
state.
These changes are designed to prevent accidentally making a device unbootable,
but they can be disruptive to automated tooling. When the commands are used as a
component of flashing all partitions, such as running fastboot flashall
, it's
recommended to use the following flow:
- Query
getvar snapshot-update-status
. - If
merging
orsnapshotted
, issuesnapshot-update cancel
. - Proceed with flashing steps.
Reduce storage requirements
Devices that don't have full A/B storage allocated in super, and are expecting
to use /data
as necessary, are strongly recommended to use the block mapping
tool. The block mapping tool keeps block allocation consistent between builds,
reducing unnecessary writes to the snapshot. This is documented under Reducing
OTA Size.
OTA compression algorithms
OTA packages can be tuned for different performance metrics. Android provides
several supported compression methods (lz4
, zstd
, and none
) that have
tradeoffs between install time, COW space usage, boot time, and snapshot merge
time. The default option enabled for virtual ab with compression is the lz4
compression method
.
Fine tuning compression
Compression algorithms can be further customized through two methods:
(compression level) (the amount of compression achieved at the expense of
speed) and (compression factor) (the maximum compressible window size).
Compression level is available to certain algorithms such as zstd
, and
changing the level incurs a tradeoff between speed and compression ratio.
Compression factor describes the maximum compression window size used during OTA
installation. The default is set at 64k, but can be overridden by customizing
the build parameter PRODUCT_VIRTUAL_AB_COMPRESSION_FACTOR
. Supported
compression factors 4k, 8k, 16k, 32k, 64k, 128k and 256k.
PRODUCT_VIRTUAL_AB_COMPRESSION_FACTOR := 65536
Incremental OTA on Pixel 8 Pro
Install time w/o postinstall phase | COW Space Usage | Post OTA boot time | Snapshot merge time | |
---|---|---|---|---|
lz4 | 18 min 15s | 2.5 GB | 32.7 sec | 98.6 sec |
zstd | 24 min 49s | 2.05 GB | 36.3 sec | 133.2 sec |
none | 16 min 42s | 4.76 GB | 28.7 sec | 76.6 sec |
Full OTA on Pixel 8 Pro
Install time w/o postinstall phase | COW Space Usage | Post OTA boot time | Snapshot merge time | |
---|---|---|---|---|
lz4 | 15 min 11s | 4.16 GB | 17.6 sec | 82.2 sec |
zstd | 16 min 19s | 3.46 GB | 21.0 sec | 106.3 sec |
none | 13 min 33s | 6.39 GB | 18.5 sec | 92.5 sec |