Android开发工具——ADB(Android Debug Bridge) <四>Device端

        这篇博客梳理Device端adbd是如何运作的,最好有前面博客的预习,1、Android开发工具——ADB(Android Debug Bridge) <一>概览,2、Android开发工具——ADB(Android Debug Bridge) <二>HOST端,3、Android开发工具——ADB(Android Debug Bridge) <三>DalvikVM之jdwp线程

        在adbd起来时,也会监听TCP:5037端口(好像没有使用),扫描当前USB设备,注册好usb transport,等待远端的连接,同时启动jdwp服务,与虚拟机的jdwp线程进行握手通信。

  先看HOST和DEVICE的连接过程。

  HOST首先发出connect请求,数据包内容如下

    apacket *cp = get_apacket();
    cp->msg.command = A_CNXN;
    cp->msg.arg0 = A_VERSION;
    cp->msg.arg1 = MAX_PAYLOAD;
    snprintf((char*) cp->data, sizeof cp->data, "%s::",
            HOST ? "host" : adb_device_banner);
         DEVICE端收到以后,解析后设置transport的状态为HOST,然后给host回一个同样的connect请求,只不过data由"host::"变成了"device::",

         HOST收到DEVICE的connect请求后,解析,

    if(!strcmp(type, "device")) {
        D("setting connection_state to CS_DEVICE\n");
        t->connection_state = CS_DEVICE;
        update_transports();
        return;
    }
          update_transports供client发送adb track-devices命令时有用。

          因此到此时为止,HOST和DEVICE已经处于online状态,准备好其它的通信了。

          这里以adb jdwp命令为例说明,jdwp是获取当前device中注册了jdwp传输的进程列表。看看jdwp是怎么从HOST到DEVICE端的。

    if (!strcmp(argv[0], "jdwp")) {
        int  fd = adb_connect("jdwp");
        if (fd >= 0) {
            read_and_dump(fd);
            adb_close(fd);
            return 0;
        } else {
            fprintf(stderr, "error: %s\n", adb_error());
            return -1;
        }
    }

这是调用adb_connect,然后直接从里面读取结果,在发送“jdwp”之前,先调用

    int fd = _adb_connect("host:version");

校验,adb版本。_adb_connect中,如果碰到“host”打头的请求,则切换transport。

    if (memcmp(service,"host",4) != 0 && switch_socket_transport(fd)) {
        return -1;
    }

在switch_socket_transport中,如果刚开始在adb命令中未指定serial 和transport type, 则,将“host:transport-any‘发往5037端口

    if(writex(fd, tmp, 4) || writex(fd, service, len)) {
        strcpy(__adb_error, "write failure during connection");
        adb_close(fd);
        return -1;
    }

等待返回一个“OKAY”

    if(adb_status(fd)) {
        adb_close(fd);
        return -1;
    }
在里面判断返回结果是否为“OK”
int adb_status(int fd)
{
    unsigned char buf[5];
    unsigned len;

    if(!memcmp(buf, "OKAY", 4)) {
        return 0;
    }
}

TCP:5037的另一端,也就是service,它的读写处理函数是local_socket_event_func,将"host:transport-any"读取出来,调用s->peer->enqueue(s->peer, p);也就是smart_socket_enqueue进行处理,

smart_socket_enqueue->handle_host_request->acquire_one_transport处理host:transport-any"请求。

在acquire_one_transport中,会查询当前的transport_list,取出符合用户要求的transport,如果有多个,则返回错误。然后,将该transport赋给当前的socket。往TCP:5037回一个“OKAY”

        transport = acquire_one_transport(CS_ANY, type, serial, &error_string);
    
        if (transport) {
            s->transport = transport;
            adb_write(reply_fd, "OKAY", 4);
        } else {
            sendfailmsg(reply_fd, error_string);
        }

由此可知,切换transport后,才将"host:version"请求发送到TCP:5037端口,同样经过smart_socket_enqueue->handle_host_request函数,执行下面语句

    // returns our value for ADB_SERVER_VERSION
    if (!strcmp(service, "version")) {
        char version[12];
        snprintf(version, sizeof version, "%04x", ADB_SERVER_VERSION);
        snprintf(buf, sizeof buf, "OKAY%04x%s", (unsigned)strlen(version), version);
        writex(reply_fd, buf, strlen(buf));
        return 0;
    }
返回结果的先导也有一个OKAY。TCP:5037的另一端,也就是service,它的读写处理函数是local_socket_event_func,讲"host:version"结果

再来看“jdwp”请求,smart_socket_enqueue->handle_host_request,handle_host_request发现处理不了,所以回到smart_socket_enqueue继续执行下面语句,

    s->peer->ready = local_socket_ready_notify;
    s->peer->close = local_socket_close_notify;
    s->peer->peer = 0;
        /* give him our transport and upref it */
    s->peer->transport = s->transport;

    connect_to_remote(s->peer, (char*) (p->data + 4));
    s->peer = 0;
    s->close(s);

