Dynamic partitioning is implemented using the dm-linear device-mapper
    module in the Linux kernel. The super partition contains
    metadata listing the names and block ranges of each dynamic partition
    within super. During first-stage init, this
    metadata is parsed and validated, and virtual block devices are created to
    represent each dynamic partition.
  
When applying an OTA, dynamic partitions are automatically created, resized, or deleted as needed. For A/B devices, there are two copies of the metadata, and changes are applied only to the copy representing the target slot.
    Because dynamic partitions are implemented in userspace, partitions needed
    by the bootloader can't be made dynamic. For example, boot,
    dtbo, and vbmeta are read by the bootloader, and
    so must remain as physical partitions.
  
    Each dynamic partition can belong to an update group. These
    groups limit the maximum space that partitions in that group can consume.
    For example, system and vendor can belong to a
    group that restricts the total size of system and
    vendor.
  
Implement dynamic partitions on new devices
This section details how to implement dynamic partitions on new devices launching with Android 10 and higher. To update existing devices, see Upgrading Android devices.
Partition changes
        For devices launching with Android 10, create
        a partition called super. The super
        partition handles A/B slots internally, so A/B devices don't need
        separate super_a and super_b partitions.
        All read-only AOSP partitions that aren't used by the bootloader must
        be dynamic and must be removed from the GUID Partition Table (GPT).
        Vendor-specific partitions don't have to be dynamic and may be placed
        in the GPT.
      
        To estimate the size of super, add the sizes of the
        partitions being deleted from the GPT. For A/B devices, this
        should include the size of both slots. Figure 1 shows
        an example partition table before and after converting to dynamic
        partitions.
      
        The supported dynamic partitions are:
- System
 - Vendor
 - Product
 - System Ext
 - ODM
 
        For devices launching with Android 10, the
        kernel command line option androidboot.super_partition
        must be empty so that the command sysprop
        ro.boot.super_partition is empty.
      
Partition alignment
        The device-mapper module may operate less efficiently if the
        super partition is not properly aligned. The
        super partition MUST be aligned to the minimum I/O
        request size as determined by the block layer. By default, the
        build system (via lpmake, which generates the
        super partition image), assumes that a 1 MiB alignment
        is sufficient for every dynamic partition. However, vendors should
        ensure that the super partition is properly aligned.
      
        You can determine the minimum request size of a block device by
        inspecting sysfs. For example:
      
# ls -l /dev/block/by-name/super lrwxrwxrwx 1 root root 16 1970-04-05 01:41 /dev/block/by-name/super -> /dev/block/sda17 # cat /sys/block/sda/queue/minimum_io_size 786432
        You can verify the super partition's alignment in a
        similar manner:
      
# cat /sys/block/sda/sda17/alignment_offsetThe alignment offset MUST be 0.
Device configuration changes
        To enable dynamic partitioning, add the following flag in
        device.mk:
      
PRODUCT_USE_DYNAMIC_PARTITIONS := true
Board configuration changes
        You're required to set the size of the super partition:
      
BOARD_SUPER_PARTITION_SIZE := <size-in-bytes>
        On A/B devices, the build system throws an error if the total size
        of dynamic partition images is more than half of the super
        partition size.
      
        You can configure the list of dynamic partitions as follows. For
        devices using update groups, list the groups in the
        BOARD_SUPER_PARTITION_GROUPS variable. Each group name
        then has a BOARD_group_SIZE
        and BOARD_group_PARTITION_LIST variable.
        For A/B devices, the maximum size of a group should cover only one
        slot, as the group names are slot-suffixed internally.
      
        Here's an example device that places all partitions into a group
        called example_dynamic_partitions:
      
BOARD_SUPER_PARTITION_GROUPS := example_dynamic_partitions BOARD_EXAMPLE_DYNAMIC_PARTITIONS_SIZE := 6442450944 BOARD_EXAMPLE_DYNAMIC_PARTITIONS_PARTITION_LIST := system vendor product
        Here's an example device that places system and product services into
        group_foo, and vendor, product,
        and odm into group_bar:
      
BOARD_SUPER_PARTITION_GROUPS := group_foo group_bar BOARD_GROUP_FOO_SIZE := 4831838208 BOARD_GROUP_FOO_PARTITION_LIST := system product_services BOARD_GROUP_BAR_SIZE := 1610612736 BOARD_GROUP_BAR_PARTITION_LIST := vendor product odm
- 
          For Virtual A/B launch devices, the sum of maximum sizes of all groups must
          be at most:
BOARD_SUPER_PARTITION_SIZE- overhead
See Implementing Virtual A/B. - 
          For A/B launch devices, the sum of maximum sizes of all groups must
          be:
