老李推荐:第8章6节《MonkeyRunner源码剖析》MonkeyRunner启动运行过程-启动Monkey 4

在获得比对设备序列号后,findAttachedDevice就会跟提供的序列号进行比对,如果吻合就返回给调用者” 代码8-6-3 AdbBackend - waitForConnection”了。而AdbBackend的waitForConnection在获得这个Device实例后就会把它传到AdbChimpDevice的构造函数中来构造AdbChimpDevice的实例对象。我们看看它的构造函数是怎么做的:

68   public AdbChimpDevice(IDevice device)

69   {

70     this.device = device;

71     this.manager = createManager("127.0.0.1", 12345);

72

73     Preconditions.checkNotNull(this.manager);

74   }

代码8-6-8 AdbChimpDevice构造函数

如前面一直强调的,AdbChimpDevice是一个很重要的类,它是一个高层抽象的设备对象,它组合了代表通过monkey控制的设备ChimpManager和通过ADB控制的设备Device。这个组合关系就是通过上面这个AdnbChimpDevice构造函数体现出来的了。第70行组合的就是Device设备,71行组合的就是ChimpManager实例。只是Device实例是在启动设备监控线程DeviceMonitor中就已经实例化创建好的,而ChimpManager是在这个时候才进行创建的。创建的时候指定的是本机回环IP地址”127.0.0.1”,端口指定是monkey本地转发端口12345

创建ChimpManager的调用createManager的代码有点长,我们会分两部分来进行分析,其中第一部分是启动Monkey,第二部分是创建ChimpManager。我们先看第一部分:

123   private ChimpManager createManager(String address, int port) {

124     try {

125       this.device.createForward(port, port);

126     } catch (TimeoutException e) {

127       LOG.log(Level.SEVERE, "Timeout creating adb port forwarding", e);

128       return null;

129     } catch (AdbCommandRejectedException e) {

130       LOG.log(Level.SEVERE, "Adb rejected adb port forwarding command: " + e.getMessage(), e);

131       return null;

132     } catch (IOException e) {

133       LOG.log(Level.SEVERE, "Unable to create adb port forwarding: " + e.getMessage(), e);

134       return null;

135     }

136

137     String command = "monkey --port " + port;

138     executeAsyncCommand(command, new LoggingOutputReceiver(LOG, Level.FINE));

139

140     try

141     {

142       Thread.sleep(1000L);

143     } catch (InterruptedException e) {

144       LOG.log(Level.SEVERE, "Unable to sleep", e);

145     }

146     InetAddress addr;

147     try

148     {

149       addr = InetAddress.getByName(address);

150     } catch (UnknownHostException e) {

151       LOG.log(Level.SEVERE, "Unable to convert address into InetAddress: " + address, e);

152       return null;

153     }

...

}

代码8-6-9 AdbChimpDevice - createManager之启动monkey

createManager首先做的事情就是去把目标设备端的monkey服务进程给启动起来接收MonkeyRunner测试脚本发送过去的请求。代码流程如下所示:

  • 125行: 设置本机到目标机器monkey进程监听端口的端口转发,调用的是Device的createForward的方法,这个方法我们在下一章描述Device类详解的时候会进行分析。这里只需要它基本可以看作是在命令行发送”adb forward 12345 12345“来完成从本机12345端口到远程monkey监控的12345端口的转发就好了。设置好端口转发后往下的代码就能直接连接本机的12345端口,这就等同于连上的是远端目标设备中monkey监听的12345端口了
  • 139-138行: 设置好monkey端口转发后,createManager方法就会往ADB服务器发送shell命令”monkey --port 12345”来启动monkey去监听端口12345。发送adb shell命令使用的方法是createAsyncCommand方法,其实该方法没有什么好分析的,因为它把发送命令请求直接转发给Device类的executeShellCommand而已,而executeShellCommand这个方法我们也是在下一章会进行分析
  • 149行: 将本机监听地址“127.0.0.1”转换成InetAddress对象格式,这样往下创建Socket连接的时候才能直接使用

createManager之启动monkey到了这里就完成了,往下我们继续看第二部分createManager之创建ChimpManager:

