Android与PC通过USB通讯

最近在调研Android和PC通过USB连接的相关项目,这里我们结合ADT插件的重要开发工具DDMS中的源码进行分析。在android git中的sdk.git文件中,可以找到ddmlib这个文件夹。而ddmlib这个库,其实你们可以在SDK的tools\lib文件夹下找到ddmlib.jar,说明Google官方是支持开发者来开发相关功能的。下面我们来分析一下ddmlib这个库的关键源码。在文章结尾,我会提供ddmlib的源码。

   AdbHelper.java文件中

  

[java]  view plain copy
  1. public static SocketChannel open(InetSocketAddress adbSockAddr,  
  2.          Device device, int devicePort) //这是一个重载版本,主要是关联Device实例。  
  3.          throws IOException, TimeoutException, AdbCommandRejectedException {  
  4.   
  5.      SocketChannel adbChan = SocketChannel.open(adbSockAddr); //构造SocketChannel对象,使用常规的open方法创建  
  6.      try {  
  7.          adbChan.socket().setTcpNoDelay(true); //设置TCP非延迟  
  8.          adbChan.configureBlocking(false); //非阻塞  
  9.   
  10.          setDevice(adbChan, device); //本句和NIO没有多大关系,这句是指定具体的设备,比如模拟器,或Android手机的厂家代号,比如宏达电的以HTXXXXX这样的方式  
  11.   
  12.          byte[] req = createAdbForwardRequest(null, devicePort); //设置端口转发,这句很关键,否则PC和手机通过USB是无法互通的。  
  13.          write(adbChan, req); //发送数据  
  14.   
  15.          AdbResponse resp = readAdbResponse(adbChan, false); //读取收到的内容  
  16.          if (resp.okay == false) {  
  17.              throw new AdbCommandRejectedException(resp.message);  
  18.          }  
  19.   
  20.          adbChan.configureBlocking(true);  
  21.      } catch (TimeoutException e) { //一般要处理超时异常  
  22.          adbChan.close(); //释放channel句柄  
  23.          throw e;  
  24.      } catch (IOException e) { //处理常规的IO异常  
  25.          adbChan.close();  
  26.          throw e;  
  27.      }  
  28.   
  29.      return adbChan;  
  30.  }  

   有关读取ADB返回的报文方法

[java]  view plain copy
  1. static AdbResponse readAdbResponse(SocketChannel chan, boolean readDiagString)  
  2.           throws TimeoutException, IOException {  
  3.   
  4.       AdbResponse resp = new AdbResponse();  
  5.   
  6.       byte[] reply = new byte[4]; //创建4字节数组,主要检测成功与否,adb的协议是成功返回 okay,失败fail,等等。  
  7.       read(chan, reply); //读取具体的返回  
  8.   
  9.       if (isOkay(reply)) { //判断是否成功  
  10.           resp.okay = true;  
  11.       } else {  
  12.           readDiagString = true// look for a reason after the FAIL  
  13.           resp.okay = false;  
  14.       }  
  15.   
  16.       // not a loop -- use "while" so we can use "break"  
  17.       try {  
  18.           while (readDiagString) {  
  19.               // length string is in next 4 bytes  
  20.               byte[] lenBuf = new byte[4];  
  21.               read(chan, lenBuf); //读取一个字节数组,最终为了转为一个整形  
  22.   
  23.               String lenStr = replyToString(lenBuf); //字节数组转为String  
  24.   
  25.               int len;  
  26.               try {  
  27.                   len = Integer.parseInt(lenStr, 16); //String转为整形,这里Android123提示,这种写法可能比较愚蠢,但是下面为Log输出提供了一点点的便利。  
  28.               } catch (NumberFormatException nfe) {  
  29.                   Log.w("ddms""Expected digits, got '" + lenStr + "': "  
  30.                           + lenBuf[0] + " " + lenBuf[1] + " " + lenBuf[2] + " "  
  31.                           + lenBuf[3]);  
  32.                   Log.w("ddms""reply was " + replyToString(reply));  
  33.                   break;  
  34.               }  
  35.   
  36.               byte[] msg = new byte[len];  
  37.               read(chan, msg);  
  38.   
  39.               resp.message = replyToString(msg);  
  40.               Log.v("ddms""Got reply '" + replyToString(reply) + "', diag='"  
  41.                       + resp.message + "'");  
  42.   
  43.               break;  
  44.           }  
  45.       } catch (Exception e) {  
  46.           // ignore those, since it's just reading the diagnose string, the response will  
  47.           // contain okay==false anyway.  
  48.       }  
  49.   
  50.       return resp;  
  51.   }  


   有关PC上对Android手机屏幕截图的方法之一:

[java]  view plain copy
  1. static RawImage getFrameBuffer(InetSocketAddress adbSockAddr, Device device)  
  2.          throws TimeoutException, AdbCommandRejectedException, IOException {  
  3.   
  4.      RawImage imageParams = new RawImage();  
  5.      byte[] request = formAdbRequest("framebuffer:"); // 读取手机端adbd服务器的framebuffer调用返回的数组  
  6.   
  7.      byte[] nudge = {  
  8.          0  
  9.      };  
  10.      byte[] reply;  
  11.   
  12.      SocketChannel adbChan = null;  
  13.      try {  
  14.          adbChan = SocketChannel.open(adbSockAddr);  
  15.          adbChan.configureBlocking(false); //非阻塞  
  16.   
  17.          setDevice(adbChan, device); //设置我们关系的设备  
  18.   
  19.          write(adbChan, request); //发送framebuffer这个请求了  
  20.   
  21.          AdbResponse resp = readAdbResponse(adbChan, false /* readDiagString */);  
  22.          if (resp.okay == false) {   //判断返回是否ok。  
  23.              throw new AdbCommandRejectedException(resp.message);  
  24.          }  
  25.   
  26.          reply = new byte[4];  
  27.          read(adbChan, reply); //首先返回的是一个协议,目前分为两个版本,主要是兼容模式和标准的模式,兼容模式比较少见,在2.0以后几乎看不到了。部分早期的1.6或更老的T-Mobile G1会使用兼容模式,模式不同,输出的截图中的颜色编码方式略有不同。  
  28.   
  29.          ByteBuffer buf = ByteBuffer.wrap(reply);  
  30.          buf.order(ByteOrder.LITTLE_ENDIAN); //小头字节顺序  
  31.   
  32.          int version = buf.getInt(); //ByteBuffer直接转int的方法,比较方便不用自己从字节数组中构造,按位计算  
  33.   
  34.          int headerSize = RawImage.getHeaderSize(version); //根据返回的adb截图协议版本判断将收到的字节大小  
  35.   
  36.          reply = new byte[headerSize * 4]; //分配空间,具体大小需要看协议版本  
  37.          read(adbChan, reply);  
  38.   
  39.          buf = ByteBuffer.wrap(reply); //从reply数组实例化ByteBuffer  
  40.          buf.order(ByteOrder.LITTLE_ENDIAN); //注意字节序列,毕竟远端的adbd是工作在linux系统的手机上。  
  41.   
  42.          if (imageParams.readHeader(version, buf) == false) { //判断是否有效,兼容这种截图协议。  
  43.              Log.e("Screenshot""Unsupported protocol: " + version);  
  44.              return null;  
  45.          }  
  46.   
  47.          Log.d("ddms""image params: bpp=" + imageParams.bpp + ", size="  
  48.                  + imageParams.size + ", width=" + imageParams.width  
  49.                  + ", height=" + imageParams.height); //打印下截图的基本信息,比如bpp代表色深,size是需要分配dib图像的字节数组。比较原始,  
  50.   
  51.          write(adbChan, nudge); //发送一个字节,代表准备接收字节数组了  
  52.   
  53.          reply = new byte[imageParams.size]; //分配和图像大小一样的字节数组  
  54.          read(adbChan, reply); //接收图像字节数组,这里Android开发网提示大家对于Android 1.x可能为RGB565,分配大小为 wxhx2xsize ,而2.x以后基本上为32位的RGB8888,分配大小为wxhx4xsize  
  55.   
  56.          imageParams.data = reply;  
  57.      } finally {  
  58.          if (adbChan != null) {  
  59.              adbChan.close();  
  60.          }  
  61.      }  
  62.   
  63.      return imageParams;  
  64.  }  

DDMLib源码 : http://download.csdn.net/detail/hustpzb/4747185
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值