2. AOSP 源码结构:源码根目录结构、关键目录的作用

好,咱们正式开始看代码了。不过别急,先别一头扎进某个文件里。我刚开始接触AOSP时,第一反应就是直接翻 frameworks/base 的代码,结果被目录结构绕晕了。后来我才明白——先看懂根目录下每个文件夹是干嘛的,比什么都重要

说白了,AOSP 源码根目录就像一个大仓库。每个文件夹负责一类活。你只要知道哪个目录管什么,遇到问题就知道去哪找答案。

2.1 根目录下都有什么?

你下载完 AOSP 源码后,在根目录执行 ls,会看到一堆文件夹。我挑几个最核心的说说:

  • build/ —— 构建系统的核心,所有编译逻辑都在这里
  • device/ —— 具体设备的配置和适配代码
  • vendor/ —— 厂商私有的二进制、驱动、库
  • hardware/ —— 硬件抽象层(HAL)和硬件相关的代码
  • frameworks/ —— Android 框架层,应用开发者最常接触的部分
  • packages/ —— 系统应用,比如设置、电话、短信
  • kernel/ —— Linux 内核(有些版本不直接包含)
  • external/ —— 第三方开源库,比如 SQLite、libpng
  • system/ —— 底层系统服务,比如 init、adb、logd
  • art/ —— Android Runtime,负责应用运行

嗯,这里要注意:不是所有目录你都会用到。比如你只做系统应用开发,那 frameworks 和 packages 才是你的主战场。但如果你是做系统移植或 BSP 开发,那 device、vendor、hardware 就是你的命根子。

2.2 build/ 目录:构建系统的发动机

这个目录,说白了就是整个 Android 编译的指挥中心。你执行 makem 命令时,背后就是 build/ 在调度一切。

我个人习惯,遇到编译问题先看 build/ 下的几个关键文件:

  • build/envsetup.sh —— 初始化环境,设置 lunchmmm 等命令
  • build/core/main.mk —— 构建入口,定义了整个编译流程
  • build/soong/ —— 新一代构建系统(替代了老旧的 Make),用 Blueprint 文件
  • build/make/ —— 传统的 Make 构建系统,现在逐渐被 Soong 取代

核心概念:AOSP 构建系统正在从 Make 迁移到 Soong。Soong 使用 .bp(Blueprint)文件,比 Make 更简洁、更易读。如果你看到 Android.mkAndroid.bp 同时存在,优先看 .bp 文件。

我记得有一次,同事编译某个模块一直报错,折腾了半天。最后发现是 Android.bp 里少写了一个依赖。嗯,这种坑我踩过不止一次。

2.3 device/ 目录:你的设备在这里安家

device/ 目录存放的是具体设备的配置和适配代码。每个设备厂商、每个产品线,都会在这里有一个子目录。

举个例子,Google 的 Pixel 设备:

device/google/
├── pixel/          # Pixel 系列通用配置
├── pixel6/         # Pixel 6 专属配置
├── pixel7/         # Pixel 7 专属配置
└── common/         # 公共配置

每个设备目录下通常包含:

  • BoardConfig.mk —— 板级配置,比如芯片型号、内存大小、分区布局
  • device.mk —— 设备相关的 Makefile,指定要编译哪些模块
  • AndroidProducts.mk —— 定义产品名称和编译目标
  • overlay/ —— 资源覆盖,可以修改系统默认的 UI 和配置
  • init.*.rc —— 设备启动时的初始化脚本

小技巧:如果你想快速了解一个设备支持什么硬件,直接看它的 BoardConfig.mk。里面会定义屏幕分辨率、摄像头数量、传感器类型等关键信息。

2.4 vendor/ 目录:厂商的“黑盒子”

vendor/ 目录,说白了就是厂商不想开源的那部分代码。比如硬件驱动、闭源库、预编译的二进制文件。

为什么要有这个目录?因为 AOSP 是开源的,但很多硬件厂商(比如高通、联发科)的驱动和库是闭源的。它们不能放在 device/ 或 hardware/ 里,所以单独放在 vendor/ 下。

vendor/ 的典型结构:

vendor/
├── google/         # Google 的闭源组件(比如 GMS)
├── qcom/           # 高通的闭源驱动和库
├── mediatek/       # 联发科的闭源组件
└── your_company/   # 你自己的厂商目录

我曾经在一个项目里,遇到系统启动时摄像头打不开。查了半天,最后发现是 vendor/ 下的摄像头 HAL 库版本不对。嗯,这种问题在 vendor/ 里很常见——因为你看不到源码,只能靠日志和二进制替换来排查。

避坑指南:vendor/ 下的文件通常是预编译的 .so.img,不要随意修改。如果你需要调试,先确认 vendor 分区是否挂载正确,以及 SELinux 策略是否允许访问。

2.5 hardware/ 目录:硬件抽象层(HAL)的根据地

hardware/ 目录存放的是硬件抽象层(HAL)的接口定义和参考实现。HAL 的作用,说白了就是给上层框架提供一个统一的硬件操作接口,不管底层是什么芯片,上层代码都不用改。

常见的子目录:

  • hardware/libhardware/ —— HAL 的核心框架和接口定义
  • hardware/libhardware_legacy/ —— 旧的 HAL 实现(逐渐被淘汰)
  • hardware/ril/ —— 无线接口层,负责手机通信
  • hardware/interfaces/ —— HIDL 接口定义(Android 8.0 之后的新方式)

举个例子,摄像头 HAL 的接口定义就在 hardware/libhardware/include/hardware/camera.h 里。你打开看看,会发现它定义了一组函数指针:

typedef struct camera_device {
    // 打开摄像头
    int (*open)(const struct hw_module_t* module, const char* id,
                struct hw_device_t** device);
    // 关闭摄像头
    int (*close)(struct hw_device_t* device);
    // ... 其他操作
} camera_device_t;

你看,上层框架只需要调用这些函数,不用关心底层是高通还是联发科的摄像头。这就是 HAL 的魅力。

2.6 一张图看懂核心目录的关系

下面这张图,我画了 AOSP 中几个关键目录之间的协作关系。你一看就明白:

AOSP 核心目录协作关系图 packages/ (系统应用) frameworks/ (框架层) hardware/ (HAL) device/ (设备配置) vendor/ (厂商闭源) build/ (构建系统) kernel/ (Linux 内核) 提供配置 提供二进制 开源代码 闭源/厂商私有

从这张图你能看到:

  • packages/frameworks/ 是上层,负责应用和框架逻辑
  • hardware/ 是中间层,隔离了硬件差异
  • device/vendor/ 是底层,负责具体硬件适配和闭源组件
  • build/ 贯穿所有层,负责把代码编译成可运行的镜像
  • kernel/ 是最底层,直接和硬件打交道

2.7 小结

好了,这一章的内容就这些。你记住一句话就行:build/ 管编译,device/ 管设备,vendor/ 管闭源,hardware/ 管抽象。这四个目录,是 AOSP 源码结构的四根柱子。

下一章,我们会深入 build/ 目录,看看 lunchmmm 这些命令到底是怎么工作的。到时候你会明白,为什么我总说“理解了构建系统,就理解了 Android 的一半”。


公众号:蓝海资料掘金营,微信deep3321