目录
  1. 1. 一、映像文件全景图
    1. 1.1. 1.1 Android 12+ 的镜像体系
  2. 2. 二、boot.img:启动的核心
    1. 2.1. 2.1 boot.img 的结构
    2. 2.2. 2.2 boot image header 版本演进
    3. 2.3. 2.3 boot.img 的创建
    4. 2.4. 2.4 vendor_boot.img:Android 12 GKI 2.0 的关键
  3. 3. 三、system.img:系统主分区
    1. 3.1. 3.1 system.img 的文件系统格式
    2. 3.2. 3.2 system.img 的内部结构
  4. 4. 四、vendor.img / product.img / system_ext.img
    1. 4.1. 4.1 Android 10+ 的多分区架构
    2. 4.2. 4.2 vendor.img 内容
  5. 5. 五、Sparse Image 格式
    1. 5.1. 5.1 稀疏映像 vs 原始映像
    2. 5.2. 5.2 Sparse Image 格式详解
  6. 6. 六、super.img:动态分区
    1. 6.1. 6.1 为什么需要动态分区
    2. 6.2. 6.2 lpmake 创建 super.img
    3. 6.3. 6.3 动态分区与 Virtual A/B
  7. 7. 七、OTA 更新模型
    1. 7.1. 7.1 A/B 无缝更新 (Seamless Updates)
    2. 7.2. 7.2 OTA 包结构
    3. 7.3. 7.3 OTA 更新流程
  8. 8. 八、Fastboot 协议
    1. 8.1. 8.1 Fastboot 模式
    2. 8.2. 8.2 Fastboot 与 Fastbootd
  9. 9. 九、Verified Boot:启动验证链
    1. 9.1. 9.1 Verified Boot 全链路
    2. 9.2. 9.2 vbmeta.img 的结构
  10. 10. 十、recovery.img 与救援模式
    1. 10.1. 10.1 recovery.img 的结构
    2. 10.2. 10.2 Recovery 模式功能
  11. 11. 十一、核心面试题
【深入内核篇】系统映像文件

Android 构建系统编译完毕后,在 out/target/product/<product>/ 目录下会生成一系列的 .img 映像文件。这些映像文件包含了 Android 设备运行所需的全部组件,从内核到应用。理解这些映像文件的结构、格式和刷写方式,是深入理解 Android 系统启动、OTA 更新和设备恢复的基础。本文基于 Android 12 (API 31) 的 AOSP 源码深入剖析每个系统映像文件的内部结构。

一、映像文件全景图

1.1 Android 12+ 的镜像体系

┌─────────────────────────────────────────────────────┐
│ super.img (动态分区) │
│ ┌──────────────┐ ┌──────────────┐ ┌─────────────┐ │
│ │ system.img │ │ vendor.img │ │ product.img │ │
│ │ (read-only) │ │ (HAL impl.) │ │ (product) │ │
│ │ erofs │ │ erofs │ │ erofs │ │
│ └──────────────┘ └──────────────┘ └─────────────┘ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ system_ext.img│ │ odm.img │ │
│ │ (extended) │ │ (ODM) │ │
│ │ erofs │ │ erofs │ │
│ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────┐
│ boot.img │
│ ┌─────────────────┐ ┌──────────────────────────┐ │
│ │ kernel │ │ boot ramdisk │ │
│ │ (Image.gz) │ │ ├── init │ │
│ │ │ │ └── first_stage_ramdisk │ │
│ └─────────────────┘ └──────────────────────────┘ │
└─────────────────────────────────────────────────────┘

┌──────────────────┐ ┌──────────────┐ ┌──────────────┐
│ vendor_boot.img │ │ vbmeta.img │ │ recovery.img │
│ (vendor ramdisk) │ │ (verified │ │ (recovery │
│ │ │ boot meta) │ │ ramdisk) │
└──────────────────┘ └──────────────┘ └──────────────┘

二、boot.img:启动的核心

2.1 boot.img 的结构

