最近在调研Android和PC通过USB连接的相关项目,这里我们结合ADT插件的重要开发工具DDMS中的源码进行分析。在android git中的sdk.git文件中,可以找到ddmlib这个文件夹。而ddmlib这个库,其实你们可以在SDK的tools\lib文件夹下找到ddmlib.jar,说明Google官方是支持开发者来开发相关功能的。下面我们来分析一下ddmlib这个库的关键源码。在文章结尾,我会提供ddmlib的源码。
AdbHelper.java文件中
- public static SocketChannel open(InetSocketAddress adbSockAddr,
- Device device, int devicePort) //这是一个重载版本,主要是关联Device实例。
- throws IOException, TimeoutException, AdbCommandRejectedException {
- SocketChannel adbChan = SocketChannel.open(adbSockAddr); //构造SocketChannel对象,使用常规的open方法创建
- try {
- adbChan.socket().setTcpNoDelay(true); //设置TCP非延迟
- adbChan.configureBlocking(false); //非阻塞
- setDevice(adbChan, device); //本句和NIO没有多大关系,这句是指定具体的设备,比如模拟器,或Android手机的厂家代号,比如宏达电的以HTXXXXX这样的方式
- byte[] req = createAdbForwardRequest(null, devicePort); //设置端口转发,这句很关键,否则PC和手机通过USB是无法互通的。
- write(adbChan, req); //发送数据
- AdbResponse resp = readAdbResponse(adbChan, false); //读取收到的内容
- if (resp.okay == false) {
- throw new AdbCommandRejectedException(resp.message);
- }
- adbChan.configureBlocking(true);
- } catch (TimeoutException e) { //一般要处理超时异常
- adbChan.close(); //释放channel句柄
- throw e;
- } catch (IOException e) { //处理常规的IO异常
- adbChan.close();
- throw e;
- }
- return adbChan;
- }
有关读取ADB返回的报文方法
- static AdbResponse readAdbResponse(SocketChannel chan, boolean readDiagString)
- throws TimeoutException, IOException {
- AdbResponse resp = new AdbResponse();
- byte[] reply = new byte[4]; //创建4字节数组,主要检测成功与否,adb的协议是成功返回 okay,失败fail,等等。
- read(chan, reply); //读取具体的返回
- if (isOkay(reply)) { //判断是否成功
- resp.okay = true;
- } else {
- readDiagString = true; // look for a reason after the FAIL
- resp.okay = false;
- }
- // not a loop -- use "while" so we can use "break"
- try {
- while (readDiagString) {
- // length string is in next 4 bytes
- byte[] lenBuf = new byte[4];
- read(chan, lenBuf); //读取一个字节数组,最终为了转为一个整形
- String lenStr = replyToString(lenBuf); //字节数组转为String
- int len;
- try {
- len = Integer.parseInt(lenStr, 16); //String转为整形,这里Android123提示,这种写法可能比较愚蠢,但是下面为Log输出提供了一点点的便利。
- } catch (NumberFormatException nfe) {
- Log.w("ddms", "Expected digits, got '" + lenStr + "': "
- + lenBuf[0] + " " + lenBuf[1] + " " + lenBuf[2] + " "
- + lenBuf[3]);
- Log.w("ddms", "reply was " + replyToString(reply));
- break;
- }
- byte[] msg = new byte[len];
- read(chan, msg);
- resp.message = replyToString(msg);
- Log.v("ddms", "Got reply '" + replyToString(reply) + "', diag='"
- + resp.message + "'");
- break;
- }
- } catch (Exception e) {
- // ignore those, since it's just reading the diagnose string, the response will
- // contain okay==false anyway.
- }
- return resp;
- }
有关PC上对Android手机屏幕截图的方法之一:
- static RawImage getFrameBuffer(InetSocketAddress adbSockAddr, Device device)
- throws TimeoutException, AdbCommandRejectedException, IOException {
- RawImage imageParams = new RawImage();
- byte[] request = formAdbRequest("framebuffer:"); // 读取手机端adbd服务器的framebuffer调用返回的数组
- byte[] nudge = {
- 0
- };
- byte[] reply;
- SocketChannel adbChan = null;
- try {
- adbChan = SocketChannel.open(adbSockAddr);
- adbChan.configureBlocking(false); //非阻塞
- setDevice(adbChan, device); //设置我们关系的设备
- write(adbChan, request); //发送framebuffer这个请求了
- AdbResponse resp = readAdbResponse(adbChan, false /* readDiagString */);
- if (resp.okay == false) { //判断返回是否ok。
- throw new AdbCommandRejectedException(resp.message);
- }
- reply = new byte[4];
- read(adbChan, reply); //首先返回的是一个协议,目前分为两个版本,主要是兼容模式和标准的模式,兼容模式比较少见,在2.0以后几乎看不到了。部分早期的1.6或更老的T-Mobile G1会使用兼容模式,模式不同,输出的截图中的颜色编码方式略有不同。
- ByteBuffer buf = ByteBuffer.wrap(reply);
- buf.order(ByteOrder.LITTLE_ENDIAN); //小头字节顺序
- int version = buf.getInt(); //ByteBuffer直接转int的方法,比较方便不用自己从字节数组中构造,按位计算
- int headerSize = RawImage.getHeaderSize(version); //根据返回的adb截图协议版本判断将收到的字节大小
- reply = new byte[headerSize * 4]; //分配空间,具体大小需要看协议版本
- read(adbChan, reply);
- buf = ByteBuffer.wrap(reply); //从reply数组实例化ByteBuffer
- buf.order(ByteOrder.LITTLE_ENDIAN); //注意字节序列,毕竟远端的adbd是工作在linux系统的手机上。
- if (imageParams.readHeader(version, buf) == false) { //判断是否有效,兼容这种截图协议。
- Log.e("Screenshot", "Unsupported protocol: " + version);
- return null;
- }
- Log.d("ddms", "image params: bpp=" + imageParams.bpp + ", size="
- + imageParams.size + ", width=" + imageParams.width
- + ", height=" + imageParams.height); //打印下截图的基本信息,比如bpp代表色深,size是需要分配dib图像的字节数组。比较原始,
- write(adbChan, nudge); //发送一个字节,代表准备接收字节数组了
- reply = new byte[imageParams.size]; //分配和图像大小一样的字节数组
- read(adbChan, reply); //接收图像字节数组,这里Android开发网提示大家对于Android 1.x可能为RGB565,分配大小为 wxhx2xsize ,而2.x以后基本上为32位的RGB8888,分配大小为wxhx4xsize
- imageParams.data = reply;
- } finally {
- if (adbChan != null) {
- adbChan.close();
- }
- }
- return imageParams;
- }
DDMLib源码 : http://download.csdn.net/detail/hustpzb/4747185