支持 Treble 的设备必须启用第一阶段装载,以确保 init
可以加载分布在 system
和 vendor
分区的安全增强型 (SELinux) 政策 Fragment。此访问权限还可实现在内核启动后尽快加载内核模块。
如需执行提前装载,Android 必须有权访问模块所在的文件系统。Android 8.0 及更高版本支持在 init
的第一阶段(即初始化 SElinux 之前)装载 /system
、/vendor
或 /odm
。
Fstab 条目
在 Android 9 及更低版本中,设备可以使用设备树叠加层 (DTO) 为提前装载的分区指定 fstab
条目。在 Android 10 及更高版本中,设备必须使用第一阶段 ramdisk 中的 fstab
文件为提前装载的分区指定 fstab
条目。Android 10 引入了以下可在 fstab
文件中使用的 fs_mgr
标记:
first_stage_mount
表明将由第一阶段 init 装载分区。logical
表明这是一个动态分区。avb=vbmeta-partition-name
可指定vbmeta
分区。第一阶段 init 可初始化该分区,然后再装载其他分区。如果该条目的vbmeta
分区已由上一行中的其他fstab
条目指定,可以省略此标记的参数。
以下示例展示了将 system
、vendor
和 product
分区设置为逻辑(动态)分区的 fstab
条目。
#<dev> <mnt_point> <type> <mnt_flags options> <fs_mgr_flags> system /system ext4 ro,barrier=1 wait,slotselect,avb=vbmeta_system,logical,first_stage_mount vendor /vendor ext4 ro,barrier=1 wait,slotselect,avb=vbmeta,logical,first_stage_mount product /product ext4 ro,barrier=1 wait,slotselect,avb,logical,first_stage_mount
在上述示例中,供应商使用 fs_mgr
标记 avb=vbmeta
指定了 vbmeta
分区,但 product
省略了 vbmeta
参数,因为供应商已将 vbmeta
添加到了分区列表。
搭载 Android 10 及更高版本的设备必须将 fstab
文件放在 ramdisk 和 vendor
分区中。
Ramdisk
fstab
文件在 ramdisk 中的位置取决于设备如何使用 ramdisk。
具有启动 ramdisk 的设备必须将 fstab
文件放在启动 ramdisk 根目录中。如果设备同时具有启动 ramdisk 和恢复 ramdisk,就无需对恢复 ramdisk 进行任何更改。示例:
PRODUCT_COPY_FILES += device/google/<product-name>/fstab.hardware:$(TARGET_COPY_OUT_RAMDISK)/fstab.$(PRODUCT_PLATFORM)
将恢复用作 ramdisk 的设备必须使用内核命令行参数 androidboot.force_normal_boot=1
来决定是启动到 Android 还是继续启动到恢复模式。发布时搭载 Android 12 或更高版本且内核版本为 5.10 或更高版本的设备必须使用 bootconfig 传递 androidboot.force_normal_boot=1
参数。在这些设备中,第一阶段 init 在装载提前装载分区之前将根操作切换到了 /first_stage_ramdisk
,因此设备必须将 fstab
文件放在 $(TARGET_COPY_OUT_RECOVERY)/root/first_stage_ramdisk
中。示例:
PRODUCT_COPY_FILES += device/google/<product-name>/fstab.hardware:$(TARGET_COPY_OUT_RECOVERY)/root/first_stage_ramdisk/fstab.$(PRODUCT_PLATFORM)
Vendor
所有设备都必须将 fstab
文件的副本放到 /vendor/etc
中。这是因为第一阶段 init 在完成分区提前装载之后释放了 ramdisk,并执行了切换根操作,以将位于 /system
的装载移动到了 /
。因此,后续任何需要访问 fstab
文件的操作都必须使用 /vendor/etc
中的副本。示例:
PRODUCT_COPY_FILES += device/google/<product-name>/fstab.hardware:$(TARGET_COPY_OUT_VENDOR)/etc/fstab.$(PRODUCT_PLATFORM)
提前装载分区,VBoot 1.0
使用 VBoot 1.0 提前装载分区的要求包括:
- 设备节点路径必须在
fstab
和设备树条目中使用其by-name
符号链接。例如,确保对分区进行命名且设备节点为/dev/block/…./by-name/{system,vendor,odm}
,而不是使用/dev/block/mmcblk0pX
指定分区。 - 在产品的设备配置中(即
device/oem/project/device.mk
中)为PRODUCT_{SYSTEM,VENDOR}_VERITY_PARTITION
和CUSTOM_IMAGE_VERITY_BLOCK_DEVICE
指定的路径必须与fstab
/设备树条目中相应块设备节点指定的by-name
相匹配。示例:PRODUCT_SYSTEM_VERITY_PARTITION := /dev/block/…./by-name/system PRODUCT_VENDOR_VERITY_PARTITION := /dev/block/…./by-name/vendor CUSTOM_IMAGE_VERITY_BLOCK_DEVICE := /dev/block/…./by-name/odm
- 通过设备树叠加层提供的条目不得在
fstab
文件 fragment 中出现重复。例如,指定某个条目以在设备树中装载/vendor
时,fstab
文件不得重复该条目。 - 不得提前装载需要
verifyatboot
的分区(此操作不受支持)。 - 必须在
kernel_cmdline
中使用androidboot.veritymode
选项指定验证分区的真实模式/状态(现有要求)。
提前装载设备树,VBoot 1.0
在 Android 8.x 及更高版本中,init
会解析设备树并创建 fstab
条目,以在其第一阶段提前装载分区。fstab
条目采用以下形式:
src mnt_point type mnt_flags fs_mgr_flags
定义设备树属性以模拟该格式:
fstab
条目必须在设备树中的/firmware/android/fstab
下,且必须将兼容字符串设置为android,fstab
。/firmware/android/fstab
下的每个节点都被视为单个提前装载fstab
条目。节点必须定义以下属性:dev
必须指向表示by-name
分区的设备节点type
必须是文件系统类型(如在fstab
文件中一样)mnt_flags
必须是装载标记的逗号分隔列表(如在fstab
文件中一样)fsmgr_flags
必须是 Androidfs_mgr flags
列表(如在fstab
文件中一样)
- A/B 分区必须具有
slotselect fs_mgr
选项。 - 已启用 dm-verity 的分区必须具有
verify fs_mgr
选项。
示例:N6P 上的 /system 和 /vendor
下面的示例显示的是在 Nexus 6P 上为 system
和 vendor
分区提前装载设备树:
/ { firmware { android { compatible = "android,firmware"; fstab { compatible = "android,fstab"; system { compatible = "android,system"; dev = "/dev/block/platform/soc.0/f9824900.sdhci/by-name/system"; type = "ext4"; mnt_flags = "ro,barrier=1,inode_readahead_blks=8"; fsmgr_flags = "wait,verify"; }; vendor { compatible = "android,vendor"; dev = "/dev/block/platform/soc.0/f9824900.sdhci/by-name/vendor"; type = "ext4"; mnt_flags = "ro,barrier=1,inode_readahead_blks=8"; fsmgr_flags = "wait"; }; }; }; }; };
示例:Pixel 上的 /vendor
下面的示例显示的是在 Pixel 上为 /vendor
提前装载设备树(请务必为 A/B 分区添加 slotselect
):
/ { firmware { android { compatible = "android,firmware"; fstab { compatible = "android,fstab"; vendor { compatible = "android,vendor"; dev = "/dev/block/platform/soc/624000.ufshc/by-name/vendor"; type = "ext4"; mnt_flags = "ro,barrier=1,discard"; fsmgr_flags = "wait,slotselect,verify"; }; }; }; }; };
提前装载分区,VBoot 2.0
VBoot 2.0 是 Android 启动时验证 (AVB)。使用 VBoot 2.0 提前装载分区的要求如下:
- 设备节点路径必须在
fstab
和设备树条目中使用其by-name
符号链接。例如,确保对分区进行命名且设备节点为/dev/block/…./by-name/{system,vendor,odm}
,而不是使用/dev/block/mmcblk0pX
指定分区。 - VBoot 1.0 所用的构建系统变量(如
PRODUCT_{SYSTEM,VENDOR}_VERITY_PARTITION
和CUSTOM_IMAGE_VERITY_BLOCK_DEVICE
)对 VBoot 2.0 而言并不是必需的。您应定义 VBoot 2.0 中引入的 build 变量(包括BOARD_AVB_ENABLE := true
);如需查看完整配置,请参阅适用于 AVB 的构建系统集成。 - 通过设备树叠加层提供的条目不得在
fstab
文件 fragment 中出现重复。例如,如果您指定某个条目以在设备树中装载/vendor
,fstab
文件不得重复该条目。 - VBoot 2.0 不支持
verifyatboot
,无论是否启用了提前装载。 - 必须在
kernel_cmdline
中使用androidboot.veritymode
选项指定验证分区的真实模式/状态(现有要求)。确保包含以下 AVB 修复程序:
提前装载设备树,VBoot 2.0
VBoot 2.0 设备树中的配置与 VBoot 1.0 中的大致相同,但还有以下几项不同之处:
fsmgr_flag
由verify
变为avb
。- 包含 AVB 元数据的所有分区都必须位于设备树的 VBMeta 条目中,即使相应的分区并非提前装载的分区(如
/boot
)也是如此。
示例:N5X 上的 /system 和 /vendor
下面的示例显示的是在 Nexus 5X 上为 system
和 vendor
分区提前装载设备树。注意:
/system
使用 AVB 进行装载,且/vendor
的装载不需要进行完整性验证。- 由于 Nexus 5X 没有
/vbmeta
分区,因此顶层 vbmeta 位于/boot
分区的末端(如需了解详情,请参阅 AOSP 变更列表)。/ { firmware { android { compatible = "android,firmware"; vbmeta { compatible = "android,vbmeta"; parts = "boot,system,vendor"; }; fstab { compatible = "android,fstab"; system { compatible = "android,system"; dev = "/dev/block/platform/soc.0/f9824900.sdhci/by-name/system"; type = "ext4"; mnt_flags = "ro,barrier=1,inode_readahead_blks=8"; fsmgr_flags = "wait,avb"; }; vendor { compatible = "android,vendor"; dev = "/dev/block/platform/soc.0/f9824900.sdhci/by-name/vendor"; type = "ext4"; mnt_flags = "ro,barrier=1,inode_readahead_blks=8"; fsmgr_flags = "wait"; }; }; }; }; };
示例:Pixel 上的 /vendor
下面的示例显示的是在 Pixel 上提前装载 /vendor
。注意:
- 很多分区都是在 vbmeta 条目中指定的,因为这些分区受 AVB 保护。
- 请务必包含所有 AVB 分区,即使仅提前装载了
/vendor
也是如此。 - 请务必为 A/B 分区添加
slotselect
。/ { vbmeta { compatible = "android,vbmeta"; parts = "vbmeta,boot,system,vendor,dtbo"; }; firmware { android { compatible = "android,firmware"; fstab { compatible = "android,fstab"; vendor { compatible = "android,vendor"; dev = "/dev/block/platform/soc/624000.ufshc/by-name/vendor"; type = "ext4"; mnt_flags = "ro,barrier=1,discard"; fsmgr_flags = "wait,slotselect,avb"; }; }; }; }; };