2.2 Bitcomet方案设计

        本方案是在Ubuntu 20.04(下图GNU/Linux部分),部署好Docker环境。

        Bitcomet底层:其中Android 11的Docker镜像以及Anbox相关组件,均为本方案的实现,经过编译打包并导入Docker的密封环境中。

        Bitcomet中间层:在Android 11中,Anbox的后端及相关模块通过桌面下的Anbox前端产生的QEMU pipe进行通信。

        Bitcomet上层:Android在容器内缺少图形输出、渲染、音频和键盘设备操作的输入输出功能,其相关功能依赖Anbox的Gralloc、HWC、Audio等相关模块实现。这些模块在QEMU pipe通信的基础上,搭建起对外Linux沟通桥梁,为外部Linux对接内部Android的输入输出、图形输出渲染等功能。外部Anbox针对相关功能实现调用Linux系统库,实现了输入输出渲染等功能。

        如图2.5是针对Bitcomet各个部分的详细设计:

图2.5 Bitcomet方案详细架构图

        其中各个部分有相关的实现文档,具体见当前项目下Docs目录内其他文档。

2.2.1 Docker下的安卓11容器设计

图2.6 Bitcomet实现底层部分设计框架图

(1) 主要工作

        在Bitcomet方案底层部分中,使用Docker容器提供Android运行的环境。当然仅仅提供一个环境还不行,Android 11需要依赖Binder、SELinux、SDcardFS、Ashmem等环境的支持。具体的工作如下:

内核定制:Binder与Ashmem需要针对内核定制,目前较新的Linux 5.x已经自带BinderFS和Ashmem模块的支持,旧的内核需要使用Anbox提供的Binder或Ashmem模块。

SELinux安全机制处理:本方案选择了对其相关方法进行屏蔽处理,即使实际测试及Docker文档中都反应了Docker下是可以实现这个支持的,但我们仍然选择了屏蔽,其原因如下:

        第一,Docker外是针对指定配置文件的SELinux安全配置,而Android内的还需要单独配置并需要一部分特权。

        第二,不同平台的Linux内核不一定提供并使用了SELinux安全模块,遇上没有此模块的平台均无法运行。

        第三,使用SELinux后,Docker官方提到可能会对性能有一定的损失。

文件系统挂载处理:SDcardFS部分是安卓8以后提供的模块,可以让Android接管对SDcardFS下的目录文件的访问权限控制。我们选择了使用FUSE来实现挂载SDcard的虚拟文件系统,FUSE是较旧版本的Android采用的一种方式,其实现主要在用户空间,能提供几乎与SDcardFS相同的功能。但FUSE挂载SDcard的实现也有缺点,其速度比SDcardFS的实现慢,我们仍然选择FUSE方案的原因如下:

        第一, SDcardFS的实现依赖Linux内核实现,不同Linux内核对其支持不一样。

        第二, 由于SDcardFS在内核实现,挂载它也需要一定的特权。

(2) Bitcomet底层部分特点

Docker下的安卓11容器设计:
高可移植设计:使用了Docker便集成了Docker相关的优点,Docker相比原有LXC有可移植性、版本控制、回滚、快速部署等优点。同时原有LXC容器与Anbox进行了高度集成,在目前多平台和可移植性考量下,原有Anbox的系统镜像与各个配置选项都不能方便地进行更改,这将会导致我们适配到国产系统中遇到重重困难。
快速迭代更新:使用Docker提供底层容器运行环境,利用其快速部署的优点,可以使Android 11更加灵活地运行在目标平台。
高效的数据管理:利用Docker的版本控制和回滚特性,设计恢复出厂设置并清空用户数据的功能,并为以后Android镜像更新时能够快速部署,及时把新版本推送。
较高系统安全性:把安卓放在密封的容器当中,其外部访问数据都通过QEMU pipe交给上层Anbox前端应用接管,其应用也只有基本的输入输出功能,安全性较高。
极低的运行损耗:通过容器直接基于现有系统Linux内核运行,并基于Linux内核特性进行容器隔离,这一方案提高了稳定性并降低了运行损耗。

2.2.2 安卓与上层Anbox通信设计

图2.7 Bitcomet中间层部分设计原理图

(1) 主要工作

        在Bitcomet中间层中,我们复用了Anbox这一实现,把其相关实现移植到Android11,并实现其上面的各种功能。我们的主要工作如下:

通信实现:把Anbox基于QEMU pipe和qemud的实现移植到Android11,这两个实现的本质均为通过QEMU pipe实现,但由于容器内没有实质上的QEMU pipe设备,因此Anbox魔改了一下使用Unix Domain Socket实现,这种实现从原理上说与QEMU pipe的区别在于:第一,QEMU pipe设备是通过QEMU的相关模拟实现的,其模拟的设备支持DMA,理论上比Unix Domain Socket这一软件实现更有效率;第二,Anbox这里相关实现的名字还是叫做QEMU pipe,而QEMU pipe本身也有tcp socket相关的实现。

