3. AOSP源码工程与构建系统
Android 系统定制的一切工作,都建立在 AOSP(Android Open Source Project)源码工程之上。理解源码如何被组织、下载、配置、编译,以及最终产物如何刷入设备,是 Framework 定制工程师的基本功。本章围绕“源码工程 + 构建系统 + 产物 + 刷机”这条主线,把 repo、Soong、Ninja、Make、lunch 等关键工具串成一条可操作的工程链路。
一、AOSP 源码工程的整体结构
AOSP 并不是一个单一的 Git 仓库,而是由数百个 Git 仓库组成的“多仓工程”。Google 使用 repo 工具对这些仓库进行统一管理。repo 本身是一个 Python 脚本,它封装了 Git,并通过一个 manifest 清单文件描述“哪些仓库、放在哪个路径、使用哪个分支或 revision”。
典型 AOSP 根目录下会看到以下关键内容:
.repo/:repo 的元数据目录,包含 manifest、project 列表和本地 Git 镜像信息。build/:构建系统核心,包含 Soong、Make、Kati、环境脚本等。frameworks/:Framework 层源码,如frameworks/base、frameworks/native。system/、packages/、device/、vendor/:系统组件、应用、设备配置与厂商代码。out/:编译输出目录,所有中间产物和最终镜像都在这里生成。
理解“多仓 + manifest + out 目录”这三件事,就抓住了 AOSP 工程结构的骨架。
二、源码下载与 repo 工具
下载 AOSP 的标准流程是:先安装 repo,再 init 指定 manifest 分支,最后 sync 拉取全部仓库。以 Android 14 为例:
mkdir ~/aosp && cd ~/aosp
repo init -u https://android.googlesource.com/platform/manifest -b android-14.0.0_r1
repo sync -c -j8 --no-tags --no-clone-bundle
其中 -c 表示只拉取当前分支,-j8 表示 8 个并发任务,--no-tags 可减少无用标签下载。repo 常用命令还包括:
repo status:查看所有仓库的改动状态。repo forall -c "git checkout .":批量回退所有仓库改动。repo manifest -r -o pinned.xml:导出当前各仓库的精确 revision,便于复现构建。repo start mybranch --all:为所有仓库创建本地开发分支。
repo manifest -r 固化版本,避免“同一分支不同时间 sync 出不同代码”导致构建结果不可复现。三、构建系统:Soong、Ninja、Make 与 Kati 的协作
Android 7 之后,构建系统从纯 Make 逐步迁移到 Soong + Ninja。今天 AOSP 的构建流程可以概括为:Soong 解析 Android.bp → 生成 Ninja 文件 → Ninja 执行编译 → Make/Kati 处理少量遗留模块。
各组件职责如下:
| 组件 | 输入 | 职责 | 输出 |
|---|---|---|---|
| Soong | Android.bp | 解析模块定义,生成构建图 | out/soong/build.ninja |
| Kati | Android.mk | 把 Makefile 转换为 Ninja | out/build-*.ninja |
| Ninja | *.ninja | 按依赖图并行执行编译命令 | 目标文件、镜像 |
| Make | Makefile | 顶层入口,调度 Soong/Kati/Ninja | 最终镜像 |
一个典型的 Android.bp 模块定义如下:
cc_library_shared {
name: "libmylog",
srcs: ["mylog.cpp"],
shared_libs: ["liblog"],
cflags: ["-Wall"],
}
Soong 使用 Blueprint 语法,比 Android.mk 更简洁、可静态分析。新增模块时优先写 Android.bp,只有在必须兼容旧逻辑时才使用 Android.mk。
四、lunch 与编译流程
编译前必须先“选择目标”,即 lunch。lunch 决定了产品(product)、设备(device)、变体(variant)三要素,例如:
source build/envsetup.sh
lunch aosp_arm64-userdebug
make -j16
变体含义:user 为发布版,userdebug 可调试并支持 root,eng 为工程版。Framework 定制通常使用 userdebug。常用编译命令:
m:从当前目录向上查找并编译。mm:编译当前目录下的模块。mmm frameworks/base:编译指定目录模块。make snod:仅重新生成 system.img,快速验证 Framework 改动。
make snod,需确保相关模块已编译进 system.img,否则刷机后看不到改动。首次或大范围改动建议完整 make -j。五、编译产物与刷机流程
编译完成后,产物集中在 out/target/product/<device>/ 下,常见镜像包括:
system.img:系统分区,包含 Framework、系统应用。vendor.img:厂商分区,含 HAL、驱动配置。boot.img:内核与 ramdisk。userdata.img:用户数据分区。super.img:动态分区合并镜像(Android 10+)。
刷机通常使用 fastboot:
adb reboot bootloader
fastboot flash system system.img
fastboot flash boot boot.img
fastboot reboot
若设备使用动态分区,则需先 fastboot flash super super.img,或使用 fastboot update 刷入完整包。刷机前务必确认设备已解锁 bootloader,并备份 userdata。
六、常见误区与复盘
在实际工程中,初学者最容易踩的坑集中在以下几点:
- 忘记 source 环境脚本:未执行
source build/envsetup.sh就使用m、mm,命令找不到。 - lunch 选错变体:用
user变体调试 Framework,导致 adb root 不可用。 - 只 make snod 不编译模块:Framework 改动未进入 system.img,刷机后无效果。
- repo sync 后未重新 lunch:产品配置变化后未重新选择目标,构建结果异常。
- 刷机分区不匹配:动态分区设备直接 flash system.img 失败,应使用 super.img 或 fastboot update。