编完 aosp 还在刷机?云安卓了解一下,来试试网页版模拟器吧!

语言: CN / TW / HK

2022.11.01 今天惊讶地发现,Google 已经正式把这个模拟器的技术命名成了“云安卓”。感觉应该可以有更多玩法,期待国内厂商玩出花……


长期以来,很多文章一讲到框架,总是脱不开下载源码、编译、刷机三个步骤。于是乎,一台 Google 亲儿子 Pixel 手机似乎成了搞框架开发的入门必备。

事实上,Google 自己也面临着同样的问题。整个 Android 团队分布在全球各地,开发 + 设计 + 测试团队少说也有上几千人。Google 每年都会发布新手机,如果在每次研发新品都人手一台真机,消耗一定是巨大的。而且真正在手机厂商待过的同学才会知道,在新手机量产之前,测试机的资源都是十分紧张的,根本不可能做到人手一台。

但是问题是摆在这的,开发需要真机的环境,测试需要真机来验问题,稳定性团队需要大量的手机来跑 Monkey,难道就真的没有一个办法摆脱对真机的依赖吗?

引见 Cuttlefish

Cuttlefish 名字由来

要说清楚 Cuttlefish,首先要介绍一下这个名字的由来。熟悉 Google 的同学都知道他们起名字向来很搞,这个时候需要先提一下另外一条鱼,Goldfish。

早年接触过 Android 开发的同学,对 avd 这个名词应该不会陌生。没错,就是 Android Virtual Device,大家口中的“模拟器”。 在那个手机性能非常拉胯的蛮荒年代,avd 的出现解决了很多开发者需要依赖真机的问题。而 avd 背后的原理就是 Goldfish。事实上,Goldfish 同时也是 Android 的一个内核代号。

avd 确实极大程度解决了应用开发者的问题,做应用的小伙伴,改一下代码,编出一个 apk,可以直接 adb install 一下子就能看到效果,那框架开发者呢?虽然我们也有 adb push,但依然有很多变更是需要编固件才能验证的。编固件需要服务器去拉整个其他部门的代码来全编,全编需要等,好不容易等到固件出来了,需要吭哧吭哧刷机,刷机又很容易起不来,就算起来了,还有可能发现修改压根没生效……这一系列的操作完一抬头,估计下班时间也快到了,你就说你今天加不加班吧?

Google 也发现了这个问题,从 Android 11 那时候开始,就已经着手研发下一代的模拟器,思路也很简单。传统的模拟器还是太重了,现在可是云时代啊,有没有可能利用一些技术,让 Android 跑在“云端”,而用户甚至通过浏览器就可以访问到呢?时间来到 2022 年,这条鱼总算有了一个相对稳定的版本,就是下面要讲的 Cuttlefish。

什么是 Cuttlefish?

Google 官方给出的定义是:

Cuttlefish 是一种可配置的虚拟 Android 设备,既可以远程运行(使用第三方云产品,如 Google Cloud Engine),又可以在本地运行(在 Linux x86 机器上)。

怎么理解呢?大家都知道国内大厂很多都有自己的云服务,比如阿里有阿里云,腾讯有腾讯云,华为有华为云。Google 自然也不例外,他们有自己的计算平台 Google Cloud Engine(以下简称 GCP)。自己买过服务器折腾过的小伙伴应该知道,有了实例之后,你就可以装操作系统,Linux、Windows 都行,然后再跑对应的服务,就可以远程访问了。

得益于 Cuttlefish,很早之前,Google 的一些框架开发的测试验证和稳定性验证工作就不在真机去做了,而是在 GCP 的一个个实例里进行。步骤也十分简单,只需要一台 Ubuntu 实例,设置好环境,下载代码,lunch Cuttlefish 的 target,编译部署,最后直接通过浏览器访问,就可以看到一个网页在线的模拟器。而且这一切,Google 全都是开源的,并且官网也有详细的操作步骤。既然可以部署到服务器,也就意味着我们可以本地验证,下面带大家了解一下本地运行。