BOARD_SUPER_PARTITION_SIZE/ 2 - overhead - 
          For non-A/B devices and retrofit A/B devices, the sum of maximum
          sizes of all groups must be:
BOARD_SUPER_PARTITION_SIZE- overhead - At build time, the sum of the sizes of the images of each partition in an update group must not exceed the maximum size of the group.
 - Overhead is required in the computation to account for metadata, alignments, and so on. A reasonable overhead is 4 MiB, but you can pick a larger overhead as needed by the device.
 
Size dynamic partitions
Before dynamic partitions, partition sizes were over-allocated to ensure that they had enough room for future updates. The actual size was taken as is and most read-only partitions had some amount of free space in their file system. In dynamic partitions, that free space is unusable and could be used to grow partitions during an OTA. It's critical to ensure that partitions aren't wasting space and are allocated to a minimum possible size.
For read-only ext4 images, the build system automatically allocates the minimum size if no hardcoded partition size is specified. The build system fits the image so that the file system has as little unused space as possible. This ensures that the device doesn't waste space that can be used for OTAs.
Additionally, ext4 images can be further compressed by enabling block- level deduplication. To enable this, use the following configuration:
BOARD_EXT4_SHARE_DUP_BLOCKS := true
        If automatic allocation of a partition minimum size is undesirable,
        there are two ways to control the partition size. You can specify a
        minimum amount of free space with
        BOARD_partitionIMAGE_PARTITION_RESERVED_SIZE,
        or you can specify
        BOARD_partitionIMAGE_PARTITION_SIZE to force
        dynamic partitions to a specific size. Neither of these is
        recommended unless necessary.
      
For example:
BOARD_PRODUCTIMAGE_PARTITION_RESERVED_SIZE := 52428800
        This forces the file system in product.img to have
        50 MiB of unused space.
      
System-as-root changes
Devices launching with Android 10 must not use system-as-root.
        Devices with dynamic partitions (whether it launches with or retrofits
        dynamic partitions) must not use system-as-root. The Linux kernel can't
        interpret the super partition and so can't mount
        system itself. system is now mounted by
        first-stage init, which resides in the ramdisk.
      
        Don't set BOARD_BUILD_SYSTEM_ROOT_IMAGE. In
        Android 10, the
        BOARD_BUILD_SYSTEM_ROOT_IMAGE flag is only used to
        differentiate whether the system is mounted by the kernel or by the
        first-stage init in ramdisk.
      
        Setting BOARD_BUILD_SYSTEM_ROOT_IMAGE to true
        causes a build error when
        PRODUCT_USE_DYNAMIC_PARTITIONS is also true.
      
        When BOARD_USES_RECOVERY_AS_BOOT is set to true, the
        recovery image is built as boot.img, containing the recovery's
        ramdisk. Previously, bootloader used the skip_initramfs kernel
        command line parameter to decide which mode to boot into. For
        Android 10 devices, the bootloader MUST NOT pass
        skip_initramfs to the kernel command-line. Instead, bootloader
        should pass androidboot.force_normal_boot=1 to skip recovery
        and boot normal Android. Devices launching with Android 12
        or later must use bootconfig to pass androidboot.force_normal_boot=1.
      
AVB configuration changes
When using Android Verified Boot 2.0, if the device isn't using chained partition descriptors, then no change is necessary. If using chained partitions, however, and one of the verified partitions is dynamic, then changes are necessary.
        Here's an example configuration for a device that chains
        vbmeta for the system and
        vendor partitions.
      
BOARD_AVB_SYSTEM_KEY_PATH := external/avb/test/data/testkey_rsa2048.pem BOARD_AVB_SYSTEM_ALGORITHM := SHA256_RSA2048 BOARD_AVB_SYSTEM_ROLLBACK_INDEX := $(PLATFORM_SECURITY_PATCH_TIMESTAMP) BOARD_AVB_SYSTEM_ROLLBACK_INDEX_LOCATION := 1 BOARD_AVB_VENDOR_KEY_PATH := external/avb/test/data/testkey_rsa2048.pem BOARD_AVB_VENDOR_ALGORITHM := SHA256_RSA2048 BOARD_AVB_VENDOR_ROLLBACK_INDEX := $(PLATFORM_SECURITY_PATCH_TIMESTAMP) BOARD_AVB_VENDOR_ROLLBACK_INDEX_LOCATION := 1
        With this configuration, the bootloader expects to find a vbmeta
        footer at the end of the system and
        vendor partitions. Because these partitions are no longer
        visible to the bootloader (they reside in super), two
        changes are needed.
      
