1. 项目概述与背景
折腾Android源码编译,大概是每个对系统底层感兴趣或者有特定定制需求的开发者都会经历的一道坎。我之前在Nexus 5x上成功编译并修改了AOSP 7.1.1,实现了位置打卡的功能,整个过程虽然繁琐,但成就感十足。这次,我把目标转向了手头的Pixel 3,想在这台设备上复现并进一步探索Android 10.0(AOSP 10.0 r41)的编译与刷机流程。选择Pixel 3(代号blueline)的原因很简单,它是Google的亲儿子,官方驱动支持完善,社区资料也多,对于学习和实验来说,是绝佳的“小白鼠”。
然而,从Nexus 5x到Pixel 3,从Android 7.1到Android 10,看似只是设备和版本的升级,但实际操作中遇到的坑却截然不同。最大的挑战往往不是编译命令本身,而是前期的环境搭建、代码与驱动的匹配,以及刷机过程中的各种“玄学”问题。很多人,包括我自己,都曾卡在下载代码这一步,网络问题直接劝退。所以,这次我决定采用一种更“接地气”的方式:直接使用现成的、匹配好的代码分支和驱动包,绕过repo同步这个最大的拦路虎,把精力集中在编译和刷机这两个核心环节上。这篇文章,就是我在Ubuntu 18.04系统上,完整走通Pixel 3编译刷入AOSP 10.0 r41的实战记录,我会把每个步骤的细节、遇到的错误以及解决方案都掰开揉碎了讲清楚,希望能帮你少走弯路。
2. 编译环境与源码准备
2.1 虚拟机与宿主系统配置
编译AOSP对硬件资源的要求不低,强烈建议在物理机上直接安装Ubuntu进行,这样性能最好。但如果条件有限,或者像我一样需要在多系统间切换,使用虚拟机也是一个可行的选择,只是需要做好配置。
我的宿主机是Windows 10,虚拟机软件使用的是VMware Workstation 16 Pro。这里有几个关键点必须注意,直接关系到编译能否成功以及效率。首先是硬盘空间,AOSP源码本身巨大,编译产生的中间文件和输出文件更是占用海量空间。我最初只分配了150GB,结果编译到一半就空间不足,前功尽弃。血的教训是,分配给虚拟机的硬盘空间绝对不能少于250GB,我最终调整到了300GB,编译完成后剩余空间大约在30-40GB左右,这才算比较稳妥。如果你打算长期折腾多个版本,预留500GB都不为过。
其次是内存和CPU核心数。AOSP编译是一个极度消耗内存和CPU的过程。官方推荐至少16GB内存。在虚拟机上,我分配了20GB内存给Ubuntu,并将宿主机的8个CPU核心全部分配给它(如果你的宿主机核心数多,可以分配更多,但要注意给宿主机留一些)。这里有个小技巧:在VMware的虚拟机设置中,除了分配内存和处理器,务必在“处理器”选项里勾选“虚拟化Intel VT-x/EPT或AMD-V/RVI”,这个选项对于在虚拟机内高效运行编译任务至关重要,不开启可能会导致编译速度异常缓慢甚至失败。
操作系统我选择了Ubuntu 18.04 LTS(64位)。选择LTS版本是因为其长期支持,软件源稳定,社区遇到的大多数问题在这个版本上都有现成的解决方案,避免因系统版本太新或太旧带来的兼容性麻烦。
2.2 关键软件包的安装
系统安装好后,第一件事就是换源。默认的国外源下载速度慢如蜗牛,必须替换为国内的镜像源,如阿里云、清华、中科大的源。具体操作是备份并编辑/etc/apt/sources.list文件。这一步是基础,能为你后续节省大量等待时间。
接下来是安装编译所需的依赖包。AOSP官方文档会给出一个列表,但那个列表有时不够完整。下面是我结合官方文档和多次实战经验整理出来的完整安装命令,在Ubuntu 18.04上亲测有效。请注意,这些命令需要分条执行,因为有些包在同一个apt-get install命令中可能会因为依赖关系问题而安装失败。
首先,安装一些基础工具和库:
sudo apt-get update sudo apt-get install -y git-core gnupg flex bison gperf build-essential zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 lib32ncurses5-dev x11proto-core-dev libx11-dev libgl1-mesa-dev libxml2-utils xsltproc unzip然后,安装更多必要的开发库,包括一些32位兼容库(因为Android编译需要32位工具链):
sudo apt-get install -y lib32z1-dev lib32readline-dev libssl-dev liblz4-tool libesd-java libwxgtk3.0-dev squashfs-tools pngcrush schedtool sudo apt-get install -y python-markdown libswitch-perl libssl-dev bc sudo apt-get install -y tofrodos dos2unix这里有个容易忽略的点:openjdk-8-jdk。Android 10.0 (AOSP 10) 的编译必须使用Java 8,更高版本的Java会导致编译错误。安装命令如下:
sudo apt-get install -y openjdk-8-jdk安装完成后,务必通过java -version和javac -version命令确认默认的Java版本是1.8。如果不是,需要使用update-alternatives命令来切换系统的默认Java版本。
最后,安装一个有用的工具ccache。它不是必须的,但能显著加速后续的重复编译过程。它通过缓存之前的编译结果来工作。
sudo apt-get install -y ccache source ~/.bashrc echo ‘export USE_CCACHE=1‘ >> ~/.bashrc echo ‘export CCACHE_DIR=/home/你的用户名/.ccache‘ >> ~/.bashrc # 可以指定一个大的磁盘分区 prebuilts/misc/linux-x86/ccache/ccache -M 50G # 设置缓存大小为50GB,这个值可以根据你的硬盘空间调整2.3 源码与驱动获取的“捷径”
传统方法是使用repo工具同步整个AOSP代码仓库,这对于网络环境是个巨大考验。我采用的是一种更直接的方法:寻找并下载特定分支的源码快照(tarball)以及与之完全匹配的专有驱动(Proprietary Binary Drivers)。
确定分支与驱动版本:这是最关键的一步,版本不匹配会导致编译失败或刷机后无法启动。我的目标分支是
android-10.0.0_r41。通过查询Google的驱动发布页面,我找到了对应Pixel 3 (blueline) 的驱动版本号:QQ3A.200805.001。你必须确保源码分支和驱动版本号完全一致。获取源码:我通过其他渠道(如国内镜像站或已下载的备份)获得了
android-10.0.0_r41分支的完整源码压缩包。将其解压到你的工作目录,例如~/aosp。解压命令:tar -xvf aosp_android-10.0.0_r41.tar.gz -C ~/解压后,目录结构应包含
build/,frameworks/,packages/等标准AOSP目录。下载专有驱动:前往Google的官方驱动下载站点(通常需要科学上网,这里我们假设你已经通过合规方式获取),搜索
blueline和QQ3A.200805.001。你会找到两个文件,例如:google_devices-blueline-qq3a.200805.001-xxxxxxx.tgzqcom-blueline-qq3a.200805.001-xxxxxxx.tgz将它们下载到你的源码根目录(即~/aosp)下。
解压与安装驱动:
cd ~/aosp tar -zxvf google_devices-blueline-qq3a.200805.001-xxxxxxx.tgz tar -zxvf qcom-blueline-qq3a.200805.001-xxxxxxx.tgz解压后会得到两个
extract-开头的shell脚本文件(例如extract-google_devices-blueline.sh)。依次执行它们:./extract-google_devices-blueline.sh ./extract-qcom-blueline.sh执行脚本时,它会显示许可协议,一直按空格键直到最后,会提示你输入
I ACCEPT来表示同意。这一步会将必要的闭源二进制文件(如GPU驱动、固件等)释放到vendor/目录下。如果后续编译时遇到vendor目录权限问题,可以运行:sudo chmod -R a+r vendor注意:不要轻易使用
777权限,a+r(所有用户可读)通常就够了,更安全。
3. 编译流程与核心问题破解
3.1 初始化编译环境与选择目标
一切准备就绪后,就可以开始编译了。首先,需要初始化编译环境。
cd ~/aosp source build/envsetup.sh这条命令会引入一系列有用的命令(如lunch,m,mm等)到当前shell环境中。
接着,使用lunch命令来选择我们要编译的目标。运行lunch后,会看到一个长长的产品列表。对于Pixel 3,我们选择aosp_blueline-userdebug。userdebug版本带有root调试权限,刷机后默认开启adb,非常适合开发和测试。你也可以直接指定:
lunch aosp_blueline-userdebug系统会确认你的选择,并显示一系列环境变量设置信息。
3.2 启动编译与遭遇的“拦路虎”
启动全量编译,使用make命令。为了充分利用多核CPU,通常会用-j参数指定并行任务数。一个常见的经验法则是CPU核心数 * 2。我的虚拟机有8个虚拟核心,所以我使用:
make -j16但是,如果你的内存不是特别大(比如小于32GB),我建议保守一点,使用-j8或-j4,否则极易引发内存不足(OOM),导致编译进程被系统杀死,前功尽弃。我一开始用-j16就遇到了OOM,后来改用-j8才稳定下来。
编译过程漫长,可能需要数小时。在这个过程中,你很可能会遇到错误。我遇到的一个非常具体且棘手的错误是关于pathtools的测试失败:
FAILED: out/soong/.bootstrap/blueprint-pathtools/test/test.passed ... --- FAIL: TestGlobEscapes (0.02s)错误信息指向build/blueprint/pathtools/globtest.go等文件。这个问题在网络上并不常见,我花了大量时间排查。最终有效的解决方案是删除有问题的测试文件。请注意,这是一个针对特定编译错误的workaround,并非通用方案。
cd ~/aosp rm build/blueprint/pathtools/globtest.go rm build/blueprint/pathtools/fstest.go删除这两个文件后,重新运行make -j8,编译得以继续。这个操作的本质是跳过了Soong构建系统(AOSP新的构建系统)中Blueprint模块的一个有问题的单元测试。在追求编译通过的前提下,这是一个可行的办法,但理论上它可能掩盖了更深层的环境配置问题。不过在我的场景下,后续编译和系统运行都完全正常。
3.3 编译完成与输出产物
如果一切顺利,几个小时后,你会看到编译成功的提示。编译生成的系统镜像文件位于:
~/aosp/out/target/product/blueline/这个目录下有几个非常重要的文件:
boot.img:内核和初始内存磁盘(ramdisk)镜像。system.img:系统分区镜像,包含Android框架和预装应用。vendor.img:供应商分区镜像,包含我们刚才安装的专有驱动。userdata.img:用户数据分区镜像(-w参数会刷写这个)。recovery.img:恢复模式镜像。android-info.txt:设备信息文件。flash-all.sh/flash-all.bat:自动刷机脚本(但通常我们更推荐手动刷机,可控性更强)。
4. 刷机入设备:从Bootloader到系统启动
4.1 刷机前的绝对准备工作
在将编译好的系统刷入实体手机之前,有几项准备工作是必须且不可逆的,请务必确认:
解锁Bootloader:Pixel 3的Bootloader必须解锁才能刷入自定义系统。操作步骤是:手机进入“设置”->“关于手机”,连续点击“版本号”打开开发者选项。然后在“系统”->“高级”->“开发者选项”中,开启“OEM解锁”和“USB调试”。手机关机后,同时按住“音量减”和“电源键”进入Bootloader模式(一个躺着的安卓机器人界面)。通过USB连接电脑,在电脑终端执行
fastboot flashing unlock。注意:这会清除手机内所有用户数据!请提前备份。退出Google账户:这是一个非常重要的安全步骤。在刷入自编译系统前,请务必在手机的当前系统中退出所有已登录的Google账户。这是因为Google的Factory Reset Protection (FRP)机制。如果刷机后触发恢复出厂设置,而设备里仍有之前的Google账户,系统会要求验证该账户才能进入,如果你编译的系统没有通过Google认证(肯定没有),或者你忘记了密码,手机就会变“砖”。虽然可以通过一些方法绕过,但非常麻烦。提前退出账户是最简单的预防措施。
配置USB连接与驱动(Windows宿主特别注意):如果你的宿主机是Windows,并在虚拟机上编译,需要确保:
- 宿主机已安装Google USB Driver(可通过Android SDK Manager安装)。
- 在VMware中,当手机连接时,选择将USB设备连接到虚拟机(Ubuntu),而不是宿主机。
- 在Ubuntu虚拟机内,通常无需额外驱动,但需要配置udev规则让普通用户也能访问设备。可以创建一个文件
/etc/udev/rules.d/51-android.rules,内容如下(可能需要根据你的用户ID修改):
然后重新加载udev规则:SUBSYSTEM=="usb", ATTR{idVendor}=="18d1", MODE="0666", GROUP="plugdev"sudo udevadm control --reload-rules && sudo udevadm trigger。
4.2 手动刷机步骤详解
我更倾向于手动刷机,而不是使用自动脚本,因为每一步都清晰可见,出了问题也容易定位。
进入Bootloader模式:确保手机关机。然后同时按住“音量减”和“电源键”,直到进入Bootloader界面(显示
START,RECOVERY MODE等字样)。连接设备并检查:在Ubuntu终端中,进入AOSP源码的
out目录下的host工具目录,并提升fastboot权限(避免每次都用sudo):cd ~/aosp/out/host/linux-x86/bin sudo chown root:root fastboot sudo chmod +s fastboot回到源码根目录,设置环境变量指向你的编译输出目录:
cd ~/aosp export ANDROID_PRODUCT_OUT=$(pwd)/out/target/product/blueline检查设备是否被识别:
fastboot devices应该会显示你的设备序列号,状态为
fastboot。执行刷机命令:这是最关键的一步。使用
fastboot flashall命令。-w参数代表擦除(wipe)userdata分区,这会清除手机所有数据,请再次确认已备份。fastboot flashall -w这个命令会依次刷入
bootloader,radio(基带),boot,recovery,system,vendor,userdata等所有必要的分区。你会看到终端滚动显示发送和写入每个镜像的进度。处理版本不匹配错误:如果你像我一样,手机之前运行的是Android 9或其他版本,直接刷入Android 10可能会在刷写
bootloader或radio时失败,提示bootloader version not supported或类似信息。这是因为跨大版本刷机时,基带和引导程序可能需要升级。最安全的方法是先刷入一次官方的、完整的、与你要编译的版本号(QQ3A.200805.001)一致的工厂镜像。- 从Google官方下载Pixel 3 (blueline) 对应
QQ3A.200805.001的工厂镜像。 - 解压后,手机进入Bootloader模式,在宿主机(Windows)上执行
flash-all.bat(Linux/Mac执行flash-all.sh)。这个操作会完全恢复手机到该版本的官方状态,包括Bootloader和基带。 - 官方镜像刷写成功后,再重新执行上面的手动刷机步骤,刷入我们自己编译的镜像。这时就不会再有版本冲突的错误了。
- 从Google官方下载Pixel 3 (blueline) 对应
完成与重启:
flashall命令执行成功后,手机会自动重启。第一次启动自编译的Android系统会非常慢,因为要进行ART预编译等操作,请耐心等待5-15分钟。如果长时间卡在Google Logo或开机动画,可以尝试强制重启(长按电源键),或者进入Recovery模式执行一次Wipe data/factory reset(这也会清除数据)。
5. 常见问题排查与实战心得
5.1 编译阶段问题速查表
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
repo init或repo sync失败/极慢 | 网络连接问题,无法访问Google源 | 1. 使用国内镜像源(如清华、中科大)。 2. 或采用本文的“源码包+驱动包”离线方式。 |
make命令报错java.lang.OutOfMemoryError | 系统内存不足,或-j参数值太高 | 1. 增加虚拟机/物理机内存(建议16GB+)。 2. 降低 make -j后的并行数(如改为-j4)。3. 关闭其他占用内存的软件。 |
| 编译中途失败,提示某个文件找不到或权限错误 | 依赖包未安装完整,或驱动未正确解压 | 1. 回头仔细检查并安装所有依赖包。 2. 确认专有驱动脚本已执行,且 vendor/目录下有文件。3. 检查 vendor/目录权限(sudo chmod -R a+r vendor)。 |
遇到类似bison或flex的工具版本错误 | 系统中存在多个版本或版本不兼容 | 1. 使用apt-get install安装的是稳定版本,通常没问题。2. 确保没有通过其他方式(如源码编译)安装冲突版本。 |
pathtools相关测试失败(如本文所述) | Soong/Blueprint构建系统的单元测试bug | 删除build/blueprint/pathtools/目录下的globtest.go和fstest.go文件(这是一个已知workaround)。 |
5.2 刷机与连接问题
fastboot devices不显示设备:- Windows宿主机:检查VMware的USB控制器设置(建议用USB3.0),并确保在手机连接弹窗时选择了“连接到虚拟机”。在设备管理器中检查是否有带感叹号的Android设备,手动更新驱动为Google USB Driver。
- Linux/Ubuntu:检查udev规则是否正确配置,尝试使用
sudo fastboot devices。用lsusb命令查看是否能识别到Google Inc.设备。
刷机过程在某个分区(如
radio)失败:- 这几乎总是由于设备当前的Bootloader或基带版本与你要刷入的系统镜像不兼容所致。唯一的可靠解决方案是先刷入一次完整的、对应版本的官方工厂镜像,将底层固件升级到正确版本,然后再刷自编译的
system、vendor等镜像。
- 这几乎总是由于设备当前的Bootloader或基带版本与你要刷入的系统镜像不兼容所致。唯一的可靠解决方案是先刷入一次完整的、对应版本的官方工厂镜像,将底层固件升级到正确版本,然后再刷自编译的
刷机成功但手机无法启动,卡在开机动画:
- 第一次启动慢是正常的,请等待至少10-15分钟。
- 如果超过20分钟,可以尝试强制重启。
- 如果重启无效,进入Recovery模式(Bootloader界面下用音量键选择
RECOVERY MODE),执行Wipe data/factory reset和Wipe cache partition。这会清除数据。 - 如果仍不行,可能是编译本身有问题,或者驱动不匹配。需要重新检查编译日志。
5.3 个人实操心得与建议
空间是最大的敌人:给编译环境分配磁盘空间时一定要慷慨。250GB是底线,300GB比较舒适。编译过程中可以用
df -h命令随时监控磁盘使用情况。网络问题的替代方案:如果
repo sync无法进行,不要硬扛。寻找国内镜像站提供的AOSP源码快照(snapshot)或tar包,配合驱动包,是最高效的方式。这并不影响你对源码的修改和编译。编译参数调优:除了
-j,设置CCACHE能极大提升第二次及以后的编译速度。将CCACHE目录放在读写速度快的磁盘上,并分配足够大的容量(50GB+)。保持环境纯净:建议为AOSP编译单独创建一个用户或者使用一个干净的虚拟机/容器环境。避免系统中其他软件或配置的干扰。
刷机有风险,备份是关键:解锁Bootloader和刷机一定会清空数据。在开始之前,务必通过
adb backup或云服务等方式备份好手机里的重要资料。退出Google账户是防止FRP锁的保险丝。耐心与日志:编译和刷机是一个需要耐心的过程。遇到错误时,不要慌张,仔细阅读终端输出的错误信息(通常最后几行是关键),并复制错误信息去搜索引擎查找。AOSP的编译错误信息通常比较具体,很多都能在网上找到解决方案。
整个过程走下来,从环境准备到手机亮起自己编译的系统,虽然步骤繁多,但每一步都有其逻辑。它不仅仅是一个技术操作,更是一个理解Android系统层次结构、构建流程和硬件依赖关系的过程。当你看到Pixel 3屏幕上出现基于你亲手编译的源码启动的系统时,那种对设备底层的掌控感和成就感,是普通应用开发难以比拟的。这为后续进行更深度的系统定制(比如你提到的修改位置信息)打下了坚实的基础。