Monkey进阶

    之前的章节适用初学者,从本章节开始,主要介绍了一些网上没有或是初学者理解容易有偏差的地方,以及一些本人的实际工作经验。

7.Monkey的底牌

    Monkey是Google提供的一个命令行工具,可以运行在模拟器或者实际设备中。它向系统发送伪随机的用户事件(如按键、手势、触摸屏等输入),对软件进行稳定性与压力测试。

(1)Monkey程序是Android自带的,由Java语言写成,在Android文件系统中存放的路径是/system/framework/monkey.jar。
(2)monkey.jar是由一个名为"monkey"的shell脚本来启动执行,shell脚本在Android文件系统中存放的路径是system/bin/monkey。
(3)Monkey源码路径(Android4.4.4.2版本): android4.4.2_rc1\development\cmds\monkey\src\com\android\commands\monkey

8.Monkey命令基本参数

8.1 monkey事件

    查看官方文档,表里只给出了8种事件。但运行Monkey后,却发现有10种事件,再查看Android4.4.2的monkey源码,竟有11种!后来才知道,不同的Android SDK中的Event percentages种类数和顺序都是不一样的。图1就是Android4.4.2中所有的事件。图1  Android源码中monkey事件图1 Android源码中monkey事件
    官网有写touch、motion、trackball、nav、majornav、syskeys、appswitch、anyevent 分别对应序号0、1、3、5、6、7、8、10,运行monkey -h会多–pct-pinchzoom、–pct-flip,分别对应序号2、9,而–pct-rotation(旋转)对应序号4,rotation degree=0,1,2,3分别表示顺时针方向分别0°,90°,180°,270°,但也发现一个问题,–pct-rotation参数并不受通知栏“锁定屏幕方向”的控制,具体原因有待进一步研究。
    至于每个事件都是什么意思以及每个事件包括什么,直接翻译的意思就差不多,如果想进一步了解,可以自行看。

示例:

adb shell monkey --pct-syskeys 100 -v -v -v100>d:\desk\syskeys.txt

说明:查看输出文件,纵观整个日志,发现–pct-syskeys这个参数包含音量加减和home键back键。
图2 --pct-syskeys参数日志截图
图2 --pct-syskeys参数日志截图

    PS:网上有人说-v -v -v可以合起来写成-vvv,或是写成–v-v-v这个说法有失偏颇,我深受其害,这种写法会认为只有1个-v,铭记。

8.2 --throttle

    在事件之间插入固定延迟。通过这个选项可以减缓Monkey的执行速度。如果不指定该选项,Monkey将不会被延迟,事件将尽可能快地被完成。这里的事件就是上文说的那些诸如touch、montion、systemkeys之类的。

8.3 COUNT

    对于count,官网并没有对它做太多解释,前辈们似乎感觉这个也没什么好说的,就是数量的意思嘛。在官网找到另一个例子,如图3。
图3  Android官网示例
图3 Android官网示例

    官网的意思是count是指伪随机事件。不知道大家对这个“伪随机事件”的理解是什么,我语文不太好,我在长达近半年的时间里,都认为它就是上文说的那些诸如touch、montion、systemkeys之类的。曾天真的以为一个touch就是这里所说的事件,这样根据throttle参数和COUNT 参数联合起来用,就可以控制monkey的运行时间了。然而事实并非如此,经过实验发现,这里所谓的“伪随机事件”并不是事件类别里的事件,其实,正确的理解应该是一个分解动作。拿touch举例,一个touch事件,包括“ACTION_DOWN”和“ACTION_UP”两个分解动作,“ACTION_DOWN”和“ACTION_UP”这是两个伪随机事件。说起来有点绕,如图4。也就是说,一个事件类别中会有N个伪随机事件。
图4   事件与伪随机事件逻辑图
图4 事件与伪随机事件逻辑图

    所以要想控制monkey运行时间,用throttle*COUNT是不可行的。目前使用shell脚本做控制,运用相对时间是比较安全保险的,因为在ROM测试时会有更改系统时间风险。具体实现为:在shell脚本中开启一个计时脚本,就像Android中在主线程中开辟新线程一样,这样时间到了,重启pad即可。只可惜脚本只是脚本,没有类似于Android中handler一类的机制,否则也不至于每次都要重启。(当然,重启会有一些数据的初始化等,对后续测试还是有帮助的)。

9.结果分析

    目前重点对进行ANR和CRASH进行分析

