Skip to content

AOSP目录结构全景

解释 AOSP 的多仓组织方式、顶层目录职责、源码目录与运行时层次的关系,并给出可复用的源码定位方法。

基于android-17.0.0_r1
AndroidAOSP源码结构repo

AOSP目录结构全景 ​

AOSP(Android Open Source Project)并不是一个普通的单体 Git 仓库。打开源码根目录时, 我们会看到 frameworks/、system/、packages/、hardware/ 等统一排列的目录, 但这些目录背后实际挂载着许多相互独立的 Git project,再由 repo 和 manifest 组合成一棵 可以统一搜索、编译和提交的源码树。

因此,阅读 AOSP 需要同时建立三张地图:

  • 仓库地图:代码属于哪个 Git project,由哪个 manifest revision 固定。
  • 目录地图:顶层目录和子目录分别承担什么工程职责。
  • 运行时地图:这些代码最终运行在哪个进程,通过什么接口协作。

如果只看目录名,很容易把 frameworks/ 等同于 Java Framework,把 system/ 等同于 Linux 系统层,或者把 hardware/ 中的接口定义直接当成设备上的 HAL 实现。本文从多仓模型开始, 逐步把目录结构还原成 Android 的启动、Framework、Native、HAL 和 Kernel 关系。

本文是 Foundations 系列的入口,不要求读者已经使用过 repo。文章先区分 project name 与 本地 path,再说明主要顶层目录的职责,以及如何从一个 Android 问题选择第一批源码入口。 需要实际初始化和同步工作区时,继续阅读 repo初始化与同步。

1. AOSP 源码树 ​

1.1 repo ​

repo 是建立在 Git 之上的多仓管理工具。它不取代 Git,而是读取 manifest,确定需要管理哪些 project、每个 project 应检出哪个 revision,以及它们在工作区中应挂载到什么路径。

一个 project 通常包含两个容易混淆的名字:

名称示例含义
上游 project nameplatform/frameworks/base远端代码仓库的标识
本地 project pathframeworks/base源码在工作区中的挂载位置

platform/frameworks/base 和 frameworks/base 指向同一份 project,但分别用于描述远端仓库 和本地路径。阅读源码时用工作区相对路径定位文件;需要重现某个版本时,再记录 project 与 commit。

下面这张图展示 manifest 如何把独立 project 组织成统一工作区。它只表达源码管理关系,不表示 Android 运行时调用方向。

这套模型带来一个直接结论:AOSP 没有一个覆盖全部源码的单一 project commit。 frameworks/base、frameworks/native、system/core 等 project 在同一个 Android release 下分别对应自己的 commit。分析跨 project 调用链时,需要分别固定每个实际引用的 project。

1.2 remote ​

理解 AOSP 目录不需要记住完整 manifest 语法,先掌握四个核心元素即可:

元素职责阅读重点
remote定义远端获取和代码审查地址fetch 根地址、review 地址
default定义 project 的默认属性revision、remote、同步参数
project定义一个 Git projectname、path、groups、独立 revision
linkfile在工作区创建跨目录入口源文件与目标路径

当前 manifest 中的构建 project 声明了 build/make、build/soong 等本地路径,并通过 linkfile 暴露 Android.bp、build/envsetup.sh 等工作区入口。这解释了 build/envsetup.sh 与 build/make/envsetup.sh 之间的关系。工作区根目录中的入口文件不一定 属于根目录自身,它可能由某个 project 通过 manifest 投射出来。

1.3 repo init ​

repo init 准备 repo client 和 manifest,repo sync 再按 manifest 取得并检出 project。 在目录地图中只需要知道这个职责分界;参数、网络/本地阶段、失败恢复和危险选项由 repo初始化与同步 专门解释。

2. 顶层目录职责 ​

2.1 工程职责 ​

AOSP 顶层目录首先表达代码的工程归属。它并不严格对应 Android 官方架构图中的 Applications、Framework、Native Libraries、HAL 和 Kernel 层。

