第1章 AOSP源码下载与Repo使用
1.1 Repo工具角色与设计原理
AOSP 仓库数量超过 800 个 Git 库,Google 设计 Repo 工具来统一管理这些子仓库元数据的拉取与切换。Repo 本质是对 Git 的批量操作封装,自身不存储代码,只维护一份 XML 清单文件,该文件描述每个子仓库的远程 URL、分支、标签和本地路径。
| 组件 | 职责 | 技术形态 |
|---|---|---|
| repo 命令 | 初始化、同步、分支切换、diff 查看 | Python 脚本 + 内嵌 Git 命令 |
| manifest 仓库 | 存放 default.xml(及其他变体) | Git 仓库,通常托管在 android.googlesource.com |
| 各子 Git 仓库 | 实际业务代码(kernel、framework、bionic…) | 标准 Git 仓库,使用 detached HEAD 管理模式 |
设计取舍:Google 没有使用 git submodule,而是自研 Repo。原因是 submodule 在超大规模仓库(800+)下同步性能和分支切换灵活性都达不到 AOSP 开发需求。Repo 的 XML 清单允许在不同版本之间快速切换整个项目基线。
1.2 repo init 工作原理与参数
repo init 不拉取任何业务代码,只完成两件事:
- 在
.repo/manifests目录克隆清单仓库。 - 在
.repo/manifest.xml建立指向 default.xml 的符号链接。
mkdir ~/aosp
cd ~/aosp
# 使用国内镜像源加速初始化(清华大学 TUNA 镜像)
repo init -u https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest \
-b android-14.0.0_r15 \
--depth=1 \
--partial-clone
| 参数 | 作用说明 |
|---|---|
-u <URL> | manifest 仓库的远程地址 |
-b <分支> | 指定清单仓库的分支或 Tag,决定拉取哪个 Android 版本 |
--depth=1 | 浅克隆,只下载最新提交,大幅减少首次同步数据量 |
--partial-clone | 启用 Git 部分克隆(promisor remote),按需下载对象 |
--worktree | 使用 Git worktree 替代符号链接,减少重复对象存储 |
执行 init 前必须确保环境变量
REPO_URL 指向正确的 Repo 引导脚本地址。如果遇到 fatal: cannot get manifest url,通常是网络代理未配置或镜像源不可用。
1.3 清单文件(manifest.xml)结构解析
清单文件是整个 AOSP 代码的“地图”。一个标准 default.xml 包含以下核心元素:
<?xml version="1.0" encoding="UTF-8"?>
<manifest>
<remote name="aosp"
fetch=".."
review="https://android-review.googlesource.com/" />
<default revision="refs/tags/android-14.0.0_r15"
remote="aosp"
sync-j="4" />
<project path="build/make" name="platform/build" groups="pdk" />
<project path="frameworks/base" name="platform/frameworks/base" />
<project path="kernel/build" name="kernel/build" revision="android-14.0.0_gki" />
<project path="pdk/apps/Contacts" name="platform/pdk/apps/Contacts" />
<!-- 仅 Linux 平台下载 -->
<project path="prebuilts/clang/host/linux-x86"
name="platform/prebuilts/clang/host/linux-x86"
groups="notdefault,linux-x86" />
<include name="another/manifest.xml" />
</manifest>
| 标签 | 用途 | 常见属性 |
|---|---|---|
| <remote> | 定义可用的远程 Git 仓库别名 | name, fetch, review |
| <default> | 全局默认配置,各 project 可覆盖 | revision, remote, sync-j, sync-c |
| <project> | 声明一个子仓库,path 是本地路径,name 是远端路径 | path, name, revision, groups, upstream |
| <include> | 引用其他 XML 文件,支持分模块管理清单 | name |
| <remove-project> | 从父清单中移除特定项目,常用于自定义裁剪 | name |
调试技巧:被
groups="notdefault" 标记的 project 不会出现在 repo sync 默认拉取列表里。如果编译时遇到“missing header”错误,可以检查对应 project 是否被 groups 排除,手动用 repo sync <path> 补拉。
1.4 repo sync 完整流程与断点续传
repo sync 是日常最频繁使用的命令。执行时 Repo 会按以下顺序处理:
- 读取
.repo/manifest.xml中所有 project 条目。 - 对每个 project 执行
git fetch,必要时执行浅克隆或部分克隆。 - 如果本地库已经存在,执行
git pull --rebase避免合并提交。 - 更新
m/<branch>远程跟踪分支。 - 将子仓库 checkout 到 XML 中指定的 revision。
# 全量同步(所有 project)
repo sync -j8
# 只同步指定子仓库(减少等待时间)
repo sync frameworks/base build/make
# 强制覆盖本地未提交修改
repo sync --force-sync
# 丢弃所有本地修改并回到远端状态
repo sync --force-sync --detach
断点续传:repo sync 支持
--fail-fast 和自动重试。默认连续失败 3 次会跳过该仓库。网络中断后重新执行 repo sync 会仅拉取未完成的仓库,不会重头开始。
1.5 分支切换与源码基线管理
切换 AOSP 版本本质是更改清单文件的分支引用。不需要为每个版本单独下载一份源码,只需切换 manifest 的 revision:
# 查看当前所有已同步的分支
cd .repo/manifests
git branch -a
# 切换清单到 android-13.0.0_r30
cd ~/aosp
repo init -b android-13.0.0_r30
repo sync -j8
# 查看更详细的可用分支/标签
cd .repo/manifests
git ls-remote --tags origin | grep android-14
| 操作 | 命令 | 影响范围 |
|---|---|---|
| 切换所有子仓库分支 | repo init -b <branch> + repo sync | 整个源码树 |
| 单仓库切换分支 | cd <path> && git checkout <branch> | 仅当前仓库 |
| 查看当前基线 Revision | repo version / head .repo/manifest.xml | 无修改 |
| 恢复到 Manifest 指定版本 | repo sync --detach | 所有子仓库强制 detached HEAD |
不要在子仓库内直接
git commit 和 git push,除非你理解 Repo 的 review 流程。直接提交会导致后续 repo sync 出现冲突,需要使用 repo abandon <topic> 清理。
1.6 常见错误与调试方法
以下是在实际工作中最常见的 Repo 错误案例及解决方案:
# 错误1:SSL certificate problem
# 现象:fatal: unable to access 'https://...': SSL certificate problem
# 解决:关闭 SSL 验证(仅限内网环境)
export GIT_SSL_NO_VERIFY=1
# 错误2:无法解析 manifest URL
# 现象:fatal: manifest url '...' is not a valid URL
# 解决:检查 repo init -u 参数,确保末尾没有多余空格,协议使用 https
# 错误3:sync 中途连接中断
# 现象:error: Failed to connect to android.googlesource.com port 443
# 解决:配置 git 代理
git config --global http.proxy http://proxy:port
git config --global https.proxy https://proxy:port
# 错误4:.repo/repo 损坏或版本不匹配
# 现象:error: repo is not a git repository
# 解决:重新拉取 repo 工具
curl -s https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
chmod a+x ~/bin/repo
1.7 性能优化:使首次同步从 6 小时降到 20 分钟
大团队或 CI 环境中,优化首次同步速度至关重要:
- 使用
--depth=1 --partial-clone避免下载全部 Git 历史。 - 指定
--clone-bundle(默认已启用)从服务器下载预打包的 .bundle 文件。 - 尽量选择地理位置最近的镜像源(清华大学、中科大、华为云)。
- 使用
repo sync -c --no-tags跳过标签拉取,可再减少 10%~15% 数据传输。
# 面向首次同步的完整优化参数
repo init -u https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest \
-b android-14.0.0_r15 \
--depth=1 \
--partial-clone \
--clone-bundle
repo sync -c --no-tags -j$(nproc)
以 Android 14(约 60GB 源码树,含 Git 历史则超过 100GB)为例,使用优化参数后磁盘占用减少约 40%,首次同步时间从常规的 5~6 小时缩短至 15~25 分钟(视网络带宽而定)。