boot.img 是 Android 设备启动的第一个映像文件,由 bootloader (LK/ABL) 加载到内存。它采用 Android Boot Image 格式:

boot.img 布局(Android 12 GKI 2.0):
┌──────────────────────────────┐
│ boot_img_hdr (header) │ <- 文件头,描述镜像结构
│ ├── magic: "ANDROID!" │
│ ├── kernel_size │
│ ├── kernel_addr │
│ ├── ramdisk_size │
│ ├── ramdisk_addr │
│ ├── second_size │
│ ├── second_addr │
│ ├── tags_addr │
│ ├── page_size │
│ ├── header_version │ <- v0~v4 (Android 12 使用 v4)
│ ├── os_version │
│ └── name: "boot" │
├──────────────────────────────┤
│ kernel (Image.gz / Image.lz4)│ <- 压缩的内核映像
├──────────────────────────────┤
│ ramdisk (gzip/lz4) │ <- GKI 通用 ramdisk
│ ├── init │ <- 第一阶段 init 二进制
│ └── first_stage_ramdisk/ │ <- 第一阶段挂载点
├──────────────────────────────┤
│ (second stage — for v0) │ <- 二级 bootloader(不再使用)
├──────────────────────────────┤
│ device tree blob (DTB/DTBO) │ <- 设备树(v2+)
└──────────────────────────────┘

2.2 boot image header 版本演进

Version Android 版本 关键变化
v0 Android 6- 原始格式:kernel + ramdisk + second
v1 Android 7+ 添加 recovery_dtbo 字段
v2 Android 9+ 添加 dtb 字段(设备树 blob)
v3 Android 11+ 移除 second stage,ramdisk 变为通用 (GKI 1.0)
v4 Android 12+ vendor_boot 独立分区(GKI 2.0)

2.3 boot.img 的创建

# 创建 boot.img 的命令(由 build/make/core/Makefile 驱动)
# mkbootimg 工具:
# system/tools/mkbootimg/mkbootimg (Python 或用 system/core/mkbootimg/ 的 C 版本)

mkbootimg \
--kernel out/target/product/<product>/kernel \
--ramdisk out/target/product/<product>/ramdisk.img \
--header_version 4 \
--os_version 12.0.0 \
--os_patch_level 2022-01-05 \
--pagesize 4096 \
--cmdline "console=ttyMSM0,115200n8 androidboot.hardware=qcom" \
--output out/target/product/<product>/boot.img

C 语言解析 boot.img header:

// system/tools/mkbootimg/include/bootimg/bootimg.h
typedef struct boot_img_hdr_v0 {
uint8_t magic[8]; // "ANDROID!"
uint32_t kernel_size;
uint32_t kernel_addr;
uint32_t ramdisk_size;
uint32_t ramdisk_addr;
uint32_t second_size;
uint32_t second_addr;
uint32_t tags_addr;
uint32_t page_size;
uint32_t header_version; // v0 = 0
uint32_t os_version;
uint8_t name[16];
uint8_t cmdline[512];
uint8_t id[32];
uint8_t extra_cmdline[1024];
} boot_img_hdr_v0;

2.4 vendor_boot.img:Android 12 GKI 2.0 的关键

在 GKI 2.0 架构中,boot.img 中的 ramdisk 变为通用(Generic Ramdisk),由 Google 提供。所有 vendor 特定的 ramdisk 内容(如 init .rc 文件、.so 文件、firmware)移入 vendor_boot.img:

vendor_boot.img 布局(header v4):
┌──────────────────────────┐
│ vendor_boot_img_hdr │
│ ├── magic │
│ ├── header_version (4) │
│ ├── page_size │
│ ├── kernel_addr │
│ ├── ramdisk_size │
│ ├── ramdisk_addr │
│ ├── vendor_ramdisk_size │ <- vendor ramdisk 大小
│ ├── dtb_size │ <- 设备树大小
│ └── vendor_cmdline │
├──────────────────────────┤
│ vendor ramdisk │ <- vendor .rc 文件、HAL .so
│ ├── init.rc │
│ ├── fstab.<hardware> │ <- vendor 特定的 fstab
│ └── vendor/ │
├──────────────────────────┤
│ DTB (Device Tree Blob) │ <- SoC 设备树
└──────────────────────────┘

