安卓Monkey源码分析之运行流程
在《MonkeyRunner源码分析之与Android设备通讯方式》中,我们谈及到MonkeyRunner控制目标android设备有多种方法,其中之一就是在目标机器启动一个monkey服务来监听指定的一个端口,然后monkeyrunner再连接上这个端口来发送命令,驱动monkey去完成相应的工作。
当时我们只分析了monkeyrunner这个客户端的代码是怎么实现这一点的,但没有谈monkey那边是如何接受命令,接受到命令又是如何处理的。
所以自己打开源码看了一个晚上,大概有了概念。但今天网上搜索了下,发现已经有网友“chenjie”对monkey的源码做过相应的分析了,而且文章写得非常有概括性,应该是高手所为,果断花了2个积分下载下来,不敢独享,本想贴上来分享给大家,但发现pdf的文档直接拷贝上来会丢失掉图片,所以只好贴上下载地址:http://download.csdn.net/download/zqilu/6884491
但文章主要是架构性得去描述monkey是怎么工作的,按照我自己的习惯,我还是喜欢按照自己的思维和有目的性的去了解我想要的,在这里我想要的是搞清楚monkey是如何处理monkeyrunner过来的命令的。
本文我们就先看下monkey的运行流程。
1. 运行环境设置
和monkeyrunner一样,monkey这个命令也是一个shell脚本,它是在我们的目标android设备的“/system/bin/monkey”,其实这是一个android上面java程序启动的标准流程。
base=/system
export CLASSPATH=$base/framework/monkey.jar
trap "" HUP
exec app_process $base/bin com.android.commands.monkey.Monkey $*
android中可以通过多种方式启动java应用,通过app_process命令启动就是其中一种,它可以帮忙注册android JNI,而绕过dalvik以使用Native API(如我般不清楚的请百度)所做的主要事情如下:
- 设置monkey的CLASSPATH环境变量指向monkey.jar
- 通过app_process指定monkey的入口和传进来的所有参数启动上面CLASSPATH设定的monkey.jar
2.命令行参数解析
/**
* 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);
}
- 处理命令行参数
- 根据命令行参数启动不同的事件源,也就是我们的测试事件究竟是从网络如monkeyrunner过来的还是monkey内部的random测试数据集过来的还是脚本过来的如此之类
- 跳入runMonkeyCyncle方法针对不同的事件源开始获取并执行不同的事件
private int run(String[] args) {
...
if (!processOptions()) {
return -1;
}
...
}
进去之后就是很普通的读取命令行的参数然后一个个进行解析保存了,没有太多特别的东西,这里就直接贴出monkey的参数选项大家看看就好了:
3. 初始化测试事件源
private int run(String[] args) {
...
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();
}
...
mNetworkMonitor.start();
int crashedAtCycle = runMonkeyCycles();
mNetworkMonitor.stop();
...
}
事件源代表测试数据的事件是从哪里过来的,不同的event source会有不同的类来做相应的实现:
- MonkeySourceNetwork.java: 事件是从网络如monkeyrunner过来的,处理的是《MonkeyRunner源码分析之与Android设备通讯方式》描述的界面控制操作事件
- MonkeySourceNetworkVars.java: 事件也是从网络如monkeyrunner过来的,处理的是《MonkeyRunner源码分析之与Android设备通讯方式》提到的getPropery事件
- MonkeySourceNetworkViews.java:事件也是从网络如monkeyrunner过来的,处理的是《MonkeyRunner源码分析之与Android设备通讯方式》提到的Views相关的事件
- MonkeySourceRandom.java:事件是从monkey内部生成的随机事件集,也就是我们通过命令行启动monkey测试目标app的常用方式
- MonkeySourceRanodomeScript.java: 上面的随机内部数据源也可以通过指定setup脚本来创建
- MonkeySourceScript.java: 用户也可以遵循一定的规则编写monkey脚本来驱动monkey进行相关测试,与上面不同的是它不再是随机的
- 从指定的源获取命令
- 把命令翻译成monkey事件然后放到命令队列EventQueue
4. 循环执行事件
private int run(String[] args) {
...
int crashedAtCycle = runMonkeyCycles();
...
}
如前所述,runMonkeyCyles方法会根据不同的数据源开始一条条的获取事件并进行执行:
/**
* 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);
...
}
...
}
....
}
注意这里的mEventSource就是我们上面提到的事件源的接口,它屏蔽了每个事件实现类的具体细节,我们只需要告诉这个接口我们现在需要取一条事件然后执行它,该结构根据面向对象的多态原理,就会自动取事件的实现类获得对应的事件进行返回。
| 作者 | 自主博客 | 微信第一手行业资讯分享 | CSDN |
| 天地会珠海分舵 | http://techgogogo.com |
服务号:TechGoGoGo 扫描码:
|
http://blog.csdn.net/zhubaitian |
安卓Monkey源码分析之运行流程的更多相关文章
- [原创]java WEB学习笔记70:Struts2 学习之路-- struts2拦截器源码分析,运行流程
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
- 安卓MonkeyRunner源码分析之工作原理架构图及系列集合
花了点时间整理了下MonkeyRunner的工作原理图,请配合本人博客里面MonkeyRunner其他源码分析文章进行阅读.下面整理成相应系列列表方便大家阅读: MonkeyRunner源码分析之-谁 ...
- Monkey源码分析之事件源
上一篇文章<Monkey源码分析之运行流程>给出了monkey运行的整个流程,让我们有一个概貌,那么往后的文章我们会尝试进一步的阐述相关的一些知识点. 这里先把整个monkey类的结构图给 ...
- Monkey源码分析之事件注入
本系列的上一篇文章<Monkey源码分析之事件源>中我们描述了monkey是怎么从事件源取得命令,然后将命令转换成事件放到事件队列里面的,但是到现在位置我们还没有了解monkey里面的事件 ...
- openVswitch(OVS)源码分析之工作流程(哈希桶结构体的解释)
这篇blog是专门解决前篇openVswitch(OVS)源码分析之工作流程(哈希桶结构体的疑惑)中提到的哈希桶结构flex_array结构体成员变量含义的问题. 引用下前篇blog中分析讨论得到的f ...
- monkey源码分析之事件注入方法变化
在上一篇文章<Monkey源码分析之事件注入>中,我们看到了monkey在注入事件的时候用到了<Monkey源码分析番外篇之Android注入事件的三种方法比较>中的第一种方法 ...
- nodejs的Express框架源码分析、工作流程分析
nodejs的Express框架源码分析.工作流程分析 1.Express的编写流程 2.Express关键api的使用及其作用分析 app.use(middleware); connect pack ...
- Okhttp源码分析--基本使用流程分析
Okhttp源码分析--基本使用流程分析 一. 使用 同步请求 OkHttpClient okHttpClient=new OkHttpClient(); Request request=new Re ...
- 安卓MonkeyRunner源码分析之启动
在工作中因为要追求完成目标的效率,所以更多是强调实战,注重招式,关注怎么去用各种框架来实现目的.但是如果一味只是注重招式,缺少对原理这个内功的了解,相信自己很难对各种框架有更深入的理解. 从几个月前开 ...
随机推荐
- iOS 要定义自己的导航栏button样式Button Image 执行出彩是不一样的与原来的颜色 -解
在相机闪光灯,在导航栏中自己定义"闪"样式.点击变换的图像期望,但一直没有变化.原来是该条款的Global Tint颜色.因此,系统会自己主动改变图片的颜色Global Tint颜 ...
- HDU ACM 1290 献给杭电五十周年校庆的礼物
解析: 1.n条直线把平面切割成的区域数为: f(n)=f(n-1)+n=n(n+1)/2+1; 2.把空间切割为最多区域数的时候,第n个平面与前(n-1)个平面相交.且无三面共线,因此该平面与前(n ...
- Linux
介绍了相关的文件夹
学习Linux,先了解Linux标准的文件夹结构是非常重要的,学习的一个很好的铺垫之后的行动.去罗列大而全的所有文件夹. 本文主要说明.笔者本人接触,须要了解的一些文件文件夹,当然本文也会不断的更新或 ...
- NSIS:使用FileFunc.nsh头文件判断文件版本
原文 NSIS:使用FileFunc.nsh头文件判断文件版本 这里,轻狂拿WMP10做一个例子.关于WMP10的原始安装文件,可以下载后通过/C /T:D:\Windows Media Player ...
- Android开发模板------自己定义SimpleCursorAdapter的使用
使用SimpleCursorAdapter所设计的table(数据表)一定要有_id字段名称,否则会出现"找不到_id"的错误 SimpleCursorAdapter直接使用的方法 ...
- 谈论HashMap,HashSet,HashTableeasy被我们忽视
在正常发育,HashMap,HashTable,HashSet 他们批准了经常使用的按键值地图数据结构.在这里,我主要写一些平时我们使用的这些数据结构easy忽略. HashMap HashMap的结 ...
- Xcode HeaderDoc 过程(1)
原版的: http://www.raywenderlich.com/66395/documenting-in-xcode-with-headerdoc-tutorial 了解如何从代码中生成文档! X ...
- POJ 3692:Kindergarten(最大的使命)
id=3692">Kindergarten Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 4920 Ac ...
- Cocos2d-X采用CCScrollView创建滚动视图
CCScrollView滚动视图可以让游戏有效果,并能够通过滚动视图切换游戏场景,滚动视图通常用来选择在游戏中的级别 实例1:使用CCScrollView创建一个简单的滚动视图 首先创建一个Scrol ...
- Unity插件之NGUI学习(8)—— Table和NGUI尺寸转换为世界坐标系尺寸
依据 Unity插件之NGUI学习(2),创建一个UI Root,在UI Root下创建一个Texture作为背景图,并设置图片,在Wiget下调整大小:然后在UI Root下再创建一个Panel. ...