例如:

  • frameworks/native 既包含应用进程会加载的 Native 库,也包含独立运行的 SurfaceFlinger。
  • packages/modules 中的 Mainline 模块可能同时提供 API、系统服务和独立进程。
  • system/core 不只是底层库,还包含 init、debuggerd、fs_mgr 等可执行程序。
  • hardware/interfaces 主要定义稳定接口,真实设备实现可能位于其他 hardware、vendor 或设备仓库。

所以,目录表的价值是帮助定位代码,不是代替运行时架构。

2.2 核心顶层目录 ​

目录主要职责典型内容
art/Android RuntimeRuntime、GC、JIT/AOT、dex2oat
bionic/Android C 标准库与动态链接器libc、libm、libdl、linker
bootable/启动和恢复相关组件Recovery、bootloader 公共代码
build/构建和产品配置Make、Soong、Blueprint、release 配置
device/设备与产品定义product、BoardConfig、overlay、fstab
external/第三方开源依赖压缩、图形、网络、编解码等独立项目
frameworks/Android Framework 与核心 Native 框架base、native、av、opt
hardware/HAL 接口与参考实现AIDL/HIDL 接口、libhardware
kernel/Linux 内核及 Android 内核代码Binder、DRM、Input、调度和内存
libcore/Java 核心类库ojluni、luni
packages/系统应用、Mainline 模块和服务apps、modules、services
prebuilts/预编译工具与依赖JDK、Clang、SDK、构建工具
system/Android 用户空间底层能力init、vold、sepolicy、日志、基础库
test/、cts/平台与兼容性测试CTS、VTS 关联测试、测试框架
tools/平台研发工具兼容性、生成、分析和开发工具
trusty/Trusty TEE内核、应用、库与接口

这些目录之下通常仍包含多个 Git project。例如 frameworks/base 和 frameworks/native 是不同 project;packages/modules/Connectivity 与 packages/modules/Wifi 也分别维护。

2.3 frameworks/base ​

frameworks/base 是理解 Android Framework 最重要的入口之一,但它内部仍有明确分区:

text
frameworks/base/
├── core/
│   ├── java/               # android.* 核心 Java API 与内部实现
│   ├── jni/                # Java Framework 对应的 JNI 桥接
│   └── res/                # Framework 核心资源
├── services/
│   ├── java/               # SystemServer 等服务启动入口
│   └── core/java/          # AMS、PMS、WMS、Power 等服务实现
├── packages/               # SystemUI 等与 Framework 紧密相关的组件
├── libs/                   # WindowManager Shell 等库
├── tools/                  # Framework 构建和开发工具
└── tests/                  # Framework 测试

应用侧的 Activity、View、PowerManager 等 API 多从 core/java/android 开始; 系统侧的 AMS、PMS、WMS 等服务则主要位于 services/core/java/com/android/server。 阅读一次 Binder 调用时,通常需要在这两个区域之间往返。

2.4 native ​

frameworks/native 是 Native Framework 的核心入口:

text
frameworks/native/
├── libs/
│   ├── binder/             # Binder Native 客户端、服务端与线程池
│   ├── gui/                # Surface、BufferQueue、BLASTBufferQueue
│   ├── ui/                 # GraphicBuffer、Dataspace 等图形类型
│   └── renderengine/       # SurfaceFlinger 使用的渲染引擎
├── services/
│   ├── surfaceflinger/     # 显示合成服务
│   ├── inputflinger/       # 输入读取与分发
│   └── sensorservice/      # 传感器服务
└── cmds/                   # servicemanager 等 Native 命令与守护程序

这里的 libs 和 services 不应混为一谈。libs/binder 可以被多个进程链接使用, services/surfaceflinger 则构建为长期运行的系统服务进程。

2.5 system ​

system 下的 project 更接近 Android 用户空间的底层基础设施:

路径主要职责
system/core/initfirst-stage init、SELinux setup、second-stage init
system/core/fs_mgr文件系统挂载、AVB、动态分区相关能力
system/core/debuggerdNative crash 收集与 tombstone
system/core/libutilsLooper、线程等 Native 基础类型
system/sepolicy平台、system_ext、product、vendor SELinux 策略
system/vold卷管理、文件系统、加密和用户存储
system/loggingliblog、logd 相关实现
system/tools/aidlAIDL 编译器

