3. GKI架构总览
GKI(Generic Kernel Image,通用内核镜像)是 Android 为解决内核碎片化而提出的工程方案。它的核心思想是:把与 SoC、板级硬件强相关的驱动从内核主体中剥离出去,让 Google 维护一份可跨设备复用的内核镜像,而设备厂商只提供可动态加载的供应商模块。理解 GKI,必须同时看清三件事:GKI1 与 GKI2 的演进差异、通用内核镜像与供应商模块的边界划分、以及 KMI 稳定接口如何充当两者之间的契约。
一、核心原理:为什么要拆分内核
在 GKI 之前,每台 Android 设备的内核都是厂商基于某个 LTS 版本自行裁剪、打补丁、加驱动的结果。结果是:同一个安全补丁要适配几十上百个内核分支,升级周期长、验证成本高。GKI 的做法是把内核切成两层:
- 通用内核镜像(GKI):由 Google 基于 Android Common Kernel 构建,包含调度、内存管理、文件系统、网络协议栈、电源管理等核心子系统,以及少量通用驱动。
- 供应商模块(Vendor Modules):以
.ko形式存在,包含 SoC 相关驱动、显示、摄像头、音频、存储、充电等硬件强相关代码,由厂商编译并随设备发布。
两者通过 KMI(Kernel Module Interface)稳定接口连接。KMI 是一组被冻结的符号与结构体 ABI,只要厂商模块只依赖 KMI 中的符号,就能在 Google 发布的新 GKI 镜像上继续加载,从而实现“内核升级、模块不动”。
二、GKI1 与 GKI2 的区别
GKI1 是 Android 11 引入的过渡方案,GKI2 是 Android 13 起全面推行的成熟方案。二者最本质的差别在于“模块化程度”和“接口稳定性保障方式”。
| 对比维度 | GKI1 | GKI2 |
|---|---|---|
| 引入版本 | Android 11(5.4 内核) | Android 13 起(5.10/5.15/6.1 等) |
| 模块化范围 | 部分驱动仍编入内核,模块边界不彻底 | 绝大多数硬件驱动强制以模块形式存在 |
| KMI 保障 | 符号列表较宽松,ABI 监控不完整 | 严格冻结 KMI,提供 ABI 监控与符号列表校验 |
| 模块签名 | 支持,但校验策略较松 | 强制模块签名,未签名模块无法加载 |
| 升级方式 | 常需与厂商模块同步升级 | GKI 可独立升级,模块保持兼容 |
| 典型内核版本 | android11-5.4 | android13-5.10、android14-6.1 |
一句话概括:GKI1 是“内核开始通用化”,GKI2 是“内核与模块彻底解耦,并用 KMI 把接口冻结成契约”。
三、通用内核镜像与供应商模块的边界
边界划分是 GKI 工程中最容易出错的地方。判断一个驱动该放在哪一侧,可以遵循以下原则:
- 是否与具体 SoC 型号强绑定?是则放入供应商模块。
- 是否被多个 SoC 平台共用且接口稳定?是则可留在 GKI。
- 是否需要在启动极早期(如中断控制器、定时器)使用?这类通常留在 GKI 或作为 built-in。
- 是否依赖未冻结的私有符号?若依赖,则必须改为模块并只使用 KMI 符号。
下面是一个典型的模块加载与边界示意:
# 查看当前设备已加载的供应商模块
adb shell lsmod | grep -E "vendor|wlan|touch|charger"
# 查看模块依赖的 KMI 符号
adb shell modinfo /vendor/lib/modules/wlan.ko | grep depends
# 校验模块签名
adb shell dmesg | grep -i "module verification"
如果厂商模块引用了非 KMI 符号,加载时会报 Unknown symbol 或 disagrees about version of symbol,这正是边界被破坏的信号。
四、KMI 稳定接口概念
KMI 不是某个具体文件,而是一组被 Android 官方冻结的符号集合与数据结构 ABI。它由符号列表(symbol list)和 ABI 描述共同定义。Google 在每个 GKI 内核版本中发布 abi_gki_aarch64 等文件,列出允许被模块引用的符号。
- 符号冻结:KMI 中的函数、变量、结构体布局在同一个 GKI 大版本内不允许破坏性变更。
- ABI 监控:通过
abi-monitor、stgdiff等工具对比新旧内核的 ABI,发现不兼容立即拦截。 - 模块签名:模块必须用与 GKI 匹配的密钥签名,防止任意模块注入内核。
- 版本兼容:同一 KMI 版本内,GKI 可独立升级,模块无需重新编译。
KMI 的稳定性是“向后兼容”而非“永不变化”。当必须新增符号时,通过扩展符号列表实现;破坏性修改则要等到下一个 GKI 大版本。
五、案例与场景:一次 GKI 升级
假设某设备使用 android13-5.10 GKI,厂商提供了 display.ko、touch.ko、wlan.ko。当 Google 发布 5.10 的安全补丁 GKI 镜像时:
- 厂商无需重新编译模块,直接替换 GKI 镜像。
- 启动时内核加载原有
.ko,KMI 符号匹配成功。 - 若新 GKI 中某个 KMI 符号被移除,模块加载失败,需回退或等待厂商适配。
这正是 GKI2 的价值:把“内核升级”从“整机适配”降级为“镜像替换 + 兼容性验证”。
六、常见误区与复盘
- 误区一:GKI 就是 AOSP 内核。 GKI 是 Android Common Kernel 的构建产物,包含 Android 特定补丁,不等同于上游 LTS。
- 误区二:所有驱动都必须做成模块。 启动早期必需的驱动仍可 built-in,关键是不得破坏 KMI 边界。
- 误区三:KMI 冻结等于不能加符号。 可以新增,但不能删除或改变已有符号的 ABI。
- 误区四:模块签名只是形式。 未签名或签名不匹配的模块会被内核直接拒绝加载。
排障提示:若设备升级 GKI 后出现 Unknown symbol、module verification failed 或开机卡在 vendor 分区,优先检查模块是否只依赖 KMI 符号、签名是否匹配、以及模块是否被错误地编入 GKI。
总结来看,GKI 架构的本质是一次“内核接口治理”:GKI1 完成了镜像通用化的第一步,GKI2 通过严格 KMI 冻结和模块签名把通用内核与供应商模块彻底解耦。掌握边界划分原则与 KMI 符号规则,才能在升级、排障和模块开发中做出正确判断。