ubuntu 22.04.2编译Android 12.1源代码&模拟器

Android 11系统映像可直接将 ARM 指令转换成 x86 指令,因此以前很多需要真机测试的情况,现在只需要模拟器就可以进行操作了。

不过,根据官方博客 Run ARM apps on the Android Emulator 尾部的一段注意事项:

Note that the ARM to x86 translation technology enables the execution of intellectual property owned by Arm Limited. It will only be available on Google APIs and Play Store system images, and can only be used for application development and debug purposes on x86 desktop, laptop, customer on-premises servers, and customer-procured cloud-based environments. The technology should not be used in the provision of commercial hosted services.

这段事项说明,自己编译的镜像是没办法用上这个功能的,必须是Google编译好的镜像。

由于众所周知的原因,我们是没办法正常下载Android的源代码的,因此只能使用国内的镜像来操作了。

1.安装repo工具以及依赖

$ sudo apt-get install gcc make perl

$ sudo apt-get install ccache

$ sudo apt-get install curl

$ sudo apt-get install python3

# 升级pip
$ pip3 install pip --upgrade

# 清理可能的无效缓存
$ pip cache purge

# 安装repo
$ sudo apt-get install repo

$ sudo apt-get install aria2

$ sudo apt-get install git

$ sudo apt install -y libssl-dev

# 解决 
# prebuilts/clang/host/linux-x86/clang-3289846/bin/clang.real: error while loadin
g shared libraries: libncurses.so.5: cannot open shared object file: No such fi
le or directory

$ sudo apt install libncurses5


# 安装VSCode,方便后续查看代码
$ sudo snap install code --classic

$ git config --global user.email "user@email.com"

$ git config --global user.name "user"

2.在需要存储代码的地方创建文件夹

$ mkdir ~/AndSrc

$ cd ~/AndSrc

3.使用镜像下载Android源代码

清华大学的镜像

# 针对ubuntu 22.04不建议直接下载压缩包,建议直接使用repo更新,原因是ubuntu 22.04的python被升级成了python3,python2被完全移除。
# 而清华镜像压缩包里面的repo还是python2时候创建的,会引起各种初始化异常
# aria2 -c https://mirrors.ustc.edu.cn/aosp-monthly/aosp-latest.tar

$ mkdir aosp

$ cd aosp

$ repo init -u https://aosp.tuna.tsinghua.edu.cn/platform/manifest --repo-url=https://gerrit-googlesource.lug.ustc.edu.cn/git-repo

4.Android 模拟器编译(可选)

# Android 12模拟器对应分支 emu-31-release 

$ repo init -b emu-31-release 

# 会失败多次,不断尝试,直到完全成功,目前测试发现单线程虽然慢点,但是基本不会失败,多线程经常失败
$ repo sync -j4 --fail-fast

$ cd external/qemu/android/

$ ./rebuild.sh --no-tests

编译完成之后,产生的模拟器可执行文件及库文件都位于`external/qemu/objs/android`目录下:

~/AndSrc/aosp/external/qemu/android/objs$ ls
android_emu64_unittests           emulator64-mips
android_emu_metrics64_unittests   emulator64_simg2img
bin64                             emulator64_test_crasher
build                             emulator64-x86
emugl64_common_host_unittests     emulator-check
emulator                          lib
emulator64-arm                    lib64
emulator64_crashreport_unittests  lib64GLcommon_unittests
emulator64-crash-service          lib64OpenglRender_unittests
emulator64_img2simg               qemu
emulator64_libui_unittests        resources
emulator64_make_ext4fs

后面就可以像执行 SDK 中的模拟器那样,执行我们编译的模拟器了:

# 下面是个例子,只有设备上已经通过Android SDK 创建过 Nexus_5_API_30_x86,才可以成功执行

~/AndSrc/aosp/external/qemu/android/objs$ ./emulator -avd Nexus_5_API_30_x86

5.列出android-12全部分支

$ cd ~/AndSrc/aosp

$ cd .repo/manifests && git branch -a | cut -d / -f 3 | grep android-12

6.编译Android 12系统镜像

$ cd ~/AndSrc/aosp

# 前面的编译可能会产生部分垃圾文件,需要清理一下,清理之前,编译好的文件提前备份一下	 
$ rm -rf *

