Monkey源码分析之运行流程
来源:互联网 发布:淘宝直通车的规则 编辑:程序博客网 时间:2024/06/03 13:41
在《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 $*
- 设置monkey的CLASSPATH环境变量指向monkey.jar
- 通过app_process指定monkey的入口和传进来的所有参数启动上面CLASSPATH设定的monkey.jar
2.命令行参数解析
通过以上的app_process指定的monkey入口,我们可以知道我们的入口函数main是在com.android.commands.Monkey这个类里面的:
- /**
- * 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);
- }
入口函数很简单,直接跳到run这个方法,这是一个很重要的方法,里面大概会做以下这些事情:
- 处理命令行参数
- 根据命令行参数启动不同的事件源,也就是我们的测试事件究竟是从网络如monkeyrunner过来的还是monkey内部的random测试数据集过来的还是脚本过来的如此之类
- 跳入runMonkeyCyncle方法针对不同的事件源开始获取并执行不同的事件
这个方法会比较长,我们只看我们现在想要的关键片段,可以看到里面调用了命令行处理函数processOptions.
- private int run(String[] args) {
- ...
- if (!processOptions()) {
- return -1;
- }
- ...
- }
3. 初始化测试事件源
如前所述,run方法里面在获得命令行参数后会进入下一个环节,就是根据不同的参数去初始化不同的事件源
- 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();
- ...
- }
- 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
这里需要注意的是每一个EventSource类都是实现了MonkeyEventSource这个接口的,这个接口最重要的就是要求实现类必须实现getNextEvent这个方法来生成并获取事件。这样子做的好处就是屏蔽了每一个具体事件源的实现细节,其他地方的代码只需要调用这个接口的getNextEvent方法获得事件源就行了,而无需关心这些事件是从哪个源过来的。这些都是面向对象的面向接口编程的基础了,大家有不清楚的最好先去了解下java的一些基本知识,这样理解起来会快很多。
4. 循环执行事件
run方法根据参数从不同的事件源获得事件并放入到EventQueue后,就会开始执行一个循环去从EventQueue里获取事件进行执行
- private int run(String[] args) {
- ...
- int crashedAtCycle = 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);
- ...
- }
- ...
- }
- ....
- }
所以这里大家还需要对多态这个概念有所了解,特别是一些从手动测试转到自动化测试的朋友,可能之前没有接触过太多面向对象的知识。本人以前做过开发,所以还ok。这里只是做一个善意的提醒。
获得事件后下一步就是去执行相应的事件了,不同的事件会有不同的处理方式,或只是执行个命令,或调用WindowManager隐藏接口做事件注入等,这些都会在今后文章进行进一步阐述
这一篇文章就到此为止了,目的就是让大家对整一个monkey执行的流程有个初步的了解,方便理解往下的相关文章。
0 0
- Monkey源码分析之运行流程
- Monkey源码分析之运行流程
- Webmagic源码分析之运行流程
- WhatWeb源码分析之运行流程
- 第5章2节《MonkeyRunner源码剖析》Monkey原理分析-启动运行: 启动流程概览(原创)
- Monkey源码分析之事件源
- Monkey源码分析之事件注入
- Monkey源码分析之事件源
- Monkey源码分析之事件注入
- android Monkey测试源码分析之二
- 源码-spark运行流程分析
- spark源码分析:spark运行总流程
- 结合源码分析Struts2运行流程
- 【源码分析】storm拓扑运行全流程源码分析
- 【源码分析】storm拓扑运行全流程源码分析
- monkey源码分析之事件注入方法变化
- monkey源码分析之事件注入方法变化
- monkey源码分析之事件注入方法变化(api16之后)
- Android 按两次返回键退出应用
- C#.Net 持久化对象为XML文件
- 一个简单的手机拨号器
- 机器学习(3)——KNN算法及手写数字的识别(一)
- memset的问题
- Monkey源码分析之运行流程
- 内存分配函数
- onvif 客户端发现
- 关于 redis、memcache、mongoDB 的对比
- C++多态性的分类
- Python设计模式——工厂方法模式
- POJ 3696 The Luckiest number (整数的阶+欧拉定理)
- 东营市胜利第一中学2015年自主招生工作实施方案
- Java支付宝接口心得