Physical Address:
ChongQing,China.
WebSite:
也许在很多人的眼里,Android是只能运行在ARM之上的。在我们日常生活中,运行的Android设备几乎都是ARM类型的CPU。但实际上Android也可以运行在x86的环境上,这时候我们需要在x86上模拟Android设备,本文探讨的即是Android模拟相关的一些技术。
谈到对Android的模拟,肯定会有人想到Android Emulator,也叫做Android Virtual Device(AVD)。作为日常中比较常见的的一种对Android模拟方式,我们可以在很多Android模拟器,包括AndroidStudio内看到它。事实上其本身是基于Android Goldfish所产生的版本。除了Goldfish,Google还有一套名为Cuttlefish的虚拟化架构,同样可以让你自由模拟出虚拟的Android设备。目前大体上就这两种方案,以下将会对这两种方案做一些介绍。
Android Virtual Device(Android Emulator)其底层基于QEMU,而QEMU本身在发展过程中又分为两个阶段,即QEMU1与QEMU2,Google对应地将其命名为Goldfish和Ranchu,而在QEMU之下,则又是基于KVM的。由于层层嵌套,实际上 Android Virtual Device 或者说AVD的性能是比较差的,无法很好地发挥硬件性能。关于 Android Virtual Device 的软件架构,可以参考下方示意图(来源于官方网站):
在Android Emulator中,你可以利用完整的Android框架去开发你自己的APP,但是也仅限于APP。也就是说你无法修改到Java Framwork,Native Sevice包括Hal及以下的东西。一般我们会将AVD用于测试我们自己开发的APP,确保APP功能的可用性、兼容性等等,这也是其作为AndroidStudio常用组件之一的原因。
一般来讲,我们使用AVD时,可以自行将写好的APP通过adb安装到AVD内进行测试,也可以通过AndroidStuido进行安装测试。如果我们需要与其他人共享自己的开发环境,我们也可以通过源码编译的形式将编译好的镜像导入给他人使用。
如何去创建、编译以及手动运行AVD呢,可以遵循如下步骤:
#拉取源码
repo init -u https://xxxxxx -b xxxxx
repo sync -j16
#初始化环境,注意选择对应的镜像
source ./build/envsetup.sh
lunch sdk_xxxx_x86
#开始编译
make -j16
最终我们会在out目录下得到一个名为sdk-repo-linux-sys
tem-images-eng.[username].zip
的压缩包。
我们可以将该镜像分发给其他人,使用Android Emulator进行启动,也可以在编译完成后的环境内直接使用emulator命令进行启动。
在Android Emulator启动时,我们可以通过命令参数来进行一些额外的设定或获得一些额外信息,此处列举一些比较常用的设定项:
参数 | 用途 |
-no-snapshot-load | 如果可能,执行快速启动,但在退出时不保存模拟器状态。 |
-camera-back mode -camera-front mode | 设置后置或前置相机的模拟模式。它会替换 AVD 中的任何相机设置。mode 可以是以下任何值:emulated – 模拟器在软件中模拟相机。webcamn – 模拟器使用连接到开发计算机的摄像头,由数字指定。如需查看摄像头列表,请使用 -webcam-list 选项;例如 webcam0 。none – 在虚拟设备中停用相机。 |
-webcam-list | 列出开发计算机上可用于模拟的摄像头 |
-show-kernel | 在终端窗口中显示内核调试消息 |
-accel mode | 配置模拟器虚拟机加速 |
-kernel filepath | 使用特定的模拟内核 |
-ramdisk filepath | 指定 ramdisk 启动映像 |
-system filepath | 指定初始系统文件 |
关于Android Emulator的更多信息,可以点击这里进行获取。
上面我们讲了Android Virtual Device,不难看出其有一个很大的缺点,那就是除了验证APP,无法进行更底层的一些验证。鉴于此,Google官方又推出了另一个类型的模拟器,名为Cuttlefish。
与Goldfish或者说Ranchu不同,Cuttlefish从设计之初,就有者以下截然不同的目标:
1.使平台和应用开发者不再依赖于物理硬件来开发和验证代码更改
2.过与核心框架保持高度一致,以高保真度为重点来复制真实设备的基于框架的行为
3.在各个 API 级别达到一致的功能水平,与物理硬件上的行为保持一致
4.提供可配置的设备,能够调整外形规格、R AM、CPU 等
5.实现规模化运行,支持多实例并发
简单来讲,Cuttlefish最大的好处在于:在尽可能地保证系统框架的一致性前提下可以不依赖于物理硬件进行开发和测试。也正由此,Cuttlefish常用于框架合规性测试、持续性的集成测试和先导性开发等工作。
Cuttlefish的整体软件架构其实与Goldfish没有太大的差异,不过最大的差异在于底层VM的实现上。在Cuttlefish中,底层VM实现是CrossVM,在Goldfish或者说Ranchu中则是QEMU。CrossVM基于Rust语言编写,相对QEMU而言更加轻量化,性能也更好。但两者同样依赖于KVM,同样存在嵌套的问题。
关于如何运行Cuttlefish,可以参考我的另一篇博文:Vmware+Ubuntu20+Cuttlefish模拟运行Android12
我们都知道Android本身有Phone版本,auto版本,TV版本等等。而Cuttlefish作为Google主推的虚拟化方案,在AAOS(Automotive Android Operating System)中又有着特殊的适配版本。这些适配工作主要是基于车载应用中的场景而去完成的。
这里需要明确的是,Trout本身基于Cuttlefish,只是针对车载做了许多额外的适配。这些适配工作主要集中在Virtio标准实现上,涉及到的内容包括:
功能 | 虚拟化技术 |
音频控制 HAL | vsock/gRPC |
音频 HAL | virtio-snd |
蓝牙 | virtio-console |
转储状态 HAL | vsock/gRPC |
增强型视觉系统 (EVS) | virtio-video |
图形 | virtio-gpu |
传感器 HAL 2.0 | virtio-scmi and IIO |
触摸屏输入 | virtio-input |
事实上在车载行业中,这种类似的虚拟化技术已经开始进行落地,大概的软件框架如下图所示:
从这个框架图中,我们可以看到VirtIO是很重要的一部分。在这个框架中,首先Guest VM的内核需要实现VirtIO相关的驱动。而当前的Android内核中都没有完整实现这些驱动,其中音频的实现算是比较完整的,而Virtio-gpu与Virtio-video都没有,预计完整的支持还得再等三到五年。
除了Guest端,Host端需要运行一个用户态的VM管理器(Trout中就是CrossVM),其实现Virtio相关的后端,再接入实际的硬件驱动(通过Host Kernel)。这样,通过Virtio驱动就可以完全将Guest VM的驱动进行标准化,用户在一次开发后可以运行到任何满足Virtio标准的Host机器上。
当然这种方式由于存在层层嵌套,性能的损耗也是比较大的。如果将Virtio驱动实现在HyperVisor内并直接接管硬件驱动,则可以降低性能损失。
关于Trout的更多有用信息,可以参考这里
未完待续,本文将持续更新….