- 
          Add 
vbmeta_systemandvbmeta_vendorpartitions to the device's partition table. For A/B devices, addvbmeta_system_a,vbmeta_system_b,vbmeta_vendor_a, andvbmeta_vendor_b. If adding one or more of these partitions, they should be the same size as thevbmetapartition. - 
          Rename the configuration flags by adding 
VBMETA_and specify which partitions the chaining extends to:BOARD_AVB_VBMETA_SYSTEM := system BOARD_AVB_VBMETA_SYSTEM_KEY_PATH := external/avb/test/data/testkey_rsa2048.pem BOARD_AVB_VBMETA_SYSTEM_ALGORITHM := SHA256_RSA2048 BOARD_AVB_VBMETA_SYSTEM_ROLLBACK_INDEX := $(PLATFORM_SECURITY_PATCH_TIMESTAMP) BOARD_AVB_VBMETA_SYSTEM_ROLLBACK_INDEX_LOCATION := 1 BOARD_AVB_VBMETA_VENDOR := vendor BOARD_AVB_VBMETA_VENDOR_KEY_PATH := external/avb/test/data/testkey_rsa2048.pem BOARD_AVB_VBMETA_VENDOR_ALGORITHM := SHA256_RSA2048 BOARD_AVB_VBMETA_VENDOR_ROLLBACK_INDEX := $(PLATFORM_SECURITY_PATCH_TIMESTAMP) BOARD_AVB_VBMETA_VENDOR_ROLLBACK_INDEX_LOCATION := 1
 
A device may be using one, both, or none of these partitions. Changes are need only when chaining to a logical partition.
AVB bootloader changes
If the bootloader has embedded libavb, include the following patches:
- 818cf56740775446285466eda984acedd4baeac0 — "libavb: Only query partition GUIDs when the cmdline needs them."
 - 5abd6bc2578968d24406d834471adfd995a0c2e9 — "Allow system partition to be absent"
 - 9ba3b6613b4e5130fa01a11d984c6b5f0eb3af05 — "Fix AvbSlotVerifyData->cmdline might be NULL"
 
If using chained partitions, include an additional patch:
- 49936b4c0109411fdd38bd4ba3a32a01c40439a9 — "libavb: Support vbmeta blobs in beginning of partition."
 
Kernel command line changes
        A new parameter, androidboot.boot_devices, must be added
        to the kernel command line. This is used by init to
        enable /dev/block/by-name symlinks. It should be the
        device path component to the underlying by-name symlink created by
        ueventd, that is,
        /dev/block/platform/device-path/by-name/partition-name.
        Devices launching with Android 12 or later must use
        bootconfig to pass androidboot.boot_devices to init.
      
        For example, if the super partition by-name symlink is
        /dev/block/platform/soc/100000.ufshc/by-name/super,
        you can add the command line parameter in the BoardConfig.mk file as
        follows:
BOARD_KERNEL_CMDLINE += androidboot.boot_devices=soc/100000.ufshc
BOARD_BOOTCONFIG += androidboot.boot_devices=soc/100000.ufshc
fstab changes
The device tree and device tree overlays must not contain fstab entries. Use an fstab file that will be part of the ramdisk.
Changes must be made to the fstab file for logical partitions:
- 
          The fs_mgr flags field must include the 
logicalflag and thefirst_stage_mountflag, introduced in Android 10, which indicates that a partition is to be mounted in the first stage. - 
          A partition may specify
          
avb=vbmeta partition nameas anfs_mgrflag and then the specifiedvbmetapartition is initialized by first stageinitbefore attempting to mount any devices. - 
          The 
devfield must be the partition name. 
The following fstab entries set system, vendor, and product as logical partitions following the above rules.
#<dev> <mnt_point> <type> <mnt_flags options> <fs_mgr_flags> system /system ext4 ro,barrier=1 wait,slotselect,avb=vbmeta,logical,first_stage_mount vendor /vendor ext4 ro,barrier=1 wait,slotselect,avb,logical,first_stage_mount product /product ext4 ro,barrier=1 wait,slotselect,avb,logical,first_stage_mount
Copy the fstab file into the first stage ramdisk.
SELinux changes
        The super partition block device must be marked with the label
        super_block_device. For example, if the super partition by-name symlink is
        /dev/block/platform/soc/100000.ufshc/by-name/super,
        add the following line to file_contexts:
      
