自动化工具 (无需 Root) 基于 Android Monkey 二次开发,实现高速点击的 Android Monkey 自动化工具 fastmonkey - 代号 Maxim

zhangzhao_lenovo · 2018年01月19日 · 最后由 zhangzhao_lenovo 回复于 2019年01月16日 · 16805 次阅读
本帖已被设为精华帖!

打造一款快速高效且高度可复用的android自动化测试工具 (qq群 :608824162)

主页入口 请点我
https://github.com/zhangzhao4444/Maxim

优势

  1. 高速点击,每秒 10-15 action!
  2. 多平台兼容! 同时兼容Android 5-9
  3. 轻量极简!

如何使用

  1. adb push  framework.jar  monkey.jar  文件到 /sdcard
  2. 执行 
    adb shell CLASSPATH=/sdcard/monkey.jar:/sdcard/framework.jar exec app_process /system/bin tv.panda.test.monkey.Monkey -p com.panda.videoliveplatform --uiautomatormix --running-minutes 60

    脱机运行(#53楼

参数说明

  1. tv.panda.test.monkey.Monkey 主调入口  无需修改
  2. -p com.panda.videoliveplatform  待测appid
  3. 策略模式

    --uiautomatormix 混合模式(70%控件解析随机点击,其余30%按原Monkey事件概率分布) 
    --pct-uiautomatormix n 可自定义混合模式中控件解析事件概率
    --uiautomatordfs DFS深度遍历算法(优化版)(注 Android5不支持dfs)
    --uiautomatortroy Troy模式 见 (#74楼
    非以上两种为原始Monkey策略

  4. 执行时长
    --running-minutes 60        执行60分钟monkey

  5. 场景细粒度控制
    --act-whitelist-file  /sdcard/awl.strings    自定义Activity白名单
    例:

    com.panda.videoliveplatform.activity.WelcomeActivity
    com.panda.videoliveplatform.activity.SplashWakeActivity
    com.panda.videoliveplatform.activity.MainFragmentActivity
    com.panda.videoliveplatform.activity.LiveRoomActivity

    锁定跳转只可进入其中的某个Activity
    --act-blacklist-file        同上

  6. 其他参数及用法同原始Monkey

特性简介

a. 速度快 每秒10-15个Action事件
界面控件解析算法通过改造底层framework,直接使用AccessibilityNodeInfo并优化减化其调度流程,解析速度控制在50ms内,可对界面变化做快速反应。

{
val clickable = ArrayList<AccessibilityNodeInfo>()
collectClickable(clickable, root) //递归算法生成node树结构
......
val node = clickable[random.nextInt(count)]
val nodeRect = Rect()
node.getBoundsInScreen(nodeRect) //选取其中某个node的 rect ,随机点击其中某point

generateClickEventAt(nodeRect, 0L)
}

b. Android全平台兼容
兼容Android5,6,7,8,p各系列。通过反射原理动态解析各平台Api差异,使用一套逻辑兼容全系列。

{
Class<?> clazz = mAm.getClass();
String name = "setActivityController"; //存在差异的api
Method method = findMethod(clazz, name, android.app.IActivityController.class); //反射动态search api
if (method != null) {
......
}
method = findMethod(clazz, name, android.app.IActivityController.class, boolean.class);
if (method != null) {
......
}

c. 防跳出
控件解析时获取进程推栈Top Activity,按非白即黑立即执行切回。各事件执行时按特有逻辑屏蔽掉状态栏,防止误操作。

{
......
cn = this.mDevice.mAm.getTasks(1, 0).get(0).topActivity //取top activity
if (cn != null) currentPackage = cn.getPackageName()

if (!MonkeyUtils.packageFilter.isPackageValid(currentPackage!!)) { //判断非白即黑
this.mQ.clear()
this.generateActivity()
......
}

d. 防休眠
休眠时自动检测并唤醒屏幕。

{
......
if (!this.mPM!!.isInteractive) { //判断处于休眠中
......
val i = Runtime.getRuntime().exec(arrayOf("input", "keyevent", "26")).waitFor() //唤醒设备
......
}

e. 熔断机制
当事件按某个特有模式固定执行一段时间时则自动触发熔断开始自拉活,防止假死。如重复点击同一位置n秒。

private fun isBlocked(): Boolean{
val jam = true
......
val last = actionsHistory.last()
for (i in 2..30){ //重复点击n次 触发熔断
if (mVerbose > 1) Logger.log("last action is ${actionsHistory.size-1} code = $last, action${actionsHistory.size-i} code = ${actionsHistory[actionsHistory.size-i]}")
if (last != actionsHistory[actionsHistory.size-i]){
return false
}
}
//其他熔断
.....
}

f. 场景细粒度
引入Activity黑白名单,可控制限定在某些场景内。如只测试某几个相关页面。

private inner class ActivityController : IActivityController.Stub() {
override fun activityStarting(intent: Intent, pkg: String): Boolean {
var allowActivity = true
if (MonkeyUtils.activityFilter.hasValidActivitys()){
val currentActivity: String? = try {intent.component.className} catch (e:Exception){null}
if (currentActivity != null){
allowActivity = MonkeyUtils.activityFilter.checkEnteringActivity(currentActivity) //通过filter的才允许跳转
}
Logger.log("// Activity : ${currentActivity} in Intent")
}
......
}
......
}

g. 随机自动输入
检测当遇到可输入模式时,按设定(ape.string)或随机输入键盘事件。如输入666或2333弹幕
随机输入 需要提前安装adbkeyboard
https://github.com/senzhk/ADBKeyBoard

{ 
......
val inputMethodVisbleHight = this.mDevice.mIMM!!.getInputMethodWindowVisibleHeight() //存在键盘输入栏
if (inputMethodVisbleHight <= 0) return
//注入键盘事件
try { generateRandomKeyEvents() }catch (e : Exception){ }
......
}

h. 崩溃堆栈自动保存
当崩溃(crash、oom)发生时自动抓取,并存于/sdcard/crash-dump.log

{ 
override fun appCrashed(processName: String, pid: Int, shortMsg: String, longMsg: String, timeMillis: Long, stackTrace: String): Boolean {
......
writeDumpLog("// CRASH: $processName (pid $pid) (dump time: $dateStr)")
writeDumpLog("// Build Time: ${Build.TIME}")
writeDumpLog("// ${stackTrace.replace("\n", "\n// ")}")
....
}

todo

  1. 特殊事件序列 - 已完成
  2. 引入GT性能测试
  3. 控件黑名单 - 已完成
  4. xposed 模式 --见xmonkey
  5. Ai算法 模式

** 其他 **

扫盲贴: https://testerhome.com/topics/11884

常见问题排查

  1. 小米手机未开启 “开发者选项” -> "USB调试(安全设置) 允许通过usb调试修改权限或模拟点击"。
    开启后ok 。报错log如下图

  2. accessibilityservice 被其他驱动占用 agent未注销。如使用过atx 未执行unregister。
    执行unregister后OK。报错log 如下图,或无log


  3. 厂商修改造成 dex 无法load ,maxim启动后就退出。实际什么都未执行。无log输出。 logcat如下图。此问题暂时待查

4.运行maxim无任何log,启动后就退出。需检查/sdcard/是否存在monkey.jar ,framework.jar。部分机型发现adb push过去monkey.jar 自动被更名成monkey. 导致无法运行。

5.vivo7.1 运行maxim报错,需要关闭锁屏和开启usb模拟点击 ,然后就可以跑monkey了。报错如下:

update

#40楼
支持特殊事件序列 max.xpath.actions
如何查看特殊事件log #79楼

#44楼 #52楼
支持屏蔽黑控件或黑区域 max.widget.black

#57楼
支持截图,dump xml
崩溃回溯式截图 #92楼

#74楼
Troy模式

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 101 条回复 时间 点赞

先赞一个👍

给力,用起来

先赞一个

4楼 已删除

学习一下,之前想改一直没真正找到点,没敢下手。

期待一下特殊事件序列

高速点击不应该是核心测试需求的诉求吧,实际的压测需要有页面缓冲、动效显示、图片加载的处理间隔,还应有等待回收逻辑处理完成,所以还是模拟用户行为间隔更重要。否则会引起研发不认可的bug及内存泄露压力不够的问题。

浮云 回复

高速是指解析界面算法。如果觉得event太快可以自行添加 Throttle。 速度不够何谈压力

思寒_seveniruby 将本帖设为了精华贴 01月23日 20:47

哦,原来指的是算法能力上能支持高速点击。实际压测还是要分压测场景和压测目的具体平衡事件比例,过快的操作更多考验的是未完成事件的中断,往往会发生用户正常操作不会遇到的bug。
而针对内存占用的压力还是需要图片加载,视频缓冲,合理节奏下的GC释放场景的正常测试。对app压测评估、对app压测bug补漏、通过app压测系统和底层服务等不同目的的方案设计还是有区别的。建议针对不同场景的使用可以做下建议性参数配置实例。

你好楼主使用你的工具 替换包名后 运行 提示

   ..                    ..:.
..t.. Maxim .h..
..i.. . ....... . ..si
sandroidmonkeystreste
.sttoolMaxim.thistool.
.helpyoutofoundappcrash.thi
..stooluserandomordfsalgorithm:.
.smonkeyMaxim machine gunmonkey..
..monkey,..,monkeymonkeym,..,onkeym.
.onkeymon..keymon.keymonke..ymonkeym.
,onkeymonkeymonkeymonkeymonkeymon.key.
.monkeymonkeymonkeymonkeymonkeymonkeym.
.onkeymonkeymonkeythxforphdguxiaotian.:
.anythingUcancontactpanda_zzaqq77227005
. .

. .

[Maxim] *** ERROR // : No activities found to run, monkey aborted.

666,实践一下

斯拉 回复

monkey命令参数可能输错了。把你的adb shell 那条命令发来看看

很感谢分享,想问一下如何修改monkey源码进行二次开发?主要对这个过程感兴趣,网上这方面的资料很少,方便的话可以详细说一下过程吗?小白也想试试自己改一下

ice 回复

加q群说吧。这个简单一两句说不清楚

额 不知道Q群是多少?方便告知一下吗

看到了 谢谢

仅楼主可见
斯拉 回复

加q说吧

497703927

源码方便放到github上么?

spring-ssh 回复

后续会开源的,请关注

移动终端需要root权限吧

走刀口 回复

不需要root

仅楼主可见
走刀口 回复

“开发者选项” -> "USB调试(安全设置) 允许通过usb调试修改权限或模拟点击" 这个可否打开了?

"USB调试(安全设置) 允许通过usb调试修改权限或模拟点击"这个打开后就可以了,给力!👍

小马 Maxim-高速 Android Monkey 工具使用记录 中提及了此贴 02月03日 11:04
zhangzhao_lenovo Android 的 Monkey Test 疑问 中提及了此贴 02月05日 20:04
zhangzhao_lenovo monkey 稳定性测试 中提及了此贴 02月05日 20:08
zhangzhao_lenovo Android 性能测试之 Monkey 中提及了此贴 02月05日 20:09
ice 回复

方便给下群号吗 我也想加群 了解下,自带的monkey太随机了

zhanglimin 回复

qq群 :608824162

2018.02.23 update

  1. 增加支持 特殊事件序列(mix dfs troy均支持)

需要配置 max.xpath.action 文件
案例:

[
{
"prob": 1,
"activity":"tv.panda.account.activity.WebLoginActivity",
"actions": [
{
"xpath": "//*[@class='android.widget.EditText']",
"action": "INPUTTEXT",
"text": "13810751000",
"index": 0,
"throttle": 300
},
{
"xpath": "//*[@class='android.widget.EditText']",
"action": "INPUTTEXT",
"text": "123400",
"index": 1,
"throttle": 300
},
{
"xpath": "//*[@content-desc='登录' and @class='android.view.View']",
"index": 0,
"action": "CLICK",
"throttle": 1000
}]
},
{
"prob": 1,
"actions": [
{
"xpath": "//*[@class='android.view.View']",
"index": 0,
"action": "SWIPE",
"args": "10,1000,800,1000,100",
"throttle": 3000
}]
},
{
"prob": 1,
"actions": [
{
"xpath": "//*[@class='android.view.View']",
"index": 0,
"action": "TOUCH",
"args": "500,1000",
"throttle": 1000
}]
},
{
"prob": 1,
"actions": [
{
"xpath": "//*[@class='android.view.View']",
"index": 0,
"action": "KEYEVENT",
"keycode": 4,
"throttle": 1000
}]
}
]

上述包含3个特殊事件
发生概率 prob =1 为100%发生
仅当 当前activity 为 tv.panda.account.activity.WebLoginActivity 时或无activity配置时做事件查找
xpath 为待查找控件的xpath 支持复杂型xpath,支持 index 索引选择
throttle 为该特殊步骤执行完后sleep n 毫秒
Action 支持
1.Click 点击匹配到的xpath控件
2.INPUTTEXT 在匹配到的xpath控件中输入 text 指定字符,输入需要提前安装adbkeyboard
3.TOUCH 点击指定坐标 args = (x,y)
4.SWIPE 按执行路径滑动 args = (x1,y1,x2,y2,step)
5.KEYEVENT 执行键盘事件 keycode

注 配置完成后请贴在 json.cn 检查格式,注意” : , 非中文

将该文件 push 到 /sdcard/max.xpath.actions

如果要执行的一个事件序列,执行过程中会出现activity跳转,则应该将该序列拆分成两个actions进行配置。

更新后 发现
是ape.strings 对应现在的 max.strings
ape.xpath.actions 对应现在的 max.xpath.actions

还多了一个max.config 是配置什么的

cmd@TR:~/workspace/git/Maxim$ cat max.config 
max.startAfterNSecondsofsleep = 6000
max.wakeupAfterNSecondsofsleep = 4000

小马 回复

帮助文档里有写这个,配置命名我规范了下 之前太随意了

zhangzhao_lenovo Monkey 测试基本操作介绍 (一) 中提及了此贴 02月26日 19:47

2018.02.28 update

  1. 支持黑控件 黑区域屏蔽(mix dfs troy均支持)

配置max.widget.black
案例

[
{
"activity":"com.panda.videoliveplatform.activity.MainFragmentActivity",
"xpath": "//*[@class='android.widget.TextView' and @text='我的校园' and @resource-id='com.panda.videoliveplatform:id/tv_title']"
},
{
"activity":"com.panda.videoliveplatform.activity.MainFragmentActivity",
"xpath": "//*[@class='android.widget.TextView' and @text='车队' and @resource-id='com.panda.videoliveplatform:id/tv_title']",
"index": 0,
"bounds": "[0,633][900,789]"
},
{
"activity":"com.panda.videoliveplatform.activity.MainFragmentActivity",
"bounds": "[0,1107][900,1263]"
}
]

当且仅当 当前activity == 所配activity 或未配activity时 做黑检查
三种方式:
1.仅配置bounds
屏蔽某个区域,在该区域内的控件或坐标不会被点击。
2.配置xpath
查找匹配的控件,屏蔽点击该控件。
3.xpath+bounds
查找匹配的控件,当控件存在时屏蔽指定的区域。

注 配置完成后请贴在 json.cn 检查格式,注意” : , 非中文
将该文件 push 到 /sdcard/max.widget.black

android5.1,加入特殊事件序列后,执行,一到特殊事件序列的activity,monkey就停止了

东子 回复

monkey停打印的log是什么? 加我q下 77227005 调试看下问题

楼主,这个不提供源码吗

chunyong 回复

还得过段时间。

按照楼主的操作文档执行了之后,为什么没有反应呢? 我是华为Mate9下操作的,手机USB已经打开,已经把framework.jar 和 monkey.jar push到手机里,执行的命令是 adb shell CLASSPATH=/sdcard/monkey.jar:/sdcard/framework.jar exec app_process /system/bin tv.panda.test.monkey.Monkey -p xxxx(我要测试的进程名)—uiautomatormix —running-minutes 3 麻烦楼主帮忙看下是什么原因

王华 回复

贴里 有三处 "常见问题排查"
可以先排查看看 或加我q

先赞一个

关于黑控件 max.widget.black
-v -v -v -v 4级log 可以看到 blackWidget

生成:
每次刷新activity 生成黑区域 会对控件tree 按xpath进行search,若找到则加入黑区域 或只配bounds 则直接加入黑区域.

检测:
有2种:

  1. 获取控件tree 时 如果一个控件在 黑区域内 会打印 inside black List 。该控件不会加入到后续点击队列
  2. 随机point时 如果point在 黑区域内 会打印 in pointer event:mblackwidgets 。会重新映射到黑区域外取point。再执行点击point

关于如何脱机运行(adb 后拔掉usb)

adb shell "CLASSPATH=/sdcard/monkey.jar:/sdcard/framework.jar exec app_process /system/bin tv.panda.test.monkey.Monkey -p com.panda.videoliveplatform --uiautomatormix --running-minutes 60 -v -v  >/sdcard/monkeyout.txt 2>/sdcard/monkeyerr.txt &"

不就多了个 & ? windows cmd 支持& 吗?

小马 回复

问这个脱机的人很多,我原来就不知道。

小马 回复

这个和windows没关系,""里面的都是丢给adb shell的,都是linux,脱机可行,好像是自己会变成daemon,测过

2018.03.09 update

1.(MIX支持) 高速截图 及 dump xml

配置
Max.config
max.takeScreenShot = true 开启截图
max.savePageSource = true 保存xml

将该文件 push 到 /sdcard/max.config

截图的生效条件

throttle > 200  &&  max.takeScreenSho= true
1 默认保存在  /sdcard/    
2 也可以自定义路径 --output-directory /sdcard/max1/
当自定义路径已存在 会自动mkdir max1.1 并将截图保存在max1.1

案例:

adb shell CLASSPATH=/sdcard/monkey.jar:/sdcard/framework.jar exec app_process /system/bin tv.panda.test.monkey.Monkey -p com.panda.videoliveplatform --uiautomatormix --running-minutes 6 -v -v --throttle 400 --output-directory /sdcard/max1/

备注:每分钟100-200截图,故因大量截图对手机空间要求较高,仅为复现崩溃时建议开启截图

666,膜拜大神

请教一下,如果出现了anr跟crash,日志的也是跟原生monkey的一样么

thanksdanny 回复

嗯基本一致。只是将崩溃堆栈重定向输出到log

😁 好的谢谢!今晚试用了下觉得很不错啊,想把他替换掉原生的monkey来用了

666,做的很棒。appium底层的uiautomate2 server在解析xpath的时候有点bug,我也在想着如何改进。你后续可以尝试支持下webdriver协议了。

thanksdanny 回复

多谢支持,有建议或问题 可随时q我

今年大会你可以这个开源项目提交个topic,挺实用的,百度和腾讯的都没开源,正好你的开源了。

执行白名单中的activity, 请问这个命令有问题吗? adb shell CLASSPATH=/sdcard/monkey.jar:/sdcard/framework.jar exec app_process /system/bin tv.panda.test.monkey.Monkey -p packagename --uiautomatormix --pkg-whitelist-file /sdcard/awl.strings 200

hover 回复

你那里报错了吗? 加q群吧 看下log

仅楼主可见
MJW 回复

qq我下帮你看下原因 77227005

手机设置了不锁屏,发现跑的过程中会被锁屏,不知道大家遇到过这个情况没有?

你好,请问支持页面滑动吗

Caroline 回复

支持的

大神坐等源码,最近也在研究monkey源码,也想改造适合自己使用的monkey

2018.03.22 update

  1. TROY模式(支持特殊事件、黑控件等) 配置 max.xpath.selector troy控件选择子来定制自有的控件选择优先级,例子如下
[
{
"firstList":
[
{ "xpath": "//*[contains(@text,'绝地求生')]" }
],
"selectList":
[
{ "xpath": "//*[@clickable='true']" },
{ "xpath": "//*[@clickable='true']//*[contains(name(),'Text')]" },
{ "xpath": "//*[@clickable='true']//*[contains(name(),'Button')]" },
{ "xpath": "//*[@clickable='true']//*[contains(name(),'Image')]" }
],
"lastList":
[
{ "xpath": "//*[../*[@selected='true']]" },
{ "xpath": "//*[../../*/*[@selected='true']]" },
{ "xpath": "//*[../../*/*[@selected='true'] and contains(@resource-id,'tab_')]" },
{ "xpath": "//*[contains(@resource-id,'HorizontalScrollView')]" }
],
"blackList":
[
{ "xpath": "//*[contains(@resource-id,'wrapper_in_custom_title_bar')]//*[contains(@resource-id,'right_button')]" },
{ "xpath": "//*[contains(@resource-id,'share')]" }
]
}
]

控件选择策略 会按 1first 2select 3last 并屏蔽black 来执行遍历操作。

adb shell CLASSPATH=/sdcard/monkey.jar:/sdcard/framework.jar exec app_process /system/bin tv.panda.test.monkey.Monkey -p com.panda.videoliveplatform --uiautomatortroy --running-minutes 15 -v -v 

另注 max.xpath.selector 需要push 到/sdcard/

大神 666

zhangzhao_lenovo 关于 monkey 的--throttle 参数 中提及了此贴 04月28日 17:57

用来压力测试很不错
楼主, 这个工具有开源的计划吗?

zsg5566 回复

github上已有 dfs算法 可以参考

关于特殊事件的log 如何查看?

  1. Max运行 开头会打印出 load的Special Event

  2. 解析生成Tree结构

分别表示
index|height|depth|childCount|descendantCount,className,contentDesc,text,xpath,clickable,rect

3.针对一个xpath进行查找
找到打印Find it,已经对应执行的event

[Maxim] // Rejecting start of Intent { act=android.content.pm.action.REQUEST_PERMISSIONS pkg=com.google.android.packageinstaller cmp=com.google.android.packageinstaller/com.android.packageinstaller.permission.ui.GrantPermissionsActivity } in package com.google.android.packageinstaller

如何能点到权限框?

Kane 回复

问题没看明白,qq 加我说吧

--output-directory /sdcard/MonkeyLog/log.txt

输出的日志,只有文件夹,没有log啊....能像原生monkey那样把log定向到PC端吗?

Smile 回复

你的参数传错了
正确的: --output-directory /sdcard/MonkeyLog

这个output目录 主要是保存 crash,anr traces,截图,pagesources xml

关于max 标准输出流和异常流 可以重定向保存到pc github上有个issue有说明

谢谢~ 也可以通过 > 保存全部的log是吧~

再膜拜一下大神~~这个比原生的monkey要好用很多😊

Smile 回复

adb shell xxx >log.txt 2>err.txt

仅楼主可见

关于 crash-dump.log 及 崩溃捕获

一般如果app自己实现了crash上报的功能 就会去重写这个defaultUncaughtHandler接口,如果app没有捕获crash, ActivityManagerProxy 会调handleApplicationCrash 进入系统crash处理流程(如上图)

UIHandler.sendMessage 就是我们最常见的app弹了个 无响应的弹窗。我们主要关注ams.crashApplication(下图红框)

monkey里实现了 这个IActivityController.appCrashed 回调,于是乎就把crash记录下来了。

源码参考
http://gityuan.com/2016/06/24/app-crash

针对这个,我这边的尝试是把截图藏在PC端,可以使用minicap工具

楼主,我问下,不同版本的android系统,照理monkey.jar和framework.jar是不一样的,你那只有一份这两个jar包,如何支持android5~9版本啊?

pxrgod 回复

多平台兼容 可以参考下,道理差不多 https://testerhome.com/topics/15089

2018.07.25 update

1.崩溃回溯式截图

运行时shell增加 --imagepolling 参数 , 开启崩溃回溯截图、关闭原截图逻辑
当崩溃发生时 进行截图保存,实现可回溯崩溃场景,默认会在 /sdcard/crash_$timestamp/图

配置max.config

max.takeScreenShot = true 开启截图
max.flushImagesThreshold =xx 回溯区间大小xx张
截图的生效条件: throttle > 200 && max.takeScreenShot = true && --imagepolling

请问下屏蔽掉状态栏是如何做到的?我目前想的方法是检测当前是否存在状态栏,但是不知道用啥方法?

你好,我有两个问题请教:
1.做Monkey 的时候能够收集到点击事件实际触发的那个view的具体元素吗?我看楼主支持特殊事件序列 max.xpath.actions 不知道这个里面定义的xpath在定义后执行的时候应该是判断的,既然能判断应该也能dump出当前页面的所有元素的,是不是可以拿到点击的坐标元素?
2.src下的MonkeySourceUiAutomatorDFS.kt文件对于执行有什么用?我看里面好多api。麻烦能讲解下吗?

pxrgod 回复

注入event时 point选取范围去掉状态栏区域

Boxer 回复
  1. 可以拿到具体view元素, 最终click的也是对应元素的坐标
  2. DFS.kt 就对应 dfs 深度遍历算法

每分钟100-200截图,故因大量截图对手机空间要求较高,仅为复现崩溃时建议开启截图

想问下怎么做到仅在复现崩溃时开启截图?
是使用崩溃回溯式截图这个功能吗?

watchdog 回复

是的,使用崩溃回溯式截图

monkey.jar的是下发指令执行操作的,那这个framework.jar是做什么的用的,他跟原生的/system/framework.jar有什么区别

仅楼主可见

膜拜大神,坐等开源

simple 专栏文章:[精华帖] 社区历年精华帖分类归总 中提及了此贴 12月13日 14:44

命令:adb shell CLASSPATH=/sdcard/monkey.jar:/sdcard/framework.jar exec app_process /system/bin tv.panda.test.monkey.Monkey -p com.yangle.xiaoyuzhou --running-minutes 2 --uiautomatordfs --throttle 500 -v -v >/Users/wangshaoce/testlog/monkeylog/monkeyout.txt 2>/Users/wangshaoce/testlog/monkeylog/monkeyerr.txt &

monkeyerr收集到到error为:
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(1 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(1 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(2 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(3 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(4 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(5 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(6 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(7 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(8 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(9 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(10 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(11 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(12 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(13 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(14 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(15 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(16 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(1 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(2 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(3 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(4 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(5 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(6 times), use default events generator.
[Maxim] *** ERROR // : null root node returned by UiTestAutomationBridge(7 times), use default events generator.

未能准确收集到报错信息,请问 如何解决 已加楼主q

少策 回复

这是什么厂设备? Android版本多少的? 看上去像是AccessibilityService被禁用了。

106楼 已删除

出现crash或者anr的后,还会继续执行monkey吗,直到达到设定时间才会停止么?

Leo 回复

嗯。

109楼 已删除
wenxiaomao MixMonkey 基于 Android Monkey 中提及了此贴 12月31日 21:49

支持出现crash或者anr后即停止monkey运行么?

如果运行多轮monkey,那么每轮出现的crash信息或者oom traces 是追加还是覆盖写入sdcard/crash-dump.log和/sdcard/oom-traces.log?

Leo 回复

追加写入

Leo 回复

--ignore-crashes 原monkey有个参数如果不设置就是你说的这个场景。 但是如果启用了--running-minutes 则crash后会继续执行

simple [精彩盘点] TesterHome 社区 2018年 度精华帖 中提及了此贴 01月07日 12:08

Hi,作者:
我想问下这个framework.jar的作用是啥呢?为啥我push framework.jar和monkey.jar到手机后启动,然后同时抓取logcat的输出,发现系统在处理这个framework.jar时抛出了异常,这个应该没有起作用吧。下面是logcat中的输出:

01-14 16:43:21.256 E/System  (31646): Unable to open zip file: /sdcard/framework.jar
01-14 16:43:21.258 E/System (31646): java.util.zip.ZipException: error in opening zip file
01-14 16:43:21.258 E/System (31646): at java.util.zip.ZipFile.open(Native Method)
01-14 16:43:21.258 E/System (31646): at java.util.zip.ZipFile.<init>(ZipFile.java:225)
01-14 16:43:21.258 E/System (31646): at java.util.zip.ZipFile.<init>(ZipFile.java:148)
01-14 16:43:21.258 E/System (31646): at java.util.jar.JarFile.<init>(JarFile.java:161)
01-14 16:43:21.258 E/System (31646): at java.util.jar.JarFile.<init>(JarFile.java:98)
01-14 16:43:21.258 E/System (31646): at libcore.io.ClassPathURLStreamHandler.<init>(ClassPathURLStreamHandler.java:47)
01-14 16:43:21.258 E/System (31646): at dalvik.system.DexPathList$Element.maybeInit(DexPathList.java:532)
01-14 16:43:21.258 E/System (31646): at dalvik.system.DexPathList$Element.findResource(DexPathList.java:568)
01-14 16:43:21.258 E/System (31646): at dalvik.system.DexPathList.findResource(DexPathList.java:440)
01-14 16:43:21.258 E/System (31646): at dalvik.system.BaseDexClassLoader.findResource(BaseDexClassLoader.java:74)
01-14 16:43:21.258 E/System (31646): at java.lang.ClassLoader.getResource(ClassLoader.java:793)
01-14 16:43:21.258 E/System (31646): at java.lang.ClassLoader.getResourceAsStream(ClassLoader.java:977)
01-14 16:43:21.258 E/System (31646): at java.util.ResourceBundle$RBClassLoader.getResourceAsStream(ResourceBundle.java:464)
01-14 16:43:21.258 E/System (31646): at java.util.ResourceBundle$Control$1.run(ResourceBundle.java:2603)
01-14 16:43:21.258 E/System (31646): at java.util.ResourceBundle$Control$1.run(ResourceBundle.java:2589)
01-14 16:43:21.258 E/System (31646): at java.security.AccessController.doPrivileged(AccessController.java:67)
01-14 16:43:21.258 E/System (31646): at java.util.ResourceBundle$Control.newBundle(ResourceBundle.java:2587)
01-14 16:43:21.258 E/System (31646): at java.util.ResourceBundle.loadBundle(ResourceBundle.java:1438)
01-14 16:43:21.258 E/System (31646): at java.util.ResourceBundle.findBundle(ResourceBundle.java:1402)
01-14 16:43:21.258 E/System (31646): at java.util.ResourceBundle.findBundle(ResourceBundle.java:1356)
01-14 16:43:21.258 E/System (31646): at java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:1298)
01-14 16:43:21.258 E/System (31646): at java.util.ResourceBundle.getBundle(ResourceBundle.java:723)
01-14 16:43:21.258 E/System (31646): at java.util.logging.Level.<init>(Level.java:223)
01-14 16:43:21.258 E/System (31646): at java.util.logging.Level.<clinit>(Level.java:96)
01-14 16:43:21.258 E/System (31646): at java.util.logging.Logger.<clinit>(Logger.java:177)
01-14 16:43:21.258 E/System (31646): at java.util.logging.Logger.getLogger(Logger.java:393)
01-14 16:43:21.258 E/System (31646): at android.icu.util.TimeZone.<clinit>(TimeZone.java:92)
01-14 16:43:21.258 E/System (31646): at java.util.TimeZone.setDefault(TimeZone.java:712)
01-14 16:43:21.258 E/System (31646): at com.android.internal.os.RuntimeInit.commonInit(RuntimeInit.java:132)
01-14 16:43:21.258 E/System (31646): at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:256)

上面的issue,附上测试机型:

  1. google nexus 6 Android版本:7.1.1
  2. 魅族15 Android版本:7.1.1
  3. OPPO R17 Android版本:8.1.0
Viking Den 回复

hello 加我qq 77227005,看上去问题不大

simple 有没有啥定制 monkey 的方法? 中提及了此贴 01月16日 09:57
120楼 已删除

在max.widget.black加了黑控件屏蔽,为什么没有生效?还是会点到
在max.widget.black加了以下控件的黑名单:
{
"activity": "com.netease.mobimail.activity.LoginActivity",
"xpath":"//*[@class='android.widget.TextView' and @resource-id='com.netease.mail:id/tv_forget_password']"
},

{
"activity": "com.netease.mobimail.activity.LoginActivity",
"xpath":"//*[@class='android.widget.Button' and @resource-id='com.netease.mail:id/button_register']"
},

{
"activity": "com.netease.mobimail.activity.TabActivity",
"xpath":"//*[@class='android.widget.ImageView' and @resource-id='com.netease.mail:id/iv_mail_list_filter']"
}
运行时还能点击到,log输出:

但是如果配在max.xpath.selector 的blackList里面是有效的,那max.widget.black还有什么用?

foly2019 回复

log: inside black list 是会把这些控件从 select 队列里删除掉

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册