三、system.img:系统主分区

3.1 system.img 的文件系统格式

Android 系统分区使用只读优化的文件系统:

  • ext4(传统):标准的 Linux 文件系统,支持 journal 和权限
  • erofs(Android 10+ 推荐):Enhanced Read-Only File System,专为只读分区优化

erofs 相比 ext4 的优势:

  • 镜像体积约小 20%(更高效的压缩和元数据存储)
  • 更好的只读性能(数据结构针对读优化)
  • 支持 lz4 和 lz4hc 压缩
# 创建 erofs 格式的 system.img
mkfs.erofs \
-zlz4hc \ # 使用 lz4hc 压缩
-T 1230768000 \ # 时间戳
--fs-config-file=system_fs_config \ # 文件权限和 owner 配置
--product-out=out/target/product/xxx \ # 产品输出目录
system.img \ # 输出文件
system/ # 输入目录树

3.2 system.img 的内部结构

system/
├── bin/ # 系统可执行文件
│ ├── init # init 进程(系统启动第一个用户态进程)
│ ├── servicemanager # Binder 服务管理器
│ ├── surfaceflinger # 显示合成引擎
│ ├── app_process64 # Zygote/App 进程入口
│ └── ...
├── lib/ / lib64/ # 系统动态库
│ ├── libandroid_runtime.so # Android Runtime JNI 库
│ ├── libbinder.so # Binder IPC 库
│ ├── libgui.so # GUI 库(Surface/BufferQueue)
│ ├── libcutils.so # C 工具库
│ └── ...
├── etc/
│ ├── init/ # init.rc 文件目录
│ │ ├── hw/init.rc # 主 rc 文件
│ │ └── ... # 各种 .rc 文件
│ ├── vintf/ # VINTF 兼容性清单
│ │ └── manifest.xml
│ ├── selinux/ # SELinux 策略文件
│ │ └── ...
│ └── ...
├── framework/ # Java 框架
│ ├── framework.jar # 框架 API
│ ├── services.jar # 系统服务
│ ├── boot-framework.art # ART boot image
│ └── ...
├── build.prop # 系统属性文件
├── apex/ # APEX 模块(Android 10+)
│ ├── com.android.art.apex
│ ├── com.android.runtime.apex
│ └── ...
└── fonts/ # 系统字体

四、vendor.img / product.img / system_ext.img

4.1 Android 10+ 的多分区架构

从 Android 10 开始,为提高 Treble 兼容性,系统文件被拆分到多个分区:

Android 9 及以前:
/system 包含一切

Android 10+:
/system — AOSP 系统核心(Google 提供)
/system_ext — 系统扩展(OEM 可使用)
/product — 产品层(OEM 定制)
/vendor — SoC vendor HAL 实现
/odm — ODM/OEM 设备特定配置

这种拆分的理由:

  1. 独立更新:system 可以独立于 vendor 更新(GSI 镜像)
  2. 许可隔离:不同分区可以使用不同的许可证
  3. VTS 合规:vendor 实现必须能运行在任意 system 上
  4. 构建效率:修改 system 不需要重新构建 vendor

4.2 vendor.img 内容

vendor/
├── bin/
│ └── hw/
│ ├── android.hardware.camera.provider@2.4-service
│ ├── android.hardware.graphics.composer@2.3-service
│ ├── android.hardware.audio@5.0-service
│ └── ... (HAL 服务可执行文件)
├── lib/ / lib64/
│ ├── hw/
│ │ ├── camera.<hw>.so # Camera HAL 实现
│ │ ├── gralloc.<hw>.so # Gralloc HAL 实现
│ │ ├── lights.<hw>.so # LED HAL 实现
│ │ └── ...
│ └── ...
├── etc/
│ ├── init/ # vendor .rc 文件
│ ├── vintf/manifest.xml # HAL manifest
│ └── selinux/ # vendor SELinux 策略
├── build.prop # vendor 属性
├── firmware/ # 固件文件
└── overlay/ # RRO 资源覆盖

