您的位置:首页 > 移动开发 > Android开发

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

2016-05-30 10:49 901 查看


【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这个组的成员运行。
 

分类: 软件测试

标签: Android自动化测试

好文要顶 关注我 收藏该文 

 






胖喵~
关注 - 5
粉丝 - 31

+加关注

2

0

(请您对文章做出评价)

« 上一篇:【Android测试】【第六节】Monkey——认识和使用
» 下一篇:【Android测试】【第八节】Monkey——源码改造

posted @ 2015-08-08 16:54 胖喵~ Views(522)
Comments(17) Edit 收藏

Post Comment

  
#1楼 2015-08-27
17:31 | smile花儿  

楼主写的非常的好
支持(0)反对(0)

  
#2楼[楼主] 2015-08-31
13:50 | 胖喵~  

@ smile花儿

谢谢支持 我会继续的
支持(0)反对(0)

  
#3楼 2016-03-09
15:31 | 疯狂的坏丫头  

第八节源码改造博文的阅读密码是什么?
支持(0)反对(0)

  
#4楼[楼主] 2016-03-09
15:36 | 胖喵~  

@ 疯狂的坏丫头

看我给你的私信
支持(0)反对(0)

  
#5楼 2016-04-22
16:29 | 宇智波臀  

Lz,第八节阅读密码是啥
支持(0)反对(0)

  
#6楼[楼主] 2016-04-22
19:29 | 胖喵~  

@ 宇智波臀

私信你~
支持(0)反对(0)

  
#7楼 2016-05-04
15:53 | double11  

Lz,第八节阅读密码是什么?
支持(0)反对(0)

  
#8楼 2016-05-15
00:16 | luceion  

楼主很赞,第八节到了关键的部分了,求私信下密码~谢谢
支持(0)反对(0)

  
#9楼[楼主] 2016-05-16
16:33 | 胖喵~  

@ luceion

私信你
支持(0)反对(0)

  
#10楼 2016-05-17
09:45 | mars66  

很想看第八节的内容,求下私信密码,感激不尽
支持(0)反对(0)

  
#11楼[楼主] 2016-05-17
23:16 | 胖喵~  

@ mars66

已经私信你
支持(0)反对(0)

  
#12楼 2016-05-26
14:08 | 酸酒鸭  

楼主看到了第八节内容,求密码,谢谢
支持(0)反对(0)

  
#13楼 2016-05-27
15:51 | 白开水echo  

求下一章密码
支持(0)反对(0)

  
#14楼[楼主] 2016-05-27
15:55 | 胖喵~  

@ 酸酒鸭

私信你了
支持(0)反对(0)

  
#15楼[楼主] 2016-05-27
15:55 | 胖喵~  

@ 白开水echo

私信你了
支持(0)反对(0)

  
#16楼 2016-05-27
17:10 | 白开水echo  

源码哪里下载?链接不可以
支持(0)反对(0)

  
#17楼[楼主] 2016-05-29
17:43 | 胖喵~  

@ 白开水echo

可以下载的 得绕过墙
支持(0)反对(0)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: