OTA 适用于具有动态分区的 A/B 设备

Android 10 支持动态分区,这是一种用户空间分区系统,可以在 OTA(无线下载)更新期间创建、调整大小和销毁分区。

本页面介绍了在为搭载动态分区支持的 A/B 设备(运行 Android 9 及更低版本的设备)更新期间如何调整动态分区的大小。

背景

设备上有一个 super 分区。此分区没有槽后缀。块设备必须与 fstab/miscblk_device 条目一起存在。例如,如果 fstab 文件列出

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

那么 super 的块设备必须存在于 /dev/block/bootdevice/by-name/super 中,但 super 分区不需要在 fstab 文件中列出。

super 分区中,有两个元数据槽,编号为 0 和 1,分别对应于分区的 A/B 槽。在本页面中,元数据槽称为元数据 S(来源)和元数据 T(目标)。同样,分区被称为 system_svendor_t 等。

在升级之前,元数据 S 包含正在使用的动态分区的信息(通常为 system_svendor_sproduct_s 等)。系统会在更新期间读取这些分区的范围,因此无法删除这些分区。

分区属于更新组。有关详情,请参阅实现动态分区

设备上元数据的示例如下。

  • 元数据 0
    • foo_a
      • 分区 system_a
      • 分区 product_services_a
      • Foo 更新的其他分区
    • 组 bar_a
      • 分区 vendor_a
      • 分区 product_a
      • Bar 更新的其他分区
    • foo_b(上次升级遗留)
    • bar_b(上次升级遗留)
  • 元数据 1
    • foo_a(上次升级遗留)
    • bar_a(上次升级遗留)
    • foo_b
      • 分区 system_b
      • 分区 product_services_b
      • Foo 更新的其他分区
    • bar_b
      • 分区 vendor_b
      • 分区 product_b
      • Bar 更新的其他分区

您可以使用 lpdump 工具(源代码位于 system/extras/partition_tools 下)来转储设备上的元数据。例如:

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

更新流程

  1. 初始化 super 分区元数据。
    1. 从元数据 S 加载源动态分区的范围。设 M 为加载的元数据。
    2. 从 M 中移除目标组和分区(例如,foo_tbar_t),使 M 仅包含带有 _s 后缀的分区和组。
    3. 根据更新清单中的 dynamic_partition_metadata 字段添加目标组和分区。
      每个分区的大小可以在 new_partition_info 中找到。
    4. 将 M 写入元数据 T。
    5. 将添加的分区在设备映射器上映射为可写。
  2. 对块设备应用更新。
    1. 如有必要,将源分区在设备映射器上映射为只读。对于侧加载,这是必要的,因为源分区在更新之前未映射。
    2. 对目标槽上的所有块设备应用完整更新或增量更新。
    3. 挂载分区以运行安装后脚本,然后卸载分区。
  3. 取消映射目标分区。

更新前后,以下系统属性应具有各自的值

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

向更新清单添加组和分区

在具有动态分区的 A/B 设备或正在添加对动态分区支持的 A/B 设备上执行 OTA 更新时,您需要向更新清单添加组和分区。以下代码段显示了有关更新清单以支持动态分区的其他信息。有关每个字段的详细文档,请参阅 update_metadata.proto

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;
}