【Android测试】【第七节】Monkey——源码浅谈

转载 2016年05月30日 10:49:24

【Android测试】【第七节】Monkey——源码浅谈

 版权声明:本文出自胖喵~的博客,转载必须注明出处。

    转载请注明出处:http://www.cnblogs.com/by-dream/p/4713466.html

 

 

前言


   根据上一篇我们学会了Monkey的用法,知道了Monkey可以非常容易的模拟伪随机的模拟事件。也许有的时候我们想让他稍微智能化一些,例如只在某个屏幕范围产生伪随机事件,或者说是只对某些指定Activity进行操作,这样就需要我们对Monkey进行改良了。而改良必须去改Monkey的源码,因此本节课们就简单的说说Monkey的源码。

  源码下载地址:https://code.google.com/p/android-source-browsing/source/browse/cmds/monkey/src/com/android/commands/monkey/?repo=platform--development&name=android-cts-4.2_r2  ( 这里只是Monkey的源码,如果要编译Monkey需要下载Android的源码 )

  

概述


  如果你真的打算改造一个属于你的Monkey,那么过程必须要做的是:

  1、下载Android源码

  2、阅读Monkey源码如果需要修改代码

  3、代码编译

  4、运行Monkey

  本节内容主要针对第二部分的 “阅读Monkey源码”,其他的1、3、4 部分会在另外一篇“只允许注册用户访问的”的番外篇里进行介绍,因为这部分有些内容不是本人原创,因此对博客进行了加密处理,以免侵犯到源作者的权利,如需交流这部分内容,请留言给我。

 

Monkey源码


      Monkey的入口在 Monkey.java中:

复制代码
 /**
     * Command-line entry point.
     *
     * @param args The command-line arguments
     */
    public static void main(String[] args) {
        // Set the process name showing in "ps" or "top"
        Process.setArgV0("com.android.commands.monkey");

        int resultCode = (new Monkey()).run(args);
        System.exit(resultCode);
    }
复制代码

  第一句的意思就是在 shell 命令行下 使用 ps | grep com.**.monkey 就找到正在运行的monkey进程

  第二句是后续的内容,我们继续看后续干了什么。

 run

  这个run中的内容基本就是Monkey运行的流程,主要做了:

  1、处理命令行参数

if (!processOptions()) {
            return -1;
        }

    没有什么特殊的地方,主要是针对下面这张图里我们用到的参数进行一个统计和预处理。

  

  2、处理要拉起的应用程序的Activity:

    我们在运行Monkey的时候,如果指定了“ -p 包名 ”,那么Monkey一定会拉起这个App的第一个Activity,这个究竟是怎么实现的呢?就是借助Intent这个东西:

     // now set up additional data in preparation for launch
        if (mMainCategories.size() == 0) {
            mMainCategories.add(Intent.CATEGORY_LAUNCHER);
            mMainCategories.add(Intent.CATEGORY_MONKEY);
        }

 

  3、处理Source模块:

    Source模块,以MonkeyEventSource为接口,衍生出三种Source类:MonkeySourceRandom类(随机生成事件)、MonkeySourceScript(从脚本获取事件)、MonkeySourceNetwork(从网络获取事件)。    

复制代码
      if (mScriptFileNames != null && mScriptFileNames.size() == 1) {
            // script mode, ignore other options
            mEventSource = new MonkeySourceScript(mRandom, mScriptFileNames.get(0), mThrottle,
                    mRandomizeThrottle, mProfileWaitTime, mDeviceSleepTime);
            mEventSource.setVerbose(mVerbose);

            mCountEvents = false;
        } else if (mScriptFileNames != null && mScriptFileNames.size() > 1) {
            if (mSetupFileName != null) {
                mEventSource = new MonkeySourceRandomScript(mSetupFileName,
                        mScriptFileNames, mThrottle, mRandomizeThrottle, mRandom,
                        mProfileWaitTime, mDeviceSleepTime, mRandomizeScript);
                mCount++;
            } else {
                mEventSource = new MonkeySourceRandomScript(mScriptFileNames,
                        mThrottle, mRandomizeThrottle, mRandom,
                        mProfileWaitTime, mDeviceSleepTime, mRandomizeScript);
            }
            mEventSource.setVerbose(mVerbose);
            mCountEvents = false;
        } else if (mServerPort != -1) {
            try {
                mEventSource = new MonkeySourceNetwork(mServerPort);
            } catch (IOException e) {
                System.out.println("Error binding to network socket.");
                return -5;
            }
            mCount = Integer.MAX_VALUE;
        } else {
            // random source by default
            if (mVerbose >= 2) { // check seeding performance
                System.out.println("// Seeded: " + mSeed);
            }
            mEventSource = new MonkeySourceRandom(mRandom, mMainApps, mThrottle, mRandomizeThrottle);
            mEventSource.setVerbose(mVerbose);
            // set any of the factors that has been set
            for (int i = 0; i < MonkeySourceRandom.FACTORZ_COUNT; i++) {
                if (mFactors[i] <= 0.0f) {
                    ((MonkeySourceRandom) mEventSource).setFactors(i, mFactors[i]);
                }
            }

            // in random mode, we start with a random activity
            ((MonkeySourceRandom) mEventSource).generateActivity();
        }