五、Sparse Image 格式

5.1 稀疏映像 vs 原始映像

Android 的 .img 文件通常采用 sparse image(稀疏映像)格式而非原始 bitwise 映像:

# 原始映像:包含整个分区的所有块(包括空块)
# 如果 system 分区是 2GB,img 也是 2GB

# 稀疏映像:仅包含非空块 + 索引
# 大小取决于实际内容(通常远小于分区大小)

# 转换工具
img2simg system.img system_sparse.img # 原始 → 稀疏
simg2img system_sparse.img system.img # 稀疏 → 原始

5.2 Sparse Image 格式详解

// system/core/libsparse/sparse_format.h
// 稀疏映像文件头
typedef struct sparse_header {
uint32_t magic; // 0xED26FF3A
uint16_t major_version; // 1
uint16_t minor_version; // 0
uint16_t file_hdr_sz; // sizeof(sparse_header_t)
uint16_t chunk_hdr_sz; // sizeof(chunk_header_t)
uint32_t blk_sz; // 块大小(通常是 4096)
uint32_t total_blks; // 总分区块数
uint32_t total_chunks; // 总 chunk 数
uint32_t image_checksum; // CRC32 校验和
} sparse_header_t;

// Chunk 类型
typedef enum {
CHUNK_TYPE_RAW = 0xCAC1, // 原始数据跟随
CHUNK_TYPE_FILL = 0xCAC2, // 填充(相同值重复)
CHUNK_TYPE_DONT_CARE = 0xCAC3, // 跳过(空洞)
CHUNK_TYPE_CRC32 = 0xCAC4, // CRC32 校验
} chunk_type_t;

稀疏映像在 fastboot 刷写时的处理流程:

// system/core/fastboot/fastbootd.cpp
// 1. fastboot 接收 sparse image
// 2. 解析 chunk header
// 3. 对 CHUNK_TYPE_RAW:直接写入对应块
// 4. 对 CHUNK_TYPE_FILL:用指定值填充对应块
// 5. 对 CHUNK_TYPE_DONT_CARE:跳过(保持分区原有内容)
// 6. 这样刷写只写入非空块,大大加快刷机速度

六、super.img:动态分区

6.1 为什么需要动态分区

传统 Android 系统将 system、vendor、product 等分区固定大小划分。这导致:

  • system 分区过大 → 浪费存储空间
  • vendor 分区不够 → OTA 更新失败
  • 分区大小在出厂后无法更改

Android 10 引入动态分区(Dynamic Partitions),使用 super.img 统一管理多个只读分区:

super.img (固定大小,如 4GB)
├── metadata (分区元数据)
│ ├── system_a — offset 0, size 1.2G
│ ├── system_b — offset 1.2G, size 1.2G
│ ├── vendor_a — offset 2.4G, size 300M
│ ├── vendor_b — offset 2.7G, size 300M
│ ├── product_a — offset 3.0G, size 500M
│ └── product_b — offset 3.5G, size 500M
└── data blocks

6.2 lpmake 创建 super.img

# 使用 lpmake 创建 super.img
# system/extras/partition_tools/lpmake
lpmake \
--metadata-size 65536 \
--super-name super \
--metadata-slots 2 \
--device super:4294967296 \ # super 分区总大小 4GB
--group qti_dynamic_partitions:3221225472 \ # group 大小 3GB
--partition system:readonly:1288490188:qti_dynamic_partitions \
--image system=out/target/product/xxx/system.img \
--partition vendor:readonly:314572800:qti_dynamic_partitions \
--image vendor=out/target/product/xxx/vendor.img \
--partition product:readonly:524288000:qti_dynamic_partitions \
--image product=out/target/product/xxx/product.img \
--sparse \
--output out/target/product/xxx/super.img

