• Android Monkey(转载)


    这两天在读Android Monkey的源代码.代码不多,放出分享.

    我现说一下,Monkey是干什么的:简单的说就是,模拟用户的touch screen和keyboard的输入.其实这个功能就已经很恐怖了.  Google自己说的下面:

    // Only bind this to local host.  This means that you can only

    // talk to the monkey locally, or though adb port forwarding.

    就是觊觎这个强大的力量.Monkey是用JAVA写成的,但是我们确可以这样运行:

    $adb shell monkey ......

    这是为什么呢?是因为在/system/bin目录下有一个monkey的shell脚本.内容如下:

    # Script to start "monkey" on the device, which has a very rudimentary

    # shell.

    #

    base=/system

    export CLASSPATH=$base/framework/monkey.jar

    exec app_process $base/bin com.android.commands.monkey.Monkey $*

    exec 会运行起/system/framework/monkey.jar这只Java程序.后面我们还会用到这个脚本.

    先给出Monkey的架构图:

    又是我的手绘图.哈哈.实际上,并不复杂.

    Monkey.java 里面有main()函数.而main()->Run().Run()里面作了下面的操作:

    1.processOptions()初始化参数(通过传入入参来初始化参数).还有一些的操作函数如:nextOption() nextOptionLong()。。

    2.做接口的检查,也就是申请这些接口资源.

    3.关键的一步:

    if(mServerPort!=1)

    { try{

    mEventSource = new MonkeySourceNetWork(mServerPort);

    ...省略

    开始ServerSocket.监听用户输入的command.

    4.mNetworkMonitor.Start();开始监控网络状态

    5.关键的一步:

    runMonkeyCycles(),代码如下:

    while()

    {

    MonkeyEvent ev = mEventSource.getNextEvent();

    ev.inject(....);

    ...省略

    开始Event loop,把每个CommandQueue中的消息都执行.

    6.mNetworkMonitor.Stop()

    这里我们看到使用了SocketServer,所以理论上来说,可以在PC端发送command给device,但是必须透过USB的连接.这点我在上面已经说的很清楚了.(PC端,Android不可能帮你实现,我们只要在PC端使用Socket向device发送命令就可以了).

    好了,我们接着往下分析:

    MonkeyEvent的实现是典型的OO思想.

    MonkeyEvent.java仅仅是一个abstract class.

    最重要的方法都由子类去实现.(把Event放入当前的Activity去运行)

    public abstract int injectEvent(IWindowManager iwm, IActivityManager iam, int verbose);

    monkey*Event.java都是MonkeyEvent.java的子类.

       

    来讲一下,MonkeySourceNetwork.java.

    这个类相对较大,里面有许多的内嵌类.(ps. 我不是写Java出身的,看到内嵌类就不符合我的审美习惯)

    1.有一个MonkeyCommand的类,这是一个interface. *Command都是他的子类.

    其中定义了一个很重要的方法:这个方法将string 类型的command转换为MonkeyEvent对象,并放入

    commandQueue.

    MonkeyCommandReturn translateCommand(List<String> command, CommandQueue queue);

    好了,首先MonkeyCommandReturn又是一个类,是命令执行成功还是失败的一个类.

    commandQueue是实际上是一个interface,然后它的实现是在CommandQueueImpl这个类中.

    实现了如下的方法:

    public void enqueueEvent(MonkeyEvent e) {

    queuedEvents.offer(e);

    }

    将Event放入queueEvents队列中.而queueEvents是这样定义的:

    private final Queue<MonkeyEvent> queuedEvents = new LinkedList<MonkeyEvent>();

    无非就是一个LinkedList而已拉.

    2.下面我在来说说MonkeySourceNetwork类中的方法:

    private void translateCommand(String commandLine)

    和上面的方法同名.实际上这个translateCommand是上面的封装.我们来RTFS:

    List<String> parts = commandLineSplit(commandLine);

    if (parts.size() > 0) {

    MonkeyCommand command = COMMAND_MAP.get(parts.get(0));

    if (command != null) {

    MonkeyCommandReturn ret = command.translateCommand(parts,commandQueue);

    COMMAND_MAP这是个什么东西呢?

    private static final Map<String, MonkeyCommand> COMMAND_MAP = new HashMap<String, MonkeyCommand>();

    看了没,是一个Map.以Command string作为Key, MonkeyCommand作为Value.这样的话,就建立了,

    输入的命令和Command的关系。

    static {

    // Add in all the commands we support

    COMMAND_MAP.put("flip", new FlipCommand());

    COMMAND_MAP.put("touch", new TouchCommand());

    COMMAND_MAP.put("trackball", new TrackballCommand());

    COMMAND_MAP.put("key", new KeyCommand());

    COMMAND_MAP.put("sleep", new SleepCommand());

    COMMAND_MAP.put("wake", new WakeCommand());

    COMMAND_MAP.put("tap", new TapCommand());

    COMMAND_MAP.put("press", new PressCommand());

    COMMAND_MAP.put("type", new TypeCommand());

    COMMAND_MAP.put("listvar", new MonkeySourceNetworkVars.ListVarCommand());

    COMMAND_MAP.put("getvar", new MonkeySourceNetworkVars.GetVarCommand());

    }

    但也不是所有的命令都放入COMMAND_MAP中.quit 和 done 就是例外,原因也很简单,没必要放进Map.

    再来分析下这条语句:MonkeyCommandReturn ret = command.translateCommand(parts,commandQueue);

    首先,command已经是MonkeyCommand的sub class了.so 调用translateCommand将会表现出不同的行为.

    例如,command假设为PressCommand.则translateCommand的表现为:

    queue.enqueueEvent(new MonkeyKeyEvent(....))

    每一个MonkeyEvent又都代表了一些对AP GUI错作.所以,也就是把操作放入了Queue.

    okay.就这么多了.才不多这次就说这么多吧.我再附上我的手绘图,希望有帮助.

       

  • 相关阅读:
    Scala 学习之 aggregate函数
    CentOS6.5+hadoop-2.5.2+hbase-1.0.1.1+zookeeper-3.4.6之zookeeper配置
    swiper.min.js.map访问404解决办法
    CentOS6.5上搭建hadoop 2.5.2 笔记
    Java 多线程编程中单例的实现
    关于 nohup 执行命令以后 需要再按回车才能起效的解决办法
    java定时任务之 Timer
    关于solr异常:org.apache.solr.client.solrj.SolrServerException: IOException occured when talking to server at: http:192.168.0.11/solr/的解决
    关于dubbo服务产生异常之:Caused by: com.alibaba.dubbo.remoting.TimeoutException: Waiting server-side response timeout by scan timer.
    关于maven使用产生的异常之:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:2.3.2:compile (default-compile
  • 原文地址:https://www.cnblogs.com/xiwix/p/2450976.html
Copyright © 2020-2023  润新知