复制代码

    这部分只要是来判断Monkey的事件源来自何方,根据这些事件的来源,由不同的类做处理。MonkeySourceRandom事件的来源就是我们在命令行输入参数后的伪随机压力测试;MonkeySourceScript事件来源于Monkey识别的一种脚本,事实上Monkey也可以做到通过脚本指定位置点击,滑动等操作,但是该脚本的可读性非常的差,编写不易,因此这里我也没有介绍;第三种MonkeySourceNetwork来自于后面我们要讲的Monkeyrunner,Monkeyrunner通过socket将一些要处理的事件发给Monkey,由Monkey来完成最后的处理。

 

  4、循环处理事件:

        mNetworkMonitor.start();
        int crashedAtCycle = runMonkeyCycles();
        mNetworkMonitor.stop();    

    主要看看 runMonkeyCycles() 这个函数主要做了什么:

复制代码
    /** 
     * Run mCount cycles and see if we hit any crashers. 
     * <p> 
     * TODO: Meta state on keys 
     * 
     * @return Returns the last cycle which executed. If the value == mCount, no 
     *         errors detected. 
     */  
    private int runMonkeyCycles() {  
        int eventCounter = 0;  
        int cycleCounter = 0;  
  
        boolean shouldReportAnrTraces = false;  
        boolean shouldReportDumpsysMemInfo = false;  
        boolean shouldAbort = false;  
        boolean systemCrashed = false;  
  
        // TO DO : The count should apply to each of the script file.  
        while (!systemCrashed && cycleCounter < mCount) {  
                ...  
            MonkeyEvent ev = mEventSource.getNextEvent();  
            if (ev != null) {  
                int injectCode = ev.injectEvent(mWm, mAm, mVerbose);  
                ...  
             }  
        ...  
        }  
       ....  
}  
复制代码

    这里涉及到了一个重要的东西就是MonkeyEvent。

    以MonkeyEvent为基类,衍生出各种Event类,如Monkey中常见的点击,输入,滑动事件;

    那么一个点击的操作究竟是怎么进行下去的呢?我们可以到上面调用的是injectEvent,这个方法是由基类定义的,每一个子类去实现不同的内容,点击、滑动等这个方法都是通过第一个参数一个iWindowManager的对象而完成的,当然也有不需要这个参数,例如MonkeyThrottleEvent这个类的实现方法,根本没有用到iwm:

复制代码
@Override  
public int injectEvent(IWindowManager iwm, IActivityManager iam, int verbose) {  
  
    if (verbose > 1) {  
        System.out.println("Sleeping for " + mThrottle + " milliseconds");  
    }  
    try {  
        Thread.sleep(mThrottle);  
    } catch (InterruptedException e1) {  
        System.out.println("** Monkey interrupted in sleep.");  
        return MonkeyEvent.INJECT_FAIL;  
    }  
      
    return MonkeyEvent.INJECT_SUCCESS;  
}  
复制代码

    那么这个iWindowManager的对象究竟是什么呢?这个事系统隐藏的一个接口,通过这个接口可以注入一些操作事件,那么我们以后是不是也可以用这个接口来进行事件的注入呢?答案是no,为什么呢?我们来看看:

    谷歌为了方便Monkey能够轻松的完成一些点击、滑动事件,因此在使用了这个系统隐藏的接口,Monkey这个应用拥有这个两个独特的权限:第一个是SET_ACTIVITY_WATCHER这个权限,它允许monkey对activity的生命周期进行全权控制。第二个就是INJECT_EVENTS这个权限它允许monkey去模拟触摸和按键事件。为了防止这个系统隐藏接口暴露出的漏洞,普通的App是不能请求到这些权限的,只有android系统同意的应用才会得到允许获得这些权限。为了防止坏人使用Monkey来进行这个事件的注入,Monkey也只被允许root运行或者是shell这个组的成员运行。

 

