Android OTA [Seamless] Update Overview [Part2] - Detailed Analysis of OTA[A/B] Update

Detailed Analysis

In the previous tutorial we saw an overviw of the OTA [A/B Based] Update mechanism introduced by Android and mandated after Android 11.

Changes to Android Makefiles for enabling Android A/B OTA Updates


With the introduction of A/B style of updates, The device manufacturers must make changes to the existing Compilation and Flashing steps. Let us have a look at them below.

For the present analysis, Let us use the Google’s Marlin device as an example.



A/B MUST Define Flags

Variables that the system must define

AB_OTA_UPDATER := true

AB_OTA_PARTITIONS := boot system vendor

BOARD_BUILD_SYSTEM_ROOT_IMAGE := true
#Put the boot ramdisk in the system partition

TARGET_NO_RECOVERY := true

BOARD_USES_RECOVERY_AS_BOOT := true
#Put the recovery ramdisk in the boot.img file

PRODUCT_PACKAGES += update_engine update_verifier

A/B Optionally Defined Flags


A/B Variables optionally defined by the system

PRODUCT_PACKAGES_DEBUG += update_engine_client

A/B MUST NOT Define Flags


A/B Variables that the system cannot define

BOARD_RECOVERYIMAGE_PARTITION_SIZE
BOARD_CACHEIMAGE_PARTITION_SIZE
BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE

More details can be obtained by searching these variables in the build/core/Makefile


Let’s go over a few of these.





We see that now the build system does not generate recovery.img, Additionally the boot.img now has the recovery ramdisk and not the actual rootfs ramdisk.

Communication between the bootloader & the A/B System

The variable bootloader_message_ab is used to communicate the structure of the message to be passed to the bootloader using the 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 belongs to the vendor
 * space of /misc partition. Also, the A/B-specific contents 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];
};

The bootloader_message is further explained below
/* 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.
 *
 * The command field is updated by linux when it wants to
 * reboot into recovery or to update radio or bootloader firmware.
 * It is also updated by the bootloader when firmware update
 * is complete (to boot into recovery for any final cleanup)
 *
 * The status field was used by the bootloader after the completion
 * of an "update-radio" or "update-hboot" command, which has been
 * deprecated since Froyo.
 *
 * The recovery field is only written by linux and used
 * for the system to send a message to recovery or the
 * other way around.
 *
 * The stage field is written by packages which restart themselves
 * multiple times, so that the UI can reflect which invocation of the
 * package it is.  If the value is of the format "#/#" (eg, "1/3"),
 * the UI will add a simple indicator of that status.
 *
 * 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 is supposed to have a custom implementation of the boot control HAL and I would not like to talk about any specific implementation. 

However Google also has a reference implementation for its IOT devices [Brillo], Let’s have a close look at the contents of the boot_loader message for Brillo.


The major point of interest are
// Currently active slot.
  uint8_t active_slot;

  // Information about each slot.
  BrilloSlotInfo slot_info[2];

This is used by the boot control HAL to implement logic to inform about the slot status to the bootloader to help chose the right slot to boot.

Let’s see the API’s of the boot control HAL below with the most important API's marked.



bootctrl  Test

In addition to defining the interface of the HAL layer, AOSP also provides boot_control tools in a module called bootctl, located at:
system/extras/bootctl/bootctl.c

We can run the bootctrl –help to get more information.

Update Verifier & Boot Control HAL

The update_verifier module in bootable/recovery/update_verifier also uses the bootcontrol HAL to check if the update has been verified before marking the slot successful.


Finally, The bootloader reads the slot to boot from using the “metadata” partition as below.


Comments

Popular posts from this blog

Android Audio Tutorial [Part Three] : AudioFlinger Introduction and Initialization

Android External Storage Support: Volume Daemon (vold) Architecture

Android Audio Tutorial [Part One] : Introduction