部署 Cuttlefish

Google 其实已经在官网给出了详细的操作步骤了,不过最后那几步是让我们下载他编译好的镜像。我们不一样!我准备带大家现编现卖,毕竟我们可是开发者!

环境配置

一台 x86_64 的电脑,Linux 环境,我自己惯用的是 Linux mint,理论上 Ubuntu 20.04 即可。没必要装太老的版本。

基本步骤

  1. 确定一下电脑有没有 kvm,换句话说,确认一下是否支持虚拟化:

bash grep -c -w "vmx\|svm" /proc/cpuinfo

上面的命令应该返回一个大于 0 的值,证明环境没问题。

  1. 使用如下命令安装 CuttleFish 所需的依赖:

bash sudo apt install -y git devscripts config-package-dev debhelper-compat golang curl git clone https://github.com/google/android-cuttlefish cd android-cuttlefish for dir in base frontend; do cd $dir debuild -i -us -uc -b -d cd .. done sudo dpkg -i ./cuttlefish-base_*_*64.deb || sudo apt-get install -f sudo dpkg -i ./cuttlefish-user_*_*64.deb || sudo apt-get install -f sudo usermod -aG kvm,cvdnetwork,render $USER sudo reboot

注意,最后那个命令是重启电脑,记得保存手头工作关掉其他窗口。

  1. 下载 AOSP 源码,国内推荐大家用清华或者科大的镜像,可以参考这篇文章来进行。

  2. 选择目标,开始编译:

bash source build/envsetup.sh lunch aosp_cf_x86_64_phone-userdebug

注意,这里的 aosp_cf_x86_64_phone-userdebug 是手机的镜像。如果我们想要编译其他目标,可以输入 lunch,然后在菜单里进行选择。其实我们从这里就可以看到,Google 这几年一直在积极开发 CuttleFishaosp_cf 后面有各种设备类型,从手机,到TV,再到车机,反而是最下面 sdk_ 开头的目标没有那么多了,要知道,这可是之前编本地模拟器时候的目标呀。如果大家有兴趣的话,可以选择其它目标进行编译。

  1. 开始编译:

bash m

你没看错,就是一个 m。很多教程里还会让大家加上 -j 参数来指定任务数,我在这里并不推荐,因为每个人的电脑性能不同,这个参数设大了,在性能差的设备上编译会被直接 kill,设小了,又没法把性能跑满,所以还不如不传,编译脚本会根据你的电脑配置自己决定的。 如果是新同步的代码,第一次会全编 AOSP 所有模块并输出镜像。我使用一台 Dell Precision 3660,时间大约在 50 分钟左右。

  1. 模拟器开机:

bash $ launch_cvd --start_webrtc=true

Google 的命名梗又来了,他们把经由 Cuttlefish 搭建的模拟器称为 cvd,正好与 avd相对应。--start_webrtc 声明了我们需要在浏览器中使用 WebRTC 管理访问 Cuttlefish 设备。

就这么简单,如果一切顺利,不会一会儿就可以在命令行见到一串 Boot completed,这代表模拟器已经启动好了。

launch_cvd --start_webrtc=true_001.png

这个时候我们打开浏览器,输入 https://localhost:8443,回车,就可以看到 Cuttlefish 自动帮我们利用 WebRTC 搭建并运行的页面,我们在左侧选择刚才启动的 cvd 实例,在右边就可以看到它的实时画面,和传统的 avd 没有区别,点击事件什么的也完全能够响应,同时左侧还有一个工具条,可以模拟一些高级操作,这一点也和之前用的 avd 类似。

image.png

使用 Cuttlefish

adb 命令

Cuttlefish 一旦跑起来之后,和本机用数据线插着一台手机是没什么两样的,使用 adb devices 可以看到这台设备,打开 Android Studio,也可以看到 logcat 里有日志输出。

多实例启动

前面说过,Google 的测试团队很早就开始用 Cuttlefish 来验 bug 和跑 Monkey 了,这就面临多设备的问题,而 Cuttlefish 是完美支持多开的,只需要在启动的时候加上 --num_instances 参数即可,后面的数字代表你要启动几个实例。这里我以启动 2 个实例为例:

