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.bpSoong 的模块定义文件,声明模块名、类型、源文件、依赖每个模块目录下均可存在
Android.mk旧版 Make 构建文件,仍被部分模块使用与 Android.bp 共存或逐步迁移
Makefile顶层 Make 入口,最终调用 Soong 与 Katimake 或 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 源码树中四类核心对象的分层与引用关系:

AOSP 源码树分层与构建关系 顶层文件与入口 envsetup.sh · Android.bp · Android.mk · Makefile build/ 构建规则层 soong/ · make/core/ · envsetup.sh · target/ 解析 Android.bp → 生成 Ninja → 打包镜像 device/ 设备层 AndroidProducts.mk BoardConfig.mk · device.mk init/ · sepolicy/ vendor/ 厂商层 HAL 实现 · 固件 预编译 so 库 vendor/<厂商>/<平台>/ 引用 out/ 编译输出 system.img · vendor.img · boot.img · userdata.img