在《MonkeyRunner源码分析之与Android设备通讯方式》中,我们谈及到MonkeyRunner控制目标android设备有多种方法,其中之一就是在目标机器启动一个monkey服务来监听指定的一个端口,然后monkeyrunner再连接上这个端口来发送命令,驱动monkey去完成相应的工作。
当时我们只分析了monkeyrunner这个客户端的代码是怎么实现这一点的,但没有谈monkey那边是如何接受命令,接受到命令又是如何处理的。
所以自己打开源码看了一个晚上,大概有了概念。但今天网上搜索了下,发现已经有网友“chenjie”对monkey的源码做过相应的分析了,而且文章写得非常有概括性,应该是高手所为,果断花了2个积分下载下来,不敢独享,本想贴上来分享给大家,但发现pdf的文档直接拷贝上来会丢失掉图片,所以只好贴上下载地址:http://download.youkuaiyun.com/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.命令行参数解析
- /**
- * 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;
- }
- ...
- }
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();
- ...
- }
- 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();
- ...
- }
- /**
- * 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);
- ...
- }
- ...
- }
- ....
- }
本文详细介绍了Monkey工具的执行流程,包括运行环境设置、命令行参数解析、初始化测试事件源及循环执行事件等关键步骤。
2074

被折叠的 条评论
为什么被折叠?



