系统镜像结构
在 AOSP 中看到 out/target/product/<product>/system/、system.img、super.img 和设备上的 /system 时,初学者很容易把它们都理解成“system 分区”。实际上它们分别处于安装目录、文件系统 镜像、逻辑分区容器和运行时挂载点四个层次。
模块化编译 已经说明单模块产物怎样进入 output tree; 编译错误排查 说明怎样定位失败 action。本文继续回答:这些安装产物怎样 被打包成镜像,启动时又怎样从块设备变成进程可读取的目录。
本文不展开完整刷机和 OTA payload,也不假定每台设备都具有相同分区。Android 17 源码定义的是一套 可配置机制;产品和 BoardConfig 决定最终启用哪些镜像、使用什么文件系统以及怎样组织 A/B slot。 读完后,读者应能从一个安装路径追到镜像构建规则、AVB footer、super 中的逻辑分区和 first-stage mount 消费者,并能区分“文件进入 staging 目录”“镜像生成成功”和“设备启动后挂载生效”。
1. 对象边界
1.1 安装目录
构建模块先把文件安装到 PRODUCT_OUT 下的目录树,例如:
out/target/product/<product>/
├── system/
├── system_ext/
├── product/
├── vendor/
├── odm/
├── vendor_dlkm/
└── root/这些目录是镜像的输入,不是设备分区。adb sync system 也从这里选择待同步文件。
1.2 镜像文件
system.img、vendor.img 等通常包含 ext4、EROFS 或 F2FS 文件系统。镜像内部记录目录项、inode、 权限、SELinux label、块布局,并可能带 Android sparse 表示或 AVB hashtree/footer。
1.3 物理/逻辑分区
物理分区由底层存储分区表或 bootloader 暴露,例如 boot_a、vbmeta_a、super。动态分区设备还会 根据 super 中的 LP metadata 创建 system_a、vendor_a 等逻辑分区。逻辑分区通常表现为 device-mapper 块设备,不要求每个逻辑分区在 GPT 中占有独立固定区间。
1.4 挂载点
/system、/vendor、/product 是运行时目录。first-stage init 读取 fstab,找到块设备、建立 dm-linear/dm-verity 映射,再把文件系统挂载到这些路径。
1.5 聚合镜像
super.img 是用于初始化或刷写动态分区布局的聚合产物。它包含 LP metadata,并可携带逻辑分区的 数据 extent;它本身不是挂载到 /super 的普通文件系统。
2. 镜像家族
2.1 挂载镜像
| 镜像 | 常见挂载点 | 主要所有权 | 典型消费者 |
|---|---|---|---|
system.img | /system 或 system-as-root 中的 / | 平台核心 | init、framework、system_server、系统 native 服务 |
system_ext.img | /system_ext | 平台扩展 | 与 system 紧密协作但需要独立交付的系统组件 |
product.img | /product | 产品配置 | 产品 APK、资源、overlay 和系统侧产品扩展 |
vendor.img | /vendor | vendor 实现 | HAL 服务、vendor native 库、VINTF、vendor 配置 |
odm.img | /odm | 具体设备/板级差异 | ODM HAL、配置与覆盖 |
system_dlkm.img | /system_dlkm | system kernel module 集合 | 通用或 system 侧内核模块加载流程 |
vendor_dlkm.img | /vendor_dlkm | vendor kernel module 集合 | 设备相关内核模块 |
odm_dlkm.img | /odm_dlkm | ODM kernel module 集合 | 更具体的板级内核模块 |
userdata.img | /data | 运行时可写数据 | 应用数据、用户数据、系统持久化状态 |
metadata.img | /metadata | 启动与更新元数据 | FBE、Virtual A/B snapshot、DSU 等早期流程 |
这张表描述职责,不保证某个产品一定构建独立镜像。例如 vendor 内容可以在旧布局中位于 /system/vendor,但当 TARGET_COPY_OUT_VENDOR=vendor 时才使用独立 vendor image。判断具体设备应看 产品配置、target files 和运行时 fstab。
2.2 启动镜像
| 镜像 | 主要内容 | 运行时角色 |
|---|---|---|
boot.img | kernel,以及按配置存在的 generic ramdisk | bootloader 加载内核和早期用户空间 |
init_boot.img | generic ramdisk | 将通用 first-stage ramdisk 从 boot 中独立出来 |
vendor_boot.img | vendor ramdisk、DTB、vendor cmdline、bootconfig、ramdisk fragments | 为设备启动提供 vendor 侧早期内容 |
vendor_kernel_boot.img | 可选 vendor kernel ramdisk 与 DTB | 进一步拆分 vendor kernel 启动内容 |
dtbo.img | device tree overlays | bootloader/kernel 选择设备树覆盖 |
recovery.img | recovery kernel/ramdisk,具体布局受产品条件控制 | recovery 启动环境 |
vbmeta.img | AVB descriptors、签名和 chained vbmeta 引用 | Verified Boot 信任根和验证关系 |
不能把这些文件当作 ext4 镜像直接 mount。应使用 unpack_bootimg、avbtool info_image 或对应格式 工具读取。
3. 文件系统镜像生成
3.1 镜像输入
build_image.py 的 BuildImage 接收:
in_dir:分区 staging 目录;- property dictionary:文件系统、分区大小、SELinux、AVB、稀疏格式等配置;
out_file:最终.img;target_out:供fs_config查设备权限配置的 system 输出目录。
核心入口先处理 system-as-root,再选择文件系统和 verity builder:
源码文件:build/make/tools/releasetools/build_image.py
相关函数/类型:BuildImage
in_dir, fs_config = SetUpInDirAndFsConfig(in_dir, prop_dict)
SetUUIDIfNotExist(prop_dict)
fs_type = prop_dict.get("fs_type", "")
# 说明:EROFS和压缩F2FS不一定用文件系统内容填满整个partition。
fs_spans_partition = True
if fs_type.startswith("erofs"):
fs_spans_partition = False
elif fs_type.startswith("f2fs") and prop_dict.get("f2fs_compress") == "true":
fs_spans_partition = False
verity_image_builder = verity_utils.CreateVerityImageBuilder(prop_dict)property dictionary 来自产品全局信息和分区专属变量。ImagePropFromGlobalDict 支持的只读分区包括 system、vendor、product、system_ext、odm 和三个 dlkm 分区;data 则使用可写文件系统配置。
3.2 文件系统格式
BuildImageMkfs 根据 fs_type 选择工具:
源码文件:build/make/tools/releasetools/build_image.py
相关函数/类型:BuildImageMkfs
if fs_type.startswith("ext"):
build_command = [prop_dict["ext_mkuserimg"]]
build_command.extend([
in_dir, out_file, fs_type,
prop_dict["mount_point"],
prop_dict["image_size"],
])
elif fs_type.startswith("erofs"):
build_command = ["mkfs.erofs"]
build_command.extend([
"--mount-point", prop_dict["mount_point"],
])
elif fs_type.startswith("f2fs"):
build_command = ["mkf2fsuserimg"]
build_command.extend([
"-t", prop_dict["mount_point"],
])
else:
raise BuildImageError(
"Error: unknown filesystem type: {}".format(fs_type)
)选择文件系统不是“所有 system 都是 EROFS、所有 data 都是 F2FS”的固定规则。BoardConfig 和产品变量 决定最终值,设备内核也必须支持该文件系统及所需 feature。
3.3 SELinux输入
目录中的 Unix mode 不是完整权限来源。构建还会使用 fs_config、设备专属配置和 file contexts, 把 uid/gid、capabilities 与 SELinux label 写入镜像。只复制文件到 staging 目录但漏掉配置,最终设备上 可能出现权限、执行或 SELinux 访问失败。
3.4 system-as-root
构建 system image 时,脚本会创建临时根目录,把 root staging 与 system/ 合并,并把 mount point 改为 /:
源码文件:build/make/tools/releasetools/build_image.py
相关函数/类型:SetUpInDirAndFsConfig
if prop_dict["mount_point"] != "system":
return origin_in, fs_config
in_dir = common.MakeTempDir()
root_dir = prop_dict.get("root_dir")
if root_dir:
shutil.rmtree(in_dir)
shutil.copytree(root_dir, in_dir, symlinks=True)
in_dir_system = os.path.join(in_dir, "system")
shutil.copytree(origin_in, in_dir_system, symlinks=True)
# 说明:输出镜像表示根文件系统布局,而不是只表示/system子目录。
prop_dict["mount_point"] = "/"test_SetUpInDirAndFsConfig 构造 root 中的 init、system 文件和 symlink,断言合并后的 staging 同时 包含根内容和 /system 内容,并确认 mount point 变为 /。这解释了为什么“打开 system.img 后最外层 不是预期目录”不能直接判定构建错误。
4. 镜像大小边界
4.1 镜像大小
静态分区配置通常给出 partition_size。动态分区可以启用 use_dynamic_partition_size,让脚本根据 目录或压缩后镜像大小计算空间,再加入 reserved、headroom、alignment 和 AVB footer 所需空间。
源码文件:build/make/tools/releasetools/build_image.py
相关函数/类型:BuildImage
if (prop_dict.get("use_dynamic_partition_size") == "true" and
"partition_size" not in prop_dict):
if fs_type.startswith("erofs"):
# 说明:压缩文件系统先生成,再按实际压缩尺寸估算。
mkfs_output = BuildImageMkfs(...)
size = GetDiskUsage(out_file)
else:
size = GetDiskUsage(in_dir)
size = CalculateSizeAndReserved(prop_dict, size)
size = common.RoundUpTo4K(size)4.2 headroom意义
headroom 是镜像内容之外仍需保留的空间,不等于 host 磁盘剩余量。ext4 构建后会解析 mke2fs 输出, 确认空闲 blocks 能满足 partition_headroom。test_CheckHeadroom_InsufficientHeadroom 把要求从 1000 blocks 提高到 1001 blocks,断言构建抛出 BuildImageError。
如果镜像大小超限,正确入口是检查文件增长、重复安装、文件系统压缩、reserved/headroom、AVB footer 与逻辑分区 group 上限,而不是只增大一个随机常量。
4.3 sparse 格式
Android sparse image 是传输/存储表示,用 chunk 描述 raw 数据、填充值和跳过区间。一个 sparse system.img 内部仍可以是 ext4。分析工具若要求 raw image,需要先转换;但对支持 Android sparse 的 fastboot 或构建工具,不应无条件转换后再刷写。
5. 启动镜像
5.1 启动镜像构建
Android 17 的 board_config.mk 不假定所有产品都有三张镜像:
- boot 是否构建受
PRODUCT_BUILD_BOOT_IMAGE、kernel 和 recovery-as-boot 影响; - 存在
BOARD_INIT_BOOT_IMAGE_PARTITION_SIZE或产品显式开启时构建 init_boot; BOARD_BOOT_HEADER_VERSION >= 3时默认构建 vendor_boot;- vendor ramdisk fragments 要求 vendor_boot,并且 header version 4 才允许相关配置;
- 还可能使用 prebuilt boot、prebuilt init_boot 或 GKI APEX 提供的 boot image。
所以“缺少 init_boot.img”可能只是产品没有启用该分区,而不是构建漏产物。
5.2 ramdisk
boot image 规则在没有 init_boot 时把 INSTALLED_RAMDISK_TARGET 加入 boot;启用 init_boot 后,这个 ramdisk 从 boot 参数中移除:
源码文件:build/make/core/Makefile
相关函数/类型:INTERNAL_BOOTIMAGE_ARGS
INTERNAL_BOOTIMAGE_ARGS := \
$(addprefix --second ,$(INSTALLED_2NDBOOTLOADER_TARGET))
ifneq ($(BUILDING_INIT_BOOT_IMAGE),true)
# 说明:没有init_boot时,generic ramdisk仍进入boot。
INTERNAL_BOOTIMAGE_ARGS += --ramdisk $(INSTALLED_RAMDISK_TARGET)
endifinit_boot 则明确使用 generic ramdisk:
源码文件:build/make/core/Makefile
相关函数/类型:init_boot rule
INSTALLED_INIT_BOOT_IMAGE_TARGET := $(PRODUCT_OUT)/init_boot.img
INTERNAL_INIT_BOOT_IMAGE_ARGS := --ramdisk $(INSTALLED_RAMDISK_TARGET)
$(MKBOOTIMG) $(INTERNAL_INIT_BOOT_IMAGE_ARGS) \
$(INTERNAL_MKBOOTIMG_VERSION_ARGS) \
$(BOARD_MKBOOTIMG_INIT_ARGS) \
--output "$@"5.3 mkbootfs
vendor_boot 规则从 TARGET_VENDOR_RAMDISK_OUT 收集文件,用 mkbootfs 生成 vendor ramdisk,还可加入:
- DTB;
- vendor kernel cmdline;
- vendor bootconfig;
- 命名 vendor ramdisk fragments;
- 按配置迁移的 recovery resources;
- GSI AVB keys 等设备启动输入。
header version 4 的 ramdisk table 允许多个 fragment 带 name/type。fastboot 的 vendor_boot_img_utils_test.cpp 使用不同 header fixture 重打包 DTB、bootconfig 和 fragments,并检查 结果及 AVB footer 保持,证明工具必须按 header 结构处理,不能把 vendor_boot 当成“一个固定 cpio”。
6. super容器
6.1 LP metadata
LP metadata 至少描述:
- super metadata device 与实际 block devices;
- metadata slot 数;
- partition groups 及其最大空间;
- 逻辑 partition 名称、属性与所属 group;
- 每个 partition 对应的 extent;
- Virtual A/B 等 header flags。
逻辑分区可以由多个 extent 组成,extent 指向 super block device 上的区间。运行时通过 device-mapper 把这些不必连续的区间映射为一个线性块设备。
6.2 配置
build_super_image.py 把 misc_info 中的动态分区信息转换为 lpmake 命令:
源码文件:build/make/tools/releasetools/build_super_image.py
# 符号:BuildSuperImageFromDict
cmd = [
info_dict["lpmake"],
"--metadata-size", "65536",
"--super-name", info_dict["super_metadata_device"],
]
if ab_update:
cmd += ["--metadata-slots", "3"]
else:
cmd += ["--metadata-slots", "2"]
if virtual_ab:
cmd.append("--virtual-ab")
for device in block_devices:
cmd += ["--device", "{}:{}".format(device, size)]group 和 partition 随后加入。A/B 模式为 group 创建 _a/_b,初始化 super image 时把正常 image 填入 partition_a,B slot 通常为空;如果存在 system_other.img,它可以作为 system B slot 输入。
6.3 group空间
group 不是 mount point,也不是目录。它给一组逻辑分区设置总大小上限,OTA 调整 system/vendor 等 大小时必须保持 group 约束。单个 image 能成功生成,不表示它和同组其他 image 一定能装入 super。
6.4 super布局
| 产物 | LP metadata | 分区数据 | 主要用途 |
|---|---|---|---|
super.img | 有 | 可包含 system/vendor/product 等 image | 初始化或整体刷写动态分区布局 |
super_empty.img | 有 | 逻辑分区通常为空 | 建立空布局,供后续逐分区写入或测试 |
构建 super.img 还需要 PRODUCT_BUILD_SUPER_PARTITION=true 和 super size/config。源码同时提供 dist 版本、开发版本和 nodeps 入口,不能仅凭 output tree 中缺少 super.img 判断动态分区未启用。
SuperFlashHelper.ImageEquality 读取 super_empty.img,加入 system_a image 后生成 sparse layout,再 逐字节与 lpmake 生成的 super.img 比较;除 lpmake 对 super 总大小追加的零填充外,内容必须一致。 这个测试反向验证了“empty metadata + logical image → super layout”的组合关系。
7. first-stage init
7.1 分区映射
FirstStageMount::Create 读取默认 fstab,只保留 first_stage_mount entry。只要某个 entry 带 logical flag,IsDmLinearEnabled() 就返回 true,init 会寻找 super block device。
7.2 metadata顺序
Android first-stage mount 会先尝试挂载 /metadata,因为 Virtual A/B snapshot merge 等状态可能影响 逻辑分区应映射到原始 extent 还是 snapshot/COW 设备:
源码文件:system/core/init/first_stage_mount_android.cpp
// 符号:FirstStageMountAndroid::DoCreateDevices
auto metadata_partition = std::find_if(
fstab_.begin(), fstab_.end(),
[](const auto& entry) {
return entry.mount_point == "/metadata";
});
if (metadata_partition != fstab_.end()) {
MountPartition(metadata_partition, true);
}
// 说明:snapshot状态可改变后续逻辑分区映射。
if (!CreateLogicalPartitions()) return false;7.3 dm-linear
普通动态分区路径会读取当前 slot 的 LP metadata,初始化 backing devices,再调用 CreateLogicalPartitions:
源码文件:system/core/init/first_stage_mount_android.cpp
// 符号:FirstStageMountAndroid::CreateLogicalPartitions
auto metadata = android::fs_mgr::ReadCurrentMetadata(super_path_);
if (!metadata) {
LOG(ERROR) << "Could not read logical partition metadata from "
<< super_path_;
return false;
}
if (!InitDmLinearBackingDevices(*metadata.get())) {
return false;
}
// 说明:LP extents在这里变成可供fstab使用的device-mapper设备。
return android::fs_mgr::CreateLogicalPartitions(
*metadata.get(), super_path_);Virtual A/B 更新进行中时,流程可能改为 snapshot mapping,并启动 snapuserd。此时逻辑分区看到的内容 可能由 base partition 与 COW snapshot 合成,不能只看 super 原始 extent 判断当前读到的数据。
7.4 AVB后才挂载
MountPartition 对 logical entry 先更新逻辑块设备并等待 dm device,再建立 dm-verity/AVB,最后执行 文件系统 mount:
源码文件:system/core/init/first_stage_mount.cpp
// 符号:FirstStageMount::MountPartition
if (begin->fs_mgr_flags.logical) {
if (!fs_mgr_update_logical_partition(&(*begin))) {
return false;
}
if (!block_dev_init_.InitDmDevice(begin->blk_device)) {
return false;
}
}
if (!SetUpDmVerity(&(*begin))) {
return false;
}
bool mounted = (fs_mgr_do_mount_one(*begin) == 0);同一 mount point 可以有多个候选 entry,前一种文件系统挂载失败后会尝试后续 entry;但非 no_fail、 非 formattable 的关键分区最终失败时,first-stage mount 返回 false,启动不会假装成功继续。
8. AVB信任
8.1 mkbootimg
boot、init_boot、vendor_boot 等整体读取的镜像通常添加 hash footer;system、vendor、product 等大文件 系统镜像通常使用 hashtree,使运行时能够按块验证。具体算法、key 和 rollback index 由 BoardConfig 决定。
boot 构建规则先运行 mkbootimg,检查最大尺寸,再调用:
源码文件:build/make/core/Makefile
相关函数/类型:AVB hash footer
$(AVBTOOL) add_hash_footer \
--image $(1) \
--partition_name boot \
$(INTERNAL_AVB_BOOT_SIGNING_ARGS)init_boot 和 vendor_boot 也有各自 partition name 与 signing args。文件系统镜像的 property dictionary 则让 CreateVerityImageBuilder 预留 footer/hashtree 空间并在 mkfs 后完成 verified image。
8.2 vbmeta 验证
vbmeta.img 保存 descriptors、签名、公钥关系和 chained vbmeta 信息,不复制 system/vendor 文件。 构建规则还会为 system、product、system_ext、boot、init_boot、vendor 等 descriptor 加入 OS version、 fingerprint 或 security patch properties。
8.3 验证失败
first-stage mount 的 SetUpDmVerity 失败时不会继续挂载关键分区。设备解锁状态、允许的验证模式、 rollback index 和 chained vbmeta 配置会影响处理结果,但不能把“bootloader 已加载 kernel”理解成 所有系统分区都已通过验证。
9. A/B
9.1 A/B是slot集合
A/B 设备通常有 slot-suffixed boot chain 分区,并在 super metadata 中描述 slot-suffixed logical partitions。build_super_image.py 对 A/B group 创建 _a/_b,metadata slot 数从 2 变为 3。
当前 slot 由 boot control 与 bootloader 选择。查看运行时布局时应同时记录:
adb shell getprop ro.boot.slot_suffix
adb shell bootctl get-current-slot
adb shell ls -l /dev/block/by-name并非所有命令在每个产品都预装或允许执行,slot suffix 和实际 partition name 应以设备输出为准。
9.2 Slot元数据
Virtual A/B 利用 snapshot/COW 保存更新差异,在新 slot 启动和 merge 期间由 dm-snapshot、snapuserd 等 组合数据。super 仍提供 base logical partition layout;/metadata 和 /data 上的更新状态/映像参与 first-stage 映射。
因此,更新过程中 lpdump super、当前 dm table 与挂载后文件内容可能回答不同问题:前者描述基础 LP layout,dm table 描述当前映射,文件系统内容描述消费者实际看到的数据。
10. 构建产物检查
10.1 产品产物
product_out="$(get_build_var PRODUCT_OUT)"
find "$product_out" -maxdepth 1 -name '*.img' -print | sort不要用教程中的固定列表判断缺失。产品可能不构建 cache、recovery、init_boot、vendor_boot、super, 也可能增加 vendor_kernel_boot 或自定义镜像。
10.2 判断镜像类型
file "$product_out/system.img"
file "$product_out/boot.img"
avbtool info_image --image "$product_out/system.img"
unpack_bootimg --boot_img "$product_out/boot.img" --out /tmp/boot-unpacked
lpdump "$product_out/super.img"file 只能提供初步识别。sparse image、AVB footer 和自定义容器会让输出不直观;应结合专用工具。
10.3 super提取
lpunpack "$product_out/super.img" /tmp/super-unpacked
find /tmp/super-unpacked -maxdepth 1 -type f -print | sortA/B 初始化 super 可能同时出现 _a/_b,B slot image 也可能为空。提取结果应结合 lpdump 中的 group、 extent 和 attributes 解读。
10.4 simg2img
对 ext4 raw image 可以在 Linux 上只读 loop mount;EROFS 应使用内核支持或对应工具。Android sparse 需要先确认工具是否支持,必要时用 simg2img 转为 raw。任何 mount 或提取结果都只代表该 image, 不自动代表设备当前 slot 和 snapshot 映射正在使用它。
11. 构建与运行边界
11.1 adb sync
adb sync system 从 ANDROID_PRODUCT_OUT/system 同步到设备 /system 视图。它不重打 boot.img, 也不重新生成 super LP metadata。是否能写入取决于 adbd root、remount、verity、overlayfs 与产品策略。
11.2 remount覆盖
first-stage mount 在基础分区完成后还会处理 overlay entries 和 scratch partition。调试设备上 adb remount 可能通过 overlayfs 让只读分区呈现可写视图。此时文件修改可以立即被进程加载,但底层 system.img 或 super extent 未必变化,重启、禁用 overlay 或重新刷写后可能恢复。
11.3 车机匹配
设备能够 adb root 和 adb remount,只能证明当前车机开放调试能力。若它运行厂商镜像而不是当前 AOSP product,主机生成的模块、分区布局、签名、ABI、VINTF、APEX 和 overlay 可能不匹配。部署前至少 要把构建 product、设备 build fingerprint、slot、目标 mount point 与实际消费者对应起来。
完整 fastboot/fastbootd、分区选择和恢复方案属于后续刷机专题。系统镜像结构文章只负责说明目标产物 是什么以及运行时怎样消费。
12. 常见判断错误
12.1 system.img
可能只构建了模块目标,或 product 使用 Soong-defined filesystem、target files 阶段生成、system-only 输出等路径。先查 Ninja target、PRODUCT_OUT 和产品配置。
12.2 super内容
super 的首要结构是 LP metadata 和 extent。需要先用 lpdump/lpunpack 找到逻辑分区 image,再按文件 系统格式查看内容。
12.3 vendor边界
vendor 是分区 ABI 与所有权边界,不是“凡是厂商添加的文件都放这里”。产品 APK 可能属于 product, 设备差异可能属于 odm,kernel modules 可能属于 vendor_dlkm/odm_dlkm,boot-time 内容可能属于 vendor_boot。
12.4 boot.img组成
启用 init_boot 时 generic ramdisk 不在 boot;GKI、vendor_boot、vendor_kernel_boot、recovery-as-boot 等配置也会改变内容。必须先读 header version 和产品变量。
12.5 remount结果
remount 改变的是当前挂载视图;overlayfs、snapshot 和 slot 都可能使它与物理 image 不同。重启后是否 保留、AVB 是否仍成立、OTA 是否会覆盖,需要分别验证。
13. 源码入口
理解镜像结构的有效方式不是背分区表,而是选择一个真实文件,沿所有权反向追踪。
| 文件或修改 | staging目录 | 镜像/逻辑分区 | 运行时消费者 |
|---|---|---|---|
services.jar 中的 framework 修改 | PRODUCT_OUT/system/framework | system.img → system[_slot] | system_server |
| vendor HAL service | PRODUCT_OUT/vendor/bin/hw | vendor.img → vendor[_slot] | init 启动的 HAL 进程 |
| 产品 overlay/APK | PRODUCT_OUT/product | product.img → product[_slot] | ResourceManager 或应用进程 |
| vendor kernel module | PRODUCT_OUT/vendor_dlkm/lib/modules | vendor_dlkm.img | early/late module loader |
| first-stage vendor rc/模块 | vendor ramdisk staging | vendor_boot.img fragment | first-stage init |
对每个对象都应回答:谁把它安装到 staging,谁选择文件系统和 image size,是否进入 super,fstab 如何 找到它,AVB 验证哪一层,最后哪个进程或内核路径读取它。
以 framework 修改为例,完整链路不是“编译 services.jar 后刷 system.img”这么短:
framework源码
-> services模块与installed output
-> PRODUCT_OUT/system/framework/services.jar
-> build_image生成system.img并加入AVB数据
-> build_super_image将system image放入逻辑分区extent
-> first-stage init创建dm-linear/dm-verity设备
-> mount为/system
-> zygote/system_server加载新的framework代码如果设备通过 overlayfs 接收单文件更新,链路中“重建 system.img 与 super”可以被调试路径暂时绕过, 但文件的逻辑归属、签名边界和最终消费者没有改变。能够把单个文件沿这条链路定位清楚,才真正理解了 Android 系统镜像结构。
