4. 源码目录结构
AOSP 的源码树是一个“分层协作”的工程体系:顶层目录并不是随意堆放,而是按照“构建系统—平台框架—系统服务—硬件适配—厂商定制—内核”的职责边界划分。理解这些目录的作用与组织逻辑,是后续编译、裁剪、移植和排障的基础。只有先建立目录地图,才能在几十 GB 的源码中快速定位问题。
一、核心原理:AOSP 目录的职责分层
AOSP 顶层目录大致可以按“构建—框架—系统—适配—内核”五层理解。每一层都有明确的输入输出关系:构建系统负责把各层源码组织成镜像;框架层提供 Java/C++ API;系统层提供 native 服务与运行时;适配层描述具体硬件;内核层提供驱动与平台支持。
- build/:构建规则、产品配置、镜像打包脚本,是“编译入口”。
- frameworks/:Android 框架层,包含 Java API、系统服务、UI 框架等。
- system/:native 系统组件,如 init、logd、netd、binder、libcutils 等。
- vendor/:厂商私有实现,通常存放闭源 HAL、驱动和定制服务。
- device/:具体设备的产品配置、BoardConfig、HAL 声明和 overlay。
- kernel/:Linux 内核源码、配置和 DTB,部分平台也放在 device 下。
这些目录之间不是孤立的,而是通过 Android.bp、Android.mk、BoardConfig.mk、device.mk 等文件相互引用。构建系统根据产品配置决定“编译哪些模块、生成哪些镜像、使用哪些 HAL”。
二、方法流程:从产品配置到镜像生成
理解目录结构后,需要把它和实际编译流程对应起来。典型流程如下:
- 选择产品:
lunch aosp_arm64-userdebug,该产品由device/下的AndroidProducts.mk定义。 - 加载配置:读取
BoardConfig.mk、device.mk,确定架构、分区、HAL 和模块列表。 - 解析构建规则:Soong 读取
Android.bp,Make 读取Android.mk,生成构建图。 - 编译模块:frameworks、system、vendor 中的模块按依赖关系编译。
- 打包镜像:build 目录中的脚本把产物打包为
system.img、vendor.img、boot.img等。
# 典型产品配置入口
device/<vendor>/<device>/
├── AndroidProducts.mk
├── BoardConfig.mk
├── device.mk
├── vendorsetup.sh
├── overlay/
└── sepolicy/
# 编译命令
source build/envsetup.sh
lunch aosp_arm64-userdebug
make -j8
可以看到,device/ 是“产品定义中心”,build/ 是“构建执行中心”,而 frameworks/、system/、vendor/ 则是被组织和编译的“内容层”。
三、案例场景:新增一个自定义 HAL 模块
假设要为某设备新增一个自定义 HAL,并让它被系统正确加载。目录操作通常如下:
- 在
vendor/<vendor>/<platform>/hal/下实现 HAL 服务与Android.bp。 - 在
device/<vendor>/<device>/device.mk中加入PRODUCT_PACKAGES += my.hal.service。 - 在
device/<vendor>/<device>/manifest.xml中声明 HAL 接口。 - 在
device/<vendor>/<device>/sepolicy/中补充 SELinux 规则。 - 若涉及内核驱动,在
kernel/或device/<vendor>/<device>/kernel/中修改 defconfig 和 DTS。
这个案例说明:一个功能往往同时跨越 vendor/、device/、kernel/ 和 build/ 多个目录。只改一个目录通常无法完成完整适配。
四、误区与复盘:常见目录理解偏差
初学者容易把 vendor/ 和 device/ 混为一谈。实际上,device/ 更偏向“产品与板级配置”,vendor/ 更偏向“厂商私有实现”。另一个常见误区是认为 frameworks/ 只包含 Java 代码,实际上它还包含 native 服务、JNI、图形和多媒体框架。
| 目录 | 核心职责 | 典型文件 | 常见误区 |
|---|---|---|---|
| build/ | 构建规则与镜像打包 | envsetup.sh、core/、soong/ | 误以为只放编译脚本 |
| frameworks/ | Java/C++ 框架与系统服务 | base/、native/、av/ | 误以为只有 Java API |
| system/ | native 系统组件与运行时 | init、logd、netd、binder | 误以为等同于 system.img |
| vendor/ | 厂商私有 HAL 与驱动 | HAL 实现、闭源库 | 误以为所有设备都必须有 |
| device/ | 产品配置与板级适配 | BoardConfig.mk、device.mk | 误以为只放设备树 |
| kernel/ | Linux 内核与驱动 | defconfig、DTS、驱动源码 | 误以为一定在顶层 |
device/<vendor>/<device>/kernel/,vendor 也可能拆分为多个子目录。阅读源码时应以当前项目的实际结构为准,不要死记固定路径。
掌握这些目录的职责边界与协作关系后,后续进行产品配置、HAL 移植、内核适配和镜像裁剪时,就能快速判断“改哪里、为什么改、改完影响谁”。这是 AOSP 工程能力从“会编译”走向“能移植”的关键一步。