2. AOSP源码下载与编译:环境准备(Ubuntu)、Repo工具使用、源码下载策略、编译目标选择(lunch)、首次编译避坑

好,咱们正式开始动手了。这一章,我带你走一遍AOSP源码下载和编译的完整流程。说实话,这一步是很多新手的第一道坎,也是我当年踩坑最多的地方。别担心,我把那些坑都标记好了,你跟着走就行。

2.1 环境准备:Ubuntu系统配置

先说系统。AOSP官方推荐Ubuntu,我个人习惯用 Ubuntu 20.04 LTS22.04 LTS。为什么?因为这两个版本的GCC、Python、Make等工具链跟AOSP的兼容性最好。你想想看,要是系统版本太新,某些库还没适配,编译到一半报错,那才叫崩溃。

硬件方面,我建议至少 16GB内存 + 500GB硬盘空间。我在项目中遇到过用8GB内存编译,结果swap分区狂转,一个编译任务跑了整整12小时。嗯,别省这个钱。

2.1.1 安装必要依赖包

打开终端,执行以下命令。这是我从官方文档里提炼出来的最小依赖集,少了任何一个都可能让你卡在某个奇怪的地方。

sudo apt update
sudo apt install -y git-core gnupg flex bison build-essential \
zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 \
libncurses5 lib32ncurses5-dev x11proto-core-dev libx11-dev \
lib32z1-dev libgl1-mesa-dev libxml2-utils xsltproc unzip fontconfig
小提示: 如果你用的是Ubuntu 22.04,记得额外安装 python2。AOSP某些老版本脚本还依赖Python 2,虽然官方说在迁移,但实际项目中我遇到过因为缺Python 2导致repo init失败的案例。

2.1.2 配置Git与SSH

源码下载需要Git,建议先配好用户名和邮箱。这一步看似简单,但很多人忽略。我见过同事因为没配邮箱,导致提交记录全是乱码,后面追查问题非常痛苦。

git config --global user.name "你的名字"
git config --global user.email "你的邮箱@example.com"

另外,如果你需要访问私有仓库或Gerrit,建议配置SSH密钥。生成方式很简单:

ssh-keygen -t rsa -b 4096 -C "你的邮箱"
cat ~/.ssh/id_rsa.pub

把输出的公钥添加到你的Git托管平台(比如Gerrit或GitHub)的SSH Keys里。这一步不做,后面repo sync可能会频繁要求输入密码,非常烦人。

2.2 Repo工具使用:不只是下载器

Repo是Google为AOSP量身定做的多仓库管理工具。说白了,它就是一个Python脚本,帮你批量操作几百个Git仓库。我第一次用Repo时,觉得它就是个「高级版git clone」,后来才发现它远不止如此。

2.2.1 安装Repo

安装Repo很简单,但要注意版本。我建议用Google官方源,别用系统包管理器里的旧版本。

mkdir -p ~/bin
curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
chmod a+x ~/bin/repo
export PATH=$PATH:~/bin

记得把 export PATH=$PATH:~/bin 加到你的 ~/.bashrc~/.zshrc 里,不然每次开新终端都要重新设置。

2.2.2 Repo init:选择分支

初始化一个AOSP工作目录,核心命令是 repo init。这里有个关键点:选择正确的分支。我刚开始做车载开发时,直接拉了master分支,结果编译出来的系统跟车机硬件不兼容,折腾了两天才发现是分支选错了。

对于车载系统,我建议选择稳定分支,比如 android-13.0.0_rXXandroid-12.0.0_rXX。具体版本号可以去 AOSP官方构建号页面 查。

mkdir aosp-car
cd aosp-car
repo init -u https://android.googlesource.com/platform/manifest -b android-13.0.0_r41
注意: 国内网络访问Google源可能很慢。你可以使用清华或中科大的镜像站。比如:repo init -u https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest -b android-13.0.0_r41。我在项目中一直用清华源,速度稳定,没出过问题。

2.3 源码下载策略:别傻等

repo sync 是下载源码的命令。但如果你直接执行 repo sync,可能会等到天荒地老。AOSP源码大概有30-50GB,包含几百个仓库。我分享几个实战策略。

2.3.1 断点续传与并行下载

网络不稳定时,repo sync 可能会中断。别慌,它支持断点续传。我一般这样写:

repo sync -c -j4 --no-tags
  • -c:只下载当前分支的代码,不下载所有分支的历史。省空间。
  • -j4:4个并行任务。根据你的CPU核心数和网络带宽调整。我一般设为核心数的一半。
  • --no-tags:不下载标签。能省不少时间。

如果中途断了,重新执行同样的命令就行。它会从断点继续,不会从头开始。

2.3.2 使用镜像仓库加速

如果你需要多次同步(比如团队多人开发),我建议先下载一个完整镜像,然后从镜像同步。这样第二次以后的速度会快很多。