6.3 动态分区与 Virtual A/B

Android 11 引入 Virtual A/B,它结合了动态分区和 device-mapper (dm-linear):

传统 A/B 系统:
两个完整的分区副本(system_a + system_b = 2x 分区大小)

Virtual A/B:
只有一个物理 super 分区
├── system (当前使用的 slot A)
├── system_b (slot B 的目标,仅在 OTA 更新期间存在)
└── OTA 更新时使用 snapshot (dm-snapshot) 机制
├── 写入 COW (Copy-On-Write) 设备
└── 更新完成后合并到主分区

Virtual A/B 的 OTA 更新流程:

1. 正常运行时:只使用 slot A
2. OTA 下载完成
├── 创建 COW 设备
├── 映射 slot B (base + snapshot)
└── 写入更新数据到 COW 设备
3. 设备重启
├── bootloader 切换到 slot B
├── dm-snapshot 合并 COW 数据
├── 如果合并成功 → 新系统运行
└── 如果合并失败 → 回退到 slot A

七、OTA 更新模型

7.1 A/B 无缝更新 (Seamless Updates)

A/B 系统维护两个完整的系统分区副本(slot A 和 slot B):

A/B 分区布局:
┌──────────┬──────────┬──────────┬──────────┐
│ slot A │ slot A │ slot B │ slot B │
│ boot │ system │ boot │ system │
└──────────┴──────────┴──────────┴──────────┘

正常运行时:使用 slot A (active slot)
OTA 更新时:写入 slot B (inactive slot)
重启后:切换到 slot B
下次 OTA:写入 slot A

优点:

  • 更新在后台完成,用户无感知
  • 更新失败自动回退到旧 slot
  • 不需要 recovery 分区就可以完成更新

缺点:

  • 需要双倍的存储空间(被动态分区部分解决)

7.2 OTA 包结构

update.zip (OTA 包)
├── META-INF/
│ └── com/
│ └── android/
│ ├── metadata # OTA 元数据
│ └── otacert # OTA 签名证书
├── payload.bin # 差分更新负载
│ └── (由 update_engine 处理)
├── payload_properties.txt # payload 属性
├── care_map.txt # 需要验证的块列表
└── compatibility.zip # 兼容性检查信息

OTA 引擎 update_engine (system/update_engine/) 使用 bsdiff / puffdiff 算法生成和应用差分包:

  • bsdiff:通用二进制差分
  • puffdiff:针对 deflate 压缩文件的优化差分

7.3 OTA 更新流程

// system/update_engine/update_attempter_android.cc
// OTA 更新状态机
enum class UpdateStatus {
IDLE,
CHECKING_FOR_UPDATE,
UPDATE_AVAILABLE,
DOWNLOADING,
VERIFYING,
FINALIZING,
UPDATED_NEED_REBOOT,
REPORTING_ERROR_EVENT,
ATTEMPT_ROLLBACK, // 回滚
};

八、Fastboot 协议

8.1 Fastboot 模式

Fastboot 是 Android 设备的底层刷写协议,通常在 bootloader 阶段运行:

# 进入 fastboot 模式
adb reboot bootloader

# 常用 fastboot 命令
fastboot devices # 列出设备
fastboot flash boot boot.img # 刷写 boot 分区
fastboot flash system system.img # 刷写 system 分区
fastboot flashing unlock # 解锁 bootloader
fastboot flashing lock # 锁定 bootloader
fastboot boot recovery.img # 临时启动 recovery
fastboot erase userdata # 擦除用户数据
fastboot reboot # 重启设备
fastboot getvar all # 查看所有变量

8.2 Fastboot 与 Fastbootd

Android 10+ 引入了 userspace fastboot(fastbootd),运行在 Android 系统内而非 bootloader 中:

传统 fastboot (bootloader 模式):
bootloader 实现 → 只能操作 bootloader 支持的分区

fastbootd (userspace 模式):
Android recovery/system 中实现 → 可以操作动态分区 (super.img)
进入方式:adb reboot fastboot

