4. 镜像文件格式解析

Android 系统的烧录过程,本质上就是把一组分区镜像写入到 eMMC/UFS 的对应分区中。理解每个镜像的格式、内部结构和打包解包方式,是排查“烧录成功但无法启动”“分区大小不匹配”“镜像校验失败”等问题的前提。本章从镜像格式入手,梳理常见分区的组成与操作方法。

一、核心原理:Android 镜像的三种基本形态

Android 分区镜像并非单一格式,按封装方式大致可分为三类:

  • Android 专用镜像(Android Image):如 boot.img、recovery.img、dtbo.img,头部带有 ANDROID! 魔数,内部由 header、kernel、ramdisk、second、dtb 等段组成,并带有 SHA1 校验。
  • 稀疏镜像(Sparse Image):如 system.img、vendor.img、super.img,为节省传输与存储空间,采用 0xED26FF3A 魔数的稀疏格式,只记录非零数据块。
  • 文件系统镜像:如 userdata.img、metadata.img,通常是 ext4 或 f2fs 裸文件系统镜像,可直接挂载。

boot.img 与 recovery.img 结构相同,区别仅在于 recovery 内含 recovery 模式的 ramdisk;dtbo.img 则是设备树 overlay 的集合,用于在运行时叠加硬件描述。system.img 与 vendor.img 在 Android 10 之后常被合并进 super.img,通过动态分区(Dynamic Partitions)在逻辑上划分。

Android 常见镜像格式与内部结构 boot.img / recovery.img ANDROID! Header Kernel Ramdisk Second / DTB 含 SHA1 校验,mkbootimg 打包 dtbo.img DTBO Header DTB Entry 0 DTB Entry 1 … 设备树 overlay 集合,mkdtimg 打包 super.img(动态分区) LP Metadata Header system 逻辑分区 vendor 逻辑分区 product system_ext 稀疏格式,lpmake 打包,逻辑分区可调 稀疏镜像(Sparse) Sparse Header(魔数 0xED26FF3A) Chunk Header + 非零数据块 Chunk Header + 非零数据块 … system.img / vendor.img 常用,img2simg 转换 烧录前需 simg2img 还原为 raw 镜像 文件系统镜像 ext4 / f2fs 超级块 inode 表 / 数据块 userdata / metadata 可直接 mount 挂载查看 make_ext4fs / mkfs.f2fs 生成

二、方法流程:镜像的打包与解包

不同镜像使用不同工具链,掌握对应命令即可完成解包与重打包。以下为常用操作:

# 1. boot.img 解包(使用 mkbootimg 工具集中的 unpack_bootimg)
unpack_bootimg --boot_img boot.img --out ./boot_out
# 输出:kernel、ramdisk、second、dtb、bootimg.json

# 2. 重新打包 boot.img
mkbootimg --kernel kernel --ramdisk ramdisk \
  --header_version 4 --output boot_new.img

# 3. dtbo.img 解包
mkdtimg dump dtbo.img -b dtbo_out
mkdtimg create dtbo_new.img --page_size=2048 dtbo_out/*.dtb

# 4. 稀疏镜像还原为 raw
simg2img system.img system_raw.img
# raw 转稀疏
img2simg system_raw.img system_sparse.img

# 5. super.img 解包(lpunpack)
lpunpack super.img ./super_out
# 输出 system.img、vendor.img、product.img 等逻辑分区

# 6. 挂载 ext4 镜像查看内容
sudo mount -o loop system_raw.img /mnt/system

打包时需特别注意 header_version 与 page_size 参数,它们必须与设备 bootloader 的解析能力匹配,否则会出现“镜像写入成功但校验失败”的现象。

三、案例场景:一次 super.img 烧录失败的分析

某项目在 Android 12 设备上烧录 super.img 后无法进入系统,串口日志显示 Failed to load metadata for slot _a。排查过程如下:

  1. 确认 super.img 大小是否超过物理 super 分区容量,动态分区元数据中记录了每个逻辑分区的大小。
  2. 使用 lpdump super.img 查看元数据,发现 system 逻辑分区被设置为 3.2GB,而实际镜像仅 2.8GB,剩余空间未正确回收。
  3. 重新执行 lpmake 并指定 --partition system:readonly:3221225472:group=main,确保大小与镜像一致。
  4. 烧录后系统正常启动,问题定位为动态分区元数据与镜像大小不匹配。
动态分区(super.img)中逻辑分区的大小由元数据决定,而非镜像文件本身。修改镜像内容后,务必同步更新元数据,否则会出现分区读取越界或校验失败。

四、误区与复盘

常见误区后果正确做法
直接用 fastboot flash 烧录稀疏镜像部分 bootloader 不支持稀疏格式,写入失败先用 simg2img 还原为 raw 再烧录
忽略 boot.img 的 header_version内核无法解析 ramdisk 地址,启动卡死与设备 bootloader 支持的版本保持一致
修改 system.img 后未重新生成 super.img动态分区内容与元数据不一致使用 lpmake 重新打包 super.img
dtbo.img 中 DTB 顺序错误硬件描述叠加失败,外设无法识别按设备树 overlay 优先级排列 DTB 条目
用 mount 直接挂载稀疏镜像提示“wrong fs type”先 simg2img 转换,再 mount
解包与重打包过程中,务必保留原始镜像的校验信息(如 boot.img 的 SHA1、super.img 的元数据)。任何修改后都应重新计算校验值,否则 bootloader 会拒绝加载。