本文为大家梳理Device端adbd的运作原理。在此之前最好是已经看了前三篇文章:ADB概论HOST端Dalvik虚拟机之jdwp线程

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

  先看HOST和DEVICE的连接过程。

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

C++代码
  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请求后,解析。

C++代码
  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端的。

C++代码
  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”之前,先调用:

C++代码
  1. int fd = _adb_connect("host:version");  

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

C++代码
  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端口。

C++代码
  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”。

C++代码
  1. if(adb_status(fd)) {   
  2.     adb_close(fd);   
  3.     return -1;   
  4. }  

       在里面判断返回结果是否为“OK”。

C++代码
  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”。

C++代码
  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函数,执行下面语句:

C++代码
  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继续执行下面语句,

C++代码
  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

C++代码
  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进行处理。

C++代码
  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里面去。

C++代码
  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,回调:

C++代码
  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。

C++代码
  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;  

       然后调用:

C++代码
  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。

C++代码
  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接收到以后,

C++代码
  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,还调用

C++代码
  1. s->ready(s);  

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

C++代码
  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:

C++代码
  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收到以后

C++代码
  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里面,调用

C++代码
  1. int r = adb_write(s->fd, p->ptr, p->len);  

       写入端口5037,这样,client就能看到jdwp的进程信息了。就像下面这样。

C++代码
  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  

       因此,流程应该大致如图所示,具体的步骤太复杂,只能粗略表示一下。

Android开发工具ADB教程之四:Device端

本文发布:Android开发网
本文地址:http://www.jizhuomi.com/android/environment/226.html
2012年10月7日
发布:鸡啄米 分类:Android开发环境 浏览: 评论:0