PC和Android adb通信

前几天研究截屏,查看ddmlib源码,发现adb通信是通过socket完成的,通过流传输可以提高效率。

adb 命令:adb forward,可以创建socket,官方解释如下

Forwarding Ports

You can use the forwardcommand to set up arbitrary port forwarding — forwarding of requests ona specific host port to a different port on an emulator/deviceinstance. Here's how you would set up forwarding of host port 6100 toemulator/device port 7100:

adb forward tcp:6100 tcp:7100
我的理解就是pc机端口127.0.0.1:6100映射到Android设备的7100端口。
模型图
我以PC为客户端,Android设备为服务端写个例子。
PC端口为1352,Android设备端口为2235,这是我的电话号码前几位。
Android服务端:
写一个监听2235端口的服务
首先添加权限
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

Java代码
服务端监听连接,连接后发一个ack "you connect me"给pc客户端,等待用户发过来的消息。
   protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
        try {
            mServerSocket = new ServerSocket(2235);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    
    protected void onDestroy()
    {
        bRun = false;
    }
    
    public void onClick(View vt)
    {
        Log.i(TAG, "start listen socket accept");
        acceptThread();
    }
    
    private void acceptThread(){
        if (bRun)
            return;
        
        bRun = true;
        Runnable r = new Runnable() {
            
            @Override
            public void run() {
                
                // TODO Auto-generated method stub
                while(bRun) {
                    Socket sock = accept();
                    if (sock != null) {
                        Log.i(TAG, "sock is not null ptr:" + sock.getPort() + " is connect");
                        new SocketChild(sock).start();
                        
                    } else {
                        //Log.i(TAG, "sock is null");
                    }
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
        };
        new Thread(r).start();
    }
    
    private Socket accept() {
        Socket sock = null;
        try {
            sock = mServerSocket.accept();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return sock;
    }


    public class SocketChild extends Thread{
        private Socket mSocket;
        public  SocketChild(Socket sock) {
            // TODO Auto-generated constructor stub
            mSocket = sock;
            ack("you connect me");
        
        }
        
        private void ack(String ack) {
            try {
                mSocket.getOutputStream().write(ack.getBytes());
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        
        @Override
        public void run() {
            while(bRun) {
                try {
                    sleep(100);
                    read();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            try {
                mSocket.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        
        private void read() throws IOException {
            InputStream input;
            byte [] buffer = new byte[1024];
            input = mSocket.getInputStream();
            int len = input.read(buffer, 0, 1024);
            Log.i(TAG, new String(buffer).substring(0, len));
        }
    }

PC端
准备条件:
1、配置好adb环境
2、使用TCP调试工具

建立连接,在PC端CMD输入:adb forward tcp:1352 tcp:2235
代开TCP调试工具,连接1352端口,发送"hello world",得到Android设备回传的"you connect me".


再看Android服务端
我这边偷懒,直接用Locat打印Android服务端显示

这就完成了一个完整的连接,发送,应答的过程。

通过这个命令可以引申很多东西,如果你想使用screencap -p持续生成图像,再使用adb pull导出来,一次过程也得几秒,使用这种流的方式就高效多了,可以参考/system/core/adb/framebuffer_service.c的方式把图像数据导出来,这样就可以保证图像的流畅度。framebuffer_service.c 执行screencap获取原始的图像数据,再写到socket。
以下是framebuffer_service.c的参考代码:
void framebuffer_service(int fd, void *cookie)
{
    struct fbinfo fbinfo;
    unsigned int i;
    char buf[640];
    int fd_screencap;
    int w, h, f;
    int fds[2];

    if (pipe(fds) < 0) goto done;

    pid_t pid = fork();
    if (pid < 0) goto done;

    if (pid == 0) {
        dup2(fds[1], STDOUT_FILENO);
        close(fds[0]);
        close(fds[1]);
        const char* command = "screencap";
        const char *args[2] = {command, NULL};
        execvp(command, (char**)args);
        exit(1);
    }

    fd_screencap = fds[0];

    /* read w, h & format */
    if(readx(fd_screencap, &w, 4)) goto done;
    if(readx(fd_screencap, &h, 4)) goto done;
    if(readx(fd_screencap, &f, 4)) goto done;

    fbinfo.version = DDMS_RAWIMAGE_VERSION;
    /* see hardware/hardware.h */
    switch (f) {
        case 1: /* RGBA_8888 */
            fbinfo.bpp = 32;
            fbinfo.size = w * h * 4;
            fbinfo.width = w;
            fbinfo.height = h;
            fbinfo.red_offset = 0;
            fbinfo.red_length = 8;
            fbinfo.green_offset = 8;
            fbinfo.green_length = 8;
            fbinfo.blue_offset = 16;
            fbinfo.blue_length = 8;
            fbinfo.alpha_offset = 24;
            fbinfo.alpha_length = 8;
            break;
        case 2: /* RGBX_8888 */
             ......
        default:
            goto done;
    }

    /* write header */
    if(writex(fd, &fbinfo, sizeof(fbinfo))) goto done;

    /* write data */
    for(i = 0; i < fbinfo.size; i += sizeof(buf)) {
      if(readx(fd_screencap, buf, sizeof(buf))) goto done;
      if(writex(fd, buf, sizeof(buf))) goto done;
    }
    if(readx(fd_screencap, buf, fbinfo.size % sizeof(buf))) goto done;
    if(writex(fd, buf, fbinfo.size % sizeof(buf))) goto done;

done:
    TEMP_FAILURE_RETRY(waitpid(pid, NULL, 0));

    close(fds[0]);
    close(fds[1]);
    close(fd);
}

有耐心的朋友可以看看adb源码、ddmlib源码
adb源码:android源码内/system/core/adb
ddmlib源码:http://www.boyunjian.com/javasrc/com.google.android.tools/ddmlib/r13/_/com/android/ddmlib/
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值