Monkey源代码分析之执行流程

Monkey源代码分析之执行流程

大家好,又见面了,我是全栈君。

在《MonkeyRunner源代码分析之与Android设备通讯方式》中。我们谈及到MonkeyRunner控制目标android设备有多种方法。当中之中的一个就是在目标机器启动一个monkey服务来监听指定的一个port,然后monkeyrunner再连接上这个port来发送命令。驱动monkey去完毕对应的工作。

当时我们仅仅分析了monkeyrunner这个client的代码是怎么实现这一点的,但没有谈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.命令行參数解析

通过以上的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);    }
入口函数非常easy,直接跳到run这种方法,这是一个非常重要的方法,里面大概会做下面这些事情:
  • 处理命令行參数
  • 依据命令行參数启动不同的事件源,也就是我们的測试事件到底是从网络如monkeyrunner过来的还是monkey内部的random測试数据集过来的还是脚本过来的如此之类
  • 跳入runMonkeyCyncle方法针对不同的事件源開始获取并运行不同的事件
这种方法会比較长,我们仅仅看我们如今想要的关键片段。能够看到里面调用了命令行处理函数processOptions.
    private int run(String[] args) {    ...        if (!processOptions()) {            return -1;        }    ...}

进去之后就是非常普通的读取命令行的參数然后一个个进行解析保存了,没有太多特别的东西,这里就直接贴出monkey的參数选项大家看看就好了:

Monkey源代码分析之执行流程

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();
        ...
}

事件源代表測试数据的事件是从哪里过来的。不同的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
这里须要注意的是每个EventSource类都是实现了MonkeyEventSource这个接口的,这个接口最重要的就是要求实现类必须实现getNextEvent这种方法来生成并获取事件。这样子做的优点就是屏蔽了每个详细事件源的实现细节,其它地方的代码仅仅须要调用这个接口的getNextEvent方法获得事件源即可了,而无需关心这些事件是从哪个源过来的。

这些都是面向对象的面向接口编程的基础了。大家有不清楚的最好先去了解下java的一些基本知识。这样理解起来会快非常多。


4. 循环运行事件

run方法依据參数从不同的事件源获得事件并放入到EventQueue后,就会開始运行一个循环去从EventQueue里获取事件进行运行
    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就是我们上面提到的事件源的接口。它屏蔽了每一个事件实现类的详细细节,我们仅仅须要告诉这个接口我们如今须要取一条事件然后运行它。该结构依据面向对象的多态原理,就会自己主动取事件的实现类获得相应的事件进行返回。

所以这里大家还须要对多态这个概念有所了解,特别是一些从手动測试转到自己主动化測试的朋友,可能之前没有接触过太多面向对象的知识。

本人曾经做过开发。所以还ok。

这里仅仅是做一个善意的提醒。

获得事件后下一步就是去运行对应的事件了。不同的事件会有不同的处理方式,或仅仅是运行个命令。或调用WindowManager隐藏接口做事件注入等。这些都会在今后文章进行进一步阐述

这一篇文章就到此为止了。目的就是让大家对整一个monkey运行的流程有个初步的了解,方便理解往下的相关文章。


 

作者

自主博客

微信

CSDN

天地会珠海分舵

http://techgogogo.com


服务号:TechGoGoGo

扫描码:

Monkey源代码分析之执行流程

http://blog.csdn.net/zhubaitian


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/116556.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • idea 2022 3.2激活码[最新免费获取]「建议收藏」

    (idea 2022 3.2激活码)这是一篇idea技术相关文章,由全栈君为大家提供,主要知识点是关于2021JetBrains全家桶永久激活码的内容IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.net/100143.html1M2OME2TZY-eyJsaWN…

    2022年3月13日
    152
  • JS创建和存储 cookie的一些方法

    JS创建和存储 cookie的一些方法

    2021年10月31日
    45
  • android一键换机功能实现,不同品牌手机一键换机教程「建议收藏」

    android一键换机功能实现,不同品牌手机一键换机教程「建议收藏」我们正处于一个数码产品更新换代非常快速的时代,很多消费者会紧跟时代潮流,经常更换新手机,但是更换手机之后我们通常需要将旧手机里的数据进行转移,不同品牌之间的手机怎么进行一键换机呢?以安卓手机更换苹果手机转移数据为例:1、首先我们需要在安卓手机上安装“转移到iOS”APP,通过该应用我们可以将安卓手机的数据转移到新的苹果手机上2、确保安卓设备处于WiFi状态3、将安卓设备以及苹果设备连接电源4、设置…

    2022年5月9日
    239
  • tof相机很好的总结~

    tof相机很好的总结~1.1TOF初探TOF是Timeofflight的简写,直译为飞行时间的意思。所谓飞行时间法3D成像,是通过给目标连续发送光脉冲,然后用传感器接收从物体返回的光,通过探测光脉冲的飞行(往返)时间来得到目标物距离。这种技术跟3D激光传感器原理基本类似,只不过3D激光传感器是逐点扫描,而TOF相机则是同时得到整幅图像的深度信息。TOF相机与普通机器视觉成像过程也有类似之处,都是由光源、光

    2022年5月9日
    52
  • 手机修改域名服务器,手机修改域名服务器ip地址

    手机修改域名服务器,手机修改域名服务器ip地址手机修改域名服务器ip地址内容精选换一换安装依赖时,使用pip3.7.5installxxx命令安装相关软件时提示无法连接网络,且提示“Couldnotfindaversionthatsatisfiestherequirementxxx”,提示信息如下所示。没有配置pip源。配置pip源,配置方法如下:如果提示目录不存在,则执行如下命令创建:在.pip目录安装依赖时,使用p…

    2022年6月16日
    31
  • PROXY SERVER 代理服务器[通俗易懂]

    Proxy是什么呢,是代理。普通的因特网访问是一个典型的客户机与服务器结构:用户利用计算机上的客户端程序,如浏览器发出请求,远端WWW服务器程序响应请求并提供相应的数据。而Proxy处于客户机与服务器之间,对于服务器来说,Proxy是客户机,Proxy提出请求,服务器响应;对于客户机来说,Proxy是服务器,它接受客户机的请求,并将服务器上传来的数据转给客户机。它的作用很象现实生活中的代理服务商…

    2022年4月18日
    43

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号