Android内核驱动开发基础 - 第3节
3.1 AOSP 源码下载与内核源码获取
Android 内核驱动开发的第一步是获取完整的 Android 源码树(AOSP)以及独立的内核源码。AOSP 仓库包含了构建 Android 系统所需的所有组件,而内核源码则位于 kernel/ 目录下,按芯片平台分仓管理。
3.1.1 环境准备与 repo 工具
AOSP 源码体积庞大(通常超过 50GB),Google 使用 repo 工具对数百个 Git 仓库进行统一管理。repo 本身是一个 Python 脚本,底层封装了 Git 操作。
安装 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
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 内核源码树的顶层模块组织关系,以及驱动开发者在各目录中的主要关注点:
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
prebuilts/gcc/linux-x86/aarch64/ 目录下已包含 Google 验证过的交叉编译器,推荐优先使用,避免版本兼容问题。
3.3.2 内核配置与编译流程
编译内核的标准流程分为三步:配置 → 编译 → 打包。以下以 ARM64 架构为例:
- 清理旧配置和编译产物
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- distclean
- 生成默认配置(基于
arch/arm64/configs/下的 defconfig)
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- defconfig
- 自定义内核配置(可选,用于启用/禁用驱动模块)
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- menuconfig
- 编译内核镜像
# 编译 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)
- 编译设备树(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 图
下图展示了从源码到最终启动镜像的完整编译流水线:
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 构建系统会自动检测内核源码变更并触发增量编译,大幅缩短迭代周期。