1. 内核编译概述:Android内核源码结构、内核版本与GKI、编译环境基本要求

Android 内核编译是嵌入式系统开发和系统定制的基础环节。本章从源码结构、版本演进与编译环境三个维度,帮助开发者建立对 Android 内核编译的整体认知。

1.1 Android 内核源码结构

Android 内核基于 Linux 主线内核,但增加了大量面向移动设备的驱动、框架与安全模块。其源码仓库通常包含以下核心目录:

目录/文件 说明
arch/ 体系结构相关代码,如 arm64、x86、riscv
block/ 块设备 I/O 调度层
drivers/ 设备驱动,包括 Android 特有的 binder、ashmem、ion 等
fs/ 文件系统,如 ext4、f2fs、sdcardfs
kernel/ 核心调度、进程管理、锁机制
net/ 网络协议栈,包含 Android 网络过滤与 VPN 支持
sound/ 音频子系统
security/ SELinux、密钥管理、加密模块
android/ Android 专用补丁与 GKI 框架层
Makefile 顶层构建入口,定义编译目标与配置
提示: 在独立编译内核模块时,最常打交道的目录是 drivers/ 和 include/。模块代码通常放在 drivers/staging/ 或自定义目录中,通过 Kconfig 和 Makefile 接入构建系统。

1.2 内核版本与 GKI(通用内核映像)

Android 内核版本管理经历了从碎片化到统一化的演进。GKI(Generic Kernel Image)是 Google 在 Android 11 之后推行的内核标准化方案,其核心思想是将内核核心与设备驱动解耦。

Android 内核版本演进与 GKI 架构 传统内核(碎片化) 厂商定制驱动 板级配置 内核核心 + 补丁 演进 GKI 内核(统一化) 通用内核核心 GKI 框架层 可加载模块接口 厂商模块 A 厂商模块 B GKI 将内核核心与厂商驱动分离,厂商通过标准接口加载模块,无需修改内核核心代码。 内核版本号格式:android-5.10-xxx 表示基于 Linux 5.10 的 GKI 内核。

GKI 带来的关键变化:

  • 内核核心统一:所有设备共享同一个内核二进制,Google 负责核心维护。
  • 模块化驱动:厂商驱动以可加载模块形式存在,通过 modprobe 动态加载。
  • ABI 稳定性:GKI 定义了稳定的内核模块接口(KMI),模块跨内核小版本兼容。
  • 版本命名:例如 android14-6.1 表示 Android 14 基于 Linux 6.1 的 GKI 内核。
注意: 如果你的目标设备是 Android 12 及以上,强烈建议基于 GKI 内核进行模块开发。非 GKI 内核(如 Android 10 及更早)的模块编译方式差异较大,需要额外处理板级头文件。

1.3 编译环境基本要求

独立编译 Android 内核模块需要一套精简但完整的工具链与环境配置。以下是核心要求清单:

组件 要求 说明
操作系统 Ubuntu 20.04 / 22.04 LTS 推荐 x86_64 架构,WSL2 也可用
交叉编译工具链 Clang/LLVM 14+ 或 GCC arm64 Google 推荐使用 Clang,可从 AOSP 预编译工具链获取
内核源码 对应设备的内核树 从 android.googlesource.com 或厂商仓库克隆
内核构建配置 defconfig 或 gki_defconfig 需与目标设备内核配置一致
依赖软件包 build-essential, flex, bison, libssl-dev, libncurses-dev 用于内核配置与编译的基础工具
Python 3 3.8+ 内核构建脚本依赖
环境验证命令:
# 检查工具链版本
clang --version
aarch64-linux-gnu-gcc --version

# 检查内核源码树
ls -la kernel/  # 应包含 Makefile、Kconfig、arch/ 等

# 检查依赖包
dpkg -l | grep -E "build-essential|flex|bison|libssl-dev|libncurses-dev"

1.4 编译流程概览

一个典型的内核模块独立编译流程包含以下步骤:

  1. 准备内核源码树:克隆或解压对应版本的内核源码。
  2. 配置内核:使用 make defconfig 或加载目标设备的 .config 文件。
  3. 编译内核核心(可选):生成 vmlinux 和模块依赖。
  4. 编写模块代码:创建 hello.c、Kconfig、Makefile。
  5. 编译模块:使用 make M=drivers/staging/hello 独立编译。
  6. 部署与测试:将 .ko 文件推送到设备,使用 insmod 加载。
内核模块独立编译流程 准备源码树 配置内核 编译核心 编写模块 编译模块 部署测试 虚线表示:模块编译依赖内核核心的 Module.symvers 和头文件,但不需要完整重新编译内核。 独立编译的核心命令:make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- M=path/to/module

1.5 常见问题与避坑

  • 内核版本不匹配:模块必须与目标设备运行的内核版本完全一致,否则 insmod 会报 Invalid module format。
  • 缺少 Module.symvers:如果只编译模块而不先编译内核核心,需要从预编译内核中提取该文件,否则模块可能无法正确链接符号。
  • 头文件路径错误:确保 KERNEL_SRC 环境变量指向正确的内核源码树,且 include/ 目录包含所有必要的头文件。
  • GKI 模块签名:Android 12+ 的 GKI 内核要求模块经过签名才能加载,开发阶段可通过关闭 CONFIG_MODULE_SIG 绕过。
最佳实践: 在开始模块开发前,先使用 make kernelrelease 确认内核版本,并用 modinfo 检查目标设备上已有模块的编译参数,确保环境一致。