在不插 USB 的情况下对设备远程操作/启动测试任务一直是一个非常有用的功能,因为公司里的测试设备总是分散的,而且一堆 USB 线连测试设备总是非常麻烦。ATX 项目组提供的 uiautomator2 借助了一系列的工具,使得能够用 Python 编写自动化脚本,同时可以脚本可以通过 WiFi 直接操控同 WiFi 下的设备。另一方面 Maxim 提供了一个非常稳定而且高效的 UI 全自动话压力/稳定性/遍历测试。两者如果能结合,效果可观。作为同时两个项目的贡献者,分享调和两者的成果以及方案。

背景介绍

uiautomator2 有如下组件:

设备端大管家是 atx-agent,必须有 adb shell 运行权限,保活其他三个,同时是设备端 HTTP 服务器入口,负责路由 HTTP 请求给另外三个部件

Maxim 有两个组件framework.jarmonkey.jar,都是设备端的,其中framework.jar是一个定制的 AccessibilityService,而monkey.jar大改自 Google 原生 monkey,实现遍历逻辑等。一般通过 adb shell 命令行启动,必须有 adb shell(同 android-uiautomator-server,这样才能操作其他 APP),可以脱机运行(类似 nohup),即启动后可以关掉命令行进程不会被杀直到运行完成。

结合方案设计

矛盾点: uiautomator2 和 Maxim 工作时都需要连接系统的 AccessibilityService,而 AccessibilityService 只能单连接;所以启动了 uiautomator2 才有免 USB 操作的能力,但是占用了 AccessibilityService,如果通过 uiautomator2 启动 Maxim 会挂。

经过研究,android-uiautomator-server 只是 uiautomator2 中与 selector,click 等相关的服务;atx-agent 提供执行设备端 shell 命令的功能(fork,执行,因为 fork 自 atx-agent 所以有 adb shell 权限),所以可以首先启动所有 uiautomator2 组件待 WiFi 无线操作可用后,暂时关闭 android-uiautomator-server,然后通过 atx-agent 启动 Maxim,执行完成后再通过 atx-agent 重新拉活 android-uiautomator-server 恢复 uiautomator2 的功能,相关片段整理如下:

import uiautomator2 as u2

d = u2.connect('192.168.0.149') # 连接设备
print(d.info)
# 启动前关闭atx-agent守护的uiautomator-server进程
d.service('uiautomator').stop()
# Maxim正常运行
task = d.shell("CLASSPATH=/sdcard/monkey.jar:/sdcard/framework.jar exec app_process /system/bin tv.panda.test.monkey.Monkey -p com.hotbitmapgg.ohmybilibili --running-minutes 2 --throttle 1500 --uiautomatormix --output-directory /sdcard/max-output", stream=True) # stream模式,保证不会timeout导致杀掉,底层上是一个requests库提供的streaming 模式的response
try:
    for line in task.iter_lines():
        print(line)
finally:
    task.close()
print('Done')
# 重新让atx-agent拉活uiautomator-server进程,或者执行下一条需要uiautomator-server的命令也会自行拉活
d.service('uiautomator').start()
d.press('home')

贡献者招募


↙↙↙阅读原文可查看相关链接,并与作者交流