/dev/block/platform/soc/10000\.ufshc/by-name/super u:object_r:super_block_device:s0
fastbootd
The bootloader (or any non-userspace flashing tool) doesn't understand dynamic partitions, so it can't flash them. To address this, devices must use a user-space implementation of the fastboot protocol, called fastbootd.
For more information on how to implement fastbootd, see Moving Fastboot to User Space.
adb remount
        For developers using eng or userdebug builds, adb remount
        is extremely useful for fast iteration. Dynamic partitions pose a
        problem for adb remount because there is no longer free
        space within each file system. To address this, devices can enable
        overlayfs. As long as there is free space within the super partition,
        adb remount automatically creates a temporary dynamic
        partition and uses overlayfs for writes. The temporary partition is
        named scratch, so don't use this name for other
        partitions.
      
For more information on how to enable overlayfs, see the overlayfs README in AOSP.
Upgrade Android devices
If you upgrade a device to Android 10, and want to include dynamic partitions support in the OTA, you don't need to change the built-in partition table. Some extra configuration is required.
Device configuration changes
        To retrofit dynamic partitioning, add the following flags in
        device.mk:
      
PRODUCT_USE_DYNAMIC_PARTITIONS := true PRODUCT_RETROFIT_DYNAMIC_PARTITIONS := true
Board configuration changes
You're required to set the following board variables:
- Set 
BOARD_SUPER_PARTITION_BLOCK_DEVICESto the list of block devices used to store extents of dynamic partitions. This is the list of names of existing physical partitions on the device. - Set 
BOARD_SUPER_PARTITION_partition_DEVICE_SIZEto the sizes of each block device inBOARD_SUPER_PARTITION_BLOCK_DEVICES, respectively. This is the list of sizes of existing physical partitions on the device. This is usuallyBOARD_partitionIMAGE_PARTITION_SIZEin existing board configurations. - Unset existing 
BOARD_partitionIMAGE_PARTITION_SIZEfor all partitions inBOARD_SUPER_PARTITION_BLOCK_DEVICES. - Set 
BOARD_SUPER_PARTITION_SIZEto the sum ofBOARD_SUPER_PARTITION_partition_DEVICE_SIZE. - Set 
BOARD_SUPER_PARTITION_METADATA_DEVICEto the block device where dynamic partition metadata is stored. It must be one ofBOARD_SUPER_PARTITION_BLOCK_DEVICES. Usually, this is set tosystem. - Set 
BOARD_SUPER_PARTITION_GROUPS,BOARD_group_SIZE, andBOARD_group_PARTITION_LIST, respectively. See Board configuration changes on new devices for details. 
For example, if the device already has system and vendor partitions, and you want to convert them to dynamic partitions and add a new product partition during the update, set this board configuration:
BOARD_SUPER_PARTITION_BLOCK_DEVICES := system vendor BOARD_SUPER_PARTITION_METADATA_DEVICE := system # Rename BOARD_SYSTEMIMAGE_PARTITION_SIZE to BOARD_SUPER_PARTITION_SYSTEM_DEVICE_SIZE. BOARD_SUPER_PARTITION_SYSTEM_DEVICE_SIZE := <size-in-bytes> # Rename BOARD_VENDORIMAGE_PARTITION_SIZE to BOARD_SUPER_PARTITION_VENDOR_DEVICE_SIZE BOARD_SUPER_PARTITION_VENDOR_DEVICE_SIZE := <size-in-bytes> # This is BOARD_SUPER_PARTITION_SYSTEM_DEVICE_SIZE + BOARD_SUPER_PARTITION_VENDOR_DEVICE_SIZE BOARD_SUPER_PARTITION_SIZE := <size-in-bytes> # Configuration for dynamic partitions. For example: BOARD_SUPER_PARTITION_GROUPS := group_foo BOARD_GROUP_FOO_SIZE := <size-in-bytes> BOARD_GROUP_FOO_PARTITION_LIST := system vendor product
SELinux changes
        The super partition block devices must be marked with the attribute
        super_block_device_type. For example, if the device already has
        system and vendor partitions, you want to use them as block
        devices to store extents of dynamic partitions, and their by-name symlinks are marked as
        system_block_device:
      
/dev/block/platform/soc/10000\.ufshc/by-name/system u:object_r:system_block_device:s0 /dev/block/platform/soc/10000\.ufshc/by-name/vendor u:object_r:system_block_device:s0
        Then, add the following line to device.te:
      
