Android P中的AVB校验(二)

上一篇是大概知道了Android P中的AVB校验流程,其中我们说了目的就是为了挂载,那么怎么挂载呢?这一篇一起来学习一下前辈的文章:https://blog.csdn.net/rikeyone/article/details/83274988

前言

Android O/P 版本以来,谷歌加入了A/B system的特性,此时ramdisk和system是一起放在同一个system.img镜像中的

而系统起来之后也就不存在system分区了,而是直接把system镜像挂载到/根目录上。那么这个操作是怎么进行的呢?

system.img默认是需要使能dm-verity来挂载的,那么这就涉及到如何使能dm-verity来挂载/根分区。还有一个重要的点,如果我们想要禁用dm-verity功能又要如何操作?这又涉及更深的层次,如果配置/根分区的挂载方式为dm-verity或者非dm-verity方式?带着这些问题,我们进行逐步的深入研究。

1、vbmeta

Android P 中有一个vbmeta分区,这是一个主要起检验作用的分区,存放有各个分区的校验数据以及签名和其他信息。主要分三个部分:Vbmeta Header(头部)/Authentication Data(校验数据)/Auxiliary Data(其他附加信息)。我们可以使用android在带的avbtool对vbmeta.img进行解析:

avbtool info_image --image vbmeta.img > vbmeta.img.info

解析出来的结果实例如下:

 Minimum libavb version:   1.0
 Header Block:             256 bytes
 Authentication Block:     576 bytes
 Auxiliary Block:          3456 bytes
 Algorithm:                SHA256_RSA4096
 Rollback Index:           0
 Flags:                    0
 Release String:           'avbtool 1.1.0'
 Descriptors:
     Chain Partition descriptor:
       Partition Name:          system
       Rollback Index Location: 2
       Public key (sha1):       cdbb77177f731920bbe0a0f94f84d9038ae0617d
     Chain Partition descriptor:
       Partition Name:          recovery
       Rollback Index Location: 1
       Public key (sha1):       2597c218aae470a130f61162feaae70afd97f011
     Hash descriptor:
       Image Size:            35553280 bytes
       Hash Algorithm:        sha256
       Partition Name:        boot
       Salt:                  baa1ce5d7db69d1b3943a78b5b142ae4d77b4ed60b9885c8661e845172b29a13
       Digest:                ec7cb1ad89fed3104a03191434d5487b5b4acc78e6bfeb84d7178af40df7db75
       Flags:                 0
     Hashtree descriptor:
       Version of dm-verity:  1
       Image Size:            1056714752 bytes
       Tree Offset:           1056714752
       Tree Size:             8327168 bytes
       Data Block Size:       4096 bytes
       Hash Block Size:       4096 bytes
       FEC num roots:         2
       FEC offset:            1065041920
       FEC size:              8421376 bytes
       Hash Algorithm:        sha1
       Partition Name:        vendor
       Salt:                  abbf0829ed7bc08913b83f9a994a37ad2a85b5e9
       Root Digest:           39a22a035ebff2d339dc682603adedb91da01374
       Flags:                 0
     Hash descriptor:
       Image Size:            176641 bytes
       Hash Algorithm:        sha256
       Partition Name:        dtbo
       Salt:                  386837807aa5a7d9cbe51e7f768009f4e5fca5190af4b3e856a7c96a96c33e0a
       Digest:                dabdbe5be19c38a3428efd046182d215f8522ab7cd3804e84f196fe73e9052f7
       Flags:                 0


1、Vbmeta Header

在Android自带的Library/avb/libavb/avb_vbmeta_image.h中可以找到该结构体的定义:

typedef struct AvbVBMetaImageHeader {
	...
/* 120: Flags from the AvbVBMetaImageFlags enumeration. This must be
 * set to zero if the vbmeta image is not a top-level image.
 */
uint32_t flags;
	...
}AVB_ATTR_PACKED AvbVBMetaImageHeader;

这里我们仅仅截取关键的部分 flags,这个成员标志着是否要使能dm-verity或者verification。

 typedef enum {
   AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED = (1 << 0),
   AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED = (1 << 1)
 } AvbVBMetaImageFlags;

这个也就是今天要解说的重点了,刚刚我们提到system image使用dm-verity挂载应该是一个可配置选项,那这个可配置功能就是利用这个flag中的AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED位。如果我们利用adb disable-verity命令操作了设备,设备就会去重写vbmeta分区中对应的该bit位为1,这样在后续的bootloader加载时就会做这个flag的判断,由此确定是否使能dm-verity去挂载system镜像。

2、Authentication Data

校验数据主要包含了hash摘要和签名,这是为了AVB启动准备的,不再本文讨论范围内,不做深入讲解。

3、Auxiliary Data

附加数据在system挂载时是需要讲解的,附加数据包含了三类信息:描述符/公钥/公钥元数据