9.1 ANR

    ANR,是“Application Not Responding”的缩写,即“应用程序无响应”。
    在Android中,ActivityManagerService(简称AMS)和WindowManagerService(简称WMS)会监测应用程序的响应时间,如果应用程序主线程(即UI线程)在超时时间内对输入事件没有处理完毕,或者对特定操作没有执行完毕,就会出现ANR。对于输入事件没有处理完毕产生的ANR,Android会显示一个对话框,提示用户当前应用程序没有响应,用户可以选择继续等待或者关闭这个应用程序。
    Android有四大组件,都运行在MainThread。实际上,每个组件均有一个容器来管理。通过查看源码,可以看到Activity的Maneger是ActivityManagerService,那么作为容器它就有责任去检测所管理的对象是否处于可用状态。ActivityManagerService的方式是每隔一段时间向容器中的对象发消息,同时附有delayTime(5000ms),如果在此时间内Manager没有收到回应,容器便认为对象已处于不可用状态,就会出现所谓的ANR状态。如开头所说,四大组件运行在MainThread上,如果我们在MainThread上做耗时操作(耗时IO及其它耗时操作),那么就会发生ANR。

9.1.1 ANR超时时间

(1)ANR因不同类型,其超时时间也是不同的:

  • Event Dispatch ANR超时时间是5s。

android4.4.2_rc1\frameworks\base\services\input\InputDispatcher.cpp:
在这里插入图片描述 android4.4.2_rc1\frameworks\base\services\java\com\android\server\am\ActivityManagerService.java:
在这里插入图片描述

  • Services ANR超时时间是20s。

    android4.4.2_rc1\frameworks\base\services\java\com\android\server\am\ActiveServices.java
    在这里插入图片描述

    Broadcast ANR超时时间根据是foregroud或background分别是10s和60s。

android4.4.2_rc1\frameworks\base\services\java\com\android\server\am\ActivityManagerService.java
在这里插入图片描述
    三种ANR发生时都会在log中输出错误信息,这三种ANR不是孤立的,有可能会相互影响。例如一个应用程序进程中同时有一个正在显示的Activity和一个正在处理消息的BroadcastReceiver,它们都运行在这个进程的主线程中。如果BR的onReceive函数没有返回,此时用户点击屏幕,而onReceive超过5秒仍然没有返回,主线程无法处理用户输入事件,就会引起第1种ANR。如果继续超过10秒没有返回,又会引起第2种ANR。
    勾选开发者选项-应用-显示所有“应用无响应”(ANR)之后,对后台的ANR也进行弹窗显示,方便查看运行情况。当然,仅作参考,log才是最地道的,界面只是辅助。
     出现ANR,一般用logcat打印的信息,如图5。log会有提供是那个包出现的ANR,这个ANR是由于什么方面的原因造成的以及此时cpu负载信息及各个应用占用cpu的情况。
