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”。

AOSP 关键目录分层与组织逻辑 build/ 构建规则 · 产品配置 · 镜像打包 · Soong/Make 入口 frameworks/ Java API · 系统服务 · UI 框架 base / native / av / opt system/ init · logd · netd · binder · libcutils native 系统组件与运行时 vendor/ 厂商私有 HAL · 驱动 · 定制服务 通常闭源,按厂商/平台划分 device/ 产品配置 · BoardConfig · overlay HAL 声明与设备专属模块 kernel/ Linux 内核源码 · defconfig · DTB · 驱动与平台支持 构建系统按产品配置组织各层源码,最终生成 system/vendor/boot 等镜像

二、方法流程:从产品配置到镜像生成

理解目录结构后,需要把它和实际编译流程对应起来。典型流程如下:

  1. 选择产品:lunch aosp_arm64-userdebug,该产品由 device/ 下的 AndroidProducts.mk 定义。
  2. 加载配置:读取 BoardConfig.mk、device.mk,确定架构、分区、HAL 和模块列表。
  3. 解析构建规则:Soong 读取 Android.bp,Make 读取 Android.mk,生成构建图。
  4. 编译模块:frameworks、system、vendor 中的模块按依赖关系编译。
  5. 打包镜像: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/ 多个目录。只改一个目录通常无法完成完整适配。

提示:在 AOSP 中定位问题时,先判断问题属于“构建配置”“框架行为”“native 服务”“厂商实现”还是“内核驱动”,再进入对应目录,能显著减少无效搜索。

四、误区与复盘:常见目录理解偏差

初学者容易把 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、驱动源码 误以为一定在顶层
注意:不同芯片平台和 Android 版本会调整目录布局,例如 kernel 可能位于 device/<vendor>/<device>/kernel/,vendor 也可能拆分为多个子目录。阅读源码时应以当前项目的实际结构为准,不要死记固定路径。

掌握这些目录的职责边界与协作关系后,后续进行产品配置、HAL 移植、内核适配和镜像裁剪时,就能快速判断“改哪里、为什么改、改完影响谁”。这是 AOSP 工程能力从“会编译”走向“能移植”的关键一步。