3. GKI 架构解析

GKI(Generic Kernel Image,通用内核镜像)是 Android 从 Android 11 开始正式推行的内核交付模型。它的核心目标是把内核中与 SoC、板级硬件强相关的部分,从内核核心中剥离出来,形成“Google 维护的通用内核 + 供应商维护的模块”两层结构。这样 Android 平台升级时,内核核心可以独立更新,而供应商只需保证自己的模块与 KMI 稳定接口兼容,从而显著降低碎片化、缩短安全补丁落地周期。

GKI 不是“一个内核文件”,而是一套约束:通用内核镜像由 Google 构建并签名,供应商模块以 .ko 形式在启动时加载,二者之间只能通过 KMI(Kernel Module Interface)稳定接口交互。

一、GKI 的分层结构

理解 GKI,最有效的方式是看它的分层与依赖关系。下图展示了从硬件到 Android 框架的纵向结构:最底层是 SoC 与板级硬件,其上是供应商模块(vendor modules),再上是 KMI 稳定接口,最上层是 Google 提供的通用内核镜像与 Android 平台。

GKI 分层架构与依赖关系 Android 平台 / Framework 通过系统调用与内核交互,不直接依赖供应商模块 通用内核镜像 GKI(boot.img / kernel) Google 构建、签名、维护;包含核心子系统、调度、内存、驱动框架 版本随 Android 平台升级,不随 SoC 变化 KMI 稳定接口(符号表 + 结构体 ABI) GKI 与供应商模块之间的唯一契约,受 ABI 兼容性约束 供应商模块(vendor modules,.ko) SoC 驱动、外设驱动、电源/时钟/引脚控制等板级相关代码 由供应商编译,随设备镜像发布,启动时加载 SoC 与板级硬件 CPU、GPU、ISP、Modem、传感器、存储等物理器件 依赖方向

从图中可以看出,GKI 的关键在于“中间层”——KMI。它既是通用内核暴露给供应商模块的符号与结构体集合,也是 ABI 兼容性检查的对象。供应商模块只能调用 KMI 中列出的符号,不能依赖未导出的内部实现。

二、通用内核镜像与供应商模块的职责边界

通用内核镜像由 Google 统一构建,包含内核核心、调度器、内存管理、文件系统、网络协议栈以及通用驱动框架。它不包含任何 SoC 专属的驱动代码。供应商模块则负责所有与具体硬件相关的部分,例如显示控制器、摄像头传感器、电源管理 IC、时钟控制器、GPIO 扩展等。

对比项 通用内核镜像(GKI) 供应商模块(Vendor Modules)
维护方 Google 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
如果供应商模块使用了未列入 KMI 白名单的符号,或者依赖了某个结构体的内部字段,那么当 GKI 升级后,模块可能无法加载,表现为 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

排障时可按以下顺序进行:

  1. 确认模块依赖的符号是否在目标 GKI 的 KMI 白名单中,若不在,需要供应商改用稳定接口或申请新增符号。
  2. 检查模块编译时使用的内核头文件版本是否与目标 GKI 一致,避免结构体布局错位。
  3. 使用 ABI 比对工具生成差异报告,定位是符号缺失还是结构体字段变化。
  4. 若为签名问题,确认模块是否使用与设备匹配的密钥签名,并检查 CONFIG_MODULE_SIG_FORCE 配置。
GKI 适配中,最常见的误区是“把供应商模块当成内核的一部分来编译”。正确做法是:供应商模块必须作为独立模块编译,只引用 KMI 导出的符号,并通过 modules.load 或 vendor_boot 中的模块列表在启动时加载。

总结来看,GKI 通过“通用内核 + 供应商模块 + KMI 稳定接口”三层结构,把内核升级与硬件适配解耦。理解 KMI 的边界与 ABI 兼容性要求,是设备树与启动适配工作中必须掌握的基础能力。只有确保供应商模块严格依赖 KMI 白名单符号,才能在 GKI 内核升级时保持设备稳定启动。