OTA for A/B devices with dynamic partitions

Android 10 supports dynamic partitions, a userspace partitioning system that can create, resize, and destroy partitions during over-the-air (OTA) updates.

This page describes how to resize dynamic partitions during an update for A/B devices that launched with dynamic partitions support, for devices running Android 9 and lower.

Background

There's one super partition on the device. This partition isn't slot suffixed. The block device must exist along with the blk_device entry for /misc in fstab. For example, if the fstab file lists:

/dev/block/bootdevice/by-name/misc    /misc    # Other fields

Then the block device for super must exist in /dev/block/bootdevice/by-name/super, but the super partition doesn't need to be listed in the fstab file.

In the super partition, there are two metadata slots, numbered 0 and 1, corresponding to A/B slots for partitions. In this page, the metadata slots are called Metadata S (source) and Metadata T (target). Similarly, partitions are referred to as system_s, vendor_t, and so on.

Before the upgrade, Metadata S contains the information for the dynamic partitions being used (typically, system_s, vendor_s, product_s, and so on). The system reads the extents for these partitions during the update, so they can't be deleted.

Partitions belong to update groups. See Implementing Dynamic Partitions for details.

An example of metadata on a device is as follows.

  • Metadata 0
    • Group foo_a
      • Partition system_a
      • Partition product_services_a
      • Other partitions updated by Foo
    • Group bar_a
      • Partition vendor_a
      • Partition product_a
      • Other partitions updated by Bar
    • Group foo_b (leftover from previous upgrade)
    • Group bar_b (leftover from previous upgrade)
  • Metadata 1
    • Group foo_a (leftover from previous upgrade)
    • Group bar_a (leftover from previous upgrade)
    • Group foo_b
      • Partition system_b
      • Partition product_services_b
      • Other partitions updated by Foo
    • Group bar_b
      • Partition vendor_b
      • Partition product_b
      • Other partitions updated by Bar

You can use the lpdump tool (source code under system/extras/partition_tools) to dump the metadata on your device. For example:

lpdump --slot 0 /dev/block/bootdevice/by-name/super
lpdump --slot 1 /dev/block/bootdevice/by-name/super

Update flow

  1. Initialize the super partition metadata.
    1. Load the extents for the source dynamic partitions from Metadata S. Let M be the loaded metadata.
    2. Remove target groups and partitions (for example, foo_t, bar_t) from M so that M contains only partitions and groups with the _s suffix.
    3. Add target groups and partitions according to the dynamic_partition_metadata field in the update manifest.
      The size of each partition can be found in new_partition_info.
    4. Write M to Metadata T.
    5. Map the added partitions on the device mapper as writable.
  2. Apply the update on the block devices.
    1. If necessary, map the source partitions on the device mapper as read only. This is necessary for sideloading because the source partitions aren't mapped prior to the update.
    2. Apply a full or delta update to all block devices at the target slot.
    3. Mount the partitions to run the post-install script, and then unmount the partitions.
  3. Unmap the target partitions.

Before and after the update, the following system properties should have the respective values:

ro.boot.dynamic_partitions=true
ro.boot.dynamic_partitions_retrofit=true

Add groups and partitions to the update manifest

When performing an OTA update on an A/B device with dynamic partitions, or an A/B device that is adding support for dynamic partitions, you need to add groups and partitions to the update manifest. The snippet below shows additional information on the update manifest to support dynamic partitions. See update_metadata.proto for detailed documentation on each field.

message DeltaArchiveManifest {
    optional DynamicPartitionMetadata dynamic_partition_metadata;
}

message DynamicPartitionMetadata {
    repeated DynamicPartitionGroup groups;
}

message DynamicPartitionGroup {
    required string name;
    optional uint64 size; // maximum size of group
    repeated string partition_names;
}