Android内核驱动开发基础 - 第3节

3.1 AOSP 源码下载与内核源码获取

Android 内核驱动开发的第一步是获取完整的 Android 源码树(AOSP)以及独立的内核源码。AOSP 仓库包含了构建 Android 系统所需的所有组件,而内核源码则位于 kernel/ 目录下,按芯片平台分仓管理。

3.1.1 环境准备与 repo 工具

AOSP 源码体积庞大(通常超过 50GB),Google 使用 repo 工具对数百个 Git 仓库进行统一管理。repo 本身是一个 Python 脚本,底层封装了 Git 操作。

⚠ 磁盘空间要求: 完整 AOSP 下载 + 编译至少需要 200GB 空闲磁盘空间,建议使用 ext4 文件系统,避免大小写不敏感的文件系统(如 NTFS)导致符号链接错误。

安装 repo 工具:

# 创建 bin 目录并加入 PATH
mkdir -p ~/bin
export PATH=~/bin:$PATH

# 下载 repo 脚本
curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
chmod a+x ~/bin/repo

# 验证安装
repo --version

3.1.2 下载 AOSP 主线源码

以 Android 14(代号 U)为例,下载流程如下:

# 创建工作目录
mkdir ~/aosp-14
cd ~/aosp-14

# 初始化 repo 并指定分支
repo init -u https://android.googlesource.com/platform/manifest -b android-14.0.0_r1

# 同步全部源码(耗时数小时,建议使用 -j4 控制并发)
repo sync -j4 -c --no-tags
💡 加速技巧: 国内开发者可使用清华镜像源或中科大镜像源替换 googlesource.com 域名,在 repo init 时添加 -m manifest.xml 参数指定镜像 manifest。

3.1.3 独立获取内核源码

内核源码在 AOSP 中按 kernel/<device> 路径组织。常见的内核仓库包括:

内核仓库 适用平台 Git 地址(AOSP)
kernel/common 通用内核基线 android/kernel/common
kernel/msm Qualcomm 平台 android/kernel/msm
kernel/exynos Samsung Exynos android/kernel/exynos
kernel/mediatek MediaTek 平台 android/kernel/mediatek

单独克隆内核仓库示例(以 common 内核为例):

git clone https://android.googlesource.com/kernel/common -b android-14.0.0_r1
⚠ 分支匹配: 内核分支必须与 AOSP 主分支版本严格对应,否则编译时可能出现 KMI(内核模块接口)不兼容或设备树不匹配的问题。

3.2 内核源码树结构解析

Android 内核基于 Linux LTS 版本,并叠加了 Android 特有的驱动、框架和安全性补丁。理解内核源码树的顶层目录结构是驱动开发的基本功。

3.2.1 顶层目录布局

以下为 Android 内核源码树的核心目录及其功能:

目录/文件 功能说明 驱动开发者关注点
arch/ 体系结构相关代码(arm64、x86、riscv 等) 板级设备树(dts)、启动汇编、内存布局
drivers/ 设备驱动子系统(char、i2c、spi、usb、gpio 等) 驱动模块开发的主战场
include/ 内核头文件(API 声明、数据结构、宏定义) 驱动接口与内核 API 参考
kernel/ 核心调度、进程管理、中断处理 驱动与内核核心的交互机制
mm/ 内存管理(页分配、slab、DMA 内存) DMA 缓冲区、ion 内存分配
fs/ 文件系统(ext4、f2fs、sdcardfs 等) 存储驱动、虚拟文件系统接口
net/ 网络协议栈(TCP/IP、bridge、netfilter) 网络驱动、WiFi/BT 驱动
sound/ 音频子系统(ALSA、ASoC) 音频驱动开发
Documentation/ 内核文档(设备树绑定、驱动 API 说明) 驱动开发规范参考
Makefile 顶层构建脚本 编译入口、架构选择、配置选项

3.2.2 内核源码树结构 SVG 图

下图展示了 Android 内核源码树的顶层模块组织关系,以及驱动开发者在各目录中的主要关注点:

Android 内核源码树顶层结构(驱动开发者视角) Kernel Root arch/ drivers/ include/ kernel/ mm/ 设备树 dts 驱动模块开发 内核 API 参考 中断/调度接口 DMA/ION 内存 📌 驱动开发者重点关注 drivers/、arch/arm64/boot/dts/、include/linux/

3.3 编译内核与生成 zImage/Image

Android 内核编译采用 交叉编译 方式,在 x86 主机上为目标 ARM64 或 ARM32 设备生成内核镜像。编译产物包括 Image(未压缩内核)、Image.gz(gzip 压缩)、zImage(传统 ARM 压缩格式)以及设备树 .dtb 文件。