这段语句,将smart soeckt关闭,然后将transport交给local socket,这样,connect_to_remote的参数就是local socket, “jdwp”,在connect_to_remote

    p->msg.command = A_OPEN;
    p->msg.arg0 = s->id;
    p->msg.data_length = len;
    strcpy((char*) p->data, destination);
    send_packet(p, s->transport);

把A_OPEN命令发给DEVICE端,id是socket的唯一标识,在初始化local socket的时候就确定,便于远端回复数据过来时,在socket list中能查找到该socket进行处理

void install_local_socket(asocket *s)
{
    adb_mutex_lock(&socket_list_lock);

    s->id = local_socket_next_id++;
    insert_local_socket(s, &local_socket_list);

    adb_mutex_unlock(&socket_list_lock);
}
在DEVICE端的output_thread线程,读取到消息,写到transport_socket里面去

    for(;;) {
        p = get_apacket();

        if(t->read_from_remote(p, t) == 0){
            D("from_remote: received remote packet, sending to transport %p\n",
              t);
            if(write_packet(t->fd, &p)){
                put_apacket(p);
                D("from_remote: failed to write apacket to transport %p", t);
                goto oops;
            }
        } else {
            D("from_remote: remote read failed for transport %p\n", p);
            put_apacket(p);
            break;
        }
    }
transport_socket的处理函数transport_socket_events调用handle_packet进行处理,读取到A_OPEN命令,先调用create_local_service_socket创建local socket,在调用create_remote_socket创建remote socket,

create_local_service_socket->create_jdwp_service_socket,回调:

    s->socket.ready   = jdwp_socket_ready;
    s->socket.enqueue = jdwp_socket_enqueue;
    s->socket.close   = jdwp_socket_close;
    s->pass           = 0; 
    

create_remote_socket的回调:这里的id是HOST端的local socket的id。

    s->id = id;
    s->enqueue = remote_socket_enqueue;
    s->ready = remote_socket_ready;
    s->close = remote_socket_close;
    s->transport = t;

然后调用    

                send_ready(s->id, s->peer->id, t);
                s->ready(s);

 这里的s->id是DEVICE端local socket的id, s->peer->是HOST端的local socket的id。

static void send_ready(unsigned local, unsigned remote, atransport *t)
{
    D("Calling send_ready \n");
    apacket *p = get_apacket();
    p->msg.command = A_OKAY;
    p->msg.arg0 = local;
    p->msg.arg1 = remote;
    send_packet(p, t);
}

这样,表示HOST端发送的A_OPEN命令成功了,DEVICE端的output_thread接收到以后,

    case A_OKAY: /* READY(local-id, remote-id, "") */
        if(t->connection_state != CS_OFFLINE) {
            if((s = find_local_socket(p->msg.arg1))) {
                if(s->peer == 0) {
                    s->peer = create_remote_socket(p->msg.arg0, t);
                    s->peer->peer = s;
                }
                s->ready(s);
            }
        }
        break;

根据id,找回local socket,同时创建remote socket。

前面看到,DEVICE端创建好local socket和remote socket之后,除了往HOST发一个OKAY,还调用

      s->ready(s);

这里的s是local jdwp service socket,来看它的ready函数jdwp_socket_ready

        apacket*  p = get_apacket();
        p->len = jdwp_process_list((char*)p->data, MAX_PAYLOAD);
        peer->enqueue(peer, p);
        jdwp->pass = 1;

将jdwp服务中的进程号,写入packet,调用remote socket的enqueue,也就是remote_socket_enqueue

static int remote_socket_enqueue(asocket *s, apacket *p)
{
    D("Calling remote_socket_enqueue\n");
    p->msg.command = A_WRTE;
    p->msg.arg0 = s->peer->id;
    p->msg.arg1 = s->id;
    p->msg.data_length = p->len;
    send_packet(p, s->transport);
    return 1;
}

它进程信息,写入transport,HOST的output_thread收到以后

    case A_WRTE:                                                              
        if(t->connection_state != CS_OFFLINE) {                               
            if((s = find_local_socket(p->msg.arg1))) {                        
                unsigned rid = p->msg.arg0;                                   
                p->len = p->msg.data_length;                                  
                                                                              
                if(s->enqueue(s, p) == 0) {                                   
                    D("Enqueue the socket\n");                                
                    send_ready(s->id, rid, t);                                
                }                                                             
                return;                                                       
            }                                                                 
        }                                                                     
        break;    
它调用local socket的enqueue函数local_socket_enqueue,在local_socket_enqueue里面,调用

        int r = adb_write(s->fd, p->ptr, p->len);
写入端口5037,这样,client就能看到jdwp的进程信息了。就像下面这样。

[yinlijun@localhost adb]$ adb jdwp
228
277
111
176
185
188
180
208
212
330
339
351
361
370
378
407
416
427
438
446
455
因此,流程应该大致如图所示,具体的步骤太复杂,只能粗略表示一下。












  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值