android自动化测试Monkeyrunner源码分析之二
来源:互联网 发布:河南省南乐县网络电视 编辑:程序博客网 时间:2024/05/21 07:06
2. ChimpChat
ChimpChat的getInstance方法如下,
public static ChimpChat getInstance(Map<String, String> options) { sAdbLocation = (String)options.get("adbLocation"); sNoInitAdb = Boolean.valueOf((String)options.get("noInitAdb")).booleanValue(); IChimpBackend backend = createBackendByName((String)options.get("backend")); if (backend == null) { return null; } ChimpChat chimpchat = new ChimpChat(backend); return chimpchat; }
1, 根据backend的名字来创建一个backend,其实就是创建一个AndroidDebugBridge
2,构造ChimpChat对象。
createBackendByName方法如下,
private static IChimpBackend createBackendByName(String backendName) { if ("adb".equals(backendName)) { return new AdbBackend(sAdbLocation, sNoInitAdb); } return null; }
AdbBackend的构造方法如下,
public AdbBackend(String adbLocation, boolean noInitAdb) { this.initAdb = (!noInitAdb); if (adbLocation == null) { adbLocation = findAdb(); } if (this.initAdb) { AndroidDebugBridge.init(false); } this.bridge = AndroidDebugBridge.createBridge(adbLocation, true); }
创建AndroidDebugBridge之前先要确定adb程序的位置,这就是通过findAdb方法来实现的。
然后调用createBridge方法创建AndroidDebugBridge对象,
public static AndroidDebugBridge createBridge(String osLocation, boolean forceNewBridge) { synchronized (sLock) { if (sThis != null) { if ((sThis.mAdbOsLocation != null) && (sThis.mAdbOsLocation.equals(osLocation)) && (!forceNewBridge)) { return sThis; } sThis.stop(); } try { sThis = new AndroidDebugBridge(osLocation); sThis.start(); }•••
实例化AndroidDebugBridge对象后,然后调用其start方法,启动adb
boolean start() { if ((this.mAdbOsLocation != null) && (sAdbServerPort != 0) && ((!this.mVersionCheck) || (!startAdb()))) { return false; } this.mStarted = true; this.mDeviceMonitor = new DeviceMonitor(this); this.mDeviceMonitor.start(); return true; }
1,startAdb:开启AndroidDebugBridge
2,NewDeviceMonitor并传入已经开启的adb:初始化android设备监控
3,DeviceMonitor.start:启动DeviceMonitor设备监控线程。
2.1 startAdb
startAdb的方法如下,
synchronized boolean startAdb() { if (this.mAdbOsLocation == null) { Log.e("adb", "Cannot start adb when AndroidDebugBridge is created without the location of adb."); return false; } if (sAdbServerPort == 0) { Log.w("adb", "ADB server port for starting AndroidDebugBridge is not set."); return false; } int status = -1; String[] command = getAdbLaunchCommand("start-server"); String commandString = Joiner.on(',').join(command); try { Log.d("ddms", String.format("Launching '%1$s' to ensure ADB is running.", new Object[] { commandString })); ProcessBuilder processBuilder = new ProcessBuilder(command); if (DdmPreferences.getUseAdbHost()) { String adbHostValue = DdmPreferences.getAdbHostValue(); if ((adbHostValue != null) && (!adbHostValue.isEmpty())) { Map<String, String> env = processBuilder.environment(); env.put("ADBHOST", adbHostValue); } } Process proc = processBuilder.start(); ArrayList<String> errorOutput = new ArrayList(); ArrayList<String> stdOutput = new ArrayList(); status = grabProcessOutput(proc, errorOutput, stdOutput, false); } catch (IOException ioe) { Log.e("ddms", "Unable to run 'adb': " + ioe.getMessage()); } catch (InterruptedException ie) { Log.e("ddms", "Unable to run 'adb': " + ie.getMessage()); } if (status != 0) { Log.e("ddms", String.format("'%1$s' failed -- run manually if necessary", new Object[] { commandString })); return false; } Log.d("ddms", String.format("'%1$s' succeeded", new Object[] { commandString })); return true; }
1,准备好启动db server的command字串
2,通过ProcessBuilder启动command字串指定的adb server
adb服务器进程已经运行起来了。AndroidDebugBridge启动起来后,下一步就是把这个adb实例传到DeviceMonitor来去监测所有连接到adb服务器也就是pc主机端的android设备的状态。
2.2启动DeviceMonitor设备监控线程
流程图如下,
DeviceMonitor的构造方法如下,
DeviceMonitor(AndroidDebugBridge server) { this.mServer = server; this.mDebuggerPorts.add(Integer.valueOf(DdmPreferences.getDebugPortBase())); }
Start方法如下,
void start() { new Thread("Device List Monitor") { public void run() { DeviceMonitor.this.deviceMonitorLoop(); } }.start(); }
另开一个线程无限循环来检测设备的状态。
private void deviceMonitorLoop() { do { try { if (this.mMainAdbConnection == null) { Log.d("DeviceMonitor", "Opening adb connection"); this.mMainAdbConnection = openAdbConnection(); if (this.mMainAdbConnection == null) { this.mConnectionAttempt += 1; Log.e("DeviceMonitor", "Connection attempts: " + this.mConnectionAttempt); if (this.mConnectionAttempt > 10) { if (!this.mServer.startAdb()) { this.mRestartAttemptCount += 1; Log.e("DeviceMonitor", "adb restart attempts: " + this.mRestartAttemptCount); } else { Log.i("DeviceMonitor", "adb restarted"); this.mRestartAttemptCount = 0; } } waitABit(); } else { Log.d("DeviceMonitor", "Connected to adb for device monitoring"); this.mConnectionAttempt = 0; } } if ((this.mMainAdbConnection != null) && (!this.mMonitoring)) { this.mMonitoring = sendDeviceListMonitoringRequest(); } if (this.mMonitoring) { int length = readLength(this.mMainAdbConnection, this.mLengthBuffer); if (length >= 0) { processIncomingDeviceData(length); this.mInitialDeviceListDone = true; } } } catch (AsynchronousCloseException ace) {}catch (TimeoutException ioe) { handleExpectionInMonitorLoop(ioe); } catch (IOException ioe) { handleExpectionInMonitorLoop(ioe); } } while (!this.mQuit); }
一旦发现设备有变动,该循环会立刻调用processIncomingDeviceData这个方法来更新设备信息。
private void processIncomingDeviceData(int length) throws IOException { ArrayList<Device> list = new ArrayList(); if (length > 0) { byte[] buffer = new byte[length]; String result = read(this.mMainAdbConnection, buffer); String[] devices = result.split("\n"); for (String d : devices) { String[] param = d.split("\t"); if (param.length == 2) { Device device = new Device(this, param[0], IDevice.DeviceState.getState(param[1])); list.add(device); } } } updateDevices(list); }
该方法首先会取得所有的device列表(类似"adb devices -l"命令获得所有device列表),
然后调用updateDevices这个方法来对所有设备信息进行一次更新:
•••for (Device d : devicesToQuery) { queryNewDeviceForInfo(d); }•••
调用queryNewDeviceForInfo这个方法去更新每个设备所有的porperty信息
private void queryNewDeviceForMountingPoint(final Device device, final String name) throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException, IOException { device.executeShellCommand("echo $" + name, new MultiLineReceiver() { public boolean isCancelled() { return false; } public void processNewLines(String[] lines) { for (String line : lines) { if (!line.isEmpty()) { device.setMountingPoint(name, line); } } } }); }
该方法调用了一个ddmlib库的device类里面的executeShellCommand方法来执行‘getprop'这个命令。
到目前位置我们达到的目的是知道了getSystemProperty这个MonkeyDevice的api最终确实是通过发送'adb shell getporp‘命令来获得设备属性的。
AdbHelper的executeRemoteCommand方法如下,
static void executeRemoteCommand(InetSocketAddress adbSockAddr, AdbService adbService, String command, IDevice device, IShellOutputReceiver rcvr, long maxTimeToOutputResponse, TimeUnit maxTimeUnits, @Nullable InputStream is) throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException, IOException { long maxTimeToOutputMs = 0L; if (maxTimeToOutputResponse > 0L) { if (maxTimeUnits == null) { throw new NullPointerException("Time unit must not be null for non-zero max."); } maxTimeToOutputMs = maxTimeUnits.toMillis(maxTimeToOutputResponse); } Log.v("ddms", "execute: running " + command); SocketChannel adbChan = null; try { adbChan = SocketChannel.open(adbSockAddr); adbChan.configureBlocking(false); setDevice(adbChan, device); byte[] request = formAdbRequest(adbService.name().toLowerCase() + ":" + command); write(adbChan, request); AdbResponse resp = readAdbResponse(adbChan, false); if (!resp.okay) { Log.e("ddms", "ADB rejected shell command (" + command + "): " + resp.message); throw new AdbCommandRejectedException(resp.message); } byte[] data = new byte[16384]; if (is != null) { int read; while ((read = is.read(data)) != -1) { ByteBuffer buf = ByteBuffer.wrap(data, 0, read); int written = 0; while (buf.hasRemaining()) { written += adbChan.write(buf); } if (written != read) { Log.e("ddms", "ADB write inconsistency, wrote " + written + "expected " + read); throw new AdbCommandRejectedException("write failed"); } } } ByteBuffer buf = ByteBuffer.wrap(data); buf.clear(); long timeToResponseCount = 0L; for (;;) { if ((rcvr != null) && (rcvr.isCancelled())) { Log.v("ddms", "execute: cancelled"); break; } int count = adbChan.read(buf); if (count < 0) { rcvr.flush(); Log.v("ddms", "execute '" + command + "' on '" + device + "' : EOF hit. Read: " + count); break; } if (count == 0) { try { int wait = 25; timeToResponseCount += wait; if ((maxTimeToOutputMs > 0L) && (timeToResponseCount > maxTimeToOutputMs)) { throw new ShellCommandUnresponsiveException(); } Thread.sleep(wait); } catch (InterruptedException ie) {} } else { timeToResponseCount = 0L; if (rcvr != null) { rcvr.addOutput(buf.array(), buf.arrayOffset(), buf.position()); } buf.rewind(); } } } finally { if (adbChan != null) { adbChan.close(); } Log.v("ddms", "execute: returning"); } }
方法中先创建一个面向adb服务器的socket通道,然后通过发送adb协议请求的'shell:'命令获得一个adb shell
然后再把相应的adb shell命令发送到该socket。从这里可以看到,“发送adb shell命令“其实是基于”发送adb协议请求“的,
因为在发送命令之前需要先通过组织基于adb协议的请求”shell:“来获得adb shell.
MonkeyRunner启动步骤如下,
1,实例化MonkeyRunnerStarter时会去实例化ChimpChat这个类
2,实例化ChimpChat这个类的时候会去创建AndroidDebugBridge对象启动一个adb进程来进行与adb服务器以及目标设备的adb守护进程通讯
3,.实例化ChimpChat时还会在上面创建的adb对象的基础上创建DeviceMonitor对象并
启动一个线程来监控和维护连接到主机pc的android设备信息,因为监控设备时需要通过adb来实现的
4,最后在以上都准备好后就会尝试启动jython编译器的console或者直接调用jython编译器去解析执行脚本。
- android自动化测试Monkeyrunner源码分析之二
- android自动化测试Monkeyrunner源码分析之三
- android自动化测试Monkeyrunner源码分析之四
- android自动化测试Monkeyrunner源码分析之一
- Android自动化测试之Monkeyrunner从零开始(二)
- Android自动化测试之monkeyrunner
- Android自动化测试之monkeyrunner
- Android自动化测试之monkeyrunner
- Android自动化测试之MonkeyRunner
- Android自动化测试之Monkeyrunner
- Android自动化测试之MonkeyRunner
- Android自动化测试之monkeyrunner
- Android自动化测试之MonkeyRunner
- Android自动化测试之MonkeyRunner工具(二)
- android自动化测试之MonkeyRunner使用实例(二)
- android 自动化测试之MonkeyRunner学习(二)
- android自动化测试Uiautomator源码分析之二
- android自动化测试CTS源码分析之二
- [JZOJ5061]最长路径
- 题目1522:包含min函数的栈
- 混合数组
- (懒人必备)Android开源数据库LitePal
- 坏道填补与去条带处理
- android自动化测试Monkeyrunner源码分析之二
- 智能指针总结
- Spring Boot学习(一)
- ecshop打开手机端QQ对话窗口
- POJ 1050 To the Max【DP】
- PHP源码阅读 Day.1,源码目录结构分析
- 链表
- mybatis .xml文件 遍历map集合包括二级map集合的遍历
- 今天又没有练习吉他