4. Android内核源码结构:内核源码目录树解析
Android 内核基于长期支持(LTS)版本的 Linux 内核,并在此基础上增加了大量面向移动设备、硬件抽象层(HAL)和 Android 特有驱动(如 Binder、ashmem、ion)的补丁。理解内核源码的目录结构,是进行内核裁剪、驱动开发和调试的基础。
4.1 内核源码顶层目录树
在完成内核源码下载后(通常位于 kernel/ 或 common/ 目录),顶层目录结构如下表所示。每个目录都承载着特定的功能模块。
| 目录/文件 | 功能描述 | Android 工程中的关键性 |
|---|---|---|
arch/ |
体系结构相关代码,包含 CPU 调度、内存管理、中断等底层实现 | 极高:决定内核支持哪些 SoC 架构 |
block/ |
块设备层 I/O 调度与请求处理 | 中:影响存储性能 |
crypto/ |
内核加密 API,支持硬件加速 | 中:用于文件加密(FBE/FDE) |
drivers/ |
设备驱动集合,占源码体积最大 | 极高:Android 硬件适配的核心 |
fs/ |
文件系统实现(ext4、f2fs、sdcardfs 等) | 高:f2fs 和 sdcardfs 是 Android 特色 |
include/ |
内核头文件,定义 API 与数据结构 | 极高:驱动开发必须引用 |
init/ |
内核初始化流程(main.c) | 高:启动顺序调试入口 |
kernel/ |
核心调度、进程管理、锁机制 | 极高:系统稳定性的基石 |
mm/ |
内存管理(页分配、SLAB、VMA) | 高:低内存场景优化关键 |
net/ |
网络协议栈(Wi-Fi、蓝牙、蜂窝) | 高:无线通信基础 |
sound/ |
音频子系统(ALSA) | 中:音频通路调试 |
security/ |
安全模块(SELinux、KEYS) | 极高:Android 安全模型强制依赖 |
scripts/ |
编译脚本、配置工具、DT 编译工具 | 中:编译环境配置 |
Makefile |
顶层构建文件,定义编译入口 | 极高:编译命令的起点 |
Kconfig |
内核配置菜单的顶层描述 | 高:make menuconfig 的根节点 |
实践提示: 在 Android 通用内核(ACK)中,
common/ 目录下还包含 android/ 子目录,用于存放 Android 特有的内核补丁和 vendor/ 模块钩子。这是与上游 Linux 内核最直观的差异点。
4.2 arch/arm64 与 arch/x86 目录解析
arch/ 目录是内核移植的核心。Android 设备目前以 arm64(AArch64)为主流,x86 主要用于模拟器和部分 Chromebook。两个目录的结构高度对称,但实现细节差异巨大。
4.2.1 目录结构对比
| 子目录/文件 | arch/arm64 说明 | arch/x86 说明 |
|---|---|---|
boot/ |
生成 Image.gz、dts 打包 | 生成 bzImage,传统 BIOS/UEFI 启动 |
configs/ |
提供 defconfig(如 gki_defconfig) |
提供 i386_defconfig、x86_64_defconfig |
include/ |
asm 头文件,页表、系统寄存器定义 | asm 头文件,分段、分页、MSR 定义 |
kernel/ |
异常向量表、CPU 休眠、SMP 启动 | 系统调用入口、APIC、MCE 处理 |
mm/ |
4K/16K/64K 页表、透明大页 | PAE、PAT、ioremap 实现 |
lib/ |
memcpy、cache 操作优化 | string 操作、checksum 优化 |
Kconfig |
ARM64 特有配置(页大小、虚拟化) | x86 特有配置(MTRR、微码) |
4.2.2 arm64 启动入口关键文件
对于 Android 设备,arch/arm64 的启动流程集中在以下文件中:
- head.S:内核入口点,设置页表、使能 MMU、跳转到
start_kernel。 - entry.S:异常向量表,处理同步/异步异常、系统调用。
- smp.c:多核启动协议(PSCI 实现)。
- cpu_ops.c:CPU 操作函数表,支持 spin-table 和 PSCI。
关键差异: arm64 依赖设备树(DT)传递硬件信息,而 x86 依赖 ACPI。在 Android GKI 2.0 中,强制要求 arm64 设备使用设备树叠加层(DTO)来分离 SoC 与板级配置。
4.3 drivers/ 与 kernel/ 核心目录
drivers/ 和 kernel/ 是内核工程中修改最频繁的两个目录。前者负责硬件交互,后者负责系统核心机制。
4.3.1 drivers/ 目录:硬件适配的主战场
drivers/ 包含数百个子目录,每个对应一类设备。Android 工程中重点关注以下子目录:
| 子目录 | 驱动类型 | Android 典型场景 |
|---|---|---|
staging/android/ |
Android 特有驱动 | Binder、ashmem、ion、lowmemorykiller |
input/ |
输入子系统 | 触摸屏、按键、传感器 |
gpio/ |
GPIO 控制器 | 外设控制、中断唤醒 |
pinctrl/ |
引脚复用控制 | SoC 引脚功能配置 |
regulator/ |
电压调节器 | CPU 动态调压、外设供电 |
clk/ |
时钟框架 | CPU/总线频率缩放 |
i2c/ |
I2C 总线 | 连接摄像头、传感器、PMIC |
spi/ |
SPI 总线 | 显示屏、NFC 控制器 |
dma/ |
DMA 引擎 | 音视频数据搬运 |
media/ |
多媒体驱动 | Camera、Codec、ISP |
power/ |
电源管理 | suspend/resume、wakeup source |
4.3.2 kernel/ 目录:系统核心机制
kernel/ 目录虽然代码量不如 drivers/,但决定了系统的调度、同步和进程管理行为。Android 工程中常涉及以下文件:
- sched/:调度器核心,CFS、RT 调度、EAS(能耗感知调度)——Android 对 EAS 有深度定制。
- locking/:锁机制(spinlock、mutex、rwlock),死锁检测(lockdep)。
- power/:suspend/resume 流程、wakeup count、autosleep。
- cgroup/:控制组,Android 用于 CPU/内存/IO 的资源隔离。
- printk/:内核日志系统,调试 Android 启动和驱动问题的一线工具。
调试注意: 在 Android 内核中,
kernel/printk/printk.c 经常被修改以调整日志缓冲区大小和级别。如果遇到 dmesg 日志丢失,首先检查 CONFIG_LOG_BUF_SHIFT 配置。
4.4 内核源码结构总览图
下图展示了 Android 内核源码的核心目录关系,以及从架构代码到驱动、核心机制的调用链路。
4.5 关键文件与配置示例
在实际工程中,开发者需要频繁查阅和修改以下文件。这里给出一个典型的 Android 内核配置与编译流程示例:
# 1. 进入内核源码根目录
cd kernel/common/
# 2. 查看 arm64 架构的默认配置
ls arch/arm64/configs/
# 输出示例: gki_defconfig vendor_defconfig
# 3. 加载 GKI 默认配置
make ARCH=arm64 gki_defconfig
# 4. 通过菜单界面微调配置
make ARCH=arm64 menuconfig
# 在菜单中导航到:
# -> Device Drivers
# -> Staging drivers
# -> Android
# [*] Binder IPC Driver
# 5. 查看最终生效的配置项
grep -E "CONFIG_ANDROID|CONFIG_BINDER" .config
# 输出示例:
# CONFIG_ANDROID=y
# CONFIG_ANDROID_BINDER_IPC=y
# CONFIG_ANDROID_BINDERFS=y
工程要点: 在 Android GKI 2.0 架构下,
gki_defconfig 是 Google 强制要求的基础配置。OEM 厂商必须在此基础上叠加 vendor_defconfig,且不能修改 GKI 核心配置项。违反此规则会导致设备无法通过 CTS/VTS 认证。
4.6 本章小结
- 顶层目录:
arch/、drivers/、kernel/是 Android 内核工程的三大核心目录,分别对应体系结构、硬件驱动和系统机制。 - arch/arm64 vs x86:arm64 依赖设备树(DT),x86 依赖 ACPI;arm64 的启动入口在
head.S,x86 在startup_32/64。 - drivers/:
staging/android/是 Android 特有驱动的聚集地,Binder 和 ion 是最高频的修改对象。 - kernel/:
sched/和power/是能效优化的核心,cgroup/是资源隔离的基础。 - 配置管理:使用
make menuconfig和.config文件进行内核功能裁剪,GKI 架构下需严格遵守基础配置不可变原则。