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 OTA clients resize dynamic partitions during an update for non-A/B devices.
      For non-A/B devices, the OTA update for dynamic partitions is applied
      using the updater inside the update package.
    
Update launch devices
This section applies to non-A/B devices that launch with dynamic partitions support; these devices upgrade from Android 10 to higher releases.
Generate update packages
          OTA update packages are generated by the
          ota_from_target_files script, located under
          build/make/tools/releasetools. By default, the script
          generates a package that updates the system and
          vendor partitions. If there are additional dynamic
          partitions, such as product,
          product_services, or odm, their
          updates must be generated in
          device-specific
          code.
        
          To generate updates, in the extended Python module, implement
          FullOTA_GetBlockDifferences() and
          IncrementalOTA_GetBlockDifferences(). These two
          functions return a list of BlockDifference objects,
          each describing the update patch that would be applied on a
          partition. Partitions returned by these two functions shouldn't be
          modified manually or verified elsewhere, for example in
          *_InstallBegin() or *_InstallEnd().
        
Example of an update generation:
# device/yoyodyne/tardis/releasetools.py import os from common import BlockDifference, EmptyImage, GetUserImage # The joined list of user image partitions of source and target builds. # - Items should be added to the list if new dynamic partitions are added. # - Items should not be removed from the list even if dynamic partitions are # deleted. When generating an incremental OTA package, this script needs to # know that an image is present in source build but not in target build. USERIMAGE_PARTITIONS = [ "product", "odm", ] def GetUserImages(input_tmp, input_zip): return {partition: GetUserImage(partition, input_tmp, input_zip) for partition in USERIMAGE_PARTITIONS if os.path.exists(os.path.join(input_tmp, "IMAGES", partition + ".img"))} def FullOTA_GetBlockDifferences(info): images = GetUserImages(info.input_tmp, info.input_zip) return [BlockDifference(partition, image) for partition, image in images.items()] def IncrementalOTA_GetBlockDifferences(info): source_images = GetUserImages(info.source_tmp, info.source_zip) target_images = GetUserImages(info.target_tmp, info.target_zip) # Use EmptyImage() as a placeholder for partitions that will be deleted. for partition in source_images: target_images.setdefault(partition, EmptyImage()) # Use source_images.get() because new partitions are not in source_images. return [BlockDifference(partition, target_image, source_images.get(partition)) for partition, target_image in target_images.items()]
Update flow
Behind the scenes, the following functions are added to the edify script:
- unmap_partition(name)- Unmap the partition if mapped, otherwise do nothing.
- Return the string ton success, or an empty string on failure.
 
- map_partition(name)- Map the partition if not already mapped.
- Return the absolute path of the mapped block device on success, or an empty string on failure.
 
- update_dynamic_partitions(op_list)- Apply the given operation list on dynamic partition metadata, unmapping partitions if necessary.
- 
                Return ton success, or an empty string on failure.
 
          The op_list argument to
          update_dynamic_partitions points to a file in the
          update package. Each line in the file specifies an operation. If any
          operation fails, update_dynamic_partitions immediately
          returns an empty string. The operations are:
        
- resize partition-name size- Unmap the partition, then resize it to size.
 
- remove partition_name- Unmap the partition, then remove it.
 
- add partition-name group-name- Add a new partition to the specified group.
- Abort if the group doesn't exist or if the partition already exists.
 
- move partition-name group-name- Move the partition to the specified group.
- Abort if the group doesn't exist or partition doesn't exist.
 
- 
            add_group group-name maximum-size- Add a group with the given name and maximum size.
- Abort if the group already exists.
- A maximum_size of 0 means there are no size limits on partitions in the group. Additional testing is required to ensure that partitions in the group don't exceed the available space on the device.
 
- 
            resize_group group-name maximum-size- Resize the group to the given maximum size.
- Abort if the group doesn't exist.
- A maximum_size of 0 means there are no size limits on partitions in the group. Additional testing is required to ensure that partitions in the group don't exceed the available space on the device.
 
- remove_group group-name- Remove a group.
- Abort if there are partitions in the group.
 
- remove_all_groups- Unmap all partitions from the device mapper.
- Remove all partitions and groups.
 
Incremental OTA
Incremental OTA updates use the following logic:
- Shrink partitions/delete partitions/move partitions out of group (so that there's enough space to shrink groups)
- Shrink groups (so that there's enough space to grow groups)
- Grow groups (so that we have enough space to grow/add partitions)
- Grow partitions/add partitions/move partitions to new group
            In detail, update-script is generated with this
            logic:
          
for each shrinking partition:
    block_image_update(map_partition(name), …)
update_dynamic_partitions(op_list)
for each growing / adding partition:
    block_image_update(map_partition(name), …)
            The op_list file for
            update_dynamic_partitions is generated with this
            logic:
          
for each deleting partition:
    remove
for each partition that changes groups:
    move to "default"
for each shrinking partition:
    resize
for each shrinking / removing group:
    resize_group / remove_group
for each growing / adding group:
    resize_group / add_group
for each adding partition:
    add
for each growing / adding partition:
    resize
for each partition that changes groups:
    move to target groupFull OTA
Full OTA updates use the following logic:
- Delete all existing groups and partitions
- Add groups
- Add partitions
            In detail, update-script is generated with this
            logic:
          
update_dynamic_partitions(op_list)
for each adding partition:
    block_image_update(map_partition(name), …)
            The op_list file for
            update_dynamic_partitions is generated with this
            logic:
          
remove_all_groups
for each adding group:
    add_group
for each adding partition:
    add
for each adding partition:
    resize