123   private ChimpManager createManager(String address, int port) {

... //启动monkey代码略

159     boolean success = false;

160     ChimpManager mm = null;

161     long start = System.currentTimeMillis();

162

163     while (!success) {

164       long now = System.currentTimeMillis();

165       long diff = now - start;

166       if (diff > 30000L) {

167         LOG.severe("Timeout while trying to create chimp mananger");

168         return null;

169       }

170       try

171       {

172         Thread.sleep(1000L);

173       } catch (InterruptedException e) {

174         LOG.log(Level.SEVERE, "Unable to sleep", e);

175       }

176       Socket monkeySocket;

177       try

178       {

179         monkeySocket = new Socket(addr, port);

180       } catch (IOException e) {

181         LOG.log(Level.FINE, "Unable to connect socket", e);

182         success = false; }

183       continue;

184

185       try

186       {

187         mm = new ChimpManager(monkeySocket);

188       } catch (IOException e) {

189         LOG.log(Level.SEVERE, "Unable to open writer and reader to socket"); }

190       continue;

191

192       try

193       {

194         mm.wake();

195       } catch (IOException e) {

196         LOG.log(Level.FINE, "Unable to wake up device", e);

197         success = false; }

198       continue;

199

200       success = true;

201     }

202

203     return mm;

}

代码8-6-10 AdbChimpDevice - createManager之创建ChimpManager

其实上面一堆代码无非是在一个循环中做了3个事情:

  • 179行:  创建连接到本机monkey转发端口的Socket对象
  • 187行:  根据该Socket对象构造ChimpManager实例,ChimpManager的详细分析会放到下一章的描述ChimpManager类详解的时候进行分析
  • 194行:  往monkey发送命令去唤醒休眠屏幕,如果屏幕是在休眠状态的话。wake的原理也会在下一章进行分析

分析到这里这一小节的目标就已经达到了,我们已经学习到了monkey服务进程是如何在脚本中通过调用MonkeyRunner的waitForConnection方法启动起来的了,同时我们也学习到了AdbChimpDevice和ChimpManager这两个关键类创建的相关知识点。

下一小节我们来尝试把本章学到的内容进行一个总结。

时间: 2024-10-07 05:22:21

老李推荐:第8章6节《MonkeyRunner源码剖析》MonkeyRunner启动运行过程-启动Monkey 4的相关文章

老李推荐: 第8章4节《MonkeyRunner源码剖析》MonkeyRunner启动运行过程-启动AndroidDebugBridge 1

老李推荐: 第8章4节<MonkeyRunner源码剖析>MonkeyRunner启动运行过程-启动AndroidDebugBridge 上一节我们看到在启动AndroidDebugBridge的过程中会调用其start方法,而该方法会做2个主要的事情: 715行startAdb:开启AndroidDebugBridge 722-723行:初始化android设备监控并启动DeviceMonitor设备监控线程. 其中第一点我们上一小节已经做了详尽分析了,那么我们往下就去分析下第2点. Dev

老李推荐:第6章5节《MonkeyRunner源码剖析》Monkey原理分析-事件源-事件源概览-事件

老李推荐:第6章5节<MonkeyRunner源码剖析>Monkey原理分析-事件源-事件源概览-事件 从网络过来的命令字串需要解析翻译出来,有些命令会在翻译好后直接执行然后返回,但有一大部分命令在翻译后需要转换成对应的事件,然后放入到命令队列里面等待执行.Monkey在取出一个事件执行的时候主要是执行其injectEvent方法来注入事件,而注入事件根据是否需要往系统注入事件分为两种: 需要通过系统服务往系统注入事件:如MonkeyKeyEvent事件会通过系统的InputManager往系

老李推荐:第6章3节《MonkeyRunner源码剖析》Monkey原理分析-事件源-事件源概览-命令翻译类

老李推荐:第6章3节<MonkeyRunner源码剖析>Monkey原理分析-事件源-事件源概览-命令翻译类 每个来自网络的字串命令都需要进行解析执行,只是有些是在解析的过程中直接执行了事,而有些是需要在解析后创建相应的事件类实例并添加到命令队列里面排队执行.负责这部分工作的就是命令翻译类.那么我们往下还是继续在MonkeySourceNetwork这个范畴中MonkeyCommand类是怎么一回事: 图6-3-1 MonkeyCommand族谱 图中间的MonkeyCommand是一个接口,

老李推荐: 第1章1节《MonkeyRunner源码剖析》概述:前言