system 不是 Linux Kernel。它主要是运行在用户空间的 Android 原生代码;真正的驱动和内核机制 仍位于 kernel project。

2.6 packages ​

packages 的内容可以粗略分为三类:

分区示例作用
packages/appsSettings、Car/SystemUI系统应用
packages/modulesConnectivity、Wifi、Media、PermissionMainline/APEX 可更新模块
packages/servicesCar 等独立的大型系统服务集合

不能因为路径以 packages 开头就把它理解为普通 APK。Mainline 模块可能包含 Java 服务、 Native 库、AIDL、APEX 配置和测试,边界比传统系统应用更宽。

2.7 hardware ​

hardware/interfaces 主要保存 Android 定义的 HAL 接口。接口描述了 Framework 或 Native 服务 可以依赖什么契约,但不保证某个设备使用相同实现。

device/<vendor>/<product> 则负责把平台能力组合成具体产品,常见内容包括:

  • 产品继承和 package 列表;
  • BoardConfig 与分区配置;
  • init rc、fstab、权限和 SELinux 片段;
  • overlay 与资源差异;
  • HAL service manifest 和兼容性矩阵。

厂商真正的实现还可能位于 vendor 私有仓库。AOSP 中的参考实现、模拟器实现和某个硬件平台实现 不能被直接描述为所有 Android 设备的统一行为。

3. 运行时层次 ​

目录结构回答“代码放在哪里”,运行时架构回答“代码由谁执行”。下面这张图把常用目录映射到 进程和接口边界。

这不是完整 Android 架构图,而是一张源码导航图。接下来用三个入口说明如何从目录走到运行主体。

3.1 system/core/init ​

init/main.cpp 根据启动参数进入 first stage、SELinux setup、second stage、ueventd 或 subcontext。 这说明 system/core 中不仅有基础库,也包含负责系统启动的可执行程序。

源码文件:system/core/init/main.cpp

相关函数/类型:main

cpp
int main(int argc, char** argv) {
    setpriority(PRIO_PROCESS, 0, -20);

    if (!strcmp(basename(argv[0]), "ueventd")) {
        // 说明:同一可执行文件根据 argv[0] 进入设备节点管理路径。
        return ueventd_main(argc, argv);
    }

    // ...

    if (argc > 1) {
        if (!strcmp(argv[1], "selinux_setup")) {
            // 说明:SELinux setup 是启动过程中的独立阶段。
            return SetupSelinux(argv);
        }
        if (!strcmp(argv[1], "second_stage")) {
            // 说明:second stage 继续属性、rc 解析和服务管理。
            return SecondStageMain(argc, argv);
        }
    }

#if defined(FIRST_STAGE_INIT) || defined(RECOVERY)
    return FirstStageMain(argc, argv);
#else
    LOG(FATAL) << "Second-stage init requires an argument to main()";
#endif
}

从这里继续阅读时,应进入 first_stage_init.cpp、selinux.cpp 和 init.cpp,而不是在 main.cpp 中寻找所有实现。入口文件的作用是展示阶段分派,具体职责分布在各子模块。

3.2 base services ​

SystemServer.main() 进入 run(),随后按 bootstrap、core、other 和 APEX 等阶段启动服务。 AMS、PMS、PowerManagerService 等代码虽然位于不同 package,但共享 system_server 的进程和 启动上下文。

源码文件:frameworks/base/services/java/com/android/server/SystemServer.java

java
// 符号:SystemServer.main / SystemServer.run
public static void main(String[] args) {
    // 说明:Zygote 创建 system_server 后,从这里进入统一服务启动器。
    new SystemServer().run();
}