分类: 软件测试
2
0
(请您对文章做出评价)
« 上一篇:【Android测试】【第六节】Monkey——认识和使用
» 下一篇:【Android测试】【第八节】Monkey——源码改造
posted @ 2015-08-08 16:54 胖喵~ Views(522) Comments(17Edit 收藏

  
#1楼 2015-08-27 17:31 | smile花儿  
楼主写的非常的好

  
#2楼[楼主2015-08-31 13:50 | 胖喵~  
@ smile花儿
谢谢支持 我会继续的

  
#3楼 2016-03-09 15:31 | 疯狂的坏丫头  
第八节源码改造博文的阅读密码是什么?

  
#4楼[楼主2016-03-09 15:36 | 胖喵~  
@ 疯狂的坏丫头
看我给你的私信

  
#5楼 2016-04-22 16:29 | 宇智波臀  
Lz,第八节阅读密码是啥

  
#6楼[楼主2016-04-22 19:29 | 胖喵~  
@ 宇智波臀
私信你~

  
#7楼 2016-05-04 15:53 | double11  
Lz,第八节阅读密码是什么?

  
#8楼 2016-05-15 00:16 | luceion  
楼主很赞,第八节到了关键的部分了,求私信下密码~谢谢

  
#9楼[楼主2016-05-16 16:33 | 胖喵~  
@ luceion
私信你

  
#10楼 2016-05-17 09:45 | mars66  
很想看第八节的内容,求下私信密码,感激不尽

  
#11楼[楼主2016-05-17 23:16 | 胖喵~  
@ mars66
已经私信你

  
#12楼 2016-05-26 14:08 | 酸酒鸭  
楼主看到了第八节内容,求密码,谢谢

  
#13楼 2016-05-27 15:51 | 白开水echo  
求下一章密码

  
#14楼[楼主2016-05-27 15:55 | 胖喵~  
@ 酸酒鸭
私信你了

  
#15楼[楼主2016-05-27 15:55 | 胖喵~  
@ 白开水echo
私信你了

  
#16楼 2016-05-27 17:10 | 白开水echo  
源码哪里下载?链接不可以

  
#17楼[楼主2016-05-29 17:43 | 胖喵~  
@ 白开水echo
可以下载的 得绕过墙

【Android测试】【第七节】Monkey——源码浅谈

前言    根据上一篇我们学会了Monkey的用法,知道了Monkey可以非常容易的模拟伪随机的模拟事件。也许有的时候我们想让他稍微智能化一些,例如只在某个屏幕范围产生伪随机事件,或者说是只对某...
  • carter_dream
  • carter_dream
  • 2015年12月14日 15:59
  • 346

Android稳定性测试-- Monkey源码分析

Monkey的代码框架 主控模块:主控模块即Monkey类,是入口函数所在类,主要负责参数解析和赋值、初始化运行环境,执行runMonkeyCycles()方法,针对不同的事件源开始获取并...
  • ToBeTheEnder
  • ToBeTheEnder
  • 2017年01月03日 19:40
  • 1663

[Android 测试] 压力稳定性测试之: Monkey 详解分析脚本

一、什么是稳定性测试?通过随机点击屏幕一段时间,看看app会不会奔溃,能不能维持正常运行。二. Money是什么?Monkey测试是Android平台自动化测试的一种手段,通过Monkey程序模拟用户...
  • niubitianping
  • niubitianping
  • 2016年10月11日 10:08
  • 3223

Android Monkey测试脚本

转载于:http://blog.csdn.net/quaful/article/details/6863914。 Android 的 monkey test 工具提供了 -f scriptfile ...
  • VNanyesheshou
  • VNanyesheshou
  • 2015年09月28日 11:04
  • 12522

Android自动测试命令Monkey

shell, monkey, system, Android, 文件系统Monkey, 示例, 简介 一、Monkey测试简介 Monkey测试是Android平台自动化测试的...
  • heng615975867
  • heng615975867
  • 2016年08月02日 17:04
  • 1385

Android中如何做Monkey测试

转载请注明出处! 索引 Monkey的介绍Monkey基本使用Monkey命令参考Monkey测试信息截取 CRASHANR MonkeyScript 脚本格式常用A...
  • JavaAndroid730
  • JavaAndroid730
  • 2016年11月23日 21:57
  • 5224

Android Monkey 源代码阅读

Android Monkey 源代码阅读1. Monkey开始启动 1. main函数只是设置了进程的名称,主要过程在run函数中执行。 2. 获取参数,初始化参数和随机数。然后它会获取系统的...
  • tianchi92
  • tianchi92
  • 2016年09月16日 09:46
  • 699

Android APP压力测试(一) 之Monkey工具介绍

前言   本文主要介绍Monkey工具。Monkey测试是Android平台自动化测试的一种手段,通过Monkey程序模拟用户触摸屏幕、滑动、按键等操作来对设备上的程序进行压力测试,检测程序多久...
  • tanghongchang123
  • tanghongchang123
  • 2016年07月05日 10:31
  • 852

Android中Monkey测试的使用

大多数我们自己写好了程序都自我感觉没有问题,可事实是很多情况是我们预料不到的,所以需要一个不按照我们自己的思路进行测试,又不能请一个人专门进行测试,这个时候Monkey测试可以帮助我们进行测试! 1、...
  • gufeilong
  • gufeilong
  • 2016年04月29日 14:39
  • 2186

Android Monkey测试入门

Monkey是一款通过命令行来对我们APP进行测试的工具,可以运行在模拟器里或真机上。它向系统发送伪随机的用户事件流,实现对正应用程序进行压力测试。官方介绍 :https://developer.an...
  • true100
  • true100
  • 2016年10月14日 11:27
  • 16414
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:【Android测试】【第七节】Monkey——源码浅谈
举报原因:
原因补充:

(最多只允许输入30个字)