3.3.1 编译环境配置

编译内核前需要安装必要的工具链和依赖库:

# 安装基础编译工具
sudo apt-get install -y git ccache automake flex lzop bison \
    gperf build-essential zip curl zlib1g-dev zlib1g-dev:i386 \
    lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z1-dev \
    libgl1-mesa-dev libxml2-utils xsltproc unzip

# 安装 ARM64 交叉编译工具链
sudo apt-get install -y gcc-aarch64-linux-gnu binutils-aarch64-linux-gnu

# 安装 ARM32 交叉编译工具链(如需要)
sudo apt-get install -y gcc-arm-linux-gnueabihf binutils-arm-linux-gnueabihf
💡 使用 Android 预编译工具链: AOSP 源码中 prebuilts/gcc/linux-x86/aarch64/ 目录下已包含 Google 验证过的交叉编译器,推荐优先使用,避免版本兼容问题。

3.3.2 内核配置与编译流程

编译内核的标准流程分为三步:配置 → 编译 → 打包。以下以 ARM64 架构为例:

  1. 清理旧配置和编译产物
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- distclean
  1. 生成默认配置(基于 arch/arm64/configs/ 下的 defconfig)
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- defconfig
  1. 自定义内核配置(可选,用于启用/禁用驱动模块)
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- menuconfig
  1. 编译内核镜像
# 编译 Image(未压缩)
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- Image -j$(nproc)

# 编译 Image.gz(gzip 压缩)
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- Image.gz -j$(nproc)

# 编译 zImage(ARM 传统压缩格式,仅 ARM32)
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage -j$(nproc)
  1. 编译设备树(DTB)
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- dtbs -j$(nproc)

3.3.3 编译产物说明

产物文件 路径 格式说明 典型用途
Image arch/arm64/boot/Image ELF 格式未压缩内核 QEMU 模拟、fastboot 直接启动
Image.gz arch/arm64/boot/Image.gz gzip 压缩内核 Android 设备标准启动镜像
zImage arch/arm/boot/zImage ARM 自解压格式 32 位 ARM 设备启动
*.dtb arch/arm64/boot/dts/ 设备树二进制文件 硬件描述信息,与内核一起加载
vmlinux 源码根目录 未压缩 ELF 内核(含调试符号) 内核调试、addr2line 解析

3.3.4 内核编译流程 SVG 图

下图展示了从源码到最终启动镜像的完整编译流水线:

Android 内核编译流水线(源码 → 启动镜像) ① 配置阶段 defconfig / menuconfig ② 编译阶段 make Image / zImage ③ 设备树编译 make dtbs ④ 打包启动镜像 mkbootimg / fastboot .config / autoconf.h Image / Image.gz / zImage *.dtb 设备树文件 boot.img / vendor_boot.img 🔧 关键编译变量 ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- O=out(指定输出目录)

3.3.5 编译常见问题与避坑

⚠ 常见编译错误及解决方案:
  • “No rule to make target 'Image'” — 未执行 defconfig 或 menuconfig,缺少 .config 文件。
  • “cc1: error: unknown ABI” — 交叉编译器与 ARCH 不匹配,ARM64 必须使用 aarch64-linux-gnu- 前缀。
  • “scripts/config: Permission denied” — 文件系统权限问题,检查是否在 NTFS 或 exFAT 分区上操作。
  • “Kernel panic - not syncing: VFS: Unable to mount root fs” — 内核缺少根文件系统驱动或设备树与硬件不匹配。

3.3.6 使用 AOSP 构建系统编译内核

在 AOSP 完整源码环境下,推荐使用 make bootimage 或 make vendor_bootimage 一键编译内核并打包到启动镜像中:

# 进入 AOSP 根目录
cd ~/aosp-14

# 设置编译环境
source build/envsetup.sh

# 选择目标设备(以 Pixel 6 为例)
lunch aosp_oriole-userdebug

# 编译内核并生成 boot.img
make bootimage -j$(nproc)

# 编译内核模块(如需要)
make modules -j$(nproc)

编译完成后,内核镜像位于 out/target/product/oriole/boot.img,内核二进制文件位于 out/target/product/oriole/obj/KERNEL_OBJ/arch/arm64/boot/Image。

💡 增量编译: 修改内核源码后,只需重新执行 make bootimage,AOSP 构建系统会自动检测内核源码变更并触发增量编译,大幅缩短迭代周期。

3.4 本章小结