System-as-root

搭载 Android 9 的所有新设备都必须使用 system-as-root(BOARD_BUILD_SYSTEM_ROOT_IMAGE 必须为 true),它可以将 ramdisk.img 合并到 system.img,而后者会反过来再作为 rootfs 进行装载。对于要升级到 Android 9 的设备,使用 system-as-root 并非强制要求。本文档介绍了 system-as-root、列出了 dm-verity 支持的内核要求(包括所依赖的内核补丁程序),还提供了一些设置示例。

关于系统专用 OTA

当前 Android 生态系统支持两种类型的分区布局

  • 在 A/B 分区架构中,system 分区作为 rootfs 装载。
  • 在非 A/B 分区架构中,/boot 分区中的 ramdisk.img 会被加载到内存中(反过来再作为 rootfs 进行装载),而 system 分区则在 /system 中装载。

在 Android 8.0 中进行的架构更改(在 Project Treble 项目中)支持系统专用 OTA(其中 system.img 可在不更改其他分区的情况下跨主要 Android 版本进行更新)。不过,对于非 A/B 设备来说,由于 ramdisk.img 位于 /boot 分区中,因此它无法使用 Android 8.x 架构通过系统专用 OTA 进行更新。这样一来,旧的 ramdisk.img 可能不适用于新的 system.img,具体原因如下:

  • ramdisk.img 中较旧的 /init 可能无法解析 /system 上的 *.rc 文件。
  • ramdisk 包含 /init.rc,它也可能已过期(相较于新 /system 所要求的)。

为确保系统专用 OTA 按预期运行,Android 9 中必须使用 system-as-root。非 A/B 设备必须从 ramdisk 分区布局切换到 system-as-root 分区布局;A/B 设备已被要求使用 system-as-root,因此无需做出改动。

关于 A/B 设备和非 A/B 设备

A/B 设备和非 A/B 设备的分区详情如下:

A/B 设备 非 A/B 设备
每个分区(userdata 除外)都包含两个副本(插槽):
  • /boot_a
  • /boot_b
  • /system_a
  • /system_b
  • /vendor_a
  • /vendor_b
每个分区都包含一个副本,无其他备份分区。
  • /boot
  • /system
  • /vendor

要详细了解 A/B 设备和非 A/B 设备,请参阅 A/B(无缝)系统更新

关于 system-as-root

在 Android 9 中,非 A/B 设备应采用 system-as-root,以便通过系统专用 OTA 进行更新。

与将 /boot 改编为 recovery 分区的 A/B 设备不同,非 A/B 设备必须使 /recovery 分区单独存在,因为它们没有后备插槽分区(例如,从 boot_aboot_b)。如果在非 A/B 设备上移除 /recovery 并使其与 A/B 架构类似,那么在 /boot 分区更新失败时,恢复模式可能会遭到破坏。因此,对于非 A/B 设备来说,/recovery 分区必须作为单独的分区存在(不同于非 A/B 设备的 /boot),这意味着恢复映像将继续延迟更新(即如同 Android 9 之前的设备中那样)。

非 A/B 设备在使用 Android 9 前后的分区布局差异:

组件 映像 ramdisk(9 之前) system-as-root(9 之后)
映像内容 boot.img 包含内核和 ramdisk.img:

ramdisk.img
  -/
    - init.rc
    - init
    - etc -> /system/etc
    - system/ (mount point)
    - vendor/ (mount point)
    - odm/ (mount point)
    ...
仅包含正常启动内核。
recovery.img 包含恢复内核和 recovery-ramdisk.img。
system.img 包含以下内容:

system.img
  -/
    - bin/
    - etc
    - vendor -> /vendor
    - ...
包含原始 system.img 和 ramdisk.img 的合并内容:

system.img
  -/
    - init.rc
    - init
    - etc -> /system/etc
    - system/
      - bin/
      - etc/
      - vendor -> /vendor
      - ...
    - vendor/ (mount point)
    - odm/ (mount point)
    ...
分区布局
  1. /boot
  2. /system
  3. /recovery
  4. /vendor 等
  1. /boot
  2. /system
  3. /recovery
  4. /vendor 等

设置 dm-verity

在 system-as-root 中,内核必须使用 dm-verity/(装载点)下装载 system.img。AOSP 支持 system.img 的下列 dm-verity 实现:

  1. 对于 vboot 1.0,内核必须在 /system 上解析 Android 专用元数据,然后转换为 dm-verity 参数以设置 dm-verity。需要这些内核补丁程序
  2. 对于 vboot 2.0 (AVB),引导加载程序必须先整合 external/avb/libavb,external/avb/libavb 随后会解析 /system哈希树描述符),然后将其转换为 dm-verity 参数,最后再通过内核命令行将这些参数传递给内核(/system 的哈希树描述符可能位于 /vbmeta/system 本身上)。

    需要下列内核补丁程序:

下面是来自真实设备的示例,显示的是内核命令行中 system-as-root 的 dm-verity 相关设置:

vboot 1.0

ro root=/dev/dm-0 rootwait skip_initramfs init=/init
dm="system none ro,0 1 android-verity /dev/sda34"
veritykeyid=id:7e4333f9bba00adfe0ede979e28ed1920492b40f

vboot 2.0 (AVB)

ro root=/dev/dm-0 rootwait  skip_initramfs init=/init

dm="1 vroot none ro 1,0 5159992 verity 1
PARTUUID=00000016-0000-0000-0000-000000000000
PARTUUID=00000016-0000-0000-0000-000000000000 4096 4096 644999 644999
sha1 d80b4a8be3b58a8ab86fad1b498640892d4843a2
8d08feed2f55c418fb63447fec0d32b1b107e42c 10 restart_on_corruption
ignore_zero_blocks use_fec_from_device
PARTUUID=00000016-0000-0000-0000-000000000000 fec_roots 2 fec_blocks
650080 fec_start 650080"
  

特定于设备的根文件夹

借助 system-as-root,在设备上刷写常规系统映像 (GSI) 之后(以及在运行供应商测试套件测试之前),任何通过 BOARD_ROOT_EXTRA_FOLDERS 添加的特定于设备的根文件夹都将消失,因为整个根目录内容已被 system-as-root GSI 取而代之。如果存在对特定于设备的根文件夹的依赖性(例如此类文件夹用作装载点),则移除这些文件夹可能会导致设备无法启动。

要避免出现此问题,请不要使用 BOARD_ROOT_EXTRA_FOLDERS 来添加特定于设备的根文件夹(此类文件夹将来可能会被弃用)。如果您需要指定特定于设备的装载点,请使用 /mnt/vendor/<mount point>(已在这些更改列表中添加)。这些特定于供应商的装载点可在 fstab 设备树(适用于第一阶段的装载)和 /vendor/etc/fstab.{ro.hardware} 文件中直接指定,而无需进行额外设置(因为 fs_mgr 将在 /mnt/vendor/* 下自动创建它们)。