主要介绍描述符,上面的实例可以看到,在Descriptors:一项的后面有很多内容,描述符包括很多类型的描述符,其中有一个与system挂载有关那就是cmdline descriptor,当然这个并不在vbmeta.img中有体现,因为vbmeta并不需要挂载,这个描述符只会存在于需要被kernel挂载的分区中。

cmdline

cmdline是uboot引导内核启动时传递给内核的,作用是指导内核启动。内核启动阶段会去解析cmdline,并根据cmdline去指导内核启动。

(1)格式就是由很多个项目用空格隔开依次排列,每个项目中都是项目名=项目值;
(2)整个cmdline会被内核启动时解析,解析成一个一个的项目名=项目值的字符串。这些字符串又会被再次解析从而影响启动过程。

这里需要提到一些背景,我们知道system.img现在已经和ramdisk打包在一起了,那么system.img就不是挂载到/system的地方了,而是需要直接挂载在/根目录上。

以往的版本,对于system的挂载都是由init来完成的,我们只需要修改fstab即可完成对system的挂载,但是现在不同了,根目录的挂载必须要由kernel去完成了。

因为根目录挂载是先于init的运行的,没有根目录就不会有init。那么如何由kernel去挂载system.img镜像呢?

首先我们解析出来system.img中的vbmeta校验数据:

avbtool info_image --image system.img > system.img.info

解析出来的结果实例如下:

Footer version:           1.0
Image size:               3221225472 bytes
Original image size:      3170316288 bytes
VBMeta offset:            3220549632
VBMeta size:              1856 bytes
--
Minimum libavb version:   1.0 (Sparse)
Header Block:             256 bytes
Authentication Block:     320 bytes
Auxiliary Block:          1280 bytes
Algorithm:                SHA256_RSA2048
Rollback Index:           0
Flags:                    0
Release String:           'avbtool 1.1.0'
Descriptors:
    Hashtree descriptor:
      Version of dm-verity:  1
      Image Size:            3170316288 bytes
      Tree Offset:           3170316288
      Tree Size:             24969216 bytes
      Data Block Size:       4096 bytes
      Hash Block Size:       4096 bytes
      FEC num roots:         2
      FEC offset:            3195285504
      FEC size:              25264128 bytes
      Hash Algorithm:        sha1
      Partition Name:        system
      Salt:                  1215bb10e3488f3f030d9f412c29dd5f3ca07d5a
      Root Digest:           ac8d587b82748d9128e84e8cfd2c004889ba3fd4
      Flags:                 0
    Kernel Cmdline descriptor:
      Flags:                 1
      Kernel Cmdline:        'dm="1 vroot none ro 1,0 6192024 verity 1 PARTUUID=$(ANDROID_SYSTEM_PARTUUID) PARTUUID=$(ANDROID_SYSTEM_PARTUUID) 4096 4096 774003 774003 sha1 ac8d587b82748d9128e84e8cfd2c0
04889ba3fd4 1215bb10e3488f3f030d9f412c29dd5f3ca07d5a 10 $(ANDROID_VERITY_MODE) ignore_zero_blocks use_fec_from_device PARTUUID=$(ANDROID_SYSTEM_PARTUUID) fec_roots 2 fec_blocks 780099 fec_start 780099"
 root=/dev/dm-0'
    Kernel Cmdline descriptor:
      Flags:                 2
      Kernel Cmdline:        'root=PARTUUID=$(ANDROID_SYSTEM_PARTUUID)'
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                


这里我们终于可以看到前文提到的Kernel Cmdline descriptor,但是很奇怪,这里为什么会有两个描述符呢?

还记得前面说的可配置功能吗?

  • 这里第一个cmdline描述符,是使能dm-verity要使用的cmdline,
  • 而第二个cmdline描述符,则是禁止掉dm-verity要使用的cmdline。

bootloader中需要根据我们前面vbmeta分区中的flag值来确定使用哪一个描述符。然后把cmdline添加到最终的cmdline中并写回到dtb(内存中的dtb),然后把dtb在ram中的存放地址传递给kernel去启动。

typedef enum {
  AVB_KERNEL_CMDLINE_FLAGS_USE_ONLY_IF_HASHTREE_NOT_DISABLED = (1 << 0),
  AVB_KERNEL_CMDLINE_FLAGS_USE_ONLY_IF_HASHTREE_DISABLED = (1 << 1)
} AvbKernelCmdlineFlags;


 /* Compare the flags for top-level VBMeta struct with flags in
  * the command-line descriptor so command-line snippets only
  * intended for a certain mode (dm-verity enabled/disabled)
  * are skipped if applicable.
  */
 apply_cmdline = true;
 if (toplevel_vbmeta_flags & AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED) {
   if (kernel_cmdline_desc.flags &
       AVB_KERNEL_CMDLINE_FLAGS_USE_ONLY_IF_HASHTREE_NOT_DISABLED) {
     apply_cmdline = false;
   }
 } else {
   if (kernel_cmdline_desc.flags &
       AVB_KERNEL_CMDLINE_FLAGS_USE_ONLY_IF_HASHTREE_DISABLED) {
     apply_cmdline = false;
   }
 }


