动态分区是Android的用户空间分区系统,从Android Q开始引入这个动态分区super的概念。使用此分区系统,可以在无线下载 (OTA) 更新期间创建、销毁分区或者调整分区大小。借助动态分区,供应商无需担心各个分区(例如 system、vendor 和 product)的大小。取而代之的是,设备分配一个super分区,其中的子分区可动态地调整大小。单个分区镜像不再需要为将来的 OTA 预留空间。相反,super 中剩余的可用空间还可用于所有动态分区。
从Android Q引入动态分区,到Android R/S在动态分区之上增加虚拟分区管理, OTA升级时需要对分区变更进行处理
动态分区管理的本质就是对分区数据的增删改查操作,操作的对象就是动态分区描述数据metadata。
动态分区是使用Linux内核中的dm-linear device-mapper
模块实现的。 super分区包含列出了super中每个动态分区的名称和块范围的元数据。
在第一阶段init期间,系统会解析并验证此元数据,并创建虚拟块设备来表示每个动态分区。
执行OTA时,系统会根据需要自动创建/删除动态分区,或者调整动态分区的大小。
若是A/B设备,将存在两个元数据副本,而更改仅会应用到表示目标槽位的副本。
由于动态分区是在用户空间中实现的,因此引导加载程序所需的分区不能是动态的。 例如,引导加载程序会读取 boot、dtbo 和 vbmeta,因此这些分区必须仍保持为物理分区。
每个动态分区都可以属于一个“更新组”。 这些组会限制组内的分区可以使用的最大空间
例如,system和vendor可以属于一个限制了system和vendor总大小的组
Device mapper 内核中各对象的层次关系:
所以,一个设备可能是真实的,也可能是虚拟的。对虚拟设备的访问会被Target Driver拦截,然后通过Mapping Table转发给另外一个设备。
例如,在Android Q上,对system_a或vendor_a分区的访问被驱动拦截并转发为对super分区某个区域的访问。而这里的拦截以及转发对用户是透明的,用户根本不知道,也不需要知道他最终访问的到底是哪个设备。
对于搭载Android 10及之后版本的设备,创建名为super的分区。super分区会在内部处理A/B槽位,因此A/B设备不需要单独的super_a和super_b分区。
引导加载程序未使用的所有只读AOSP分区都必须是动态的,并且必须从GUID分区表 (GPT) 中移除。 供应商专用分区则可以不是动态的,并且可以放在GPT中
注意:应避免将 userdata 或任何其他永久性读写分区放在super中
如需估算super的大小,请加总要从GPT中删除的分区的大小。对于A/B设备,这应包括两个槽位的大小。
下图显示了转换为动态分区前后的分区表示例:
新的super分区内部包含了多个原来的分区,而识别这些内部分区的方法就是:引入数据来描述super分区的布局。
在super分区开头存储用于描述分区布局的metadata
,和磁盘开头存储用于描述磁盘分区布局的gpt数据的道理一样。系统加载动态分区时读取metadata
,对其进行解析,在内存中建立super分区布局描述的LpMetadata
结构体,就知道内部的各个分区都位于哪个地方。
换句话说,metadata就是LpMetadata
结构在super
分区上的物理存储数据,而LpMetadata
是metadata
在内存中的数据结构。LpMetadata
中的信息会被转换成device mapper中的映射表Mappting Table
,基于这个映射表,super分区对应设备/dev/block/by-name/super
的不同部分被映射成多个虚拟设备,如/dev/block/mapper/system_a
,/dev/block/mapper/vendor_a
等
支持的动态分区包括:
对于搭载 Android 10 的设备,内核命令行选项androidboot.super_partition
必须为空,以使命令sysprop ro.boot.super_partition
为空。
宏观上看下物理存储的metadata:
对metadata,可以分层3个层次,见图:
LpMetadataGeometry
结构数据,填充到4K大小LpMetadataHeader
,LpMetadataPartition
,LpMetadataExtent
,LpMetadataPartitionGroup
,LpMetadataBlockDevice
等数据结构,填充到64K大小动态分区的核心数据结构主要定义在以下文件中:
如果super分区未正确对齐,device-mapper模块的运行效率可能会降低。super分区必须与最小I/O请求大小保持一致,该大小由块层决定。
默认情况下,构建系统(通过生成super分区镜像的lpmake
)假设每个动态分区有1 MiB的对齐程度即已足够。
不过,供应商应确保super分区正确对齐。
sysfs
来确定块设备的最小请求大小。例如:# 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
# cat /sys/block/sda/sda17/alignment_offset
在device.mk添加标记:
PRODUCT_USE_DYNAMIC_PARTITIONS := true
例如在Android Q源码:
//android/device/google/cuttlefish/shared/phone/device.mk
TARGET_USE_DYNAMIC_PARTITIONS ?= true
ifeq ($(TARGET_USE_DYNAMIC_PARTITIONS),true)
PRODUCT_USE_DYNAMIC_PARTITIONS := true
TARGET_BUILD_SYSTEM_ROOT_IMAGE := false
else
TARGET_BUILD_SYSTEM_ROOT_IMAGE ?= true
endif
在BoardConfig.mk添加修改,设置super分区的大小:(在A/B设备上,如果动态分区镜像的总大小超过super分区大小的一半,构建系统就会发生错误)
BOARD_SUPER_PARTITION_SIZE := <size-in-bytes>
可以按以下方式配置动态分区列表。 对于使用更新组的设备,在BOARD_SUPER_PARTITION_GROUPS
变量中列出这些组。
然后,每个组名称都有一个BOARD_group_SIZE
和BOARD_group_PARTITION_LIST
变量。 对于A/B设备,组的大小上限应仅包含一个槽位,因为组名在内部以槽位为后缀。
以下示例设备将所有分区放入名为example_dynamic_partitions
的组中:
//例如1:将所有分区放入名为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
//例如2:将系统和产品服务放入group_foo,并将vendor、product和odm放入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
例如在Android Q源码:
//android/device/google/cuttlefish/shared/BoardConfig.mk
ifeq ($(TARGET_USE_DYNAMIC_PARTITIONS),true)
BOARD_SUPER_PARTITION_SIZE := 6442450944
BOARD_SUPER_PARTITION_GROUPS := google_dynamic_partitions
BOARD_GOOGLE_DYNAMIC_PARTITIONS_PARTITION_LIST := system vendor product
BOARD_GOOGLE_DYNAMIC_PARTITIONS_SIZE := 6442450944
BOARD_SUPER_PARTITION_METADATA_DEVICE := vda
BOARD_BUILD_SUPER_IMAGE_BY_DEFAULT := true
BOARD_SUPER_IMAGE_IN_UPDATE_PACKAGE := true
TARGET_RELEASETOOLS_EXTENSIONS := device/google/cuttlefish/shared
else
# No dynamic partitions support; we must specify maximum sizes
BOARD_SYSTEMIMAGE_PARTITION_SIZE := 4294967296 # 4 GB
BOARD_VENDORIMAGE_PARTITION_SIZE := 536870912 # 512MB
BOARD_PRODUCTIMAGE_PARTITION_SIZE := 1610612736 # 1.5GB
TARGET_NO_RECOVERY ?= true
endif
BOARD_SUPER_PARTITION_SIZE - 开销
BOARD_SUPER_PARTITION_SIZE / 2 - 开销
BOARD_SUPER_PARTITION_SIZE - 开销
在采用动态分区之前,会为分区分配富余的空间,以确保它们有足够的空间满足将来的更新。分区会按分配的大小占用实际空间,大多数只读分区的文件系统中都会有一些空闲空间。
在动态分区中,这些空闲空间不可用,并且可以用于在OTA期间增大分区。 需要确保分区没有浪费空间并且尽可能将其分配给最小大小。
对于只读的ext4镜像,如果未指定硬编码分区大小,则构建系统会自动分配最小的空间。构建系统会适配镜像,以尽可能减少文件系统中的未使用空间。这样可以确保设备不会浪费可用于OTA的空间。
此外,通过启用块级重复信息删除,可以进一步压缩ext4镜像。 要启用此功能,请使用以下配置:
BOARD_EXT4_SHARE_DUP_BLOCKS := true
如果不希望自动分配最小分区大小,则可以通过两种方法来控制分区大小。
可以使用BOARD_partitionIMAGE_PARTITION_RESERVED_SIZE
指定最小可用空间,
也可以指定BOARD_partitionIMAGE_PARTITION_SIZE
以强制将动态分区设为特定大小。除非必要,这两种方法都不建议使用。
例如,这样会强制product.img的文件系统使用50MB的未使用空间:
BOARD_PRODUCTIMAGE_PARTITION_RESERVED_SIZE := 52428800 //50MB
注意:构建系统只能最佳适配ext4文件系统镜像,且只能适配构建过程中生成的镜像。若是预构建的镜像或使用其他文件系统的镜像,则必须手动确保文件系统没有浪费磁盘空间。
搭载Android 10的设备不得使用system-as-root
具有动态分区的设备(无论是搭载动态分区还是改造动态分区)不得使用system-as-root
。 Linux内核无法解读super分区,因此无法自行装载system本身。system现在由位于ramdisk中的第一阶段init装载。
不要设置BOARD_BUILD_SYSTEM_ROOT_IMAGE
。在Android 10中,BOARD_BUILD_SYSTEM_ROOT_IMAGE
标记仅用于区分系统是由内核装载还是在第一阶段装载init(在ramdisk中)。
设置BOARD_BUILD_SYSTEM_ROOT_IMAG=true
会导致PRODUCT_USES_DYNAMIC_PARTITIONS=true
。
将BOARD_USES_RECOVERY_AS_BOOT
设置为true时,recovery.img将被构建为boot.img,其中包含恢复的ramdisk。 以前,引导加载程序使用skip_initramfs
内核命令行参数来决定启动到哪种模式。
对于搭载Android 10的设备,引导加载程序不得向内核命令行传递skip_initramfs。
引导加载程序应传递androidboot.force_normal_boot=1
来跳过恢复并正常启动 Android。
发布时搭载Android 12或更高版本的设备必须使用bootconfig传递androidboot.force_normal_boot=1
警告:动态分区需要使用Android启动时验证 (AVB),但不能与启动时验证1.0搭配使用
使用 Android 启动时验证 2.0 时,如果设备未使用链式分区描述符,则不需要进行更改。但如果使用了链式分区,并且其中一个已验证分区是动态分区,则需要进行更改。
下面的设备配置示例链接system和vendor分区所对应的vbmeta。
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
使用该配置,引导加载程序可以在system分区和vendor分区的末尾找到vbmeta页脚。由于这两个分区对引导加载程序不再可见(它们位于super),因此需要进行两项更改。
将vbmeta_system和vbmeta_vendor分区添加到设备的分区表中。
对于A/B设备,请添加vbmeta_system_a、vbmeta_system_b、vbmeta_vendor_a 和 vbmeta_vendor_b。如果添加上述一个或多个分区,则它们的大小应与vbmeta分区相同。
通过添加VBMETA_
来重命名配置标记,并指定链接扩展到的分区:
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
必须在内核命令行中添加新参数androidboot.boot_devices
。init使用它来启用/dev/block/by-name
符号链接。
该参数应该是由ueventd
创建的底层by-name
符号链接(即/dev/block/platform/device-path/by-name/partition-name
)的设备路径组件。发布时搭载Android 12或更高版本的设备必须使用bootconfig
将androidboot.boot_devices
传递给init。
例如,如果super按分区的符号链接为/dev/block/platform/soc/100000.ufshc/by-name/super
,
BoardConfig.mk
文件中添加命令行参数,如下所示:BOARD_KERNEL_CMDLINE += androidboot.boot_devices=soc/100000.ufshc
BOARD_BOOTCONFIG += androidboot.boot_devices=soc/100000.ufshc
设备树和设备树叠加层不得包含 fstab 条目。 使用将成为 ramdisk 一部分的 fstab 文件。
必须对逻辑分区的 fstab 文件进行以下更改:
fs_mgr标志字段必须包含logical标志和first_stage_mountAndroid 10 中引入的 Android 标记标志,用于指示在第一阶段装载分区。
分区可以将 avb=vbmeta partition name 指定为 fs_mgr 标志,然后指定的 vbmeta 分区先由第一阶段 init 初始化,然后再尝试装载任何磁盘设备。
dev字段必须是分区名称。
以下fstab条目按照上述规则设置system、vendor和product逻辑分区。
将fstab文件复制到第一阶段ramdisk。
#<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
注意:对于非A/B设备,请勿包含slotselect
super分区块设备必须使用super_block_device
标签进行标记。
例如,如果超名称按分区的符号链接为/dev/block/platform/soc/100000.ufshc/by-name/super
,请将以下代码行添加到file_contexts中:
/dev/block/platform/soc/10000\.ufshc/by-name/super u:object_r:super_block_device:s0
引导加载程序(或任何非用户空间刷写工具)无法理解动态分区,因此无法对其进行刷写。为解决此问题,设备必须使用fastboot协议的用户空间实现,称为fastbootd。
对于使用eng或userdebug build的开发者,adb remount对快速迭代非常有用。
动态分区给adb remount造成了问题,因为每个文件系统中都不再有空闲空间。为解决此问题,设备可以启用overlayfs。
只要super分区中有空闲空间,adb remount就会自动创建临时的动态分区,并使用overlayfs
进行写入。该临时分区的名称为scratch
,因此请勿将该名称用于其他分区。
如果您想将设备升级到 Android 10,并且希望在 OTA 中包含动态分区支持,则不需要更改内置分区表。需要进行一些额外的配置。
//device.mk
PRODUCT_USE_DYNAMIC_PARTITIONS := true
PRODUCT_RETROFIT_DYNAMIC_PARTITIONS := true
BOARD_SUPER_PARTITION_BLOCK_DEVICES
设置为用于存储动态分区区段的块设备的列表。这是设备上现有物理分区的名称列表。BOARD_SUPER_PARTITION_partition_DEVICE_SIZE
分别设置为BOARD_SUPER_PARTITION_BLOCK_DEVICES
中每个块设备的大小。 这是设备上现有物理分区的大小列表。在现有板级配置中,这通常为BOARD_partitionIMAGE_PARTITION_SIZE
BOARD_SUPER_PARTITION_BLOCK_DEVICES
中的所有分区取消设置现有BOARD_partitionIMAGE_PARTITION_SIZE
BOARD_SUPER_PARTITION_SIZE
设置为BOARD_SUPER_PARTITION_partition_DEVICE_SIZE
的总和BOARD_SUPER_PARTITION_METADATA_DEVICE
设置为存储动态分区元数据的块设备。它必须是BOARD_SUPER_PARTITION_BLOCK_DEVICES
中的一个。通常,此参数设置为system
BOARD_SUPER_PARTITION_GROUPS
、BOARD_group_SIZE
和BOARD_group_PARTITION_LIST
例如,如果设备已经有system和vendor分区,并且希望在更新期间将它们转换为动态分区并添加新的product
分区,请设置以下板级配置:
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
必须使用super_block_device_type
中下载Google健身应用。
例如,如果设备已经system和vendor分区,希望将它们用作块设备来存储动态分区的范围,并且其按名称符号链接标记为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
然后将其添加到device.te:
typeattribute system_block_device super_block_device_type;
对于搭载动态分区支持的设备,请勿使用用户空间 fastboot 来刷写出厂映像,因为启动到用户空间比其他刷写方法慢。
为了解决此问题,make dist
现在会构建一个额外的super.img镜像,该镜像可以直接刷写到super分区。
除了super分区元数据之外,它还会自动捆绑逻辑分区的内容,这意味着它包含system.img、vendor.img 等。此镜像可以直接刷写到super分区,而无需任何其他工具或使用fastbootd。构建之后,super.img 会放置在${ANDROID_PRODUCT_OUT}
中。
对于搭载动态分区的A/B设备,super.img包含A槽位中的镜像。直接刷写super映像后,在重启设备之前将槽位A标记为可启动。
对于改造设备,make dist
会构建一组可以直接刷写到相应物理分区的super_*.img
镜像。例如,当BOARD_SUPER_PARTITION_BLOCK_DEVICES
是系统供应商时,make dist
会构建super_system.img和super_vendor.img。这些j镜像放置在target_files.zip
的OTA文件夹中。
动态分区具有许多不确定性的设备映射器对象。这些内容可能无法按预期方式实例化,因此,您必须跟踪所有装载操作,并使用其底层存储设备更新所有关联分区的Android属性。
init内的机制会跟踪装载并异步更新Android属性。我们不保证在特定时间段内花费的时间,因此您必须为所有on property
触发器提供足够的时间以作出回应。
特性为dev.mnt.blk.<partition>
,例如<partition>
为root、system、data或vendor。每个属性都与基本存储设备名称相关联,如以下示例所示:
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]
通过init.rc
语言,可以在规则中扩展Android属性,并且可以根据需要通过平台调整存储设备:
write /sys/block/${dev.mnt.blk.root}/queue/read_ahead_kb 128
write /sys/block/${dev.mnt.blk.data}/queue/read_ahead_kb 128
命令阶段在第二阶段(init 开始)后,epoll loop会变为活动状态,值会开始更新。
但是,由于属性触发器在init后才会进入活动状态,不能在初始启动阶段使用它们来处理root、system 或vendor。可能希望内核默认read_ahead_kb足够大,直到init.rc脚本可以替换early-fs
当多个守护进程和设施启动时)。因此,Google建议将on property
功能与sys.read_ahead_kb
等init.rc控制的属性搭配使用,以处理操作并防止出现竞态条件,如以下示例所示:
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}
Android 10支持动态分区,这是一种可以在无线下载 (OTA)更新期间创建和销毁分区以及调整分区大小的用户空间分区系统。
设备上有一个super分区。此分区没有槽后缀。块设备必须与fstab中/misc
的blk_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插槽。
分区属于更新组。
下面的示例显示了设备上的元数据。
可以使用lpdump
工具(system/extras/partition_tools
下的源代码)转储设备上的元数据。例如:
lpdump --slot 0 /dev/block/bootdevice/by-name/super
lpdump --slot 1 /dev/block/bootdevice/by-name/super
在本文档中,我们将元数据槽位称为元数据S源)和元数据T目标)。类似地,将分区命名为system_s、vendor_t等。
在升级之前,元数据S包含正在使用的动态分区(通常是system_s、vendor_s、product_s等)的信息。系统会在更新期间读取这些分区的范围,因此它们无法删除。
_s
后缀的分区和组。dynamic_partition_metadata
字段添加目标组和分区。可在new_partition_info
中找到每个分区的大小。注意:来源和目标动态分区的范围跨越整个super分区。 因此,必须加载来源元数据,以便这些范围不会用作任何目标分区的一部分
在更新之前和之后,以下系统属性应具有相应的值:
ro.boot.dynamic_partitions=true
ro.boot.dynamic_partitions_retrofit=true
在具有动态分区的A/B设备或要添加对动态分区的支持的A/B设备上执行OTA更新时,需要将组和分区添加到更新清单中。
以下代码段显示更新清单以支持动态分区的其他信息。
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;
}