zoukankan      html  css  js  c++  java
  • 老李推荐: 第8章4节《MonkeyRunner源码剖析》MonkeyRunner启动运行过程-启动AndroidDebugBridge 3

    261行创建一个和ADB服务器监听的Socket端口的一个异步非阻塞SocketChannel连接,该连接就是专门用于往后往ADB服务器发送命令用的,返回给deviceMonitorLoop方法后会被保存到mMainAdbConnection中,请大家记住它,我们往下会用到它。

    第二步关于如何调用startAdb来开启ADB服务器是上一节的重点,所以我们不会重新分析了。

    第三步是向ADB服务器发送设备监控命令,我们跳进去:

    272   private boolean sendDeviceListMonitoringRequest()

    273     throws TimeoutException, IOException

    274   {

    275     byte[] request =

    AdbHelper.formAdbRequest("host:track-devices");

    276     try

    277     {

    278       AdbHelper.write(this.mMainAdbConnection, request);

    279     

    280       AdbHelper.AdbResponse resp = AdbHelper.readAdbResponse(this.mMainAdbConnection, false);

    281     

    282

    283       if (!resp.okay)

    284       {

    285         Log.e("DeviceMonitor", "adb refused request: " + resp.message);

    286       }

    287     

    288       return resp.okay;

    289     } catch (IOException e) {

    290       Log.e("DeviceMonitor", "Sending Tracking request failed!");

    291       this.mMainAdbConnection.close();

    292       throw e;

    293     }

    294   }

    代码8-4-5 DeviceMonitor - sendDeviceListMonitoringRequest

    整个方法的功能就是去构建一个发送到ADB服务器请求服务的命令,然后发送,读取结果,返回,错误处理:

    • 275行: 构建发送给ADB服务器的请求获得设备监控服务的命令字串”host:track-devices”, 我们在下一章描述MonkeyDevice实现原理的时候会详细描述formAdbRequest是如何构造一个ADB服务请求命令的
    • 278行: 通过AdbHelper的write方法往上面建立的与ADB服务器连接的SocketChannel mMainAdbConnection写入该请求,而该write方法最终调用的是SocketChannel的write方法往Socket写数据,我们在下一章描述MonkeyDevice实现原理的时候会详细描述
    • 280行: 与写Socket对应的就是读Socket了,发送完命令后就会调用AdbHelper的readAdbResponse方法来把命令发送的结果读取出来返回了, 注意这里读回来的只是命令发送的成功还是失败信息,并不是返回的设备列表。我们在下一章描述MonkeyDevice实现原理的时候会详细描述readAdbResponse这个方法

    对应的 AdbHelper相应方法的实现细节我们下一章会详尽描述。这里我们只需要清楚这个方法做的事情就是刚才提到的往ADB服务器发送”host:track-devices”命令去请求相应设备监控服务就够了。那么这个服务请求是怎么回事呢?其实这个在第一章中已经描述过,用来就是让ADB服务器周期性的往客户端,也就是往这里的DeviceMonitor线程发送设备更新列表:

    host:track-devices

    这个服务是以上的host:devices的一个变种,客户端和ADB服务器的连接会一直保持,当有增加/移除设备或者设备状态改变的时候会主动的往连接上的客户端发送新的设备列表信息(4字节16进制长度+内容)。这样做的话就可以允许DDMS这些工具来实时跟踪所有连接上来的设备的状态,而不需要客户端每次都去连接ADB服务器获取对应信息。

    最终这个命令返回格式跟你在命令行调用ADB命令行客户端发送命令”adb devices”,返回来的就是“设备序列号 设备状态”的格式: 图8-4-2 adb devices命令返回结果

    注意这里device的状态其实就是oneline, 在ddmlib的IDevice类中有相应的定义:

    86   public static enum DeviceState { BOOTLOADER("bootloader"),

     87     OFFLINE("offline"),

     88     ONLINE("device"),

     89     RECOVERY("recovery"),

     90     UNAUTHORIZED("unauthorized");

     91

     92     private String mState;

     93

     94     private DeviceState(String state) {

     95       this.mState = state;

     96     }

    代码8-4-6 IDevice - DeviceState

    “host:track-devices”这个监控请求命令发送一次后就会不停的周期性获得ADB服务器发送过来的设备列表,所以前面的deviceMonitorLoop循环在第一次循环之后其实可以简化成以下几行代码:

    155   private void deviceMonitorLoop()

    156   {

    157     do

    158     {

    159       try

    160       {

    ...

    187         if (this.mMonitoring)

    188         {

    189           int length = readLength(this.mMainAdbConnection,

    this.mLengthBuffer);

    190

    191           if (length >= 0)

    192           {

    193             processIncomingDeviceData(length);

    194

    195

    196             this.mInitialDeviceListDone = true;

    197           }

    198         }

    199       }

    ...

    206     } while (!this.mQuit);

    207   }

    代码8-4-3 DeviceMonitor - deviceMonitorLoop简化版

    所以最终重点就是调用processIncomingDeviceData来处理更新后的设备列表。

    296   private void processIncomingDeviceData(int length) throws IOException

    297   {

    298     ArrayList<Device> list = new ArrayList();

    299   

    300     if (length > 0) {

    301       byte[] buffer = new byte[length];

    302       String result = read(this.mMainAdbConnection, buffer);

    303     

    304       String[] devices = result.split(" ");

    305     

    306       for (String d : devices) {

    307         String[] param = d.split(" ");

    308         if (param.length == 2)

    309         {

    310           Device device = new Device(this, param[0],

    IDevice.DeviceState.getState(param[1]));

    311

    312

    313

    314           list.add(device);

    315         }

    316       }

    317     }

    318   

    319

    320     updateDevices(list);

    321   }

     代码8-4-4 DeviceMonitor - processIncomingDeviceData

    方法体首先在302行获得ADB服务器发送过来的”设备序列号 状态”的设备列表,然后在后续几行循环将每个设备的序列号的和状态解析出来,然后就是根据序列号和状态创建一个代表该设备的Device对象并把其存储到一个列表list里面,最后就是调用updateDevices方法进行下一步动作了。这了我们先简单看下Device的构造函数,至于它的详细分析将会留到下一章。

    677 Device(DeviceMonitor monitor, String serialNumber, IDevice.DeviceState deviceState)
    678 {
    679 this.mMonitor = monitor;
    680 this.mSerialNumber = serialNumber;
    681 this.mState = deviceState;
    682 }

    代码8-4-5 Device构造函数

    Device的构造函数非常简单,就是把上面传进来的DeviceMonitor实例,ADB服务器主动发送过来的设备的序列号字串,以及设备当前的状态给保存起来到对应的成员变量中而已。这里要注意的的士mSerialNumber和mState,在往下分析“启动Monkey“的时候我们需要用到。

    我们往下继续分析updateDevices这个方法。这个方法的代码稍微长那么一点点,我们把它分开来分析:

    323     /**

    324      *  Updates the device list with the new items received from the monitoring service.

    325      */

    326     private void updateDevices(ArrayList<Device> newList) {

    327         // because we are going to call mServer.deviceDisconnected which will acquire this lock

    328         // we lock it first, so that the AndroidDebugBridge lock is always locked first.

    329         synchronized (AndroidDebugBridge.getLock()) {

    330             // array to store the devices that must be queried for information.

    331             // it's important to not do it inside the synchronized loop as this could block

    332             // the whole workspace (this lock is acquired during build too).

    333             ArrayList<Device> devicesToQuery = new ArrayList<Device>();

    334             synchronized (mDevices) {

    335                 // For each device in the current list, we look for a matching the new list.

    336                 // * if we find it, we update the current object with whatever new information

    337                 //   there is

    338                 //   (mostly state change, if the device becomes ready, we query for build info).

    339                 //   We also remove the device from the new list to mark it as "processed"

    340                 // * if we do not find it, we remove it from the current list.

    341                 // Once this is done, the new list contains device we aren't monitoring yet, so we

    342                 // add them to the list, and start monitoring them.

    343

    344                 for (int d = 0 ; d < mDevices.size() ;) {

    345                     Device device = mDevices.get(d);

    346

    347                     // look for a similar device in the new list.

    348                     int count = newList.size();

    349                     boolean foundMatch = false;

    350                     for (int dd = 0 ; dd < count ; dd++) {

    351                         Device newDevice = newList.get(dd);

    352                         // see if it matches in id and serial number.

    353                         if (newDevice.getSerialNumber().equals(device.getSerialNumber())) {

    354                             foundMatch = true;

    355

    356                             // update the state if needed.

    357                             if (device.getState() != newDevice.getState()) {

    358                                 device.setState(newDevice.getState());

    359                                 device.update(Device.CHANGE_STATE);

    360

    361                                 // if the device just got ready/online, we need to start

    362                                 // monitoring it.

    363                                 if (device.isOnline()) {

    364                                     if (AndroidDebugBridge.getClientSupport()) {

    365                                         if (!startMonitoringDevice(device)) {

    366                                             Log.e("DeviceMonitor",

    367                                                     "Failed to start monitoring "

    368                                                     + device.getSerialNumber());

    369                                         }

    370                                     }

    371

    372                                     if (device.getPropertyCount() == 0) {

    373                                         devicesToQuery.add(device);

    374                                     }

    375                                 }

    376                             }

    377

    378                             // remove the new device from the list since it's been used

    379                             newList.remove(dd);

    380                             break;

    381                         }

    382                     }

    383

    384                     if (!foundMatch) {

    385                         // the device is gone, we need to remove it, and keep current index

    386                         // to process the next one.

    387                         removeDevice(device);

    388                         mServer.deviceDisconnected(device);

    389                     } else {

    390                         // process the next one

    391                         d++;

    392                     }

    393                 }

    ...

    }

    代码8-4-5 DeviceMonitor - updateDevices处理移除和状态改变设备

  • 相关阅读:
    11.14 mii-tool:管理网络接口的状态
    11.15 dmidecode:查询系统硬件信息
    11.11 ntsysv:管理开机服务
    HDU 2476 String painter 刷字符串(区间DP)
    HDU 1085 Holding Bin-Laden Captive! 活捉本拉登(普通型母函数)
    母函数的应用
    HDU 1028 Ignatius and the Princess III伊格和公主III(AC代码)母函数
    HDU 1059 Dividing 分配(多重背包,母函数)
    HDU 2955 Robberies抢劫案(01背包,变形)
    HDU 1011 Starship Troopers星河战队(树形dp)
  • 原文地址:https://www.cnblogs.com/poptest/p/5089508.html
Copyright © 2011-2022 走看看