// SystemServer.run() 中的服务启动阶段
try {
    t.traceBegin("StartServices");

    // ...

    // 说明:分阶段启动表达真实依赖,不是任意顺序的服务清单。
    startBootstrapServices(t);
    startCoreServices(t);
    startOtherServices(t);
    startApexServices(t);

    updateWatchdogTimeout(t);
    CriticalEventLog.getInstance().logSystemServerStarted();
} catch (Throwable ex) {
    // 说明:关键服务启动失败会沿异常路径终止当前启动阶段。
    // ...
    Slog.e("System", "************ Failure starting system services", ex);
    throw ex;
} finally {
    t.traceEnd();  // StartServices
}

理解某个 Java 系统服务时,通常应先从 SystemServer 找到创建时机,再进入服务本身的构造、 onStart、systemReady 或 boot phase 回调。只读服务类容易遗漏初始化依赖。

3.3 native services ​

SurfaceFlinger 的入口位于 frameworks/native/services/surfaceflinger。它初始化 Binder 线程池,创建服务对象,完成初始化并向 ServiceManager 注册,最后进入长期运行循环。

源码文件:frameworks/native/services/surfaceflinger/main_surfaceflinger.cpp

相关函数/类型:main

cpp
int main() {
    // ...

    ProcessState::self()->setThreadPoolMaxThreadCount(4);

    sp<ProcessState> ps(ProcessState::self());
    // 说明:SurfaceFlinger 自己启动 Binder 线程池,
    // 它不是 system_server 内的 Java SystemService。
    ps->startThreadPool();

    sp<SurfaceFlinger> flinger =
            surfaceflinger::createSurfaceFlinger();

    // 说明:初始化在服务公开给客户端之前完成。
    flinger->init();

    // ...

    sp<IServiceManager> sm(defaultServiceManager());
    sm->addService(
            String16(SurfaceFlinger::getServiceName()),
            flinger,
            false,
            IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL |
                    IServiceManager::DUMP_FLAG_PROTO);

    // ...

    // 说明:run() 进入 SurfaceFlinger 的主循环。
    flinger->run();
}

frameworks/native 因而既是库集合,也是独立系统进程的实现位置。判断某段代码运行在哪个进程, 需要继续检查构建目标、main()、rc 文件和服务注册,而不能只看顶层目录。

4. 模块定位 ​

4.1 API路径 ​

适合应用 Framework 功能的路径:

  1. 在 frameworks/base/core/java/android 找公开 API。
  2. 找 API 持有的 Binder interface 或 manager delegate。
  3. 在 AIDL、Stub 或 ServiceManager 注册点定位服务端。
  4. 回到 SystemServer 或对应进程入口确认服务如何启动。
  5. 最后进入 HAL、Native 或 Kernel 路径。

例如,PowerManager 的应用 API 并不是电源策略实现。它通过 IPowerManager 与 PowerManagerService 通信,服务再协调 Display、Dream、Battery、SuspendBlocker 和 Power HAL。

4.2 注册点路径 ​

如果已经知道服务名,可以反向搜索:

bash
# 查找 Java 服务注册
rg 'ServiceManager\\.addService|publishBinderService' frameworks/base/services

# 查找 Native 服务注册
rg 'addService\\(' frameworks/native/services system

# 查找 init 启动的守护进程
rg '^service ' system device hardware -g '*.rc'

这些命令是入口筛选,不是事实证明。找到候选位置后,还要检查调用条件、构建配置、feature flag、 产品 overlay、权限检查和测试。

4.3 模块边界 ​

源码目录中的文件不一定属于同一个构建目标。Android.bp 可以回答:

  • 最终生成 library、binary、APK 还是 APEX;
  • 依赖哪些模块;
  • 使用哪些 srcs、defaults 和 header_libs;
  • 是否受 product variable、soong_config 或平台条件控制;
  • 安装到哪个分区或可见性范围。

当类名、目录名和运行时进程不一致时,构建目标往往是连接它们的关键证据。

4.4 模块测试 ​

正向调用链只能说明“成功时可能怎样运行”。一篇可信的源码文章还应搜索:

  • 单元测试、集成测试和 CTS/VTS 用例;
  • Binder death、权限拒绝、超时与取消;
  • feature flag、系统属性、DeviceConfig 与资源 overlay;
  • 服务未注册、HAL 不可用和设备能力缺失;
  • 多用户、多显示、多设备和进程重启。

