第5章5节《MonkeyRunner源码剖析》Monkey原理分析

天地会珠海分舵注:本来这一系列是准备出一本书的,详情请见早前博文“寻求合作伙伴编写《深入理解 MonkeyRunner》书籍“。但因为诸多原因,没有如愿。所以这里把草稿分享出来,所以错误在所难免。有需要的就参考下吧,转发的话还请保留每篇文章结尾的出处等信息。

上一节我们描述了monkey的命令处理入口函数run是如何调用optionProcess方法来解析命令行参数的。启动参数主要时去指导Monkey时怎么运行起来的,但Monkey作为MonkeyRunner框架的一部分,更重要的是如何将从MonkeyRunner测试脚本出发的命令转化成事件来注入到系统中以进行测试自动化。如前面所说,run方法除了对启动参数进行解析之外还做了很多其他的事情,比如这一小节需要分析的去建立对系统服务的引用。因为只有获得这些引用之后才能实现对系统的事件注入。当然,run方法中其中有一部分代码是跟MonkeyRunner框架不相干的,所以我们不会花时间去分析它,也免得钻进去后影响大家对monkey作为MonkeyRunner框架的服务的理解。

下面我们先看下run方法在processOptions之后调用的下一个关键方法getSystemInterfaces:

代码2-5-1 Monkey – run

(String[] args) {… 450if (!processOptions()) { 451return -1; 452}… 488if (!getSystemInterfaces()) { 489return -3; 490}…}

processOptions方法之后到488行之前的代码所做的去准备monkey测试目标packages和生成随机测试seed这些都跟作为MonkeyRunner的一个服务的monkey没有多大关系的。这些主要是当monkey扮演的是一个独立的随机压力测试工具来进行随机对指定的package进行随机压力测试才有意义。所以这里我们没有必要花篇幅去分析它,这不会影响我们对MonkeyRunner框架的理解。

这里需要关注的是488行的getSystemInterfaces的一个调用,这个方法做了一个很重要的事情,就是去获得与Android操作系统交互的3个引用:

这些引用在Monkey作为一个MonkeyRunner一个服务运行的时候重要性已经没有在老版本中那么明显了。以往系统注入按键事件为例,我们现在分析的安卓4.4.2版本中,Monkey服务是用InputManagerService服务来注入事件以触发按键等动作的。但是在比较老的版本中,往窗口注入事件主要是通过WindowManagerService服务来完成的,等会我们会给出两个不同版本的按键事件注入源码来印证这个转变。

以下我们先描述下这几个服务的作用以及获取的方式:

下面的安卓架构图显示了这些服务是处在安卓操作系统的什么位置,我相信读者肯定之前已经看过了,但读者请注意该图并没把InputManager服务给画出来,相信是该图并没有及时更新的原因。

图5-5-1 安卓架构图

从中我们可以看到整个安卓操作系统从上往下分为多个层次,其中最上层就是应用程,比如我们电话本,浏览器之类的应用就运行在这一层。支撑这些应用运行的背后是一些列的服务和系统,应用层下一层的应用程序框架层就是专门提供这种服务的,比如我们这里提供Activity管理服务的ActivityManagerService,提供窗口和控件管理服务的WindowManagerService,提供应用包管理服务的PackageManagerService,以及提供用户输入管理的InputManagerService都是运行在这一层的。

前面3个服务虽然有些已经不会用到,但是由于历史的原因,为了保持调用的一致性,有些接口还是需要传入相应的变量到相应的方法里面,虽然该方面并不会用到该服务。比如Monkey服务在需要往系统注入按键事件的时候会调用到MonkeyKeyEvent这个类的injectEvent方法,该方法支持的输入参数就有上面提到的WindowManagerService和ActivityManagerService,但实际上这两个服务并没有用到的。请看代码如下:

代码5-5-2 MonkeyKeyEvent – injectEvent示例

(IWindowManager iwm, IActivityManager iam, int verbose) { 87if (verbose > 1) { 88String note; 89if (mAction == KeyEvent.ACTION_UP) { 90note = “ACTION_UP”; 91} else { 92note = “ACTION_DOWN”; 93} 94try { + MonkeySourceRandom.getKeyName(mKeyCode)); 98} catch (ArrayIndexOutOfBoundsException e) { 99System.out.println(“:Sending Key (” + note + “): “100+ mKeyCode + ” // Unknown key event”);101}102}103KeyEvent keyEvent = mKeyEvent;104if (keyEvent == null) {105long eventTime = mEventTime;106if (eventTime <= 0) {107eventTime = SystemClock.uptimeMillis();108}109long downTime = mDownTime;110if (downTime <= 0) {111downTime = eventTime;112}113keyEvent = new KeyEvent(downTime, eventTime, mAction, mKeyCode,114mRepeatCount, mMetaState, mDeviceId, mScanCode,115KeyEvent.FLAG_FROM_SYSTEM, InputDevice.SOURCE_KEYBOARD);116}117if (!InputManager.getInstance().injectInputEvent(keyEvent,118InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT)) {119return MonkeyEvent.INJECT_FAIL;120}121return MonkeyEvent.INJECT_SUCCESS;122}123 }你是自由的,不仅是身体上的自由,

第5章5节《MonkeyRunner源码剖析》Monkey原理分析

相关文章:

你感兴趣的文章:

标签云: