ATX 安卓设备集群管理 atx-server
背景介绍
众所周知,安卓单台设备的UI自动化测试已经比较完善了,有数不清的自动化框架或者工具。但是介绍多设备管理的内容并不多,当手里的手机多了之后,要做自动化测试平台,这块的东西又不得不碰。我是一位比较喜欢实践的人,和同事在一起开发过简单的多设备管理系统,也用过开源的,后来又自己开发过。前前后后大概经历了4个不同的版本。
- 第一个版本是是将adb的服务封装成HTTP接口,可以调用adb forward,install,并且利用screencap和input keyevent这些基本命令实现了一个简单的远程控制界面(速度很慢,但是基本能用)。为了解决截图慢的问题,我还买过两个摄像头。
- 第二版版本是直接改造的openstf,本来第一个版本还在开发中,突然有同事对我说:“哎,你有没有见过这个项目呀openstf,好像跟你们最近开发的项目挺像的”,还发了一个链接过来。我当时就看了不超过10分钟,我就决定把第一个版本给废掉了。然后花了两个星期的时间把openstf的每一行代码都读了一遍(实际时间更长,因为读了很多遍)。后来在openstf上也加了不少功能,翻翻openstf的pr历史,也可以看到很多我的提交。这个项目教会了我很多,让我重新认识了nodejs,让我了解了rethinkdb
- 第三个版本出来的很意外,原来是试试看的项目,就是用Go语言重写openstf,写了一个多星期,发现改造起来也不是很难嘛,而且还让openstf的架构变简单了很多(openstf的搭建比较头疼),之后内部组织重组,各种变动,从最开始最多5个人开发,到现在又是我一个人开发,实在应了那句话“计划赶不上变化”。人多的时候架子铺的太大,坑挖的有点多,代码维护起来也很累,过了一段时间实在不想管这个项目了。
- 第四个版本:虽然我不想管第三个版本了,但是多设备管理的需求还是没消失,还是要硬着头皮维护下去。某个清空万里的好日子,突然灵机一动,把atx-agent给写了出来。这才意思到,就算没有数据线,就算没有adb,也是可以做设备自动化的嘛。关于atx-agent的介绍在杭州第三期沙龙分享过一次。基于atx-agent带来的无线连接技术,设备管理平台的硬件管理一下子就方便了好多好多,再也不用弄那些树莓派了,拉网线,还要烧代码provider代码的sd卡了。现在只要给保证手机是有电的就OK。软件层面实现一个atx-server管理一下众多的atx-agent就足够了。然后把openstf中的minicap和minitouch整合进atx-agent里面,远程控制功能就也有了。UI自动化则是使用了基于atx-agent的python uiautomator2,虽没有appium这么庞大和NB,但是麻雀虽小五脏俱全,只要你会python,各种UI自动化都能搞定。
基本架构图
+--------------+
| |
| atx-server |
| |
+--+-------+--++
| | |
| | +--------------------------+
+---+ +-------+ |
| | |
| | |
+-----------v----+ +------v---------+ +---v------------+
| Android | | Android | | Android |
| | | | | |
| +---------+ | +---------+ | +---------+
| |atx-agent| | |atx-agent| | |atx-agent|
| | | | | | | | |
+------+---------+ +------+---------+ +------+---------+
atx-agent
运行在手机的内部,为手机增加了远程控制,自动化的功能。atx-server
最重要的功能,是将atx-agent
汇总到一个网页上展示,并提供一个API可以获取所有设备的列表。
点击设备最右侧的那个眼睛图标,就可以进入远程控制界面。功能比较简单,但是基本功能够用了。
目前只试过80台设备,更多的设备应该也不成问题,不知道上限是多少,手机多的可以帮我测试下。
关于UI自动化, uiautomator2这个项目只需要知道设备的ip就可以运行自动化了,包括安装运行,推送文件,各种功能都有。在这个项目之上外加一个Jenkins之类的运行脚本的服务,稍加处理就是一个自动化测试平台了。美滋滋
辛辛苦苦终于写完了,希望看文章的人多思考思考,笔者非常期待思维的碰撞,欢迎留言。
项目地址: https://github.com/openatx/atx-server
附上cynic的实践文章:atx 安卓集群管理 安装运行及自动化的实践
手动点赞
赞呀!后面抽空试用下~
相当赞
NB,在上家公司OPENSTF我都还没看完代码就匆匆的离职了。能读完STF的所有代码收获肯定不少吧。
厉害了
厉害了我的哥
厉害了...回头马上试用一下。
回头学习下,给大佬点赞
💯
厉害了,我的哥!
我最近也在想让AppCrawler绕过appium直接支持你的atx-server。目前的需求还是以设备管理为主,把adb做成service就可以了。这样架构就可以简单了。基于这个基础,甚至都可以搞个众测设备的公有云服务了
哈哈,我又有时间折腾了
```Fetching https://golang.org/x/net/context?go-get=1
https fetch failed: Get https://golang.org/x/net/context?go-get=1: dial tcp 216.239.37.1:443: connectex: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.
我翻墙和不翻墙都下载不下来,不知道咋回事
agent 是个app吗?怎么启动?
我选择了第三个,进行解锁操作,然后第二个设备解锁了,第三个没解锁
手动点赞
手动点赞
已使用,超赞👍 请大神收下我的膝盖
执行go get -v github.com/openatx/atx-server的过程中一直有下面的提示:
go\src\github.com\openatx\atx-server\database.go:12:2: no Go files in C:\Users\用户名\go\src\gopkg.in\gorethink\gorethink.v4
单独去go get只能取到gorethink.v3;go get v4的话会提示:
can't load package: package gopkg.in/gorethink/gorethink.v4: no Go files in C:\Users\用户名\go\src\gopkg.in\gorethink\gorethink.v4
@codeskyblue 请问为啥我的远程控制界面是一直都是灰的

手机是红米4,版本是MIUI9.2,安卓版本是6.0.1,用的浏览器是ubuntu 16.04的firefox。开了好像没什么日志,logcat的这个不知道有没有用
1 EsService2 W loaded /system/lib/egl/libEGL_adreno200.so
1 EsService2 W loaded /system/lib/egl/libEGL_adreno200.so
2000 EsService I readResults: read results: 32, lastRequestId: 330
2000 I Kgd.KeyguardUpdateMonitor: mTimeTickBroadcastReceiver current state is mBootCompleted=true mDeviceProvisioned=true mPhoneState=0 Keyguard.isShowing = false Keyguard.isOccluded = false mScreenOn=true
2000 libEGL D loaded /system/lib/egl/libEGL_adreno200.so
已经使用,感谢大佬的分享,不过在使用的过程中,发现web端的手机屏幕截图刷新很慢哦
感谢楼主分享,我发现一个问题,
1、使用N5 6.0系统手机,一开始连接正常。监控页面也可以看到手机。当我关机再重启以后就无法再正常连接手机了。除非重新输入python -m uiautomator2 init。得手动重新启动atx-server吗?
2、可以直接使用adb connect ip吗?就像stf那样直接远程连接?我发现连接显示成功,但设备都是offline呢

- 不需要重启atx-server,但是需要重新init
- 如果需要adb connect的话,可以在手机连接在PC上的时候输入
adb tcpip 5555
, 然后你就可以adb connect $IP
了

感谢楼主回复。之前考虑的是如果做成公司级别的设备管理系统,手机都在大家手中。如果重启以后还需要init的话就有点不便了,估计就再也连不上了。最好可以开机自启就能重新连接。
如果可以默认的进行adb connect ip,那么安装应用也会方便很多,现在只能支持url链接。
@codeskyblue 手机黑屏的话不能唤醒,stf目前支持唤醒的,希望能把这个功能做进去。不然远程的话还要通知别人把屏幕打开。。

atx-agent不能唤醒是因为用的wlan,黑屏之后,wlan断开了,无法跟手机继续通信了。(PS: 突然想到可以断开之后,直接再自动解锁屏幕,强制恢复wlan。明天试试)
期待iOS的集群管理~~~~
现在执行了python -m uiautomator2 init 手机添加不上去,加了电脑IP+端口也不行,之前好好的,请问是什么问题呢
好厉害,最近在学go,一定拜读您的代码。
atx-agent端当IP发生变化时没法主动通知atx-server端。会造成设备离线无法管理。可否在atx-agent端做一个心跳。定时向server端报告信息.IP变化时server端也换设备IP。
atx-agent运行在手机的内部,为手机增加了远程控制,自动化的功能。atx-server最重要的功能,是将atx-agent汇总到一个网页上展示,并提供一个API可以获取所有设备的列表。----现在版本atx-agent自动化这块,就是网页端鼠标操作一台单独设备,然后该手机端会跟着执行吗?atx-server没法让所有连接到的手机一起运行同一份脚本吗?看git上atx-agent的说明,同时对所有连接的手机执行命令,是要在终端里面进行操作?但似乎没有atx里那些找图的功能可以用呀?
超赞,什么时候把logcat这块写好?很需要

你说的那个java项目是fork的,大部分代码是https://github.com/xiaocong写的, 我的java不怎么好
不懂go,但是感觉很强大~
安装成功后在本地的localhost页面,更多栏位没有出现眼睛的图标,是什么原因造成的呢
@codeskyblue ,请问一下再华为P9 plus上 下载安装微信,遇到错误,在nexus 6p下试验成功,会是什么原因?
d.app_install("http://dldir1.qq.com/weixin/android/weixin666android1300.apk"
)
13:21:54 id: 10
13:21:54 download initialing
13:21:55 download initialing
13:21:56 download 100%
13:21:56 http download error
Traceback (most recent call last):
File "", line 1, in
File "D:\Android\python36\lib\site-packages\uiautomator2_init.py", line 47
7, in app_install
return self._wait_install_finished(id, installing_callback)
File "D:\Android\python36\lib\site-packages\uiautomator2__init_.py", line 52
4, in _wait_install_finished
raise RuntimeError("error", jdata.get('error'))
RuntimeError: ('error', 'Get http://dldir1.qq.com/weixin/android/weixin666androi
d1300.apk: read udp 10.63.21.82:46756->221.12.1.227:53: i/o timeout')
你好,我的手机连接上PC运行是正常的,一旦拔出,就变成offline了。请问,这个东西需要同时usb连接到电脑上,还需要同在一个局域网内吗?
区别就是我这个专注自动化,顺便管理。
这种情况如何处理捏,红米note2
我把check_apk_installed这个函数注释了,可能就是检查太快了,没安装完就检查了
目前在内网测试了一下,在服务器页面操作手机速度还可以,但在其他同事的页面上操作设备延迟就很高。光看手机运行是可以的,但是一操作就很卡了。stf并没有类似问题,总体来说真心不错。
执行go get -v github.com/openatx/atx-server
报错,错误如下:
C:\Users\Administrator>go get -v github.com/openatx/atx-server
github.com/openatx/atx-server
github.com/openatx/atx-server
go\src\github.com\openatx\atx-server\httpserver.go:397:5: hbs.OnReconnect undefi
ned (type *heartbeat.Server has no field or method OnReconnect)

C:\Users\Administrator>python -m uiautomator2 init 10.0.1.1:8000
2018-05-08 14:26:59,427 - main.py:254 - INFO - atx-server addr 10.0.1.1:8000
2018-05-08 14:26:59,506 - main.py:269 - INFO - Detect pluged devices: ['980f
5397']
2018-05-08 14:26:59,507 - main.py:286 - INFO - Device(980f5397) initialing .
..
[Kminicap.so |################################| 13.2K / 13.2K
[?25h2018-05-08 14:27:09,736 - main.py:113 - INFO - install minicap
[Kminicap |################################| 357.9K / 357.9K
[?25h2018-05-08 14:27:22,467 - main.py:120 - INFO - install minitouch
[Kminitouch |################################| 29.5K / 29.5K
[?25h2018-05-08 14:27:27,442 - main.py:143 - INFO - app-uiautomator.apk(1.0
.13) installing ...
Traceback (most recent call last):
File "C:\Python36\lib\site-packages\urllib3\connectionpool.py", line 601, in u
rlopen
chunked=chunked)
File "C:\Python36\lib\site-packages\urllib3\connectionpool.py", line 387, in _
make_request
six.raise_from(e, None)
File "", line 2, in raise_from
File "C:\Python36\lib\site-packages\urllib3\connectionpool.py", line 383, in _
make_request
httplib_response = conn.getresponse()
File "C:\Python36\lib\http\client.py", line 1331, in getresponse
response.begin()
File "C:\Python36\lib\http\client.py", line 297, in begin
version, status, reason = self._read_status()
File "C:\Python36\lib\http\client.py", line 266, in _read_status
raise RemoteDisconnected("Remote end closed connection without"
http.client.RemoteDisconnected: Remote end closed connection without response
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Python36\lib\site-packages\requests\adapters.py", line 440, in send
timeout=timeout
File "C:\Python36\lib\site-packages\urllib3\connectionpool.py", line 639, in u
rlopen
_stacktrace=sys.exc_info()[2])
File "C:\Python36\lib\site-packages\urllib3\util\retry.py", line 357, in incre
ment
raise six.reraise(type(error), error, _stacktrace)
File "C:\Python36\lib\site-packages\urllib3\packages\six.py", line 685, in rer
aise
raise value.with_traceback(tb)
File "C:\Python36\lib\site-packages\urllib3\connectionpool.py", line 601, in u
rlopen
chunked=chunked)
File "C:\Python36\lib\site-packages\urllib3\connectionpool.py", line 387, in _
make_request
six.raise_from(e, None)
File "", line 2, in raise_from
File "C:\Python36\lib\site-packages\urllib3\connectionpool.py", line 383, in _
make_request
httplib_response = conn.getresponse()
File "C:\Python36\lib\http\client.py", line 1331, in getresponse
response.begin()
File "C:\Python36\lib\http\client.py", line 297, in begin
version, status, reason = self._read_status()
File "C:\Python36\lib\http\client.py", line 266, in _read_status
raise RemoteDisconnected("Remote end closed connection without"
urllib3.exceptions.ProtocolError: ('Connection aborted.', RemoteDisconnected('Re
mote end closed connection without response',))
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Python36\lib\runpy.py", line 193, in run_module_as_main
"main", mod_spec)
File "C:\Python36\lib\runpy.py", line 85, in _run_code
exec(code, run_globals)
File "C:\Python36\lib\site-packages\uiautomator2__main.py", line 352, in
odule>
main()
File "C:\Python36\lib\site-packages\uiautomator2__main.py", line 348, in ma
in
fire.Fire(MyFire)
File "C:\Python36\lib\site-packages\fire\core.py", line 127, in Fire
component_trace = _Fire(component, args, context, name)
File "C:\Python36\lib\site-packages\fire\core.py", line 366, in _Fire
component, remaining_args)
File "C:\Python36\lib\site-packages\fire\core.py", line 542, in _CallCallable
result = fn(*varargs, **kwargs)
File "C:\Python36\lib\site-packages\uiautomator2__main.py", line 273, in in
it
ignore_apk_check)
File "C:\Python36\lib\site-packages\uiautomator2__main.py", line 291, in _i
nit_with_serial
ins.install_uiautomator_apk(apk_version, reinstall)
File "C:\Python36\lib\site-packages\uiautomator2__main.py", line 144, in in
stall_uiautomator_apk
path = cache_download(app_url)
File "C:\Python36\lib\site-packages\uiautomator2__main_.py", line 73, in cac
he_download
r = requests.get(url, stream=True)
File "C:\Python36\lib\site-packages\requests\api.py", line 72, in get
return request('get', url, params=params, **kwargs)
File "C:\Python36\lib\site-packages\requests\api.py", line 58, in request
return session.request(method=method, url=url, **kwargs)
File "C:\Python36\lib\site-packages\requests\sessions.py", line 508, in reques
t
resp = self.send(prep, **send_kwargs)
File "C:\Python36\lib\site-packages\requests\sessions.py", line 618, in send
r = adapter.send(request, **kwargs)
File "C:\Python36\lib\site-packages\requests\adapters.py", line 490, in send
raise ConnectionError(err, request=request)
requests.exceptions.ConnectionError: ('Connection aborted.', RemoteDisconnected(
'Remote end closed connection without response',))
是直接在git 下载下来 就可以直接运行了吗?还说需要配置?
use 和离线这个状态是根据什么来判断的?

目前管理服务器部署在A服务器上,多部手机装atx服务是在B电脑装的,如何快速把手机接入到A服务器的管理平台(除了卸载服务用A服务器装以外),因为发现使用IP+端口查看info信息uuid是一致的,是否只用在A服务器某文件写入相应信息就可以连接上A服务器管理平台呢?
准备实践下,想请教下楼主,atx-agent如何解决国内各种定制手机的apk安装的限制? 比如oppo、vivo的帐号弹框,vivo还有个烦人的模拟点击,小米的安全权限等等。
重启能否自动拉起atx-agent呢?
因为安卓手机有bug,存在uid leak的情况,简单来说就是apk循环安装卸载,重复10000次,手机就没办法再安装apk了,需要卸载全部第三方apk后重启手机,这个bug报给google,但明确表示won't fix。
加油,暂时继续使用openstf
求助,现在管理设备服务器在imac上,通过其他电脑访问设备管理页面,不能操作设备,看报错,应该是无法连接手机设备。
remote.js?t=1526889597:570 WebSocket connection to 'ws://192.168.2.26:7912/minicap' failed: Error in connection establishment: net::ERR_CONNECTION_TIMED_OUT
有什么解决办法吗?
atx-agent是个apk么? 还是一个so? 运行在andoroid上会不会被杀(比如oppo vivo有些top50的手机后台定期会清理内存,加入白名单都不行)?
这个项目里的Advanced usage不是很懂,大佬可以简单说明一下吗?
win7 安装atx 报错如下:
F:\Go\src>go get -v github.com/openatx/atx-server
github.com/openatx/atx-server (download)
cd .; git clone https://github.com/openatx/atx-server F:\golang\go\src\github.
com\openatx\atx-server
Cloning into 'F:\golang\go\src\github.com\openatx\atx-server'...
fatal: unable to access 'https://github.com/openatx/atx-server/:' error:1407742E
:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version
package github.com/openatx/atx-server: exit status 128
体验了一下,貌似手机切换网络或断网,自动重连后,设备可以正常显示,但无法在web页面对手机进行远程控制操作
请问能否在uiautomator.apk里面添加把 axt-agent注册到atx-server的功能,这样不用每次连电脑注册。
所有设备连接在一个wifi下,80台手机的话是否有带宽不足的问题,能否数据线+有限网络实现,求教
大佬,其实这样就完全可以知道局域网内哪些ip的手机安装了ATX或者ui2客户端,然后测试局域网内的多台有ATX的设备哇,可以提供一个方法获取这些有用的ip,或者默认直接就测试这些ip哇,感觉可行,比较省事,省去了测不了多台手机的尴尬
页面是这样,功能用不了,求指点
我查了下是这样说的:golang不允许循环导包,如果检测到import cycle,会在编译时报错,通常import cycle是因为设计错误或包的规划问题。
可是我不知道怎么解决,有遇到的嘛
请问以后有可能支持iOS吗?

重启后可以通过连接USB线然后执行下面命令来重启服务
adb shell /data/local/tmp/atx-agent server --server 192.168.101.209:8000 -d

是的 需要手动执行, 或者找个root的android设备写个能执行adb shell命令的apk,直接在apk里执行shell脚本
楼主,USB连接的设备能直接控制吗?直接连在台式电脑上
请问为什么识别不了参数呢