上面是轮询描述符的操作,其中的toplevel_vbmeta_flags就是vbmeta.img中header保存的flags,如果其中AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED被设置为1,那么代表了dm-verity是禁止的,那么会选择cmdline descriptor中的flags为2的作为cmdline,反之选择cmdline descriptor中的flags为2的作为cmdline。

<think>嗯,用户问的是Android R相比Android P开机启动变慢的原因。首先,我需要回忆一下Android版本的变化,特别是R(也就是Android 11)和P(Android 9)之间的差异。开机启动变慢可能涉及多个方面,比如系统服务的调整、权限管理的变化、新功能的引入或者资源加载机制的不同。 首先,可能系统服务有增加或变更。比如引用[2]提到Dagger2在SystemUI中的应用,配置了更多的服务组件,像Recents、VolumeUI、Divider、StatusBar等。如果Android R中这些服务初始化更多或更复杂,可能导致启动时间延长。 其次,权限管理的加强。Android R对存储权限做了重大调整,引入了Scoped Storage,这可能在启动时增加了权限检查和初始化的工作,影响速度。另外,动态分区在R中推广,可能影响系统镜像的加载时间。 还有资源预加载的问题。引用[3]提到冷启动优化中的布局预加载和懒加载,如果R版本在预加载机制上有变化,比如需要加载更多资源或更复杂的布局,可能拖慢启动。比如系统UI组件更多使用ViewStub或动态加载,但若实现不当反而可能增加耗时。 另外,系统安全性的增强,比如启动时验证(AVB)的强化,可能会增加校验时间。还有可能系统服务的依赖注入框架(如Dagger2)的使用,虽然提高了模块化,但初始化阶段可能更耗时,如引用[2]中的服务列表加载需要更多步骤。 还要考虑硬件适配的变化,比如R对5G的支持或更高的安全标准,可能需要更多的驱动初始化,导致启动延迟。此外,用户数据迁移或加密机制的变化也可能影响启动速度。 不过,用户提供的引用中,引用[1]关于PackageInfo的信息可能关联到应用启动时的信息获取,如果系统在开机时需要加载更多应用元数据,比如sharedUserId或版本信息,也可能影响整体启动时间。例如,更多的应用需要检查或初始化,或者sharedUserId的处理更复杂。 综合这些因素,需要逐一分析每个可能的方面,看看哪些在R版本中发生了变化,并解释它们如何导致启动变慢。同时,用户可能需要具体的优化建议,所以回答中可以提到引用[3]中的优化思路,如懒加载和子线程预加载,作为可能的解决方案。</think>### Android R开机启动变慢的可能原因分析 #### 1. **系统服务初始化流程变更** - Android R(11)引入了更多系统服务组件和依赖注入机制(如Dagger2),例如引用[2]中提到的`SystemUIServiceComponents`列表扩展,可能导致初始化链条更长。例如: ```xml <string-array name="config_systemUIServiceComponents"> <item>com.android.systemui.recents.Recents</item> <item>com.android.systemui.volume.VolumeUI</item> </string-array> ``` 新增服务组件的初始化会增加启动耗时[^2]。 - **对比Android P**:Android P的系统服务相对简化,依赖注入框架使用较少。 #### 2. **权限与分区调整** - **Scoped Storage强制启用**:Android R要求应用默认使用Scoped Storage,启动时需处理更复杂的存储权限校验[^1]。 - **动态分区推广**:R版本广泛采用动态分区(如`super.img`),导致系统镜像加载和解压时间增加[^1]。 #### 3. **资源预加载机制调整** - Android R可能增强了对布局和资源的预加载要求,例如引用[3]提到的**冷启动优化技术**若未适配,可能导致主线程阻塞。例如: ```java // 子线程预加载布局(优化手段) new Thread(() -> LayoutInflater.from(context).inflate(R.layout.main, null)); ``` 若系统未合理优化预加载逻辑,反而可能延长启动时间[^3]。 #### 4. **安全验证增强** - **AVB 2.0强化**:Android R要求更严格的启动时验证(Verified Boot),导致启动阶段校验时间增加。 - **加密机制升级**:R版本可能使用更复杂的加密算法保护用户数据,影响解密速度。 #### 5. **硬件适配与驱动加载** - 针对5G和折叠屏设备的支持,Android R可能引入更多硬件抽象层(HAL)模块,驱动初始化时间增加。 --- ### 优化建议 1. **分析启动时序**:使用`adb shell am start -S -W`或`systrace`工具对比R与P的启动阶段耗时。 2. **减少主线程阻塞**:参考引用[3],将非关键服务初始化移至子线程。 3. **精简系统服务**:检查`config_systemUIServiceComponents`等配置,移除非必要组件[^2]。 ---
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TrustZone_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值