第8章2节《MonkeyRunner源代码剖析》MonkeyRunner启动执行过程-解析处理命令行參数
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第8章2节《MonkeyRunner源代码剖析》MonkeyRunner启动执行过程-解析处理命令行參数相关的知识,希望对你有一定的参考价值。
MonkeyRunnerStarter是MonkeyRunner启动时的入口类,由于它里面包括了main方法.它的整个启动过程主要做了以下几件事情:
- 解析用户启动MonkeyRunner时从命令行传输进来的參数: 由于MonkeyRunner须要依据指定的參数才干做事情,比方输入的一个须要执行的脚本。
假设确实不知道不论什么參数的话它就会进入MonkeyRunner的交互模式,事实上就是Jythong的交互模式,让用户能够边写代码边执行
- 启动AndroidDebugBridge: 事实上就是启动ADBserver,由于MonkeyRunner跟设备通信的一个很重要的方法之中的一个就是通过向ADBserver发送命令来请求目标设备的服务
- 启动设备监控线程: 事实上这个是在启动androidDebugBridge的时候一并启动的。设备监控线程主要做的事情就是取监控设备是否有接入进来或者移除出去,假设有新的设备连接进来,或者说设备变成ONLINE状态(一个设备有多个状态:ONLINE|OFFLINE|RECOVERY|UNAUTHORIZED),那么就须要取监控设备里面的每一个可调试进程,这主要是用来给DDMS等调试工具使用的。
它维护了一个最新的设备列表
- 启动AndroidDebugBridge:
- 启动Monkey:
- 执行測试脚本:
本小节我们会先去看下MonkeyRunner在启动的时候是怎样获得命令行參数并对其进行解析处理的。
整个过程事实上跟monkey在启动的时候的命令行參数分析相似。往下我们先看下牵涉到的关键类之间的关系:
图8-2-1 MonkeyRunnerStarter类图
从类图中我们看到MonkeyRunnerStarter持有了一个MonkeyRunnerOptions类型的成员变量options,这个实例保存的就是解析出来的命令行參数。同一时候该类会提供一个processOptions方法来专门解析命令行參数。
我们先进入到MonkeyRunnerStart这个类的main方法:
178 public static void main(String[] args) { 179 MonkeyRunnerOptions options = MonkeyRunnerOptions.processOptions(args); 180 181 if (options == null) { 182 return; 183 } 184 185 186 replaceAllLogFormatters(MonkeyFormatter.DEFAULT_INSTANCE, options.getLogLevel()); 187 188 MonkeyRunnerStarter runner = new MonkeyRunnerStarter(options); 189 int error = runner.run(); 190 191 192 System.exit(error); 193 } 194 }代码3-2-1 MonkeyRunnerStart - main
这里主要做了三件事情:
- 179行去处理用户启动monkeyrunner的时候输入的命令行參数
- 188行去初始化MonkeyRunnerStarter,里面主要是初始化了ChimpChat。ChimpChat又去开启AndroidDebugBridge进程和开启DeviceMonitor设备监控线程,我们往后小节会进行具体分析
- 189行去把monkeyrunner执行起来,包括带脚本參数的情况和不待脚本參数直接提供jython命令行的情况
我们这一节会先去分析下monkeyrunner是怎样对參数进行处理的,我们跳转到MonkeyRunnerOptions这个类里面的processOptions这种方法:
93 public static MonkeyRunnerOptions processOptions(String[] args) 94 { 95 int index = 0; 96 97 String hostname = DEFAULT_MONKEY_SERVER_ADDRESS; 98 File scriptFile = null; 99 int port = DEFAULT_MONKEY_PORT; 100 String backend = "adb"; 101 Level logLevel = Level.SEVERE; 102 103 ImmutableList.Builder<File> pluginListBuilder = ImmutableList.builder(); 104 ImmutableList.Builder<String> argumentBuilder = ImmutableList.builder(); 105 while (index < args.length) { 106 String argument = args[(index++)]; 107 108 if ("-s".equals(argument)) { 109 if (index == args.length) { 110 printUsage("Missing Server after -s"); 111 return null; 112 } 113 hostname = args[(index++)]; 114 } 115 else if ("-p".equals(argument)) 116 { 117 if (index == args.length) { 118 printUsage("Missing Server port after -p"); 119 return null; 120 } 121 port = Integer.parseInt(args[(index++)]); 122 } 123 else if ("-v".equals(argument)) 124 { 125 if (index == args.length) { 126 printUsage("Missing Log Level after -v"); 127 return null; 128 } 129 130 logLevel = Level.parse(args[(index++)]); 131 } else if ("-be".equals(argument)) 132 { 133 if (index == args.length) { 134 printUsage("Missing backend name after -be"); 135 return null; 136 } 137 backend = args[(index++)]; 138 } else if ("-plugin".equals(argument)) 139 { 140 if (index == args.length) { 141 printUsage("Missing plugin path after -plugin"); 142 return null; 143 } 144 File plugin = new File(args[(index++)]); 145 if (!plugin.exists()) { 146 printUsage("Plugin file doesn‘t exist"); 147 return null; 148 } 149 150 if (!plugin.canRead()) { 151 printUsage("Can‘t read plugin file"); 152 return null; 153 } 154 155 pluginListBuilder.add(plugin); 156 } else if (!"-u".equals(argument)) 157 { 158 if ((argument.startsWith("-")) && (scriptFile == null)) 159 { 160 161 162 printUsage("Unrecognized argument: " + argument + "."); 163 return null; 164 } 165 if (scriptFile == null) 166 { 167 168 scriptFile = new File(argument); 169 if (!scriptFile.exists()) { 170 printUsage("Can‘t open specified script file"); 171 return null; 172 } 173 if (!scriptFile.canRead()) { 174 printUsage("Can‘t open specified script file"); 175 return null; 176 } 177 } else { 178 argumentBuilder.add(argument); 179 } 180 } 181 } 182 183 return new MonkeyRunnerOptions(hostname, port, scriptFile, backend, logLevel, pluginListBuilder.build(), argumentBuilder.build()); 184 } 185 }代码8-2-2 MonkeyRunnerOptions - processOptions
这里首先请看99-101行的几个变量初始化,假设用户在命令行中没有指定相应的參数,那么这些默认參数就会被使用,我们且看下这些默认值各自是什么:
- hostname:相应‘-s‘參数。默认值是‘127.0.0.1‘,也就是本机。将会forward给目标设备执行的monkey。所以加上以下的转发port等同于目标机器在listen的monkey服务
- port :相应‘-p‘參数。默认值是‘12345‘,也就是monkey默认监听端口
- backend :相应‘-be‘參数,默认值是‘adb‘,事实上往后看代码我们会发现它也仅仅是支持’adb‘而已。
这里须要注意的是这是一个隐藏參数。命令行的help没有显示该參数
- logLevel :相应‘-v‘參数。默认值‘SEVERE‘,也就是说仅仅打印严重的log
代码往下就是对用户输入的參数的解析并保存了,这里要注意几个隐藏的參数:
- -u :乍一看以为这是一个什么特别的參数。从156-178行能够看到这个參数处理的意义是:当用户输入‘-u‘的时候不会作不论什么处理,但当用户输入的是由‘-’開始的但又不是monkeyrunner声称支持的那几个參数的时候,就会依据不同的情况给用户报错。
所以这段代码的意思事实上就是在用户输入了不支持的參数的时候依据不同的情况给用户提示而已
- -be :backend。如前所述。仅仅支持‘adb‘
- -plugin :这里须要一个背景知识,在google官网有说明,用户能够通过遵循一定的规范去编写插件来扩展monkeyrunner的功能,比方在monkeydevice里面按下这个动作是须要通过MonkeyDevice.DOWN这个參数来传给press这种方法的。假设你认为这样子不好,你希望添加个pressDown这种方法。里面默认就是用MonkeyDevice.DOWN来驱动MonkeyDevice的press方法,而用户仅仅须要给出坐标点就能够了,那么你就能够遵循google描写叙述的规范去编写一个这方面的插件。到时使用的时候就能够通过python方式直接import进来使用了。本书并不会把MonkeyRunner插件进行重点介绍。
在解析出全部的參数之后,processOptions方法最后依据这些參数来初始化MonkeyRunnerOptions类。
我们进入到该构造函数看下它到底做了什么事情:
38 private MonkeyRunnerOptions(String hostname, int port, File scriptFile, String backend, Level logLevel, Collection<File> plugins, Collection<String> arguments) 39 { 40 this.hostname = hostname; 41 this.port = port; 42 this.scriptFile = scriptFile; 43 this.backend = backend; 44 this.logLevel = logLevel; 45 this.plugins = plugins; 46 this.arguments = arguments; 47 }代码8-2-3 MonkeyRunnerOptions - 构造函数
所做的事情很easy。就是把解析出来的全部參数保存到MonkeyRunnerOptions类的实例里面。今后须要的时候就进去拿就好了。
注:很多其它文章请关注公众号:techgogogo或个人博客http://techgogogo.com。当然。也很欢迎您直接微信(zhubaitian1)勾搭。
本文由天地会珠海分舵原创。转载请自觉,是否投诉维权看心情。
以上是关于第8章2节《MonkeyRunner源代码剖析》MonkeyRunner启动执行过程-解析处理命令行參数的主要内容,如果未能解决你的问题,请参考以下文章
社区共读《Python编程从入门到实践》第7,8,9天阅读建议