fastbootd 的实现:

// system/core/fastboot/fastbootd.cpp
class FastbootDevice {
// 实现 fastboot 命令处理
// Flash() → 写入逻辑分区(super 内的分区)
// Erase() → 擦除逻辑分区
// Resize() → 调整逻辑分区大小
};

九、Verified Boot:启动验证链

9.1 Verified Boot 全链路

Android Verified Boot 确保了从硬件到 system 的完整信任链:

Hardware Root of Trust (eFuse/OTP)

▼ 验证
Boot ROM (不可更改)

▼ 验证
Bootloader (LK/ABL)

▼ 验证 (通过 vbmeta.img)
boot.img (kernel + ramdisk)

▼ dm-verity (通过 vbmeta 中的哈希)
system.img / vendor.img

9.2 vbmeta.img 的结构

// system/core/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
// vbmeta 使用 AVB (Android Verified Boot) 格式
// 基于 libavb (external/avb/)

typedef struct AvbVBMetaImageHeader {
uint8_t magic[4]; // "AVB0"
uint32_t required_libavb_version_major;
uint32_t required_libavb_version_minor;
uint64_t authentication_data_block_size;
uint64_t auxiliary_data_block_size;
uint32_t algorithm_type; // 签名算法 (SHA256_RSA2048 等)
uint64_t hash_offset;
uint64_t hash_size;
uint64_t signature_offset;
uint64_t signature_size;
// ...
} AvbVBMetaImageHeader;

验证链:

  1. Bootloader 读取 vbmeta.img,验证其签名的公钥与硬件中烧录的 key 匹配
  2. vbmeta 中包含 boot.img 的哈希——bootloader 验证 boot.img 未被篡改
  3. boot.img 中的 ramdisk 启动后,dm-verity 验证 system.img 的每个块的哈希
  4. 如果任何一步验证失败,根据设备配置:警告、拒绝启动(黄色/红色状态)

十、recovery.img 与救援模式

10.1 recovery.img 的结构

recovery.img 本质上是一个特殊的 boot.img,使用不同的 ramdisk 和内核命令行:

recovery.img = kernel + recovery ramdisk

recovery ramdisk:
├── init # init(恢复模式)
├── init.rc # 恢复模式 .rc 文件
├── sbin/
│ └── recovery # recovery 主二进制
├── res/
│ └── images/ # recovery UI 资源
└── etc/
└── recovery.fstab # recovery 模式分区表

10.2 Recovery 模式功能

// bootable/recovery/recovery.cpp
int main(int argc, char** argv) {
// 1. 挂载必要的分区
// 2. 显示 recovery UI(音量键 + 电源键操作)
// 3. 支持的操作:
// - Reboot system now
// - Apply update from ADB (adb sideload)
// - Apply update from SD card
// - Wipe data/factory reset
// - Wipe cache partition
// - Mount /system
// - View recovery logs
// - Run graphics test
// - Run locale test
// - Power off
}

十一、核心面试题

Q1:sparse image 和 raw image 有什么区别?为什么 Android 使用 sparse 格式进行 fastboot 刷写?

答:Raw image 是一个分区(如 system 的 2GB)的完整字节拷贝,包含所有空块。Sparse image 仅包含非空块及 chunk 索引,跳过空洞区域(CHUNK_TYPE_DONT_CARE)。传输 sparse image 到设备时数据量显著减少(通常减少 50-70%),大幅加快刷写速度。在设备端,fastbootd 解析 sparse header,只恢复存有数据的块,跳过空洞。这在开发过程中(频繁刷机)尤其重要。

Q2:GKI 2.0 (Android 12) 为什么要把 vendor ramdisk 从 boot.img 中拆出来成为 vendor_boot.img?