设备映射:在Docker中映射外部Anbox的Session Manager创建的Socket监听到容器内的/dev对应设备,以便容器内的QEMUd或者QEMU pipe相关实现进行调用。

Anbox通信模块移植:容器内Anbox为这些实现封装成了叫做HOST_CONNECTION的方法,容器外Anbox基于谷歌的ProtoBuf实现一种通信模型,其中包括OpenGL ES、HWC、模拟的Surface、Anbox Proxy等组件的RPC调用,以便内部Anbox通过这些封装的方法直接调用,我们也针对这些方法进行了移植和部分测试。

(2) Bitcomet中间层部分特点

安卓中运行qemud提供QEMU pipe这一高速管道与上层通信:
成熟的通信方案:这一通信方案基于成熟的Anbox的通信这一部分的功能实现,其上层Session Manager提供接口,由安卓和Anbox两端利用相应API把接口打开进行通信。其实现方案最早可以追溯到2013年的谷歌Goldfish的Android模拟器实现并且沿用至今,实现了Android与Linux的之间通信的兼容性与健壮性并存的实现方式。
便捷的交互方式:本方案在安卓与Linux之间的通信方案设计基于QEMU pipe这一高速通道,直接在Android与Linux之间打通一个灵活的通信渠道。本方案不用考虑需要的具体通信实现,直接在安卓HAL层服务和上层Anbox前端应用中打开相应通道进行安卓与Linux对接的数据通信。

2.2.3 上层Anbox的OpenGL ES渲染以及输入输出设计

图2.8 Bitcomet上层部分设计原理图

(1) 主要工作

        在Bitcomet的上层中,我们也复用Anbox的实现,把其相关部分移植到Android11和Ubuntu 20.04上。Android中对接外部Linux主要在图形输出、渲染、输入输出部分缺失,这些部分需要靠Anbox在中间通信层的部分实现之上,建立各个部分的连接,打通到外部Linux上。我们的主要工作如下:

HAL层模块移植:这一部分主要工作在Android中HAL层的移植以及测试,我们经过在Android工程中对AIDL与HIDL对应HWC与Gralloc部分的模块进行配置,Gralloc的HAL层复用最新Android 11中对安卓模拟器的AVD实现。我们复用Android 11的这一部分主要原因在于其安卓模拟器的实现与Anbox的实现是一样的,都是软件实现的调用ashmem申请图形缓冲区。

图形输出部分移植:从Android的HAL层中Gralloc与HWC模块开始,图形输出部分的核心模块是HWC模块,它负责被SurfaceFlinger调用进行图层合成输出到显示设备,而这里我们选择在Anbox的实现上进行移植修复。该实现主要测试点在于图形HWC,HWC中的发送图层部分开始,通过Anbox的RPC调用,发送图层到外部Anbox的Surface上,需要测试相关图层测试数据是否能到达外部Anbox上合成输出。

输入输出部分移植:在输入部分,Anbox的Session Manager注册了多个Event设备以及audio传输设备,我们需要把这些设备在Docher中映射到/dev下,以便在Android中调用。其中音频部分也复用Android11针对模拟器部分的audio HAL实现,原因在于Anbox这些部分的实现也是复用Android模拟器的实现,其原理是把音频PCM数据通过Anbox的RPC调用方法发送到外部Anbox进行解码播放。

OpenGL ES部分移植:Anbox的OpenGL库主要在Android的 /system/lib64/egl 目录下安装了三个动态库,分别为libEGL_emulation.so、libGLESv1_CM_emulation.so和libGLESv2_emulation.so。Anbox在其中提供虚拟的硬件厂商配置,为Android提供OpenGL ES渲染库。但Anbox实际渲染工作并不是上述三个库文件,这三个库文件作用为采集Android中APP渲染的OpenGL ES指令,并通过高速传输通道qemu-pipe传输将指令传至宿主机Anbox进程中,实际渲染工作由宿主机执行。这部分主要也是移植好Anbox这几个库,检验该三个库与上层Anbox的通信,这部分库也是复用谷歌Android的安卓模拟器AVD实现,主要测试工作在于做相关指令的通信以及实际渲染测试。

(2) Bitcomet上层部分特点

Anbox通过QEMU pipe与底层通信,接收安卓的渲染信息渲染以及音频在上层APP输出,把上层前端APP的输入和状态传递给安卓:
兼容性高:主要体现在Linux下对Anbox的兼容性,这一方案的设计把安卓需要与Linux交互和获取的数据都通过QEMU pipe传输给Linux处理,上层Anbox前端不依赖硬件。尤其是渲染也是调用系统现有OpenGL库实现,兼容性相比虚拟机来说更高。
易用性高:通过上层Anbox应用接管底层安卓的输入输出等部分,相当于把安卓应用直接映射给了Linux应用。这一操作安卓应用非常接近使用Linux应用的方式,极大的提高了其易用性,操作起来也更加简单。