# 第一次:下载镜像
repo init -u https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest --mirror
repo sync

# 第二次:从镜像创建工作目录
repo init -u /path/to/mirror/platform/manifest -b android-13.0.0_r41
repo sync

这个方法我在团队里推广过,效果很好。尤其是网络条件一般的环境,能节省大量时间。

2.4 编译目标选择(lunch)

源码下载完成后,进入编译环节。第一步是 source build/envsetup.sh,然后执行 lunch。这个命令会列出所有可用的编译目标。

对于车载系统,你通常会看到类似这样的选项:

1. aosp_arm-eng
2. aosp_arm64-eng
3. aosp_x86_64-eng
...
12. car_x86_64-userdebug
13. car_arm64-userdebug

这里我解释一下命名规则:设备名-编译类型

  • 设备名:比如 car_x86_64 表示车载模拟器(x86_64架构),car_arm64 表示真车机(ARM64架构)。
  • 编译类型
    • eng:工程版,带调试工具,适合开发。
    • userdebug:用户调试版,有root权限,适合测试。
    • user:用户版,无root,适合发布。

我个人建议,刚开始编译时选 car_x86_64-userdebug。为什么?因为模拟器启动快,调试方便。等你把流程跑通了,再切到真机目标。我在项目中第一次编译就选了真机目标,结果因为驱动没配好,编译出来的镜像刷进去黑屏,排查了很久才发现是lunch选错了。

source build/envsetup.sh
lunch car_x86_64-userdebug

2.5 首次编译避坑指南

好,终于到编译这一步了。执行 make -j8m(如果已经source了envsetup.sh)。但别急着敲回车,先看看下面这些坑,我当年都踩过。

2.5.1 内存不足导致编译中断

编译AOSP非常吃内存。如果你只有8GB内存,建议加上 make -j4 而不是 -j8。我曾经在16GB的机器上开 -j16,结果系统直接OOM(内存溢出),编译进程被内核杀死。嗯,从那以后我学乖了,老老实实按内存大小来算并行数。

一个简单的经验公式:并行数 = 内存大小(GB) / 4。比如16GB内存,用 -j4 比较稳妥。

2.5.2 磁盘空间不足

编译过程中会产生大量中间文件。源码+编译产物,轻松超过100GB。我建议预留 200GB以上 的空间。如果你用SSD,注意别把根目录塞满,否则系统会变得非常卡顿。

检查磁盘空间的命令:

df -h

如果空间不够,可以设置 OUT_DIR 环境变量,把编译输出放到另一个分区:

export OUT_DIR=/path/to/large/disk/out
make -j4

2.5.3 Java版本不匹配

AOSP不同版本对Java版本有要求。Android 13需要OpenJDK 11,Android 12需要OpenJDK 9。如果你装错了版本,编译到一半会报类似 Unsupported class file major version 的错误。

检查Java版本:

java -version

如果版本不对,用 update-alternatives 切换:

sudo update-alternatives --config java
我曾经 在编译Android 12时,系统默认装了Java 11,结果编译到一半报错。查了半天才发现是Java版本问题。切换回Java 9后,一切顺利。所以,开始编译前,一定先确认Java版本。

2.5.4 编译过程中的常见错误

这里列几个我遇到过的典型错误和解决方法:

错误信息 原因 解决方法
ninja: build stopped: subcommand failed. 某个模块编译失败 查看具体错误日志,通常是缺少依赖或语法错误
Out of memory: Killed process 内存不足 减少并行数,或增加swap空间
No rule to make target 缺少某个库或头文件 检查是否安装了所有依赖包
FAILED: setup-jack-server Jack服务器问题(老版本AOSP) 设置 export ANDROID_JACK_VM_ARGS="-Xmx4g"

2.5.5 首次编译成功后的验证

编译成功后,你会看到类似这样的输出:

#### build completed successfully (01:23:45) ####

这时候别急着庆祝。先验证一下编译产物是否完整。对于车载模拟器目标,产物在 out/target/product/car_x86_64/ 目录下。关键文件包括:

  • system.img:系统镜像
  • vendor.img:厂商镜像
  • ramdisk.img:内存盘镜像
  • kernel:内核文件

你可以用模拟器启动测试:

emulator -show-kernel -memory 2048

如果模拟器能正常启动并进入桌面,恭喜你,环境搭建成功了!

小技巧: 首次编译时间很长(1-2小时很正常)。我建议你利用这段时间去喝杯咖啡,或者看看下一章的内容。别一直盯着终端,那只会让你焦虑。

好了,这一章的内容就到这里。环境搭建是基础中的基础,但也是最重要的。把这一步走稳了,后面的定制开发才能顺利进行。下一章,我们开始真正动手,修改车载系统的核心服务。