答:GKI (Generic Kernel Image) 的目标是让 Google 提供一个通用的内核 + ramdisk 基础(boot.img),OEM/SoC 厂商只需提供 vendor 特定的附加组件(vendor_boot.img)。拆分的直接好处:(1) Google 可以独立更新 boot.img(内核安全补丁)而不需要 OEM 变更 vendor 组件;(2) OEM 可以独立更新 HAL 实现(在 vendor_boot 的 ramdisk 中加载 .so 和 .rc 文件)而不影响内核;(3) 简化了构建——Google 只需要构建和维护一个 boot.img(per-arch),而不是数百个 per-device boot.img。

Q3:erofs 相比 ext4 为什么更适合做 system.img?它没有 journal 会不会导致数据完整性风险?

答:erofs 专为只读分区设计,去掉了 ext4 中针对读写场景的开销(journal、block allocation bitmap、支持写入的 inode 结构等),实现了:(1) 约 20% 更小的镜像体积(更好的压缩和更紧凑的元数据);(2) 更快的挂载速度(更少的结构需要初始化);(3) 更好的读性能(数据结构针对顺序读优化)。关于数据完整性:system 分区是只读的(由 dm-verity 保证完整性),不是写入操作后才需要保证一致性的场景,所以 journal 不需要。dm-verity 在每个块被读取时验证其哈希,任何数据损坏都会在发生时被立即检测到。从这个意义上说,erofs + dm-verity 的组合比 ext4 + journal 提供更强(而非更弱)的数据完整性保证。

Q4:A/B 系统更新中如果设备在更新到 slot B 时断电了怎么办?系统还能启动吗?

答:A/B 系统的设计中有一个关键字段 bootable flag 存储在每个 slot 的元数据中。更新流程:(1) 首先标记 slot B 为 unbootable;(2) 然后开始向 slot B 写入数据;(3) 写入完成后,标记 slot B 为 bootable;(4) 尝试启动 slot B;(5) 如果启动成功(到达 userspace),标记 successful;(6) 如果多次启动失败(超过 retry_count),bootloader 自动回退到 slot A。因此如果更新过程中断电,slot B 仍然是 unbootable 状态,bootloader 会直接启动 slot A。如果已标记 bootable 但数据写入不完整(极端情况),启动失败后自动回退。这种机制确保了 “anti-brick” 保护。

Q5:super.img 中的”逻辑分区”与物理分区在 Linux 内核层面是如何区分的?device-mapper 扮演什么角色?

答:物理分区(如 mmcblk0p1)是由 GPT 分区表定义的闪存上的固定区域。逻辑分区(如 system、vendor 在 super 内)并不对应独立的物理分区——它们是由 Android init 通过 device-mapper 的 dm-linear target 创建的虚拟块设备。具体流程:init 在启动时读取 super.img 的 metadata slot(由 liblp 库解析),然后调用 device-mapper 创建 /dev/block/mapper/system_avendor_a 等 dm 设备,每个 dm-linear 设备映射到 super 分区内的一个偏移区域。这样内核通过 dm 设备进行 I/O,实际上是在 super 分区内的指定 offset 上读写。这种抽象使得分区大小可以在 OTA 时动态调整——只需更新 metadata 和重建 dm 映射。

AOSP 核心路径参考:

  • system/tools/mkbootimg/ — boot.img 创建工具
  • system/tools/mkbootimg/include/bootimg/bootimg.h — boot image header 定义
  • system/core/libsparse/ — Sparse image 处理库
  • system/core/fastboot/ — Fastboot 协议实现
  • system/core/fs_mgr/ — 文件系统管理器(dm-verity、mount 等)
  • system/core/fs_mgr/libfs_avb/ — AVB (Verified Boot) 实现
  • system/extras/partition_tools/ — 分区工具(lpmake、lpunpack 等)
  • system/update_engine/ — OTA 更新引擎
  • build/make/tools/releasetools/ — OTA 包生成工具
  • bootable/recovery/ — Recovery 模式
  • external/avb/ — libavb 库(Android Verified Boot)
  • system/core/init/ — 第一阶段挂载(first_stage_mount)
打赏
  • 微信
  • 支付宝

评论