3. GKI 架构解析
GKI(Generic Kernel Image,通用内核镜像)是 Android 从 Android 11 开始正式推行的内核交付模型。它的核心目标是把内核中与 SoC、板级硬件强相关的部分,从内核核心中剥离出来,形成“Google 维护的通用内核 + 供应商维护的模块”两层结构。这样 Android 平台升级时,内核核心可以独立更新,而供应商只需保证自己的模块与 KMI 稳定接口兼容,从而显著降低碎片化、缩短安全补丁落地周期。
一、GKI 的分层结构
理解 GKI,最有效的方式是看它的分层与依赖关系。下图展示了从硬件到 Android 框架的纵向结构:最底层是 SoC 与板级硬件,其上是供应商模块(vendor modules),再上是 KMI 稳定接口,最上层是 Google 提供的通用内核镜像与 Android 平台。
从图中可以看出,GKI 的关键在于“中间层”——KMI。它既是通用内核暴露给供应商模块的符号与结构体集合,也是 ABI 兼容性检查的对象。供应商模块只能调用 KMI 中列出的符号,不能依赖未导出的内部实现。
二、通用内核镜像与供应商模块的职责边界
通用内核镜像由 Google 统一构建,包含内核核心、调度器、内存管理、文件系统、网络协议栈以及通用驱动框架。它不包含任何 SoC 专属的驱动代码。供应商模块则负责所有与具体硬件相关的部分,例如显示控制器、摄像头传感器、电源管理 IC、时钟控制器、GPIO 扩展等。
| 对比项 | 通用内核镜像(GKI) | 供应商模块(Vendor Modules) |
|---|---|---|
| 维护方 | SoC 厂商 / OEM | |
| 构建与签名 | Google 统一构建并签名 | 供应商自行构建,随设备镜像签名 |
| 内容范围 | 内核核心、通用子系统、驱动框架 | SoC 驱动、板级驱动、外设驱动 |
| 升级方式 | 随 Android 平台或安全补丁独立升级 | 随设备 OTA 或供应商更新发布 |
| 与 KMI 的关系 | 导出 KMI 符号与结构体 | 只能使用 KMI 中导出的符号 |
| ABI 约束 | 保持 KMI 稳定,不破坏已有 ABI | 必须与目标 GKI 版本的 KMI 兼容 |
三、KMI 稳定接口与 ABI 兼容性要求
KMI 是 GKI 架构的“契约层”。它由两部分组成:一是导出的内核符号(symbol),二是这些符号所涉及的数据结构布局(struct layout)。ABI 兼容性要求意味着:当 GKI 内核升级时,KMI 中已有符号的名称、参数类型、返回值类型以及相关结构体的字段顺序、大小、对齐方式都不能发生破坏性变化。
Android 提供了 ABI 监控工具来检查这种兼容性。常见的检查命令如下:
# 查看当前内核导出的 KMI 符号
adb shell cat /proc/kallsyms | grep -i "kmi"
# 使用 ABI 工具比对两个 GKI 版本的符号与结构体
./abi_check --reference v1.0 --target v1.1 \
--symbol-list android/abi_gki_aarch64 \
--report abi_diff_report.txt
# 查看供应商模块依赖的符号是否都在 KMI 白名单中
modinfo vendor_display.ko | grep depends
Unknown symbol 或 disagrees about version of symbol 错误。这类问题必须在集成阶段通过 ABI 检查提前发现。
四、典型场景与排障思路
假设某设备从 GKI 内核 v1.0 升级到 v1.1,供应商的摄像头模块在启动时加载失败,日志如下:
[ 3.482100] vendor_camera: loading out-of-tree module taints kernel
[ 3.482355] vendor_camera: Unknown symbol v4l2_subdev_call_v2 (err -2)
[ 3.482601] vendor_camera: module verification failed: signature and/or required key missing
排障时可按以下顺序进行:
- 确认模块依赖的符号是否在目标 GKI 的 KMI 白名单中,若不在,需要供应商改用稳定接口或申请新增符号。
- 检查模块编译时使用的内核头文件版本是否与目标 GKI 一致,避免结构体布局错位。
- 使用 ABI 比对工具生成差异报告,定位是符号缺失还是结构体字段变化。
- 若为签名问题,确认模块是否使用与设备匹配的密钥签名,并检查
CONFIG_MODULE_SIG_FORCE配置。
modules.load 或 vendor_boot 中的模块列表在启动时加载。
总结来看,GKI 通过“通用内核 + 供应商模块 + KMI 稳定接口”三层结构,把内核升级与硬件适配解耦。理解 KMI 的边界与 ABI 兼容性要求,是设备树与启动适配工作中必须掌握的基础能力。只有确保供应商模块严格依赖 KMI 白名单符号,才能在 GKI 内核升级时保持设备稳定启动。