酒店无线效能研发组,负责酒店无线团队基础能力平台的研发,比如Cloud Touch平台(云端手机),内容运营平台,自动化测试流程等,通过对日常规律性事务的抽象总结提供解决方案,提高平台所承载业务的整体效能。
一、背景
携程内部会有大量的部门或团队需要在App新版本、新站点完成研发阶段所有功能测试后,在上架前(Post Release)阶段,再进行无拘束的从客人视角验收的诉求(比如竞品对比、Localization体验等)。对于已经上架的版本,我们的客服人员在客人协助、新员工培训等场合,也有着使用生产资源来获得与客人同一视角的环境诉求,这对我们研发流程中已经存在的测试环境的适用性提出了巨大的挑战,无论从操作体验、还是资源对齐等多方面,测试环境都难以满足诉求。
- 例如为满足Trip.com的新站点上线前的海外驻地验收诉求,需支持新站点的新功能提前向定向人群释放的能力。
- 例如为满足客服在对客协助时,能充分理解客人的进线问题,需支持员工和客人的视角保持一致的App操作平台。
二、全场景建设
我们综合评估了相似诉求以及平台能力可能的辐射面后,下图呈现了我们对系统(下文统一命名Cloud Touch)的适用人群的预期:
以驻地验收场景为例:基于Cloud Touch平台,可统一收口验收人员的设备管理,通过云平台提供统一的远程操作入口。这样不论我们的员工在世界任何驻地,都可以方便的使用中心化维护的设备,同时新站点的RC包将在Cloud Touch上提前上架,完成待验收版本的部署。
以客服协助场景为例:基于客服工作台给员工提供统一的进入Cloud Touch的入口,可供员工在与客人的对话中了解客人的对应App版本,能快捷的在设备池中选择相关预置好的实机进行场景鉴定工作。
(以上示意图)
三、基于Cloud Touch的技术解决方案
3.1 核心平台设计
基于以上分析,平台需要解决的是覆盖不同应用场景的设备资源的分配管理问题,实现不同地域请求的中心化分发问题,提供本地设备的远程操控以及画面的实时同步问题,以达到类似于远程桌面的交互体验。并且可基于平台化的收口能力为不同业务场景提供统一的预置参数和环境的配置,使各项工作的标准化能进一步得到提升。
3.2 设备分池设计
我们有大量的客服员工座席,同时也有研发线的测试验收人员,设备池的足够大是硬件条件,但是如何有效的利用这些设备,协调好不同应用场景的人和设备的关系,这还需要一套满足核心场景的分配策略设计,主要的核心流程如下:
3.3 远程设备操控设计与实现
实现了平台化和设备的统一分发工作后,那么技术的核心在于如何选型并实现一套端到端的远程控制方案。
因为不同系统的对接技术不同,此处我们以iOS的实现为例,WebDriverAgent是Facebook 在17年的 SeleniumConf 大会上推出的一款新的iOS移动测试框架(WDA),WebDriverAgent 在 iOS 端实现了一个 WebDriver Server 能够实现与浏览器进行交互,它的实现使用了经典的Server-Client架构(C/S),客户端发送一个Requset,服务器端返回一个Response,借助这个 Server 我们可以远程控制 iOS 设备。
WDAClient:基于WebDriverAgent实现的WDA的客户端。facebook-wda 就是 WDA 的 Python 客户端库,通过直接构造HTTP请求直接跟WebDriverAgent通信。
WDAServer:运行WDA App的机器,实现了WebDriver的通讯协议。
Session:服务器端需要维护客户端的Session,客户端首次发送请求的字符串是'/session/sessionId/url′。服务器端根据url打开对应的url地址,同时将sessionId解析成真实的值,然后返回给客户端。以后客户端再向浏览器发送请求时,会携带session值一起发送。
WebElement:WebDriverAPI中的对象,代表页面上的一个DOM元素。
JsonWireProtocol:是通过使用webdriver与remote server进行通信的 web service 协议 。通过http请求,完成和remote server的交互。
Mobile JSON Wire Protocol Specification:移动端自动化协议。
(此处引用了WDA官方的部分基础技术说明,如您感兴趣可以再进一步参考github上的facebook archive项目)
3.3.1 指令集适配
Client端可以接收多种不同类型的指令以完成不同的动作,主要包括以下几种:
(1)基本指令通信格式(iOS/Android格式公用,处理略有不同,以下用iOS举例):
{
"serial":"00008030-000D48A40291802E", // IOS设备udid
"type":"M_TOUCH", // 命令类型枚举值
"message":{
"action":0, // 鼠标或键盘 0按下 1松开
"keycodeType":"ascii", // 代表键盘事件输入的是ascii码
"keyCode":60, // 键盘按下了哪个键 非ascii时响应对应系统键
"position":{
"x":687, // 鼠标点击事件x像素坐标
"y":1116, // 鼠标点击事件y像素坐标
}
}
}
(2)基本指令:鼠标事件(点击/滑动操作)
- 前端页面根据设备上报的分辨率和用户在画面上操作的位置,计算鼠标的像素位置x,y并组装鼠标事件命令
- Client收到actinotallow=0命令时(即按下鼠标时),记录鼠标按下的坐标和命令的时间
- Client收到actinotallow=1命令时(即松开鼠标时),记录鼠标松开的坐标和命令的时间。
- Client根据设备的scale(IOS设备像素和uiKit的缩放比)将命令下发的像素坐标转换为ui操作坐标,获得命令的起点和终点。将按下和松手的时间差值作为命令的执行时间,组装WDA命令。
- 请求WDA的url为:/wda/swipe,根据起点、终点、命令执行时间、命令触发频率的不同可产生点击、长按、双击、滑动的效果
(3)基本指令:按键事件
- 前端记录用户按下的按键并转换为ascii码,组装键盘输入事件,长时间按压会连续产生的命令;用户在页面上点击的系统按键(电源、主页、菜单键)也会被转换为键盘输入事件
- Client收到actinotallow=0时,若收到ascii码的字符,则触发字符输入事件;若收到系统按键,则组装对应的命令完成操作
- 字符输入事件: /wda/keys接口默认有同步快照机制,会消耗大量时间确保输入按照顺序进行,平均响应时间1字符/秒。云手机对时效的要求更高,所以将WDA快照机制删除,并在Client中使用队列,将短时间内的多个字符合并成1个字符串,调用1次/wda/keys即可完成多个字符的输入,做到输入实时响应
- 电源键:请求/wda/locked获取当前锁屏状态后,调用/wda/lock或者/wda/unlock进行锁屏与解锁
- 主页键:请求/wda/home回到主页
- 菜单键(APP选择页):WDA未提供对应接口,通过组装上划命令请求/wda/dragfromtoforduration,模拟上划进入菜单页。注:这里不能使用/wda/swipe,没有效果
- Client收到actinotallow=1时,代表用户已经松手,不做响应
(4)复杂脚本指令
- 在上方提到的基本的操作之外,Client还可以接受更多命令入参并支持唤起UI自动化脚本,自动化脚本将会完成更加复杂的指令,从而实现智能化控制与使用
- 接收启动app类型、用户账号密码,页面deeplink等,唤起app完成用户登录后直接跳转进入对应页面
- 接收app下载地址、版本号等,实现app的卸载与安装并处理弹窗等信息
3.4 远程画面同步的设计与实现
关于画面的同步,先抛一下大家熟知的ffmpeg,这是一个开源的跨平台音视频处理工具,它可以用于录制、转换和流媒体处理等多种音视频操作。我们通过抓帧操作,数据通过ffmpeg进行处理后依次进行h.264转码,并将编码信息推给到web端直播服务,当前30s的视频约 30M,h.264转码后只有 3MB,画面流目前设置为1秒20帧。
3.4.1 画面抓取
iOS设备画面抓取流程:
(1)WDA mjpegServer
WDA自带mjpegServer,mjpegServer会不断地调用截屏API,并将截屏数据压缩后组装成mjpeg的数据流格式发送到画面流的端口。
(2)截屏速度/压缩质量参数
WDA mjpegServer可以通过参数对截图的速度,截图后的压缩质量进行设置。根据服务器性能和使用场景对FBMjpegServerScreenshotQuality和FBMjpegServerFramerate进行调整以得到最好效果。
人眼对帧数的感知在24帧左右,所以我们将FBMjpegServerFramerate设置为24,用户在使用时就不会感受到卡顿(帧率的选择在3.4.2第四小节讲述)
static NSUInteger FBMjpegScalingFactor = 100; // 截图缩放比,默认100,一般不做修改
static NSUInteger FBMjpegServerScreenshotQuality = 25; // 截图压缩质量,范围1-100,默认25。值越大图片质量越好。
static NSUInteger FBMjpegServerFramerate = 24; // 截图输出速度,即帧率,默认10
(3)Client画面获取
用户开始使用时,会产生画面初始化命令发送给Client。
Client通过GET请求画面流的端口,便可以得到连续的mjpeg画面流。
得到的画面流数据格式是以--BoundaryString分隔开的一张张mjpeg图片,每一张图片都可以单独作为jpeg图片保存下来。
3.4.2 流媒体处理
iOS画面流转视频流流程:
上文提到的Client端可以通过GET请求画面流端口得到一张张的jpeg图片,mjpeg是帧内编码,数据非常大。如果直接将该画面流数据推送给服务器,对使用方的带宽要求会非常高,所以要转成h.264的帧间编码方式。
(1)Client请求画面流端口并逐帧抓取图片
通过ffmpeg请求画面流端口,通过解码器抓取每一张jpeg图片。
(2)h.264编码
将抓取到的每一张jpeg图片都交给ffmpeg的编码器,设置参数并进行h.264编码并输出到标准输出。
补充:解码器和编码器的帧率设置需要略大于WDA设置的截屏速度,这样才能保证画面的响应一直是实时的。
(3)推流至流服务器
我们使用了平台研发中心框架架构研发部多媒体组提供的流服务器。通过引入框架团队提供的JAR包,便可方便将数据推流至服务器上。
ffmpeg编码器标准输出的每一帧,都会用设备在平台上的主键作为唯一标识标记发送给流服务器。
公司的流服务器在接收到数据后,会根据唯一标识生成类似于直播间的播放地址。前端访问该地址便可以看到手机的画面。
(4)推流码率
我们需要选取合适的帧率和码率,以达到视频流畅度和清晰度上的平衡:
以码率上限设定为4.5mbps为例,用户端所需要的网络速度峰值550KB/s左右。
所需带宽(KB/s) ≈ 推流码率最大值(bps)/8/1024。
因为实际上用户的操作速度,并不会非常快,对于带宽的占用会更少,一般操作引起的画面变动所需带宽在150-200KB/s左右,而静止状态下所需带宽仅在5-40KB/s
综合各个方面,我们是以WDA截屏速度为24的基础上适当加入了关键帧,将Client推流帧率定在30帧/s,码率上限设定为4.5mbps,实测占用带宽350KB/s左右,画面显示流畅、清晰、无花屏。
而我们使用的WIFI下载速度最高值在7.5MB/s左右,因此推流码率和带宽不是瓶颈。瓶颈主要在于ffmpeg将图片流转换为视频流的效率。通过计算,Client端java单线程ffmpeg的转码效率在每秒40帧左右,这可以通过技术优化得到提高。
四、数据采集
作为一套相关工种的员工将赖以推进日常工作的基础平台来讲,其稳定性必须是全维度可检测的,不仅需要支持对系统日常运行的健康进行监控,同时也要支持采集足够的运行数据,提供给平台研发人员分析并推进后续的迭代工作。
平台稳定性:通过各种监测维度数据及日志,提升用户感知稳定性;
使用检测量:用于评估用户依赖平台工作的量,后期平台迭代对用户影响度;
五、实践总结
在面向自动化测试领域,包括携程在内,其实有很多的UI自动化测试方案所采用的技术与此相似,甚至使用的技术底座都是相同的,比如WDA框架就是Facebook 推出的一项新的iOS移动测试框架。
无独有偶,我们团队在最初实现一些技术功能后,也是首先重点推广于测试场景。但是携程的业务面非常宽广,我们不仅有开发测试场景,还有内容核验场景,尤其是我们的国际化走在前列,有大量的海外员工也要一起参与到非常多的验收环节。
那么像应用版本,参数配置,环境初始化,资源准备这些环节在不同国别的同事间同步或培训,是相当耗费人力和成本的,且效果并不佳。基于我们对技术和平台的深度分析和演进后才发现,其实技术的应用空间很广,使一项基础的技术平台化起来后,很容易将场景、人员、设备、配置都统合在一起,很多交流成本可以直接降低,验收设备的不充分利用问题也得到很好的解决,尤其是共性问题的发现和解决变得高效。
在我们后续的工作中,还将基于当前的一些体验进行以下几个方面的持续优化:
- 模拟器场景支持并发安装包
- 单设备的多场景复用
最终使平台的体验完全可替代实机操作,让我们的潜在用户切身感受到上平台比自己在手机上做各项工作更加便利与高效。