2. Android源代码树概览
当你第一次执行 repo sync 拉取完整 AOSP 源码后,面对根目录下几十个文件夹,最容易产生的疑问是:哪个目录决定编译什么?哪个目录决定编译成什么样?哪个目录决定给哪台设备编译?理解 Android 源代码树的目录分工,是掌握 Soong 构建工程的第一步。本节从整体结构入手,重点讲清顶层文件、build/、device/、vendor/ 四类核心对象的职责与协作关系。
一、AOSP 根目录的整体分层
AOSP 源码树可以按“平台层—构建层—设备层—厂商层”四层来理解。平台层是 Android 系统本身的实现,构建层负责把源码变成镜像,设备层描述具体硬件,厂商层承载闭源或定制内容。它们不是并列的平级目录,而是存在明确的引用与依赖方向。
- 平台层:
frameworks/、system/、packages/、art/、libcore/、bionic/等,提供 Android 的核心能力。 - 构建层:
build/、soong/、tools/,定义编译规则、模块类型、镜像打包逻辑。 - 设备层:
device/,描述某款设备或某个参考平台的硬件配置与产品定义。 - 厂商层:
vendor/,存放芯片厂商、ODM/OEM 的专有代码、HAL 实现和预编译库。
此外还有 out/(编译输出)、prebuilts/(预编译工具链)、external/(第三方开源库)、cts/(兼容性测试套件)等辅助目录。它们围绕上述四层提供服务,但不改变构建主链路。
二、顶层文件:构建入口与全局开关
根目录下的几个文件是构建系统的“总控面板”,它们决定了环境初始化方式和编译目标选择。
| 顶层文件 | 作用 | 典型使用方式 |
|---|---|---|
envsetup.sh | 初始化构建环境,提供 lunch、m、mm 等命令 | source build/envsetup.sh |
build/envsetup.sh | 实际的环境脚本位置,根目录同名文件为兼容入口 | 被 source 后注册 shell 函数 |
Android.bp | Soong 的模块定义文件,声明模块名、类型、源文件、依赖 | 每个模块目录下均可存在 |
Android.mk | 旧版 Make 构建文件,仍被部分模块使用 | 与 Android.bp 共存或逐步迁移 |
Makefile | 顶层 Make 入口,最终调用 Soong 与 Kati | make 或 m 触发 |
其中 Android.bp 是 Soong 的核心配置文件。它使用 Blueprint 语法,声明式地描述模块,例如:
cc_binary {
name: "hello_soong",
srcs: ["hello.cpp"],
shared_libs: ["liblog"],
}
这段配置告诉 Soong:生成一个名为 hello_soong 的可执行文件,源文件是 hello.cpp,并链接 liblog。Soong 会解析所有 Android.bp,生成 Ninja 构建图,最终由 Ninja 执行编译。
三、build 目录:构建规则的“大脑”
build/ 是 AOSP 构建系统的核心,它不包含 Android 业务代码,而是定义“如何编译”。主要子目录包括:
build/soong/:Soong 构建系统实现,负责解析Android.bp并生成 Ninja 文件。build/make/:传统 Make 构建逻辑,包含core/、target/、tools/等。build/envsetup.sh:环境初始化脚本,定义lunch等命令。build/target/:产品配置模板,如product_config.mk。build/make/core/:核心 Makefile,定义镜像打包、模块安装规则。
构建时,lunch 命令会读取 device/ 和 vendor/ 中的产品配置,确定 TARGET_PRODUCT、TARGET_DEVICE、TARGET_BUILD_VARIANT 等变量,然后 Soong 与 Kati 协同工作,生成 out/ 下的构建产物。
关键理解:build/ 是“规则层”,它不关心具体设备,只提供通用的编译、链接、打包能力。设备差异通过变量和配置文件注入。
四、device 与 vendor:设备差异的承载者
device/ 和 vendor/ 是 AOSP 中与具体硬件绑定最紧密的两个目录,它们共同决定“为哪台设备、编译出什么产品”。
device/ 通常按厂商和设备名组织,例如 device/google/coral/ 对应 Pixel 4。它包含:
AndroidProducts.mk:声明该设备支持的产品配置。BoardConfig.mk:板级配置,定义内核、分区、编译选项。device.mk:设备模块清单,声明要安装的包和库。init/、sepolicy/:初始化脚本与 SELinux 策略。
vendor/ 则存放厂商闭源组件,例如高通、联发科的 HAL 实现、固件、预编译 so 库。它通常以 vendor/<厂商>/<平台>/ 组织。device 与 vendor 的关系可以概括为:device 定义“产品长什么样”,vendor 提供“产品跑起来需要的专有件”。
# 典型 lunch 选择
lunch aosp_coral-userdebug
# 对应解析结果
TARGET_PRODUCT=aosp_coral
TARGET_DEVICE=coral
TARGET_BUILD_VARIANT=userdebug
五、四者协作关系与常见误区
把四类对象串起来看:顶层文件提供入口,build/ 提供规则,device/ 提供产品定义,vendor/ 提供专有实现。构建时,lunch 读取 device 与 vendor 中的配置,注入到 build 系统的变量中,Soong 再根据所有 Android.bp 生成构建图。
常见误区:把 device/ 和 vendor/ 混为一谈。device 是 AOSP 可公开的产品配置,vendor 往往包含闭源内容;device 可以引用 vendor,但 vendor 不应反向依赖 device 的具体产品名。另一个误区是认为 Android.bp 可以写在任意位置却不需要注册——实际上 Soong 会自动扫描源码树中的 Android.bp,但模块名必须全局唯一。
下面这张图展示了 AOSP 源码树中四类核心对象的分层与引用关系: