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

Android 10 支持动态分区,它是一个用户空间分区系统,可以在无线下载 (OTA) 更新期间创建、销毁分区以及调整其大小。本文档介绍了 OTA 客户端如何在发布时即具有动态分区支持的 A/B 设备更新期间调整动态分区的大小。

背景

设备上有一个 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;
}