Android OTA update: How to implement A/B update mechanism

In the previous post of Android OTA update, I have discussed about what is an OTA update and how it is applied in our device. Basically, I have shown you, how OTA works internally to update your current Android OS. In this article, I will discuss, how we can implement the A/B seamless OTA update.

Table of Contents

Changes required in the make file to implement A/B OTA update

To implement the A/B seamless update, the device manufacturer must make necessary changes to the existing compilation and flashing steps. 

For our analysis, we will use, Google’s Merlin device as an example. First, we must define AB flags.

AB Flag must be defined in BoardConfig.mk

The device manufacturer must define some AB flags in BoardConfig.mk to implement the A/B seamless update.

/device/google/marlin/marlin/BoardConfig.mk

Let’s see what are the flags required.

AB_OTA_UPDATER := true
AB_OTA_PARTITIONS := boot system vendor
BOARD_BUILD_SYSTEM_ROOT_IMAGE := true
TARGET_NO_RECOVERY := true
BOARD_USES_RECOVERY_AS_BOOT := true

Now, let’s see what each flag means.

AB_OTA_UPDATER := true
This flag is self-explanatory, it sets the device to use A/B updater.

AB_OTA_PARTITIONS := boot system vendor
This will specify, which all partitions will come under AB update. You can specify more partitions according to your requirement. Like xbl, devcfg, modem, etc

BOARD_BUILD_SYSTEM_ROOT_IMAGE := true
This flag will put the boot ramdisk in the system partition.

BOARD_USES_RECOVERY_AS_BOOT := true
It will put the recovery ramdisk in the boot.img.

The last two, TARGET_NO_RECOVERY and BOARD_USES_RECOVERY_AS_BOOT, is strongly recommended to be defined if you are targeting for AB update. Now, one question should come to your mind, why it is recommended? What is its use? To understand why these two are strongly recommended refer to the below code snippet taken from MAKEFILE of Android 9.

/build/core/MAKEFILE
use of TARGET_NO_RECOVERY to implement AB update
changes to implement AB update 2
changes to implement AB update 1
output recovery file to boot partition in implementing AB update
Creating single image that contain boot and recovery both in implement AB update

As you can see, the build system does not generate recovery.img, moreover boot image and recovery image are combined into one single boot image.

Adding A/B related packages in device.mk file

The device manufacturer must add the AB related packages in .mk to implement the A/B seamless update. In our case, it is marlin.mk

/device/google/marlin/marlin.mk

Let’s see what are the packages required.

PRODUCT_PACKAGES += update_engine \
update_verifier \

Optional package to include in .mk file to implement AB OTA update

The device manufacturer may add these packages while implementing AB updates

/device/google/marlin/marlin.mk

Let’s see what are the packages required.

PRODUCT_PACKAGES += update_engine_client\
bootclt \

Avoid defining these when you are to implement AB update

We have seen, what the changes needs to be done to implement AB update. Now, here are few flags which should not be changed or modified in order to work for AB update.

  • BOARD_RECOVERYIMAGE_PARTITION_SIZE
  • BOARD_CACHEIMAGE_PARTITION_SIZE
  • BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE

How bootloader communicates with AB update system

Bootloader uses a structure bootloader_message_ab to communicate with AB system. This variable is passed to bootloader using bootcontrol HAL.

