4. GKI镜像组成与构建产物
在 GKI(Generic Kernel Image)量产交付体系中,构建产物并不是“一个内核文件”那么简单。Android 启动链路把内核、通用内核模块、厂商模块、设备树覆盖、ramdisk 与动态分区系统镜像拆分到多个独立分区中,每个分区承担明确的职责,并通过 bootconfig、cmdline、DTBO 与 vendor 模块实现“通用内核 + 厂商定制”的解耦。理解这些镜像的组成、加载顺序与依赖关系,是后续签名、OTA、回滚与量产验证的基础。
一、核心原理:为什么 GKI 要把启动产物拆成多个镜像
传统 Android 内核把大量厂商驱动直接编译进 Image,导致内核与 SoC、板级配置强耦合,无法独立升级。GKI 的核心思路是:Google 提供稳定的 KMI(Kernel Module Interface)与通用内核镜像,厂商把非通用驱动做成可加载模块,放在 vendor_boot.img 或 vendor_dlkm 中;同时把与启动强相关的通用 ramdisk 与厂商 ramdisk 分离,分别放入 init_boot.img 与 vendor_boot.img。这样内核可以随 GKI 版本独立更新,而厂商模块与设备树保持相对稳定。
因此,量产构建产物通常包括:boot.img、init_boot.img、vendor_boot.img、dtbo.img、super.img 以及若干 .ko 内核模块。它们分别对应启动阶段的不同加载点,缺一不可。
二、各镜像的组成与职责
boot.img:GKI 的核心启动镜像,包含通用内核 Image(或 Image.lz4)与通用 ramdisk。它由 Google 提供,KMI 稳定,厂商不应直接修改内核二进制。boot.img 的 header 中记录内核版本、cmdline、os_version 等元数据。
init_boot.img:从 Android 13 开始引入,专门存放通用 init ramdisk。它把原本位于 boot.img 中的 first-stage init 与 init.rc 拆分出来,使 GKI 内核与 init 可以独立升级。量产中必须保证 init_boot 与 boot 的版本匹配。
vendor_boot.img:厂商定制启动镜像,包含厂商 ramdisk、vendor_dlkm 模块、DTB/DTBO 附加段以及 vendor bootconfig。它承载 SoC 与板级差异,是 GKI 解耦的关键。
dtbo.img:设备树覆盖(Device Tree Overlay)镜像,用于在通用 DTB 基础上叠加板级硬件描述。多板型项目常通过 dtbo 的 id 与 board_id 匹配选择正确覆盖。
super.img:动态分区容器,内部包含 system、vendor、product、system_ext、vendor_dlkm 等逻辑分区。量产时通过 lpmake 生成,支持 OTA 动态调整分区大小。
内核模块 .ko:分为 GKI 模块与厂商模块。GKI 模块随内核发布,厂商模块放在 vendor_dlkm 或 vendor_boot 中。加载前必须通过 KMI 符号校验,否则会拒绝加载。
三、构建流程与关键命令
典型 GKI 量产构建流程如下:先编译 GKI 内核与模块,再编译厂商模块,随后打包各镜像,最后生成 super.img 并签名。
# 1. 编译 GKI 内核与模块
tools/bazel build //common:kernel_aarch64_dist
# 2. 编译厂商模块(以 vendor_dlkm 为例)
make -j$(nproc) vendor_dlkm
# 3. 打包 boot.img / init_boot.img / vendor_boot.img
mkbootimg --kernel Image.lz4 \
--ramdisk init_boot_ramdisk.img \
--header_version 4 \
--output boot.img
# 4. 生成 dtbo.img
mkdtboimg create dtbo.img board-*.dtbo
# 5. 生成 super.img
lpmake --device-size 6442450944 \
--partition system:readonly:2147483648:system.img \
--partition vendor:readonly:1073741824:vendor.img \
--partition vendor_dlkm:readonly:536870912:vendor_dlkm.img \
--output super.img
build.config、KMI 符号列表、ABL 版本保持一致。量产前建议用 avbtool 校验各镜像的 AVB 签名与 hash。四、量产场景与常见误区
在量产交付中,最常见的误区是“只更新 boot.img 而忽略 init_boot 与 vendor_boot 的版本匹配”。GKI 升级时,boot.img 的内核版本变化,若 init_boot 仍是旧版,first-stage init 可能无法识别新的 bootconfig,导致启动卡在 bootloader 或 init 阶段。另一个误区是把厂商模块直接编译进内核,破坏 KMI 稳定性,导致后续 GKI 升级无法复用模块。
复盘建议:建立镜像版本矩阵,记录每个量产版本的 boot、init_boot、vendor_boot、dtbo、super 与模块的 hash 和 KMI 版本;在 OTA 包中同时携带这些镜像,避免“部分升级”造成启动失败。
| 镜像/产物 | 主要组成 | 是否随 GKI 升级 | 量产关注点 |
|---|---|---|---|
| boot.img | GKI 内核 + 通用 ramdisk | 是 | KMI 版本、AVB 签名 |
| init_boot.img | 通用 init ramdisk | 是 | 与 boot 版本匹配 |
| vendor_boot.img | 厂商 ramdisk + vendor_dlkm + DTB | 否(随厂商) | board_id、模块依赖 |
| dtbo.img | 设备树覆盖 | 否 | 多板型 id 匹配 |
| super.img | system/vendor/product/vendor_dlkm | 部分 | 动态分区大小、lpmake 参数 |
| 内核模块 .ko | GKI 模块 + 厂商模块 | 部分 | KMI 符号校验、加载顺序 |
掌握这些镜像的组成与依赖关系后,后续的签名、OTA 打包、回滚策略与量产验证才能建立在正确的分区模型之上。GKI 的“通用内核 + 厂商模块 + 动态分区”结构,本质上是用清晰的边界换取长期可升级性,而每一个镜像都是这条链路上不可替代的一环。