本小节我们先描述第一点,看HierarchyViewer是如何设置本地端口到目标机器端ViewServer监听端口的端口转发的。在第13章第2小节我们也手动做过这个事情,当时发送的命令是:
adb forward tcp:4939 tcp:4939
那么HierarchyViewer是不是也是通过代码做相同的事情呢?那么我们带着这个疑问来进入深入的代码分析。我们进入setupDeviceForward这个方法:
110 /**
111 * Sets up a just-connected device to work with the view server.
112 * <p/>
113 * This starts a port forwarding between a local port and a port on the
114 * device.
115 *
116 * @param device
117 */
118 public static void setupDeviceForward(IDevice device) {
119 synchronized (sDevicePortMap) {
120 if (device.getState() == IDevice.DeviceState.ONLINE) {
121 int localPort = sNextLocalPort++;
122 try {
123 device.createForward(localPort, DEFAULT_SERVER_PORT);
124 sDevicePortMap.put(device, localPort);
125 } catch (TimeoutException e) {
126 Log.e(TAG, "Timeout setting up port forwarding for " + device);
127 } catch (AdbCommandRejectedException e) {
128 Log.e(TAG, String.format("Adb rejected forward command for device %1$s: %2$s",
129 device, e.getMessage()));
130 } catch (IOException e) {
131 Log.e(TAG, String.format("Failed to create forward for device %1$s: %2$s",
132 device, e.getMessage()));
133 }
134 }
135 }
136 }
代码14-4-2 DeviceBridge - setupDeviceForward
这个处理端口转发的方法主要分3步走:
- 第1步:获得本地ViewServer转发端口号
- 第2步:通过Device类发送adb命令创建本地到ViewServer端口转发
- 第3步:把本地端口号和对应的设备序列号保存起来以便查找
我们先看第1步,就是121行,这里要注意”sNextLocalPort”这个变量,其实它是个静态变量:
private static int sNextLocalPort = 4939;
代码14-4-3 DeviceBridge - sNextLocalPort
所以代码14-4-2中121行所代表的意思是:
- 第一个建立的ViewServer端口转发的本地端口是4939
- 下一个建立的ViewServer端口转发的本地端口是在4939的基础自增加1
注意这里自增加的写法是”sNextLocalPort ++”,如果反过来写成”++sNextLocalPort”, 那么第一个本地端口就会变成4940了,这些都是Java的基本语法了,这里以防我们做测试的没有太多编程经验,所以指出来。
好我们继续分析第2步端口转发相应代码, 这个方法传入的参数就是HierarchyViewer的成员变量mDevice,根据本章第3小节的描述,这个变量是ddmlib中的Device类的一个实例,所以以上调用”device.createForward”方法实际上调用的就是Device的createForward方法:
644 @Override
645 public void createForward(int localPort, int remotePort)
646 throws TimeoutException, AdbCommandRejectedException, IOException {
647 AdbHelper.createForward(AndroidDebugBridge.getSocketAddress(), this,
648 String.format("tcp:%d", localPort), //$NON-NLS-1$
649 String.format("tcp:%d", remotePort)); //$NON-NLS-1$
650 }
代码14-4-3 Device - createForward
像第10章《MonkeyDevice实现原理基础》所描述的那样,Device最终直接调用AdbHelper静态类的createForward方法来设置端口转发:
549 public static void createForward(InetSocketAddress adbSockAddr, Device device,
550 String localPortSpec, String remotePortSpec)
551 throws TimeoutException, AdbCommandRejectedException, IOException {
552
553 SocketChannel adbChan = null;
554 try {
555 adbChan = SocketChannel.open(adbSockAddr);
556 adbChan.configureBlocking(false);
557
558 byte[] request = formAdbRequest(String.format(
559 "host-serial:%1$s:forward:%2$s;%3$s", //$NON-NLS-1$
560 device.getSerialNumber(), localPortSpec, remotePortSpec));
561
562 write(adbChan, request);
563
564 AdbResponse resp = readAdbResponse(adbChan, false /* readDiagString */);
565 if (!resp.okay) {
566 Log.w("create-forward", "Error creating forward: " + resp.message); 567 throw new AdbCommandRejectedException(resp.message);
568 }
569 } finally {
570 if (adbChan != null) {
571 adbChan.close();
572 }
573 }
574 }
代码14-4-4 AdbHelper - createForward