|
/ |) V3 S: h& x1 Y+ a, z6 B
6 O6 H ~1 [* Y1 v4 \! i2022.11.01 今天惊讶地发现,Google 已经正式把这个模拟器的技术命名成了“云安卓”。感觉应该可以有更多玩法,期待国内厂商玩出花……
0 t8 Q* S. w/ h+ j 长期以来,很多文章一讲到框架,总是脱不开下载源码、编译、刷机三个步骤。于是乎,一台 Google 亲儿子 Pixel 手机似乎成了搞框架开发的入门必备。" _: L% @, M8 z# Z3 O% E9 k
事实上,Google 自己也面临着同样的问题。整个 Android 团队分布在全球各地,开发 + 设计 + 测试团队少说也有上几千人。Google 每年都会发布新手机,如果在每次研发新品都人手一台真机,消耗一定是巨大的。而且真正在手机厂商待过的同学才会知道,在新手机量产之前,测试机的资源都是十分紧张的,根本不可能做到人手一台。
( ^) B& p X# ^3 b但是问题是摆在这的,开发需要真机的环境,测试需要真机来验问题,稳定性团队需要大量的手机来跑 Monkey,难道就真的没有一个办法摆脱对真机的依赖吗?5 o1 `. d/ D( [ w
引见 CuttlefishCuttlefish 名字由来要说清楚 Cuttlefish,首先要介绍一下这个名字的由来。熟悉 Google 的同学都知道他们起名字向来很搞,这个时候需要先提一下另外一条鱼,Goldfish。
/ F3 ?6 l! H6 h早年接触过 Android 开发的同学,对 avd 这个名词应该不会陌生。没错,就是 Android Virtual Device,大家口中的“模拟器”。 在那个手机性能非常拉胯的蛮荒年代,avd 的出现解决了很多开发者需要依赖真机的问题。而 avd 背后的原理就是 Goldfish。事实上,Goldfish 同时也是 Android 的一个内核代号。, x7 Q; T3 q) C# o& z( W+ k4 o8 M, }
avd 确实极大程度解决了应用开发者的问题,做应用的小伙伴,改一下代码,编出一个 apk,可以直接 adb install 一下子就能看到效果,那框架开发者呢?虽然我们也有 adb push,但依然有很多变更是需要编固件才能验证的。编固件需要服务器去拉整个其他部门的代码来全编,全编需要等,好不容易等到固件出来了,需要吭哧吭哧刷机,刷机又很容易起不来,就算起来了,还有可能发现修改压根没生效……这一系列的操作完一抬头,估计下班时间也快到了,你就说你今天加不加班吧?
) \4 s% k2 N. V- W; WGoogle 也发现了这个问题,从 Android 11 那时候开始,就已经着手研发下一代的模拟器,思路也很简单。传统的模拟器还是太重了,现在可是云时代啊,有没有可能利用一些技术,让 Android 跑在“云端”,而用户甚至通过浏览器就可以访问到呢?时间来到 2022 年,这条鱼总算有了一个相对稳定的版本,就是下面要讲的 Cuttlefish。
* W" V( ~0 z8 o8 T- f" Q什么是 Cuttlefish?Google 官方给出的定义是:5 d% b' [ W; d- b1 Y: v# o
Cuttlefish 是一种可配置的虚拟 Android 设备,既可以远程运行(使用第三方云产品,如 Google Cloud Engine),又可以在本地运行(在 Linux x86 机器上)。6 l1 U3 ?* O( ]/ v" X
怎么理解呢?大家都知道国内大厂很多都有自己的云服务,比如阿里有阿里云,腾讯有腾讯云,华为有华为云。Google 自然也不例外,他们有自己的计算平台 Google Cloud Engine(以下简称 GCP)。自己买过服务器折腾过的小伙伴应该知道,有了实例之后,你就可以装操作系统,Linux、Windows 都行,然后再跑对应的服务,就可以远程访问了。% J" O2 e: q- c
得益于 Cuttlefish,很早之前,Google 的一些框架开发的测试验证和稳定性验证工作就不在真机去做了,而是在 GCP 的一个个实例里进行。步骤也十分简单,只需要一台 Ubuntu 实例,设置好环境,下载代码,lunch Cuttlefish 的 target,编译部署,最后直接通过浏览器访问,就可以看到一个网页在线的模拟器。而且这一切,Google 全都是开源的,并且官网也有详细的操作步骤。既然可以部署到服务器,也就意味着我们可以本地验证,下面带大家了解一下本地运行。
! y* j6 c3 @+ G5 y' ~( V部署 CuttlefishGoogle 其实已经在官网给出了详细的操作步骤了,不过最后那几步是让我们下载他编译好的镜像。我们不一样!我准备带大家现编现卖,毕竟我们可是开发者!% t- B, W+ V; l
环境配置一台 x86_64 的电脑,Linux 环境,我自己惯用的是 Linux mint,理论上 Ubuntu 20.04 即可。没必要装太老的版本。" ^. g" K* E$ d- P; S
基本步骤- 确定一下电脑有没有 kvm,换句话说,确认一下是否支持虚拟化:2 l- v- ]' f1 S/ r7 {! X
grep -c -w "vmx\|svm" /proc/cpuinfo复制代码上面的命令应该返回一个大于 0 的值,证明环境没问题。 - 使用如下命令安装 CuttleFish 所需的依赖:
; W6 S4 a Z1 M6 r- i. f- asudo apt install -y git devscripts config-package-dev debhelper-compat golang curlgit clone https://github.com/google/android-cuttlefishcd android-cuttlefishfor dir in base frontend; do cd $dir debuild -i -us -uc -b -d cd ..donesudo dpkg -i ./cuttlefish-base_*_*64.deb || sudo apt-get install -fsudo dpkg -i ./cuttlefish-user_*_*64.deb || sudo apt-get install -fsudo usermod -aG kvm,cvdnetwork,render $USERsudo reboot复制代码注意,最后那个命令是重启电脑,记得保存手头工作关掉其他窗口。 - 下载 AOSP 源码,国内推荐大家用清华或者科大的镜像,可以参考这篇文章来进行。
- 选择目标,开始编译:
& Q) Q/ y% Y _& Y Esource build/envsetup.shlunch aosp_cf_x86_64_phone-userdebug复制代码注意,这里的 aosp_cf_x86_64_phone-userdebug 是手机的镜像。如果我们想要编译其他目标,可以输入 lunch,然后在菜单里进行选择。其实我们从这里就可以看到,Google 这几年一直在积极开发 CuttleFish,aosp_cf 后面有各种设备类型,从手机,到TV,再到车机,反而是最下面 sdk_ 开头的目标没有那么多了,要知道,这可是之前编本地模拟器时候的目标呀。如果大家有兴趣的话,可以选择其它目标进行编译。 - 开始编译:) T4 r$ c5 p4 E) O) V8 S# n! w
m复制代码你没看错,就是一个 m。很多教程里还会让大家加上 -j 参数来指定任务数,我在这里并不推荐,因为每个人的电脑性能不同,这个参数设大了,在性能差的设备上编译会被直接 kill,设小了,又没法把性能跑满,所以还不如不传,编译脚本会根据你的电脑配置自己决定的。如果是新同步的代码,第一次会全编 AOSP 所有模块并输出镜像。我使用一台 Dell Precision 3660,时间大约在 50 分钟左右。 - 模拟器开机:
4 M; u7 ^: A8 B/ e9 s% w2 r5 B3 H0 N$ launch_cvd --start_webrtc=true复制代码Google 的命名梗又来了,他们把经由 Cuttlefish 搭建的模拟器称为 cvd,正好与 avd相对应。--start_webrtc 声明了我们需要在浏览器中使用 WebRTC 管理访问 Cuttlefish 设备。; E% c, V7 B% j" L
就这么简单,如果一切顺利,不会一会儿就可以在命令行见到一串 Boot completed,这代表模拟器已经启动好了。+ y+ V! E% [7 K" ]" Q3 u" V

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

" {- Y- I3 `; e, r% G* n使用 Cuttlefishadb 命令Cuttlefish 一旦跑起来之后,和本机用数据线插着一台手机是没什么两样的,使用 adb devices 可以看到这台设备,打开 Android Studio,也可以看到 logcat 里有日志输出。
( b- J y7 q: k t# J! s( m& h5 k* f多实例启动前面说过,Google 的测试团队很早就开始用 Cuttlefish 来验 bug 和跑 Monkey 了,这就面临多设备的问题,而 Cuttlefish 是完美支持多开的,只需要在启动的时候加上 --num_instances 参数即可,后面的数字代表你要启动几个实例。这里我以启动 2 个实例为例:
1 z8 n: u: y8 y$ launch_cvd --start_webrtc=true --num_instances= 2复制代码如果提示 launch_cvd 找不到,你应该是忘记 source build/envsetup.sh && lunch aosp_cf_x86_64_phone-userdebug 了。
+ d( d: u: `( ^7 ]) V$ r# C ) Q# c3 w7 a+ b# C, Q
可以从网页看到此时已经有2台设备在运行了,这两台设备是独立的,没有任何关系。我们尝试执行一下 adb devices:6 G$ E3 o7 S8 c0 ^! b
$ adb devicesList of devices attached0.0.0.0:6520 device0.0.0.0:6521 device复制代码确实可以看到两台设备,Cuttlefish 会从第一台设备开始,将端口号往上递增,来区分不同设备。有了多台设备,就可以轻松跑一些稳定性测试之类的了。还有很多其它用例,跟插着多台设备类似,不在此赘述。
/ X/ U a- g% u& \下图演示了在 Cuttlefish 上运行 atest 测试。说实话单元测试在很多公司似乎都不被重视,但 Google 自己的代码几乎都有单元测试。关于单元测试推荐 qing 的这篇文章:《给安卓开发小白们的unit test指南 - 这也能测?这也要测?》。
, X1 W( q4 |8 N. ?
9 \, R# w7 H F! E2 k9 g2 C# @实战:Framework 修改快速验证Cuttlefish 在我这段时间用下来而言,最大的好处无非就是方便了我对 AOSP 的开发调试和验证,免去的繁琐的编模块,·adb push,甚至刷机等过程。这里打算以 Settings 模块为例,假设我现在有一个需求,想在 Settings 启动时弹出一个 toast。8 f' a% a: `" Z& l. Y5 q
为了调试方便,这次选择 lunch eng 的类型: G+ Y; Y2 L9 p4 p# z4 i
$ source build/envsetup.sh && lunch aosp_cf_x86_64_phone-eng复制代码下面开始做需求,这里简单粗暴一些,直接打开 DashboardFragment.java,在 onCreate 加上代码:2 y$ O/ h+ n9 i9 c
@Overridepublic void onCreate(Bundle icicle) { super.onCreate(icicle); Toast.makeText(getPrefContext(), "Hello Cuttlfish", Toast.LENGTH_SHORT).show(); // Settings 原生代码 }}复制代码这只是最最最简单的改动,而更多时候,熟悉 Settings 模块的同学都知道,日常做 Settings 的需求,你可能还需要改到 SettingsLib 、 framework/base,还有其它很多关联目录,要编好几个 apk,好几个 jar,验证的时候要 push 一大堆东西到不同的目录,非常痛苦。4 {: X5 C1 E! _, V, V5 L+ _$ ^
有了 Cuttlefish 之后,似乎就没那么复杂了。我一般会直接在 AOSP 根目录执行一下全编:) \" ]' S" i4 u: r5 J
$ m复制代码有些小伙伴估计急了,你特么在逗我?全编?别慌,要知道编译是增量的。Soong 会比对前后的 Ninja 文件,如果没有差异,直接跳过,有差异,则会编对应的地方。所以一般我甚至不关心我需要编哪几个模块,整个交给编译系统就好了,如下图所示:
1 {* v8 [# Y2 R2 v/ F, P( U+ h
& n7 Q6 }7 I {- W4 \3 ]: Q因为是全编,模块编译完之后会自动生成新的 system.img。
5 z1 ^0 q# L: A/ ^/ D f " P$ p* T4 |. B" w
没有漫长的拷贝固件,没有漫长的刷机过程,无需担心能不能点亮,无需一次次点击为了跳过开机向导,而是直接启动 Cuttlefish,还记得命令吗?& f5 Q5 b' |3 F0 |% c, x
$ launch_cvd --start_webrtc=true复制代码然后打开我们修改后的模块:2 M i+ _- R+ c5 W: L. b0 X: w
+ F& r: l8 u/ a1 g' _
看到 Toast 弹出,修改已经生效了,就是这么方便!
- G- c1 B2 s2 c' i更多用法Cuttlefish 的更多用法,建议大家直接看官网,这里就不照搬了。其实 Google 很多文档写的都很详细,只可惜很多小伙伴要么不看,要么就是出问题直接搜百度,找到的都是别人消化后的东西。希望大家能养成“先看官网,后看文章”的好习惯。
3 `" v4 \% p0 I |; N7 K5 \0 d' Msource.android.com/docs/setup/…% k1 N5 u, Y7 \5 D; b2 |8 }
总结本文基于现阶段 Android Framework 工程师在开发调试阶段可能遇到的实际问题,向大家介绍了 Google 的云安卓方案,该方案不依赖物理设备,而是基于虚拟机 + WebRTC,通过浏览器就可以访问到云设备,理论上可以为 Android Framework 开发测试工作带来极大的便利。另外,云安卓整个技术理论上也会有很多其它应用场景,大家可以自行发挥创造力。7 ~3 c- M* Z& N* A
4 X0 j) R. e2 [3 x4 w0 G$ _
5 A1 O* M: C: x! y: z0 M
# b9 q, z( Y7 K$ }$ ]5 F! ~# j* `3 [/ N0 W
: Y6 z9 }& t/ U8 D7 V |
|