2. Vendor分区镜像制作:使用mkuserimg_mke2fs制作vendor.img、分区大小规划与动态分区(super分区)的关系

2.1 核心工具链:mkuserimg_mke2fs 与分区镜像生成

在 Android 构建系统中,mkuserimg_mke2fs 是制作 ext4 格式 vendor 镜像的标准工具。它封装了 mke2fs 与 e2fsdroid 两个底层工具,负责将 vendor 目录树打包为可挂载的稀疏镜像(sparse image)。

关键命令示例:
# 制作 vendor.img(非稀疏格式)
mkuserimg_mke2fs -s vendor/ vendor.img ext4 vendor /tmp/vendor_size

# 参数说明:
# -s          :生成稀疏镜像(sparse),减少存储占用
# vendor/     :输入目录,即编译产物中的 vendor 目录树
# vendor.img  :输出镜像文件
# ext4        :文件系统类型
# vendor      :文件系统标签(label)
# /tmp/vendor_size :分区大小(字节),如 1073741824(1GB)
稀疏镜像原理:稀疏镜像会跳过全零块,在烧录时由 fastboot 或 update_engine 动态解稀疏。对于 vendor 分区,建议始终使用 -s 参数,可减少 30%~50% 的镜像体积。

2.2 分区大小规划:从需求到计算

vendor 分区大小直接影响系统启动稳定性。规划不足会导致 OTA 失败或开机无法挂载;规划过大则浪费动态分区空间。以下为典型规划流程:

  1. 统计实际内容大小:执行 du -sh vendor/ 获取目录实际占用。
  2. 预留元数据与对齐空间:ext4 文件系统约需 2%~5% 的元数据开销,加上 4KB 对齐填充。
  3. 加入安全余量:建议额外预留 10%~20% 空间用于后续 HAL 驱动升级或固件扩展。
  4. 对齐到 4KB 边界:最终大小必须为 4096 的整数倍,否则 mke2fs 会报错。
场景 vendor 目录大小 元数据开销 (3%) 安全余量 (15%) 对齐后推荐大小
入门手机 (32GB eMMC) ~180 MB ~5.4 MB ~27 MB 256 MB
中端手机 (64GB UFS) ~350 MB ~10.5 MB ~52.5 MB 512 MB
旗舰手机 (128GB+ UFS) ~700 MB ~21 MB ~105 MB 1024 MB (1GB)
常见陷阱:部分厂商在 BoardConfig.mk 中直接写死 BOARD_VENDORIMAGE_PARTITION_SIZE,但未考虑后续 OTA 增量包可能增大 vendor 内容。建议在构建脚本中动态计算大小,或至少每季度重新评估一次。

2.3 动态分区(super分区)与 vendor 的关联

Android 10 起引入动态分区(super 分区),将 system、vendor、product 等逻辑分区打包进一个物理 super 分区。vendor 镜像不再是直接写入独立分区,而是作为 super 内的一个逻辑卷存在。

动态分区架构要点:
  • super 分区总大小 = system + vendor + product + 元数据 + 预留空间
  • vendor 在 super 中的占比 通常为 15%~25%,取决于设备类型
  • 逻辑分区大小 在 dynamic_partitions_op_list 中定义,构建时由 lpmake 工具打包
  • vendor 镜像大小 必须 ≤ 逻辑分区大小,否则 lpmake 报错
动态分区(super分区)与 vendor 逻辑关系 动态分区(super分区)与 vendor 逻辑关系 super 分区(物理分区) 元数据(LVM header + 分区表) system 逻辑分区 通常占 super 的 50%~65% vendor 15%~25% product 10%~20% 预留空间(Reserved) — 用于 OTA 扩展、坏块替换 vendor.img 大小 必须 ≤ 逻辑分区大小

2.4 分区大小冲突排查与解决方案

在实际项目中,vendor 分区大小问题常表现为以下三类错误:

错误现象 根因 解决方案
mke2fs: Cannot create filesystem with given size vendor 目录实际内容超过 BOARD_VENDORIMAGE_PARTITION_SIZE 增大分区大小,或清理 vendor 中冗余文件(如未使用的 HAL 库)
lpmake: Not enough space in super 所有逻辑分区总和 + 元数据 > super 分区物理大小 增大 super 分区(需修改分区表),或缩小 system/product 分区
开机 log 显示 Failed to mount /vendor vendor 镜像实际大小与分区表记录不一致 重新执行 mkuserimg_mke2fs 并确保 BOARD_VENDORIMAGE_PARTITION_SIZE 与 super 内逻辑卷大小匹配
调试技巧:使用 lpdump 命令查看当前 super 分区内的逻辑卷布局:
adb shell lpdump /dev/block/by-name/super
输出中会显示每个逻辑分区的名称、大小和槽位(slot),可用于验证 vendor 分区是否按预期分配。

2.5 构建配置与动态分区参数对照

以下为 BoardConfig.mk 中与 vendor 和动态分区相关的关键变量:

# 独立分区模式(Android 9 及以下)
BOARD_VENDORIMAGE_PARTITION_SIZE := 536870912   # 512MB
BOARD_VENDORIMAGE_FILE_SYSTEM_TYPE := ext4

# 动态分区模式(Android 10+)
BOARD_SUPER_PARTITION_SIZE := 4294967296        # 4GB
BOARD_SUPER_PARTITION_GROUPS := google_dynamic_partitions
BOARD_GOOGLE_DYNAMIC_PARTITIONS_SIZE := 4294967296
BOARD_GOOGLE_DYNAMIC_PARTITIONS_LIST := system vendor product

# vendor 在动态分区中的逻辑大小
BOARD_VENDORIMAGE_PARTITION_SIZE := 536870912   # 512MB(必须 ≤ 动态分区组内分配)
重要约束:在动态分区模式下,BOARD_VENDORIMAGE_PARTITION_SIZE 的值必须同时满足两个条件:
1. 小于等于 BOARD_SUPER_PARTITION_SIZE 减去其他逻辑分区和元数据后的剩余空间。
2. 大于等于实际 vendor 目录内容 + 元数据开销 + 安全余量。
违反任一条件都会导致构建失败。

2.6 实战:从 vendor 目录到 super 镜像的完整流程

  1. 编译 vendor 模块:make vendorimage 或 make vendorbootimage
  2. 生成 vendor.img:构建系统自动调用 mkuserimg_mke2fs,输出到 out/target/product/<device>/vendor.img
  3. 打包 super 镜像:make superimage 调用 lpmake 将 system.img、vendor.img、product.img 合并为 super.img
  4. 烧录验证:fastboot flash super super.img,重启后检查 df -h /vendor 确认挂载正常
快速验证命令:
# 检查 vendor 镜像大小
ls -lh out/target/product/<device>/vendor.img

# 检查 super 镜像内 vendor 逻辑分区大小
lpdump out/target/product/<device>/super.img | grep vendor

# 挂载验证(本地)
mkdir -p /tmp/vendor_mount
sudo mount -o loop vendor.img /tmp/vendor_mount
df -h /tmp/vendor_mount
sudo umount /tmp/vendor_mount