/**
* The A/B-specific bootloader message structure (4-KiB).
*
* We separate A/B boot control metadata from the regular bootloader
* message struct and keep it here. Everything that's A/B-specific
* stays after struct bootloader_message, which should be managed by
* the A/B-bootloader or boot control HAL.
*
* The slot_suffix field is used for A/B implementations where the
* bootloader does not set the androidboot.ro.boot.slot_suffix kernel
* commandline parameter. This is used by fs_mgr to mount /system and
* other partitions with the slotselect flag set in fstab. A/B
* implementations are free to use all 32 bytes and may store private
* data past the first NUL-byte in this field. It is encouraged, but
* not mandatory, to use 'struct bootloader_control' described below.
*
* The update_channel field is used to store the Omaha update channel
* if update_engine is compiled with Omaha support.
*/
struct bootloader_message_ab {
struct bootloader_message message;
char slot_suffix[32];
char update_channel[128];
// Round up the entire struct to 4096-byte.
char reserved[1888];
};
/* Bootloader Message (2-KiB)
*
* This structure describes the content of a block in flash
* that is used for recovery and the bootloader to talk to
* each other.
*
* We used to have slot_suffix field for A/B boot control metadata in
* this struct, which gets unintentionally cleared by recovery or
* uncrypt. Move it into struct bootloader_message_ab to avoid the
* issue.
*/
struct bootloader_message {
char command[32];
char status[32];
char recovery[768];

// The 'recovery' field used to be 1024 bytes. It has only ever
// been used to store the recovery command line, so 768 bytes
// should be plenty. We carve off the last 256 bytes to store the
// stage string (for multistage packages) and possible future
// expansion.
char stage[32];

// The 'reserved' field used to be 224 bytes when it was initially
// carved off from the 1024-byte recovery field. Bump it up to
// 1184-byte so that the entire bootloader_message struct rounds up
// to 2048-byte.
char reserved[1184];
};

Every OEM/SOC manufacturer can customize the bootcontrol HAL according to their requirement. However, Google has also given reference implementation for its iOT devices (Brillo).

Let’s see what are the contents of the boot_loader_message for Brillo.

reference to implement AB update message

The thing which needs to be focused on are:

  1. uint8_t active_slot;
  2. BrilloSlotInfo slot_info[2];

This BrilloSlotInfo is used by the boot_contol HAL to inform the bootloader about the current active slot. This info will help the Bootloader to choose, from which slot to boot.

API's of boot_control HAL

We talked about the boot_control HAL, let’s see what are the APIs it contains.

boot_control HAL APIs

As you can see it from above, the boot_control HAL contains several APIs such as getNumberSlots() – To get number of slots.
getCurrentSlot() – To get current active slot.
markBootSuccessful() – To mark, boot was successful with the slot specified.
setActiveBootSlot() – To set the active boot slot.
setSlotAsUnbootable() – To mark, the specified slot as unbootable.
isSlotBootable() – To check whether the current slot is bootable or not.
isSlotMarkedSuccessful() – To check whether the specified slot is marked successful or not.

Testing boot_control HAL

Testing with bootCtl

As stated above, every OEM vendor can customize the boot_control HAL according to their need. In addition to that they can test their implementation using bootCtl module. It is located at system/extras/bootctl/bootctl.cpp

You have to include this module in your product packages like

#Boot control HAL test app used for A/B update
PRODUCT_PACKAGES_DEBUG += bootctl

The above line will include the bootctl in debug build. After including, you can use bootctl command in adb shell to use it.

bootctl help

Verifying an A/B OTA update with update_verifier

This program verifies the integrity of the partitions after an A/B OTA
update. It gets invoked by init, and will only perform the verification if
it is the first boot after an A/B OTA update.

The update_verifier will mark the current slot as having booted successfully if the
verifier reaches the end after the verification.

update_verifier to implement AB update verification

Finally, the bootloader read the slot to boot using “metadata” as shown below.

Conclusion

This is how you can implement A/B OTA update in your android build. If you like this post, please do share it on social media like Facebook or WhatsApp. If you have any suggestions or questions please do let me know in the comment section. Or if you want to know anything about any app or software for your own purpose, write us to support@gizmomind.com, and please like our Facebook page.

Swetabh

Swetabh is an Android Developer and a Tech enthusiast. His enthusiasm drives him to know about various technologies. Now he wanted to share his knowledge to other enthusiast who are passionate to know-how and become a GIZMOMIND.

This Post Has 2 Comments

  1. Dimple

    Nice Info 🙂 Thanks for sharing!

  2. Ranjeet

    Thanks for the information

Leave a Reply