$ repo init -b android-12.1.0_r26

# 会失败多次,不断尝试,直到完全成功
$ repo sync -j4 --fail-fast

# 如果上面的命令失败,可以尝试调整为单线程,目前测试发现单线程虽然慢点,但是基本不会失败,多线程经常失败 
# repo sync -j1 --fail-fast

7.引入编译环境变量

$ source build/envsetup.sh

8.设置编译目标,此处我们指定编译x86_64下的完整调试版本(镜像无法安装ARM应用)

# 纯x86系统镜像,不能安装arm应用
# lunch sdk_phone_x86_64

# eng:代表 engineer,开发工程师的版本,拥有最大的权限(root等),具有额外调试工具的开发配置。 
# 执行 lunch 命令可以输出全部的编译目标列表 
# 更多的编译选项可以从 build/make/target/product/ 下看到 
# lunch aosp_x86_arm-eng 编译后的镜像可以安装 arm 应用, 不过在不进行任何代码调整的情况下,应用启动会崩溃 
# 不能安装 arm 应用

$ lunch sdk_phone_x86_64-eng

9.如果需要跟踪调试代码,建议编译为调试类型

$ export TARGET_BUILD_TYPE=debug

10.编译

$ export USE_CCACHE=1  

# 清理代码,为编译准备干净的环境

$ make clobber

# 由于编译的时候内存压力会非常大,即使我们已经配置了足够大的交换分区
# 如果系统内存在16GB左右,非常容易触发 ubuntu 22.04 自带的 systemd-oomd 杀进程操作
# 导致编译过程莫名中断,如果发现编译的时候,命令行窗口突然消失了,一般都是 systemd-oomd引起的
# 此时我们需要暂时停止 systemd-oomd
# sudo systemctl stop systemd-oomd

$ make -j8

注意此处如果发生编译失败,原因基本上是编译顺序导致的引用出错,也就是某些模块还没有编译完成,其他模块已经开始尝试链接,导致依赖错误,此时只要把多线程并发编译修改成单线程编译即可,即直接执行

$ make

如果由于内存不足导致的编译失败,可以增加物理内存。但是如果内存无法增加的话,那么适当增加交换分区/交换文件的大小(建议配置16GB以上的交换分区)可以解决此问题,只是编译速度会下降。

运行镜像

选择system-qemu.img和vendor-qemu.img,这两个镜像是专门为qemu运行制作的,如果选择system.img 和vendor.img,则avd运行失败。

$ cd ~/AndSrc/aosp

$ export ANDROID_BUILD_TOP=~/AndSrc/aosp

$ export PATH=$PATH:$ANDROID_BUILD_TOP/out/host/linux-x86/bin

$ export ANDROID_SWT=$ANDROID_BUILD_TOP/out/host/linux-x86/framework

$ export ANDROID_PRODUCT_OUT=$ANDROID_BUILD_TOP/out/target/product/emulator_x86_64

$ ./prebuilts/android-emulator/linux-x86_64/emulator -verbose -show-kernel

上面运行起来的镜像是从`~/AndSrc/aosp/out/debug/target/product/generic/hardware-qemu.ini`即可读取配置信息的,但是这个文件直接修改无效,我们如果需要修改参数,只能从启动参数中设置。
比如我们如果需要增大内存,开启`GPU`的支持,则执行如下命令:

$ ./prebuilts/android-emulator/linux-x86_64/emulator -gpu on -memory 4096 -verbose -show-kernel
编译支持ARM应用的镜像

尽管根据

Note that the ARM to x86 translation technology enables the execution of intellectual property owned by Arm Limited. It will only be available on Google APIs and Play Store system images, and can only be used for application development and debug purposes on x86 desktop, laptop, customer on-premises servers, and customer-procured cloud-based environments. The technology should not be used in the provision of commercial hosted services.

我们自己编译的镜像是没办法直接从源代码编译支持安装运行 ARM 应用的。

但是有两个变通方案:

  1. Google官方的 Android 12 镜像中提取需要的文件塞到我们自己编译的镜像里,参考方案: Adding ARM native bridge to the AOSP11 x86 emulatorandroid_vendor_google_emu-x86
  2. 使用 Intel Houdini 实现支持,参考方案:Include Intel Houdini in Android-x86

参考链接