Android开发工具—ADB(Android Debug Bridge) 4 - Device端

转自http://blog.csdn.net/yinlijun2004/article/details/7031443

  这篇博客梳理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请求,数据包内容如下

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

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

[cpp]  view plain copy
  1. if(!strcmp(type, "device")) {  
  2.     D("setting connection_state to CS_DEVICE\n");  
  3.     t->connection_state = CS_DEVICE;  
  4.     update_transports();  
  5.     return;  
  6. }  
          update_transports供client发送adb track-devices命令时有用。

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

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

[cpp]  view plain copy
  1. if (!strcmp(argv[0], "jdwp")) {  
  2.     int  fd = adb_connect("jdwp");  
  3.     if (fd >= 0) {  
  4.         read_and_dump(fd);  
  5.         adb_close(fd);  
  6.         return 0;  
  7.     } else {  
  8.         fprintf(stderr, "error: %s\n", adb_error());  
  9.         return -1;  
  10.     }  
  11. }  

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

[cpp]  view plain copy
  1. int fd = _adb_connect("host:version");  

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

[cpp]  view plain copy
  1. if (memcmp(service,"host",4) != 0 && switch_socket_transport(fd)) {  
  2.     return -1;  
  3. }  

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

[cpp]  view plain copy
  1. if(writex(fd, tmp, 4) || writex(fd, service, len)) {  
  2.     strcpy(__adb_error, "write failure during connection");  
  3.     adb_close(fd);  
  4.     return -1;  
  5. }  

等待返回一个“OKAY”

[cpp]  view plain copy
  1. if(adb_status(fd)) {  
  2.     adb_close(fd);  
  3.     return -1;  
  4. }  
在里面判断返回结果是否为“OK”
[cpp]  view plain copy
  1. int adb_status(int fd)  
  2. {  
  3.     unsigned char buf[5];  
  4.     unsigned len;  
  5.   
  6.     if(!memcmp(buf, "OKAY", 4)) {  
  7.         return 0;  
  8.     }  
  9. }  

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”

