一、Super分区是什么?
1、为什么需要super分区
Super分区,也叫dynamic动态分区,动态分区是 Android 的用户空间分区系统,在Android R版本开始引入。
android引入了super动态分区的设计,目的是为了解决像system,vendor等分区size大小不能动态调整的问题。
例如物理分区表中配置固定size后,如果软件版本对system,vendor分区size需要频繁调整时,需要修改物理分区表和重新编译gpt表,使用起来不是很便利。
2、引入super会产生什么影响?
引入Super动态分区后,将system,vendor等分区一起“打包”在Super分区中,物理分区表只有super,
不再单独配置system,vendor等分区的配置,其中的子分区可以动态地调整大小。
编译的时候,会将system,vendor等分区的信息以metadata的形式记录下来,生成super.img时会根据metadata信息进行处理。
另外super分区中的子分区,也可以通过fastbootd以fastboot的方式刷入,或者使用lpunpack解压开。
采用Super分区后,AVB校验流程也会有些不同
主要不同点在新增了vbmeta_system分区,这个分区和vbemta是类似的。
Vbmeta_system分区主要目的是为了校验super分区,vbmeta_system中记录了super分区中system,vendor子分区的描述信息。
这样AVB校验流程是avb先校验vbmeta,vbmeta里面校验vbmeta_system,然后vbmeta_system里面校验system,vendor分区。
二、Super分区工作原理
动态分区是使用 Linux 内核中的 dm-linear device-mapper 模块实现的。
Linear是指将device mapper设备的线性范围 映射到另一个设备的线性范围属于LVM逻辑卷管理。
Super 分区包含列出了 每个子分区的名称和块范围的metadata元数据。
在开机 init的fisrt stage第一阶段运行期间,会解析并验证metadata元数据,并创建虚拟block设备来表示每个子分区,创建logical逻辑分区出来。
在init启动的第一阶段会去加载和处理,采用和以前类似的AVB校验流程,验证通过后,super包含的几个分区全部采用hashtree类型做dm-verity验证。
在运行过程中对访问的block数据进行dm-verity安全校验。校验通过过,分别挂载这几个逻辑子分区。
三、Super分区的配置和编译
1.分区表的配置
在vbmeta_system在A/B功能打开的情况下,请增加两个64KB大小的vbmeta_system分区,如果没有A/B,则只需要增加一个64KB的vbmeta_system分区。
而super分区则不需要A/B,大小可设置大一点也没有太大影响,多余的空间几个分区可以共享。
Board配置主要包括板卡makefile、initrc配置、fstab配置和BoardConfig的配置。其他的配置这里暂不列了。
BOARD_DYNAMIC_PARTITION_ENABLE ?= true BOARD_BUILD_SUPER_IMAGE_BY_DEFAULT := true PRODUCT_BUILD_SUPER_PARTITION := true BOARD_SUPER_PARTITION_SIZE BOARD_SUPER_PARTITION_GROUPS := test_dynamic_partitions BOARD_TEST_DYNAMIC_PARTITIONS_PARTITION_LIST := system vendor BOARD_TEST_DYNAMIC_PARTITIONS_SIZE :=yoursize BOARD_EXT4_SHARE_DUP_BLOCKS := true
2. Super镜像的编译
Super镜像的编译,主要是查看对应的python脚本如何打包和生成super.img,下面介绍一下这个镜像生成的过程。
2.1 Super镜像的编译日志
下面是android R上编译打包super.img的部分日志:
[100% 125545/125545] Target super fs image for debug: out/target/product/xxx/super.img 2021-04-15 20:48:15 - build_super_image.py - INFO : Building super image from info dict... 2021-04-15 20:48:15 - sparse_img.py - INFO : Total of 215260 4096-byte output blocks in 21 input chunks. 2021-04-15 20:48:15 - sparse_img.py - INFO : Total of 45014 4096-byte output blocks in 11 input chunks. 2021-04-15 20:48:15 - sparse_img.py - INFO : Total of 55612 4096-byte output blocks in 12 input chunks. 2021-04-15 20:48:15 - sparse_img.py - INFO : Total of 227012 4096-byte output blocks in 22 input chunks. 2021-04-15 20:48:15 - common.py - INFO : Running: "lpmake --metadata-size 65536 --super-name super --metadata-slots 3 --device super:12884901888 --group test_dynamic_partitions_a:6438256640 --group test_dynamic_partitions_b:6438256640 --partition system_a:readonly:881704960:test_dynamic_partitions_a --image system_a=out/target/product/xxx/system.img --partition system_b:readonly:0:test_dynamic_partitions_b --partition system_ext_a:readonly:184377344:test_dynamic_partitions_a --image system_ext_a=out/target/product/xxx/system_ext.img --partition system_ext_b:readonly:0:test_dynamic_partitions_b --partition product_a:readonly:227786752:test_dynamic_partitions_a --image product_a=out/target/product/xxx/product.img --partition product_b:readonly:0:test_dynamic_partitions_b --partition vendor_a:readonly:929841152:test_dynamic_partitions_a --image vendor_a=out/target/product/xxx/vendor.img --partition vendor_b:readonly:0:test_dynamic_partitions_b --sparse --output out/target/product/xxx/super.img“ 2021-04-15 20:48:27 - common.py - INFO : lpmake I 04-15 20:48:15 22465 22465 builder.cpp:1031] [liblp]Partition system_a will resize from 0 bytes to 881704960 bytes lpmake I 04-15 20:48:15 22465 22465 builder.cpp:1031] [liblp]Partition system_ext_a will resize from 0 bytes to 184377344 bytes lpmake I 04-15 20:48:15 22465 22465 builder.cpp:1031] [liblp]Partition product_a will resize from 0 bytes to 227786752 bytes lpmake I 04-15 20:48:15 22465 22465 builder.cpp:1031] [liblp]Partition vendor_a will resize from 0 bytes to 929841152 bytes 2021-04-15 20:48:27 - build_super_image.py - INFO : Done writing image out/target/product/xxx/super.img
2.2 Super镜像的生成过程
看下build/core/Makefile中处理super分区的部分
.PHONY: superimage superimage: $(INSTALLED_SUPERIMAGE_TARGET) ifeq (true,$(BOARD_BUILD_SUPER_IMAGE_BY_DEFAULT)) $(INSTALLED_SUPERIMAGE_TARGET): $(INSTALLED_SUPERIMAGE_DEPENDENCIES) $(call pretty,"Target super fs image for debug: $@") $(call build-superimage-target,$(INSTALLED_SUPERIMAGE_TARGET),\ $(call intermediates-dir-for,PACKAGING,superimage_debug)/misc_info.txt) INSTALLED_SUPERIMAGE_TARGET := $(PRODUCT_OUT)/super.img INSTALLED_SUPERIMAGE_DEPENDENCIES := $(LPMAKE) $(BUILD_SUPER_IMAGE) \ $(foreach p, $(BOARD_SUPER_PARTITION_PARTITION_LIST), $(INSTALLED_$(call to-upper,$(p))IMAGE_TARGET)) INTERNAL_OTATOOLS_MODULES := \ build_super_image \ lpmake \
- build_super_image对应的是build\tools\releasetools\build_super_image.py
- lpmake是host工具,在android/out/host/linux-x86/bin/lpmake
- misc_info.txt两个,一个是obj中的,一个是out中的
- 另外可用lpunpack工具进行解压super.img,可以查看到各个子img镜像
- 这个工具默认没有编译,源码在system/extras/partition_tools/
重点看一下misc_info.txt中如下打印,和BoardConfig中配置是相对应的。
use_dynamic_partitions=true lpmake=lpmake build_super_partition=true super_metadata_device=super super_block_devices=super super_super_device_size=12884901888 dynamic_partition_list= system vendor super_partition_groups=test_dynamic_partitions super_test_dynamic_partitions_group_size=6438256640 super_test_dynamic_partitions_partition_list= system vendor super_partition_size=12884901888
四、Super分区在AVB中的校验
总体上和非super分区的校验差不多,差异点在于校验的分区多了一个vbmeta_system,且需要创建逻辑分区,需要从fstab的avb_keys中获取hash tree的key等。
bool FirstStageMount::CreateLogicalPartitions() { if (!IsDmLinearEnabled()) { return true; } … auto metadata = android::fs_mgr::ReadCurrentMetadata(super_path_); if (!InitDmLinearBackingDevices(*metadata.get())) { return false; } return android::fs_mgr::CreateLogicalPartitions(*metadata.get(), super_path_); } bool FirstStageMountVBootV2::SetUpDmVerity(FstabEntry* fstab_entry) { AvbHashtreeResult hashtree_result; if (!fstab_entry->avb_keys.empty()) { if (!InitAvbHandle()) return false; if (avb_handle_->status() == AvbHandleStatus::kHashtreeDisabled || avb_handle_->status() == AvbHandleStatus::kVerificationDisabled) { return true; // Returns true to mount the partition directly. } else { hashtree_result = avb_standalone_handle->SetUpAvbHashtree( fstab_entry, false); } } else if (fstab_entry->fs_mgr_flags.avb) { if (!InitAvbHandle()) return false; hashtree_result = avb_handle_->SetUpAvbHashtree(fstab_entry, false); } else { return true; // No need AVB, returns true to mount the partition directly. } }