Android AB Slots

From postmarketOS

What are slots?

Some Android devices contain multiple "slots" for system data, this is implemented by duplicating important partitions such as system, vendor, boot and some others. You can tell if a partition is "slotted" as its name will end in _a or _b and there will be a matching pair (you can see an example A/B partition map here). Most Android devices released after 2017 make use of slots. From 2019, most devices switched to using the new "super" partition, where the partitions aren't created directly in the GPT partition table, but are instead all inside of a large "super" partition, making it easier to manage adding new ones, resizing them etc. For more information, check Android_dynamic_partitions.

Slots are used to make it possible to roll-back an unsuccessful upgrade, as the upgrade process will not touch your working system. It also makes it possible to install upgrades whilst using the device.

Technical information

Icon TODO: Figure out how this works on devices with a super partition

Android slots are implemented in 2 parts, the GPT partition attribute fields, and the UFS bBootLunEn attribute.

Upgrade roll-back

Upgrade roll-back is implemented using a counter, it is initialised at 7 and decremented every time you boot the system unless you set the "boot successful" flag from userspace. When the counter reaches 0 the bootloader will automatically mark the slot as "unbootable" and switch to the other slot. For a lot of hackers and postmarketOS users it's quite likely that the other slot is broken (ie because you installed postmarketOS to the userdata partition), so this leads to an unbootable system, requiring the use of fastboot to clear the flags and boot your system again.

Fix an unbootable system

If you device randomly got stuck in fastboot after a reboot, that means the counter hit zero and the bootloader marked your slot as unbootable.

You can fix this quite easily, first get the current slot:

$ fastboot getvar current-slot

If the current slot is a, run the following to reset the flags:

$ fastboot set_active b
$ fastboot set_active a

Invert the order of commands if your current slot is b.

This problem should no longer happen once qbootctl is configured, for sdm845 or msm8998 devices make sure the soc-qcom-sdm845-qbootctl package is installed, and check that the qbootctl service is enabled with:

$ sudo rc-update add qbootctl default

This will automatically set the "boot successful" flag on every postmarketOS boot.

GPT

Every partition header in GPT contains 8 bytes (64 bits) of attribute flags, of those, the last 16 bits (bits 48-63) are left for vendor specific use. Qualcomm's A/B implementation uses these to store flags representing if a slot is active, if it has booted successfully, and if it is unbootable, as well as the retry count. See more here.

UFS

The UFS specification supports up to two BOOT LUNs, these are special "logical units" specifically for storing a bootloader, on Qualcomm devices these are used for the xbl_a and xbl_b partitions. Switching the active boot LUN requires writing either 1 or 2 to the bBootLunEn attribute (a 0 disables boot LUNs, on the OnePlus 6 at least this flag is ignored thankfully).

Downstream uses an old ioctl interface called "sg" for setting this attribute, whilst it was submitted to mainline it was never accepted, instead we have a different interface called UFS BSG, it must be enabled when compiling the kernel by adding "CONFIG_SCSI_UFS_BSG=y" to your kernel configuration.

Qbootctl

Qbootctl is a CLI tool for manipulating A/B slots on Android devices. It is a port of the original Android bootctrl HAL developed by Qualcomm, modified to build on Linux and provide a friendly CLI interface. It also includes a port of the gpt-utils code required by the HAL, and an implementation of the UFS BSG API.

It is currently packaged in Alpine testing.

Switching slots

It's possible to re-use the slot implementation to effectively dual boot your device, by using the Android bootctl tool as root on the Android side, and qbootctl on postmarketOS. Details for how to do that on the OnePlus 6 can be found here.

To switch slots using qbootctl, see the following:

$ # get the current slot
$ qbootctl -c
$ # Assuming current slot is "a"
$ qbootctl -s b
$ # if your current slot is b
$ qbootctl -s a

Validated devices

Qbootctl is known to work on at least the following devices (please add yours if you test it!):

See also