安卓(AOSP)13 源码编译及模拟器使用蓝牙踩坑记

Posted by HX on 2023-01-18 | 👓

为了编译 AOSP,特地跑去给笔记本升级了内存条、移动硬盘,还买了个 U 盘,好在钱没白花,最后是编译成功了==

最开始想着用 WSL2 编译然后拿生成的镜像给 Windows 上的 AVD 模拟器跑,结果模拟器部分踩了一堆天坑,到最后也没法解决,可能也是太菜了。其实解决了前面各种坑后日志可以看到模拟器已经成功跑起安卓内核并且运行 init 进程了,说明已经进入到用户态,奈何那个 surfaceflinger 不停崩溃,结果卡在启动它的死循环里…… 所以这篇文章用的是 VMware 里面的 Ubuntu 来跑,我个人因为已经用 WSL2 编译成功了,所以直接把 WSL2 的 vhdx 磁盘转成 VMware 支持的 vhd 格式,然后挂载到了 Ubuntu。其实一开始直接在 Ubuntu 走编译等整套流程应该也没问题。

开始前先确认你的机器配置符合要求:内存至少 16G,硬盘至少 500G。我这里的系统是 Windows 10(主机)+ Ubuntu 20.04(虚拟机)。

第一步,装好虚拟机。编译的话可以用 WSL2,也可以用 VMware Workstation,但运行模拟器只能用 VMware,因为 WSL 不支持图形界面(Windows 11 上 WSLg 好像是开始支持了,没试过)。WSL2 编译的话,因为默认只给分配系统的一半内存,所以如果这个一半不到 16G 的话必须手动增加,在 %USERPROFILE%\.wslconfig 中添加如下配置:

1
2
3
4
[wsl2]
memory=13GB
swap=32GB
swapFile=<随便指定一个路径存放交换文件>

配置项的意思是,给 WSL 分配 13GB 内存(视情况自己改,有时候太多了会把你系统卡死,太少了编译又会内存不足),创建一个大小为 32GB 的交换文件,存储在你指定的路径。因为编译要 16GB 内存,所以我搞了个虚拟内存来补充不足的 3GB。这个交换文件下次运行时好像要把已有的那个删掉,不然用不了。

坑点 0:不要在 Windows 的分区(NTFS/FAT32)上放源码,放在 Linux 的分区(ext*)上。因为编译过程需要一个大小写敏感的文件系统,虽然 NTFS 可以设置某个目录为大小写敏感,但为了避免后面出现其他奇怪的坑(比如 Linux 的符号链接),还是强烈建议把源码放在 ext 文件系统上,比如 WSL 中你的 ~ 目录(要确保 WSL 的虚拟 vhdx 磁盘所在的 Windows 分区容量足够)。

坑点 1:不要用 VirtualBox。VirtualBox 在我这里运行 Ubuntu 比 VMware 明显要慢,而且运行模拟器不知道为啥也跑不起来。VMware 的注册码(没办法,穷人)比想象中要容易找到得多得多,而且它也没有我想象中那么笨重。

第二步,拉取 AOSP 源码。这个网上很多教程,我用的葫芦娃(hluwa)大佬的,在虚拟机里运行如下四条命令:

1
2
3
4
wget -c mirrors.tuna.tsinghua.edu.cn/aosp-monthly/aosp-latest.tar
tar xf aosp-latest.tar
cd AOSP/.repo/repo; git pull origin master
cd ../../; ./.repo/repo/repo sync

第三步,安装依赖。运行如下命令:

1
sudo apt-get install git-core gnupg flex bison gperf 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

第四步,开始编译。运行如下命令:

1
2
3
source build/envsetup.sh
lunch aosp_x86_64-eng
m -j4

如果你想跑模拟器的话,把 lunch aosp_x86_64-eng 换成 lunch sdk_phone_x86_64(前者也可以编译,但我没试过能否跑模拟器)。也有其他架构的,可以运行 lunch 查看。最后 m -j4 里的数字表示线程数,有几颗 CPU(或几核)就设为几吧。接下来就是几个小时的编译时间,不需要模拟器的话到这就结束了。

坑点 2:编译中提示 java.lang.OutOfMemoryError: Java heap space 错误时,表示你的虚拟机内存不足。确保你分配的内存足够,如果是 WSL2,记得照第一步所说增加内存。

第五步,配置 VMware 透传蓝牙设备给虚拟机。(如果你不需要模拟器的蓝牙功能,直接跳到第六步。)在 VMware 里关机状态下编辑你的虚拟机设置,在硬件中切换到“USB 控制器”项目下,在右边取消“与虚拟机共享蓝牙设备”(是的,取消,感觉选中其实也有办法让模拟器用蓝牙,暂时懒得研究),然后选中“显示所有 USB 输入设备”。启动虚拟机,在右下角找到一个蓝牙图标,这就代表你主机的蓝牙设备,右键点连接。这会使虚拟机独占该设备,所以主机上就用不了蓝牙了。

第六步,启动模拟器。如果重新启动过虚拟机,先再次运行如下命令准备环境:

1
2
source build/envsetup.sh
lunch sdk_phone_x86_64

如果不需要蓝牙,在 AOSP 根目录运行如下命令即可启动模拟器:

1
emulator

如果需要蓝牙,先运行如下命令查看蓝牙设备的厂商号和产品号:

1
lsusb

打印出来的信息中有设备名,仔细看看哪个是蓝牙设备(我这边笔记本内置蓝牙名字挺怪的,好像叫 Intel Corp. VMware Virtual USB Mouse),再记下前面的厂商号和产品号,形如 xxxx:xxxx,其中 xxxx 是十六进制数。最后以如下命令启动模拟器并将虚拟机的蓝牙设备透传给模拟器:

1
emulator -usb-passthrough vendorid=aaaa,productid=bbbb

其中,aaaa 是刚记下的厂商号转为十进制bbbb 是产品号转为十进制。到此,启动后的安卓系统应该就可以用蓝牙了。(在网上搜到的透传参数都是 -usb -device usb-host,vendorid=<usb-vendor-id>,productid=<usb-product-id> 这样的,不知道是不是新版模拟器专门为 USB 透传新加了参数)

如果启动后模拟器一直黑屏,可以在启动命令加 -show-kernel 参数,看看内核打印出什么信息(不过就算看了我也解决不了,天坑)。

坑点 3:记得在 VMware 你的虚拟机设置 -> 处理器里启用 VT-x,在显示器里启用加速 3D 图形,并且关闭 Windows 上的 Hyper-V,包括在控制面板 Windows 可选功能中卸载 Hyper-V 相关组件、在 BCD 设置中禁用 Hyper-V。因为 AVD 模拟器其实是一个 QEMU 虚拟机,在虚拟机里跑虚拟机需要 VT-x 嵌套虚拟化的支持,Hyper-V 会影响其他虚拟机软件的嵌套虚拟化。

2023/2/12 更新:Windows 上的 Android Studio 自带模拟器也可以透传蓝牙,命令跟上面一样,数字如果用十六进制要加 0x 前缀。如果提示 Cannot load Android USB Assistant Driver for USB device 错误,需要安装 USB 驱动,点击里面 tgz 下载,然后管理员身份运行 Install_Drivers.bat。