在这里插入图片描述
图5 logcat打印的ANR相关信息
     具体的信息Google已经帮我们打印在了data/anr/ 下的traces文件里。但是,每次发生ANR时都会删除旧的traces文件,重新创建新文件。也就是说Android只保留最后一次发生ANR时的traces信息。那么以前的traces信息就丢失了么,想想就知道不会,为了增强Android的异常信息收集管理能力,从2.2开始增加了DropBox功能。每次ANR在打印到traces文件之外,还会保留一份在data/system/dropbox中。
    PS:DropBox(简称DB)是系统进程中的一个服务,在system_server进程启动时创建,并且它没有运行在单独的线程中,而是运行在system_server的ServerThread线程中。我们可以将ServerThread称作system_server的主线程,ServerThread线程除了启动并维护各个服务外,还负责检测一些重要的服务是否死锁。dropbox不仅记录app的问题,也记录了系统的问题。这为ROM测试提供了一些bug依据,但由于部分bug涉及的较底层,特别是一些native的bug,不像 Java层的,可以直接通过log定位到具体问题所在,只能看到调用了哪些库,即使是开发也难以定位,所以这方面仍有待进一步提高。想具体了解,请移步http://blog.csdn.net/ljchlx/article/details/8559963。
    当然,monkey自己打印的log已经帮我们做好了这一工作,打印在traces文件里的内容,会在每个ANR的log的后边都会有显示,省去了我们自行查看traces文件的麻烦,如图6,是火拼ABC应用在测试时出现的ANR,从log中可以明确的看到出现ANR是由于音频出现了问题,以及对应代码的具体位置。[if 在这里插入图片描述
图6 monkey打印的ANR相关日志

9.2 CRASH

    在网上搜刮了一段文字,关于Android平台程序崩溃的各种类型的一个简述和原因列举。
(1)ForceClose:

  • 发生场景:应用进程崩溃。
  • 崩溃症状:系统弹出窗口提示用户某进程崩溃。
  • 发生原因:空指向异常或者未捕捉的异常。

(2)Tombstones:

  • 发生场景:Native层崩溃。

  • 崩溃症状:如果发生崩溃的native层和UI有关联(比如Browser),我们可以在UI上发现这个崩溃。如果发生崩溃的native层是在后台并且和UI没有直接联系,那么对于用户来说是不可见的,如果是debug版本可能会有Log打印出当时的底层现场。

  • 发生原因:各种各样,需要具体情况具体分析。

(3)系统服务崩溃(System Server Crash):

  • 发生场景:系统服务是Android核心进程,此服务进程发生崩溃。

  • 崩溃症状:手机重启到Android启动界面。

  • 发生原因:

    • a.系统服务看门狗发现异常。
    • b.系统服务发生未捕获异常。
    • c.OOM。
    • d.系统服务Native发生Tombstone。

(4)KernelPanics:

  • 发生场景:Linux内核发生严重错误。
  • 崩溃症状:手机从bootloader开始完全重启。
  • 发生原因:
    • a.Linux内核内存空间发生内存崩溃。
    • b.内核看门狗发现异常。
    • c.空指针操作内核。

    从现象来说未捕获的异常和闪退(NDK引发错误) “xxx程序无响应,是否立即关闭”之类的提示框,一般是由于Java层产生的异常。如果是闪退,通常是项目中用到了NDK引发某类致命的错误导致闪退。因为NDK是使用C/C++来进行开发,指针和内存管理是最重要也是最容易出问题的地方,稍有不慎就会遇到诸如内存地址访问错误、使用野针对、内存泄露、堆栈溢出、初始化错误、类型转换错误、数字除0等常见的问题,导致最后都是同一个结果:程序崩溃。
    像分析ANR一样,最好的情况就是,Java层的CRASH,monkey打印的日志里已经写明了造成CRASH的原因,如图7,log已经指明,在com.nd.puzzle_abc.view.MyGridViewAdapter.getView 第65行,出现了数组越界的问题。
在这里插入图片描述
图7 数组越界CRASH日志

    而一旦出现了如图8的问题,即native的问题,我们只能了解到是Bus error问题,至于具体是怎么导致的总线错误,并不能从log中直接看出问题所在,虽然可以从backtrace中一步查找,但很麻烦,对于这一点,目前开发们能做的也很有限。
在这里插入图片描述
图8 native的问题

10 Monkey脚本

    Monkey是一个压力测试工具,但是它可以用来做自动化测试,而且无需任何的工具,更不需要搭建环境,只需要一个文本文档编写好脚本运行,即可实现坐标、按键等基本操作。缺点是没有逻辑性。

10.1脚本API

Monkey相关脚本的格式如下:
type=rawevents
cont=10
speed=1.0

Monkey相关脚本的API如下:
在这里插入图片描述在这里插入图片描述

10.2示例

一个简单的例子:打开网页,输入www.baidu.com

(1)首先新建一个文档,命名为monkey.txt。
(2)在里面输入:

   #头文件、控制monkey发送消息的参数
    type=raw events
    cont=10
    speed=1.0
    #以下为monkey命令
    start data >>
    #打开浏览器,并延时默认的时间   LaunchActivity(com.android.browser,com.android.browser.BrowserActivity)
    ProfileWait()
    #清空网址
    Tap(500,150)
    DispatchPress(112)
    ProfileWait()
    #输入网址
    DispatchString(www.baidu.com)
    ProfileWait()
    #确认,载入网址
    DispatchPress(KEYCODE_ENTER)
    ProfileWait()
    #完成退出浏览器
    DispatchPress(3)

(3)保存后push到手机里去

adb push D:\monkey.txt /data/local/tmp/

(4)执行monkey命令:adb shell monkey -f

adb shell monkey -f /data/local/tmp/ 10,那么这个脚本里面指定的动作就会被执行10次。

部分内容参考:
https://testerhome.com/topics/3517

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值