Android 10 支持 动态分区,这是一种用户空间分区系统,可在无线下载 (OTA) 更新期间创建、调整大小和销毁分区。
本页面介绍了 OTA 客户端在为启动时不支持动态分区的 A/B 设备更新期间如何调整动态分区的大小,以及 OTA 客户端如何升级到 Android 10。
背景
在将 A/B 设备更新为支持动态分区的过程中,设备上的 GUID 分区表 (GPT) 会被保留,因此设备上没有 super
分区。元数据存储在 system_a
和 system_b
中,但这可以通过更改 BOARD_SUPER_PARTITION_METADATA_DEVICE
来自定义。
在每个块设备中,都有两个元数据槽。每个块设备中仅使用一个元数据槽。例如,system_a
上的元数据 0 和 system_b
上的元数据 1 分别对应于 A 和 B 插槽上的分区。在运行时,更新哪个插槽都没有关系。
在本页中,元数据槽称为元数据 S(源)和元数据 T(目标)。同样,分区称为 system_s
、vendor_t
等。
有关构建系统配置的更多信息,请参阅 升级设备。
有关分区如何属于更新组的更多信息,请参阅 新设备的板配置更改。
设备上元数据的一个示例是
- 物理块设备
system_a
- 元数据 0
- 组
foo_a
- 逻辑(动态)分区
system_a
- 逻辑(动态)分区
product_services_a
- Foo 更新的其他分区
- 逻辑(动态)分区
- 组
bar_a
- 逻辑(动态)分区
vendor_a
- 逻辑(动态)分区
product_a
- Bar 更新的其他分区
- 逻辑(动态)分区
- 组
- 元数据 1(未使用)
- 元数据 0
- 物理块设备
system_b
- 元数据 0(未使用)
- 元数据 1
- 组 foo_b
- 逻辑(动态)分区
system_b
- 逻辑(动态)分区
product_services_b
- Foo 更新的其他分区
- 逻辑(动态)分区
- 组 bar_b
- 逻辑(动态)分区
vendor_b
- 逻辑(动态)分区
product_b
- Bar 更新的其他分区
- 逻辑(动态)分区
- 组 foo_b
您可以使用 system/extras/partition_tools
下的 lpdump
工具来转储设备上的元数据。例如
lpdump --slot 0 /dev/block/by-name/system_a
lpdump --slot 1 /dev/block/by-name/system_b
改造更新
在运行 Android 9 及更低版本的设备上,设备上的 OTA 客户端不支持在更新之前映射动态分区。创建了一组额外的补丁,以便可以直接将映射应用于现有的物理分区。
OTA 生成器构建最终的 super.img
文件,其中包含所有动态分区的内容,然后将映像拆分为多个映像,这些映像与对应于 system、vendor 等的物理块设备的大小相匹配。这些映像被命名为 super_system.img
、super_vendor.img
等。OTA 客户端将这些映像应用于物理分区,而不是应用于逻辑(动态)分区的映像。
因为 OTA 客户端不知道如何映射动态分区,所以在生成更新包时,会自动禁用这些分区的所有安装后步骤。有关更多详细信息,请参阅 配置安装后步骤。
更新流程与 Android 9 中相同。
更新前
ro.boot.dynamic_partitions= ro.boot.dynamic_partitions_retrofit=
更新后
ro.boot.dynamic_partitions=true ro.boot.dynamic_partitions_retrofit=true
改造更新后的未来更新
在改造更新之后,OTA 客户端会更新为可与动态分区协同工作。源分区的范围永远不会跨越目标物理分区。
使用常规更新包的更新流程
- 初始化
super
分区元数据。- 从元数据 S(源元数据)构造新的元数据 M。例如,如果元数据 S 使用 [
system_s
、vendor_s
、product_s
] 作为块设备,则新的元数据 M 使用 [system_t
、vendor_t
、product_t
] 作为块设备。M 中会丢弃所有组和分区。 - 根据更新清单中的
dynamic_partition_metadata
字段添加目标组和分区。每个分区的大小可以在new_partition_info
中找到。 - 将 M 写入元数据 T。
- 将添加的分区在设备映射器上映射为可写。
- 从元数据 S(源元数据)构造新的元数据 M。例如,如果元数据 S 使用 [
- 在块设备上应用更新。
- 如果必要,将源分区在设备映射器上映射为只读。这对于侧载是必要的,因为在更新之前未映射源分区。
- 对目标插槽上的所有块设备应用完整或增量更新。
- 挂载分区以运行安装后脚本,然后卸载分区。
- 取消映射目标分区。
使用改造更新包的更新流程
如果在已启用动态分区的设备上应用改造更新包,则 OTA 客户端直接在块设备上应用拆分的 super.img
文件。更新流程类似于改造更新。有关详细信息,请参阅 改造更新。
例如,假设以下情况
- 插槽 A 是活动插槽。
-
system_a
包含插槽 0 处的活动元数据。 -
system_a
、vendor_a
和product_a
用作块设备。
当 OTA 客户端收到改造更新包时,它会将 super_system.img
应用于物理 system_b
,将 super_vendor.img
应用于物理 vendor_b
,并将 super_product.img
应用于物理 product_b
。物理块设备 system_b
包含正确的元数据,以便在启动时映射逻辑 system_b
、vendor_b
和 product_b
。
生成更新包
增量 OTA
在为改造设备生成增量 OTA 时,更新取决于基本版本是否定义了 PRODUCT_USE_DYNAMIC_PARTITIONS
和 PRODUCT_RETROFIT_DYNAMIC_PARTITIONS
。
- 如果基本版本未定义这些变量,则这是改造更新。更新包包含拆分的
super.img
文件,并禁用安装后步骤。 - 如果基本版本确实定义了这些变量,则这与使用动态分区的典型更新相同。更新包包含逻辑(动态)分区的映像。可以启用安装后步骤。
完整 OTA
为改造设备生成两个完整 OTA 包。
-
$(PRODUCT)-ota-retrofit-$(TAG).zip
始终包含拆分的super.img
,并禁用改造更新的安装后步骤。- 它是使用
ota_from_target_files
脚本的附加参数--retrofit_dynamic_partitions
生成的。 - 它可以应用于所有版本。
- 它是使用
-
$(PRODUCT)-ota-$(TAG).zip
包含用于未来更新的逻辑映像。- 仅将此应用于启用了动态分区的版本。有关强制执行此操作的详细信息,请参见下文。
拒绝旧版本上的非改造更新
仅将常规完整 OTA 包应用于启用了动态分区的版本。如果 OTA 服务器配置不正确并将这些软件包推送到运行 Android 9 或更低版本的设备,则设备将无法启动。Android 9 及更低版本上的 OTA 客户端无法区分改造 OTA 包和常规完整 OTA 包,因此客户端不会拒绝完整包。
为了防止设备接受完整 OTA 包,您可以要求执行安装后步骤来检查现有设备配置。例如
device/device_name/dynamic_partitions/check_dynamic_partitions
#!/system/bin/sh DP_PROPERTY_NAME="ro.boot.dynamic_partitions" DP_RETROFIT_PROPERTY_NAME="ro.boot.dynamic_partitions_retrofit" DP_PROPERTY=$(getprop ${DP_PROPERTY_NAME}) DP_RETROFIT_PROPERTY=$(getprop ${DP_RETROFIT_PROPERTY_NAME}) if [ "${DP_PROPERTY}" != "true" ] || [ "${DP_RETROFIT_PROPERTY}" != "true" ] ; then echo "Error: applied non-retrofit update on build without dynamic" \ "partitions." echo "${DP_PROPERTY_NAME}=${DP_PROPERTY}" echo "${DP_RETROFIT_PROPERTY_NAME}=${DP_RETROFIT_PROPERTY}" exit 1 fi
device/device_name/dynamic_partitions/Android.mk
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE:= check_dynamic_partitions LOCAL_MODULE_TAGS := optional LOCAL_MODULE_CLASS := EXECUTABLES LOCAL_SRC_FILES := check_dynamic_partitions LOCAL_PRODUCT_MODULE := true include $(BUILD_PREBUILT)
device/device_name/device.mk
PRODUCT_PACKAGES += check_dynamic_partitions # OPTIONAL=false so that the error in check_dynamic_partitions will be # propagated to OTA client. AB_OTA_POSTINSTALL_CONFIG += \ RUN_POSTINSTALL_product=true \ POSTINSTALL_PATH_product=bin/check_dynamic_partitions \ FILESYSTEM_TYPE_product=ext4 \ POSTINSTALL_OPTIONAL_product=false \
当常规 OTA 包应用于未启用动态分区的设备时,OTA 客户端会运行 check_dynamic_partitions
作为安装后步骤并拒绝更新。