typeattribute system_block_device super_block_device_type;
For other configurations, see Implementing dynamic partitions on new devices.
For more information about retrofit updates, see OTA for A/B Devices without Dynamic Partitions.
Factory images
For a device launching with dynamic partitions support, avoid using userspace fastboot to flash factory images, as booting to userspace is slower than other flashing methods.
      To address this, make dist now builds an additional
      super.img image that can be flashed directly to the super
      partition. It automatically bundles the contents of logical
      partitions, meaning it contains system.img,
      vendor.img, and so on, in addition to the super
      partition metadata. This image can be flashed directly to the
      super partition without any additional tooling or using
      fastbootd. After the build, super.img is placed in
      ${ANDROID_PRODUCT_OUT}.
    
      For A/B devices that launch with dynamic partitions,
      super.img contains images in the A slot. After flashing the
      super image directly, mark slot A as bootable before rebooting the
      device.
    
      For retrofit devices, make dist builds a set of
      super_*.img images that can be flashed directly to
      corresponding physical partitions. For example, make dist
      builds super_system.img and super_vendor.img
      when BOARD_SUPER_PARTITION_BLOCK_DEVICES is the system
      vendor. These images are placed in the OTA folder in
      target_files.zip.
    
Device mapper storage-device tuning
Dynamic partitioning accommodates a number of nondeterministic device-mapper objects. These may not all instantiate as expected, so you must track all mounts, and update the Android properties of all the associated partitions with their underlying storage devices.
A mechanism inside init tracks the mounts and asynchronously
updates the Android properties. The amount of time this takes isn’t guaranteed
to be within a specific period, so you must provide enough time
for all on property triggers to react. The properties are
dev.mnt.blk.<partition> where
<partition> is root,
system, data, or
vendor, for example. Each property is associated with the
base storage-device name, as shown in these examples:
taimen:/ % getprop | grep dev.mnt.blk [dev.mnt.blk.data]: [sda] [dev.mnt.blk.firmware]: [sde] [dev.mnt.blk.metadata]: [sde] [dev.mnt.blk.persist]: [sda] [dev.mnt.blk.root]: [dm-0] [dev.mnt.blk.vendor]: [dm-1] blueline:/ $ getprop | grep dev.mnt.blk [dev.mnt.blk.data]: [dm-4] [dev.mnt.blk.metadata]: [sda] [dev.mnt.blk.mnt.scratch]: [sda] [dev.mnt.blk.mnt.vendor.persist]: [sdf] [dev.mnt.blk.product]: [dm-2] [dev.mnt.blk.root]: [dm-0] [dev.mnt.blk.system_ext]: [dm-3] [dev.mnt.blk.vendor]: [dm-1] [dev.mnt.blk.vendor.firmware_mnt]: [sda]
The init.rc language allows the Android properties to be
expanded as part of the rules, and storage devices can be tuned by the platform
as needed with commands like these:
write /sys/block/${dev.mnt.blk.root}/queue/read_ahead_kb 128 write /sys/block/${dev.mnt.blk.data}/queue/read_ahead_kb 128
Once command processing starts in second-stage init, the
epoll loop becomes active, and the values start to update. However,
because property triggers aren't active until late-init, they
can’t be used in the initial boot stages to handle root,
system, or vendor. You may expect the
kernel default read_ahead_kb to be sufficient until the
init.rc scripts can override in early-fs (when
various daemons and facilities start). Therefore, Google recommends that
you use the on property feature, coupled with an
init.rc-controlled property like sys.read_ahead_kb,
to deal with timing the operations and to prevent race conditions, as in these
examples:
on property:dev.mnt.blk.root=* && property:sys.read_ahead_kb=* write /sys/block/${dev.mnt.blk.root}/queue/read_ahead_kb ${sys.read_ahead_kb:-2048} on property:dev.mnt.blk.system=* && property:sys.read_ahead_kb=* write /sys/block/${dev.mnt.blk.system}/queue/read_ahead_kb ${sys.read_ahead_kb:-2048} on property:dev.mnt.blk.vendor=* && property:sys.read_ahead_kb=* write /sys/block/${dev.mnt.blk.vendor}/queue/read_ahead_kb ${sys.read_ahead_kb:-2048} on property:dev.mnt.blk.product=* && property:sys.read_ahead_kb=* write /sys/block/${dev.mnt.blk.system_ext}/queue/read_ahead_kb ${sys.read_ahead_kb:-2048} on property:dev.mnt.blk.oem=* && property:sys.read_ahead_kb=* write /sys/block/${dev.mnt.blk.oem}/queue/read_ahead_kb ${sys.read_ahead_kb:-2048} on property:dev.mnt.blk.data=* && property:sys.read_ahead_kb=* write /sys/block/${dev.mnt.blk.data}/queue/read_ahead_kb ${sys.read_ahead_kb:-2048} on early-fs: setprop sys.read_ahead_kb ${ro.read_ahead_kb.boot:-2048} on property:sys.boot_completed=1 setprop sys.read_ahead_kb ${ro.read_ahead_kb.bootcomplete:-128}