Android云真机原理以及云真机平台搭建实践

几乎每个云测平台或手机厂商都有云真机业务,解决了小团队真机设备覆盖不足、资产管理困难的问题,让开发者可以像本地设备一样在线操控和调试设备。云真机平台一般附带一些辅助操作平台,可以通过拖拽的方式安装APP,同步黏贴板,查看log,截屏跑自动化,等等这些都可以在浏览器内完成,确实给研发测试都带来了不少便捷。
云真机通过一个设备管理系统,将这些真机对外租用,相比于传统的实体机租用,在线租用免去了实体机快递和硬件损坏风险的问题,随租随用,资费透明。
但他们都有一个共同点,贵,超级贵,按秒计费。

主流的云真机平台有腾讯WeTest远程调试、TestIn远程真机、百度测试云真机等,下面是百度云真机官网的介绍。

Android云真机原理以及云真机平台搭建实践_第1张图片

ADB是什么

在讲云真机之前,需要先说说什么是ADB。
全名:Android Debug Bridge
官方解释:

Android 调试桥 (adb) 是一个通用命令行工具,其允许您与模拟器实例或连接的 Android 设备进行通信。


ADB可分为三个部分:

  • 客户端
    该组件发送命令。客户端在开发计算机上运行。您可以通过发出 adb 命令从命令行终端调用客户端。
  • 后台程序
    该组件在设备上运行命令。后台程序在每个模拟器或设备实例上作为后台进程运行。
  • 服务器
    该组件管理客户端和后台程序之间的通信。服务器在开发计算机上作为后台进程运行。

打开开发者调试模式发生了什么

ADB的后台程序相当于一个跑在手机上的服务器,通过约定的协议以TCP的方式和PC的客户端交互,执行命令。比如 adb install命令,实际上是往手机上传了一个apk文件,然后告诉手机的安装程序安装这个apk;比如断点调试代码,实际上是IDE和手机之间通过adb互传代码执行信息,代码行号之类的。

研发可以通过开启一个SocketServer来欺骗adb,执行adb connect命令就会显示连接了一个设备,可以看到每条adb命令发出的是什么样的报文,当然孤独的adb是得不到任何回应的,它连的是假的设备。

adb的权限极大,可以在偷偷的执行命令而用户看不到,就像电脑上安装了360杀毒软件,连上手机后,手机上会默默的多出一个360安全助手APP。。。

这个后台程序默认是不开启的,当你打开和关闭手机开发者设置里面的调试模式后,其实就是在开关这个后台程序。

所以不建议普通用户的手机打开这个功能,哪怕360给你说出一万个打开调试模式的好处,也不要开。

云真机是什么

这些云测平台没有骗你,真的在云端跑了大量的真机,不是虚拟机不是模拟器。所以贵也是有道理的,当你租用这个手机的时候,就是独占了一台价值不菲的设备,消耗着不小的带宽。

Android云真机原理以及云真机平台搭建实践_第2张图片

云真机原理

云真机本质上就是远程控制手机,并且通过API的方式间接调用adb命令和手机交互。
云测平台的服务器通过一些高端的USB HUB连接了很多真机,再通过一个设备管理系统,将手机屏幕类似直播的方式显示到用户的浏览器上,再接收浏览器的上的手势操作回传给服务器。

Android云真机原理以及云真机平台搭建实践_第3张图片

云真机原理

上面提到这些云测平台的云真机服务,基本都是在一个叫STF的开源软件基础上定制开发而来的。
STF 全名Smartphone Test Farm,是一个安卓设备管理在线平台(也在扩展ios支持),刚开始被设计用来将将公司内部众多的安卓设备资产统一管理,并可以直接在个人电脑上在线使用手机,后来这些云测平台改改UI,变成了一个对外租用服务。

STF平台架构

STF架构的官方说明可以看看GitHub上的DEPLOYMENT.md

这个有点不好理解,这里画个简版的架构图:

Android云真机原理以及云真机平台搭建实践_第4张图片