$ launch_cvd --start_webrtc=true --num_instances=2

如果提示 launch_cvd 找不到,你应该是忘记 source build/envsetup.sh && lunch aosp_cf_x86_64_phone-userdebug 了。

image.png

可以从网页看到此时已经有2台设备在运行了,这两台设备是独立的,没有任何关系。我们尝试执行一下 adb devices: $ adb devices List of devices attached 0.0.0.0:6520 device 0.0.0.0:6521 device 确实可以看到两台设备,Cuttlefish 会从第一台设备开始,将端口号往上递增,来区分不同设备。有了多台设备,就可以轻松跑一些稳定性测试之类的了。还有很多其它用例,跟插着多台设备类似,不在此赘述。

下图演示了在 Cuttlefish 上运行 atest 测试。说实话单元测试在很多公司似乎都不被重视,但 Google 自己的代码几乎都有单元测试。关于单元测试推荐 qing 的这篇文章:《给安卓开发小白们的unit test指南 - 这也能测?这也要测?》

image.png

实战:Framework 修改快速验证

Cuttlefish 在我这段时间用下来而言,最大的好处无非就是方便了我对 AOSP 的开发调试和验证,免去的繁琐的编模块,·adb push,甚至刷机等过程。这里打算以 Settings 模块为例,假设我现在有一个需求,想在 Settings 启动时弹出一个 toast。

为了调试方便,这次选择 lunch eng 的类型:

bash $ source build/envsetup.sh && lunch aosp_cf_x86_64_phone-eng

下面开始做需求,这里简单粗暴一些,直接打开 DashboardFragment.java,在 onCreate 加上代码:

java @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); Toast.makeText(getPrefContext(), "Hello Cuttlfish", Toast.LENGTH_SHORT).show(); // Settings 原生代码 } }

这只是最最最简单的改动,而更多时候,熟悉 Settings 模块的同学都知道,日常做 Settings 的需求,你可能还需要改到 SettingsLibframework/base,还有其它很多关联目录,要编好几个 apk,好几个 jar,验证的时候要 push 一大堆东西到不同的目录,非常痛苦。

有了 Cuttlefish 之后,似乎就没那么复杂了。我一般会直接在 AOSP 根目录执行一下全编:

bash $ m 有些小伙伴估计急了,你特么在逗我?全编?别慌,要知道编译是增量的。Soong 会比对前后的 Ninja 文件,如果没有差异,直接跳过,有差异,则会编对应的地方。所以一般我甚至不关心我需要编哪几个模块,整个交给编译系统就好了,如下图所示:

image.png

因为是全编,模块编译完之后会自动生成新的 system.img

image.png

没有漫长的拷贝固件,没有漫长的刷机过程,无需担心能不能点亮,无需一次次点击为了跳过开机向导,而是直接启动 Cuttlefish,还记得命令吗?

bash $ launch_cvd --start_webrtc=true

然后打开我们修改后的模块:

vokoscreenNG-2022-10-31_18-58-13.gif

看到 Toast 弹出,修改已经生效了,就是这么方便!

更多用法

Cuttlefish 的更多用法,建议大家直接看官网,这里就不照搬了。其实 Google 很多文档写的都很详细,只可惜很多小伙伴要么不看,要么就是出问题直接搜百度,找到的都是别人消化后的东西。希望大家能养成“先看官网,后看文章”的好习惯。

https://source.android.com/docs/setup/create/cuttlefish

总结

本文基于现阶段 Android Framework 工程师在开发调试阶段可能遇到的实际问题,向大家介绍了 Google 的云安卓方案,该方案不依赖物理设备,而是基于虚拟机 + WebRTC,通过浏览器就可以访问到云设备,理论上可以为 Android Framework 开发测试工作带来极大的便利。另外,云安卓整个技术理论上也会有很多其它应用场景,大家可以自行发挥创造力。