老李推荐: 第1章1节<MonkeyRunner源码剖析>概述:前言 前言 相信大家做过安卓移动平台UI自动化开发的必然会用过,至少听过MonkeyRunner这个名字.MonkeyRunner是一个针对安卓平台的UI自动化测试框架,这个框架的其中一个但绝不是唯一的优点是支持用当今非常流行和高效的Python语言来进行脚本开发.同时,它相比Instrumentation框架或者基于Instrumentation的自动化测试框架最大的优点之一就是可以跨应用测试. 这本书不会有什么序言或者致谢什么

第8章6节《MonkeyRunner源码剖析》MonkeyRunner启动运行过程-启动Monkey

大家可能会觉得奇怪,为什么启动目标设备端的monkey进程会放在"运行测试脚本"这一节之后来阐述. 纵观前面整个MonkeyRunner的启动流程,我们看到并没有提及到monkey进程启动的地方.那么就奇怪了,monkey是什么时候被MonkeyRunner启动起来的呢? 我们的测试脚本一开始时几乎毫无例外的都需要执行一个调用:MonkeyRunner.waitForConnection(),如果有多个设备连接到主机的话还需要指定设备序列号,还可以指定等待连接的Timeout时间,比如

第5章2节《MonkeyRunner源码剖析》Monkey原理分析-启动运行: 启动流程概览(原创)

天地会珠海分舵注:本来这一系列是准备出一本书的,详情请见早前博文"寻求合作伙伴编写<深入理解 MonkeyRunner>书籍".但因为诸多原因,没有如愿.所以这里把草稿分享出来,所以错误在所难免.有需要的就参考下吧,转发的话还请保留每篇文章结尾的出处等信息. 每个应用都会有一个入口方法来供操作系统调用执行,Monkey这个应用的入口方法就是在Monkey.java这个类里面的,也就是说Monkey.java就是整个Monkey应用的入口类. Monkey作为一个命令行应用,

第5章5节《MonkeyRunner源码剖析》Monkey原理分析-启动运行: 获取系统服务引用(原创)

天地会珠海分舵注:本来这一系列是准备出一本书的,详情请见早前博文"寻求合作伙伴编写<深入理解 MonkeyRunner>书籍".但因为诸多原因,没有如愿.所以这里把草稿分享出来,所以错误在所难免.有需要的就参考下吧,转发的话还请保留每篇文章结尾的出处等信息. 上一节我们描述了monkey的命令处理入口函数run是如何调用optionProcess方法来解析命令行参数的.启动参数主要时去指导Monkey时怎么运行起来的,但Monkey作为MonkeyRunner框架的一部分,

第6章1节《MonkeyRunner源码剖析》Monkey原理分析-事件源-事件源概览

在上一章中我们有简要的介绍了事件源是怎么一回事,但是并没有进行详细的描述.那么往下的这几个小节我们就需要把这方面的知识给补充完整. 这一节我们先主要围绕MonkeySourceNetwork这个事件源来学习事件源的框架结构.首先,要理解事件源,必须先搞清楚几个问题: 事件从哪里来? Monkey的事件来源有多个方面,但是作为MonkeyRunner框架的一部分,它的事件来源主要是来自MonkeyRunner通过网络Socket(USB/TCP协议)发送过来的命令字串.MonkeySourceNe

第3章2节《MonkeyRunner源码剖析》脚本编写示例: MonkeyDevice API使用示例(原创)

天地会珠海分舵注:本来这一系列是准备出一本书的,详情请见早前博文"寻求合作伙伴编写<深入理解 MonkeyRunner>书籍".但因为诸多原因,没有如愿.所以这里把草稿分享出来,所以错误在所难免.有需要的就参考下吧,转发的话还请保留每篇文章结尾的出处等信息. 上一节我们学习了如何通过MonkeyRunner这个类的静态方法waitForConnection来把后台和设备建立好连接,且看到了在建立连接成功后,该方法会返回来一个MonkeyDevice的实例对象.那么这一节我们

第8章5节《MonkeyRunner源码剖析》MonkeyRunner启动运行过程-运行测试脚本

MonkeyRunner在准备好AndroidDebugBridge和DeviceMonitor等服务之后,就基本上是解决了和目标设备通信的问题了,那往下需要做的就是把测试脚本运行起来了. 178 public static void main(String[] args) { 179 MonkeyRunnerOptions options = MonkeyRunnerOptions.processOptions(args); 180 181 if (options == null) { 182