zoukankan      html  css  js  c++  java
  • Android开发进阶之NIO非阻塞包(六)

    有关Android NIO的相关内容,本次Android123整理并归类如下,为了让大家感觉NIOAndroid平台联系的紧密,这里我们结合ADT插件的重要开发工具DDMS中的源码进行分析。在android git中的sdk.git文件中,可以找到ddmlib这个文件夹。有关PC和手机的互通内核在这里使用了Java来完全实现。这里Android开发网一起帮助大家了解下PC同步软件的开发原理同时学习下Java中的New I/O技术。

       比较重要的代码段我们贴出,逐一分析,其他的网友可以直接预读源码:

       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;
        }

      有关Android平台PC通过USBADB方式和手机同步原理和NIO相关技术,Android123明天继续讲解。

     

  • 相关阅读:
    我认为的架构师
    Jenkins github账号密码验证方式失效 解决方式
    android逆向奇技淫巧二十一:ida反反调试&加密算法跟踪(未完待续)(六)
    android逆向奇技淫巧十九:unidbg模拟执行和trace x音so代码(四)
    android逆向奇技淫巧十八:x音so层代码花指令防护分析(三)
    android逆向奇技淫巧十七:android客户端自动x红包(一):代码原理分析
    测试工具安装汇总
    javascript事件节流和防抖
    CompletableFuture-更优雅的使用多线程
    青春
  • 原文地址:https://www.cnblogs.com/cpcpc/p/2123004.html
Copyright © 2011-2022 走看看