[cpp]  view plain copy
  1. transport = acquire_one_transport(CS_ANY, type, serial, &error_string);  
  2.   
  3. if (transport) {  
  4.     s->transport = transport;  
  5.     adb_write(reply_fd, "OKAY", 4);  
  6. else {  
  7.     sendfailmsg(reply_fd, error_string);  
  8. }  

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

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

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

[cpp]  view plain copy
  1. s->peer->ready = local_socket_ready_notify;  
  2. s->peer->close = local_socket_close_notify;  
  3. s->peer->peer = 0;  
  4.     /* give him our transport and upref it */  
  5. s->peer->transport = s->transport;  
  6.   
  7. connect_to_remote(s->peer, (char*) (p->data + 4));  
  8. s->peer = 0;  
  9. s->close(s);  

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

[cpp]  view plain copy
  1. p->msg.command = A_OPEN;  
  2. p->msg.arg0 = s->id;  
  3. p->msg.data_length = len;  
  4. strcpy((char*) p->data, destination);  
  5. send_packet(p, s->transport);  

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

[cpp]  view plain copy
  1. void install_local_socket(asocket *s)  
  2. {  
  3.     adb_mutex_lock(&socket_list_lock);  
  4.   
  5.     s->id = local_socket_next_id++;  
  6.     insert_local_socket(s, &local_socket_list);  
  7.   
  8.     adb_mutex_unlock(&socket_list_lock);  
  9. }  
在DEVICE端的output_thread线程,读取到消息,写到transport_socket里面去

[cpp]  view plain copy
  1. for(;;) {  
  2.     p = get_apacket();  
  3.   
  4.     if(t->read_from_remote(p, t) == 0){  
  5.         D("from_remote: received remote packet, sending to transport %p\n",  
  6.           t);  
  7.         if(write_packet(t->fd, &p)){  
  8.             put_apacket(p);  
  9.             D("from_remote: failed to write apacket to transport %p", t);  
  10.             goto oops;  
  11.         }  
  12.     } else {  
  13.         D("from_remote: remote read failed for transport %p\n", p);  
  14.         put_apacket(p);  
  15.         break;  
  16.     }  
  17. }  
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,回调:

[cpp]  view plain copy
  1. s->socket.ready   = jdwp_socket_ready;  
  2. s->socket.enqueue = jdwp_socket_enqueue;  
  3. s->socket.close   = jdwp_socket_close;  
  4. s->pass           = 0;   

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

[cpp]  view plain copy
  1. s->id = id;  
  2. s->enqueue = remote_socket_enqueue;  
  3. s->ready = remote_socket_ready;  
  4. s->close = remote_socket_close;  
  5. s->transport = t;  

然后调用    

[cpp]  view plain copy
  1.                 send_ready(s->id, s->peer->id, t);  
  2.                 s->ready(s);  

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

[cpp]  view plain copy
  1. static void send_ready(unsigned local, unsigned remote, atransport *t)  
  2. {  
  3.     D("Calling send_ready \n");  
  4.     apacket *p = get_apacket();  
  5.     p->msg.command = A_OKAY;  
  6.     p->msg.arg0 = local;  
  7.     p->msg.arg1 = remote;  
  8.     send_packet(p, t);  
  9. }  

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

[cpp]  view plain copy
  1. case A_OKAY: /* READY(local-id, remote-id, "") */  
  2.     if(t->connection_state != CS_OFFLINE) {  
  3.         if((s = find_local_socket(p->msg.arg1))) {  
  4.             if(s->peer == 0) {  
  5.                 s->peer = create_remote_socket(p->msg.arg0, t);  
  6.                 s->peer->peer = s;  
  7.             }  
  8.             s->ready(s);  
  9.         }  
  10.     }  
  11.     break;  

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

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

[cpp]  view plain copy
  1. s->ready(s);  

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

[cpp]  view plain copy
  1. apacket*  p = get_apacket();  
  2. p->len = jdwp_process_list((char*)p->data, MAX_PAYLOAD);  
  3. peer->enqueue(peer, p);  
  4. jdwp->pass = 1;  

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

[cpp]  view plain copy
  1. static int remote_socket_enqueue(asocket *s, apacket *p)  
  2. {  
  3.     D("Calling remote_socket_enqueue\n");  
  4.     p->msg.command = A_WRTE;  
  5.     p->msg.arg0 = s->peer->id;  
  6.     p->msg.arg1 = s->id;  
  7.     p->msg.data_length = p->len;  
  8.     send_packet(p, s->transport);  
  9.     return 1;  
  10. }  

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

[cpp]  view plain copy
  1. case A_WRTE:                                                                
  2.     if(t->connection_state != CS_OFFLINE) {                                 
  3.         if((s = find_local_socket(p->msg.arg1))) {                          
  4.             unsigned rid = p->msg.arg0;                                     
  5.             p->len = p->msg.data_length;                                    
  6.                                                                             
  7.             if(s->enqueue(s, p) == 0) {                                     
  8.                 D("Enqueue the socket\n");                                  
  9.                 send_ready(s->id, rid, t);                                  
  10.             }                                                               
  11.             return;                                                         
  12.         }                                                                   
  13.     }                                                                       
  14.     break;      
它调用local socket的enqueue函数local_socket_enqueue,在local_socket_enqueue里面,调用

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

[cpp]  view plain copy
  1. [yinlijun@localhost adb]$ adb jdwp  
  2. 228  
  3. 277  
  4. 111  
  5. 176  
  6. 185  
  7. 188  
  8. 180  
  9. 208  
  10. 212  
  11. 330  
  12. 339  
  13. 351  
  14. 361  
  15. 370  
  16. 378  
  17. 407  
  18. 416  
  19. 427  
  20. 438  
  21. 446  
  22. 455  
因此,流程应该大致如图所示,具体的步骤太复杂,只能粗略表示一下。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值