很多“Android 就是这样”的结论,在加入这些条件后会变成“满足某个配置和能力时走这条路径”。 后者虽然更复杂,但更接近真实平台行为。

5. 常见误区 ​

5.1 目录边界 ​

frameworks/native 不等于整个 Native 层,system 也不等于 Linux Kernel。 顶层目录是代码组织入口,运行时架构需要结合进程、接口和构建目标判断。

5.2 接口/实现 ​

hardware/interfaces 中的 AIDL/HIDL 定义描述契约。真实设备可能采用不同服务实现、驱动和产品 配置。分析 HAL 时应区分:

  1. Framework 或 Native 客户端;
  2. 稳定接口定义;
  3. AOSP 参考实现;
  4. 设备或厂商实现;
  5. Kernel driver。

5.3 版本记录 ​

阅读跨 project 调用链时,release 只能标识整体发布版本,不能代替各 project 的 commit。 升级后若出现行为差异,应分别比对实际涉及的 project,而不是把整棵工作区当作一个 Git 仓库。

5.4 实现/测试 ​

类型名称和文件路径可能保留历史语义。调用方可以确认它是否仍在主路径,测试则描述维护者关心的 行为和边界。源码阅读应在实现、调用方、测试和构建配置之间往返。

5.5 符号定位 ​

行号会随着格式和注释变化而漂移。稳定引用至少应包含 project、commit、路径和符号;行号只是 方便当前版本阅读的辅助信息。

6. 源码阅读流程 ​

面对一个新模块,可以按以下顺序建立认知:

  1. 确定问题:要解释的是 API、服务、进程、协议、状态机还是故障。
  2. 确定 project:从 manifest 和本地 path 确认仓库归属。
  3. 固定版本:记录 release 与该 project 的不可变 commit。
  4. 找到构建目标:阅读附近的 Android.bp、rc、APEX 或应用 manifest。
  5. 找到入口:公开 API、main()、SystemServer、ServiceManager 或 HAL client。
  6. 追踪主路径:记录调用、线程、Binder、锁、队列和数据对象。
  7. 补失败路径:搜索错误、超时、权限、死亡通知、回滚与资源清理。
  8. 检查边界:读取测试、fixture、dump、trace 和配置。
  9. 画图和列表:只把真实关系转成时序图、状态图、依赖图或表格。
  10. 验证引用:分享结论前在固定 commit 上重新确认路径和符号。

这套流程比“从一个大类的第一行读到最后一行”更有效。Android 系统代码跨进程、跨语言、 跨 project 的情况非常普遍,先确定边界再深入实现,可以显著减少错误关联。

7. 源码导航实践 ​

AOSP 的目录结构可以概括为三层关系:

  • manifest 与 repo 把多个独立 Git project 组织成统一工作区;
  • 顶层目录按工程职责划分 Framework、系统基础、硬件接口、应用、构建和测试代码;
  • 真实运行时关系由进程、Binder、HAL、构建目标和驱动边界共同决定。

掌握这三层之后,frameworks/base 不再只是“很大的 Java 目录”, frameworks/native 也不再只是“C++ 代码集合”。读者可以从问题出发,先定位 project 和入口, 再沿调用链进入 SystemServer、Native 服务、HAL 与 Kernel,并用测试和失败路径校正结论。

实际阅读源码时,可以用下面三个任务验证目录定位是否正确:

  1. 在任意 AOSP project 中运行 repo list .,解释输出中的 path 与 project name。
  2. 给定“应用启动 Activity”,列出最先阅读的 Framework API、SystemServer 服务和 Native 边界。
  3. 给定“相机 HAL 调用失败”,区分接口定义、AOSP 服务、设备实现和 Kernel driver 的源码位置。

关于可复现工作区的建立参见 repo初始化与同步;多 project 查询、 分支与差异管理参见 repo日常命令实战。