这里面几个关键角色介绍一下:

  • 手机
    普通的安卓设备,上面会运行着一个叫Minicap的APP(在首次接入系统时被自动安装),在被租用时会以每秒60张的速度高速截图,并通过这个系统发送给用户,同步画面。
  • 设备提供方
    就是直接连着手机的电脑,负责发送设备连接状态、转发画面以及执行adb命令等任务。
  • 消息服务
    通过消息队列(ZeroMQ),向整个系统的各个模块广播设备在线状态、租用状态等信息,充当中间人。
  • Web服务
    一个NodeJs写的后台服务器,提供在线管理平台和API服务。
  • 认证服务
    提供用户认证的服务,默认没有认证,内置一个仅需提供邮箱并且不校验的简单认证服务。一般需要定制扩展,集成内部的CAS、LDAP等认证系统。
  • 数据库
    保存设备的信息,如设备型号、分辨率、在线状态、租赁状态、备注等等。STF默认用的是一个叫RethinkDB的冷门数据库,不好部署,大部分定制系统都会将其替换成MySql等。
  • 存储服务
    文件存储,比如截图产生的图片,用户上传的apk文件,自动化测试的脚本等。
  • 代理服务
    这里简单称之为代理服务,其实有多个服务,包括视频流转发服务、手势操作转发服务、远程调试转发服务、adb命令转发服务。主要是为设备被使用时的数据中转服务,因为远程控制数据量大且实时性要求高,所以不走web服务,通过WebSocket的方式独立提供服务。

运行效果

STF部署

上面所有的服务都可以是一台独立的电脑,也可以部分或全部在同一台电脑上。部署方式分为单机和集群两种。

单机

单机就是所有的服务都部署在同一台电脑上,用于自己使用。
stf的安装成功是比较困难的,命令其实很简单,主要是一些依赖库可能需要,因此建议下面的所有安装命令都要在状态下运行。安装失败建议卸载已安装的模块,全部重新安装。


安装:
首先,安装依赖项,Mac为例:

brew install rethinkdb graphicsmagick zeromq protobuf yasm pkg-config

然后再安装stf:

npm install -g stf

运行:
先启动rethinkdb:
只需要在命令行中通过rethinkdb命令启动;
再启动服务:
对于单机版,有一个快捷的命令以默认配置一键启动所有服务:

stf local --public-ip 

—public-ip 是你的内网ip,这样局域网内的其他同学也可以远程你电脑上的手机,不加这个参数就只能本机访问。

使用:
默认的web服务端口是7100,因此在浏览器输入http://localhost:7100即可使用。
接入手机,设备列表上会自动出现手机并且标记为在线状态,点击该设备就可以进入远程控制状态;拔下手机就会自动标灰,无法远程。

集群

集群就是将部分模块独立部署,以缓解节点压力,上面的每一个服务都是可以独立部署的,并且像设备提供方、web服务器、代理服务器都是可以集群的。
一种简单的集群模式可以是:

将除设备提供服务外的所有服务部署在一个公网服务器上,而在每个人的电脑上部署一个设备提供服务。
这样,每个人电脑上的部署就相对简单,而且每个人都可以将自己电脑上的设备连接到服务器上,统一管理。

  • 服务器部分:
    因为不再是单机了,每个服务都得单独启动关联,相对复杂,可以参考官方的部署方法(https://github.com/openstf/stf/blob/master/doc/DEPLOYMENT.md)
  • 个人部分:
    只要运行provider模块,所以只要使用stf provider命令,除了指定内网ip外(大家电脑上也没有公网ip),还需要其他几个必要参数,包括消息服务的地址、存储服务的地址、端口区间(用于代理服务分配端口,不能和其他设备提供方重合)等。完整的命令如下:
   stf provider     --name "%H/%i"     --connect-sub tcp://devside.stf.example.org:7250     --connect-push tcp://devside.stf.example.org:7270     --storage-url https://stf.example.org/     --public-ip ${COREOS_PRIVATE_IPV4}     --min-port=15000     --max-port=25000     --heartbeat-interval 10000     --screen-ws-url-pattern "wss://stf.example.org/d/%i/<%= serial %>/<%= publicPort %>/"

Docker部署

docker部署的成功率最高,但是在Mac下docker和宿主机无法共享USB设备,所以无法提供设备,其他其他的可以尝试。也在上面的官方部署里面有提到。

STF扩展方向

这里可以参考美团点评云真机平台实践(https://tech.meituan.com/2018/07/19/cloud-phone.html),可以扩展的方向包括:简单的页面改造、账户集成KMS、集成Jenkins自动化测试(使用API上传apk直接安装指定到测试机)、跨局域网部署(比如把Websocket换成WebRTC,使用SocketServer模拟设备转发)等等。反编译了阿里云真机的客户端程序源码,其真是通过本地开启了一个SocketServer中转云端真机的adb数据流,而我们本地Android Studio链接的设备其实是这个SocketServer,阿里云通过这个SocketServer实现了云真机的一些权限校验工作。

agent设计

背景

目前市場上,雲真機平台實時投屏主要有兩種工具:STF的minicap和GenyMotion的scrcpy;STF的minicap工具是採用截圖的方式實現實時投屏,但是minicap工具根據google發布的Android版本對應不同的工具文件,當新的Android發布時,minicap的適配版本還未及時發布可能會影響用戶體驗。Scrcpy通過獲取視頻數據實現實時投屏,但是只能支持Android 5.0以上。因此,目前這兩種投屏方式都有各自的優缺點。

我們平台採用兩種方式結合的方式,用來儘快適配google發布的android版本。最近,在新手機上線過程中,發現有些品牌(如vivo,oppo)的手機無法使用Scrcpy工具進行實時投屏,通過分析發現其H264的碼流是High檔次,而前端H264數據播放插件只支持baseline檔次的碼流。

這個問題,有兩種解決方式:一個是前端播放插件對應不同的碼流進行切換,還有一種是修改原始碼流,此處我們選擇了後者。

方案

以小米9手機爲例 (Android 9.0),雖然STF的minicap工具已經對Android 9.0進行了適配,但是前端播放插件不支持H264 baseline以外的碼流。H264格式數據的碼流通過profile_idc欄位標識,小米9獲取到的H264格式數據如圖所示:

其中profile_idc標識碼流有兩個檔次,100即High檔次碼流,66表示baseline檔次碼流。碼流的取值是由手機硬體決定的。通過scrcpy源碼(https://github.com/Genymobile/scrcpy)發現 ScreenEncoder 文件中有個 createForma t私有方法可以指定視頻流數據的格式,因此我們通過修改該方法的代碼,人爲的將視頻流數據格式化爲baseline,具體如圖所示:

修改完源碼之後實時投屏實現主要包括以下幾個步驟:
1. 將scrcpy源碼重新編譯成jar包,將jar包push到手機中。
2.在手機中執行命令

CLASSPATH=/data/local/tmp/scrcpy-server.jar app_process / --nice-name=scrcpy_servercom.genymobile.scrcpy.Server 0 8000000 true weight:height:0:0 false

其中weight和height是手機的寬度和高度。(需要注意的是每次執行命令後,之前push到手機中的jar包會被清除,所以每次啓動命令都需要pushjar包)
3.執行`adb forward`命令forward埠和手機進行socket通信連接。以獲取視頻流數據。
4.將獲取的視頻流數據解析成單條H264數據再轉發給web端,web端通過插件播放視頻流,最終實現實時投屏的效果。
修改後scrcpy.jar獲取得到的視頻流解析數據如圖所示,通過H264分析工具可以看到H264格式的數據profile_idc變成了66,碼流變成baseline格式。達到我們想要的效果:

Android云真机原理以及云真机平台搭建实践_第5张图片​​​​​​​ 

最終效果

前端播放使用Broadway插件

你可能感兴趣的:(android,java,apache)