Android开发工具——ADB(Android Debug Bridge)

来源:互联网 发布:联通怎么重置手机网络 编辑:程序博客网 时间:2024/04/27 16:02

http://blog.csdn.net/yinlijun2004/article/details/7008952


        Android Debug Bridge (adb) 是一个android开发人员必会的多功能的调试工具,确实它的名字一样,它在开发者和目标机器之间,架起了一座bridge。

        adb的用法很简单,只要看完SDK文档关于ADB的部分,(android-sdk-linux_86/docs/guide/developing/tools/adb.html),再稍加练习,基本上就满上就能很熟练的使用了。但是对它的实现感兴趣,最好的途径就是阅读源代码,它android 2.2的位置是:

[plain] view plaincopy
  1. system/core/adb  
        adb是slient-server架构的,包含三个部分,

1、 client,运行于开发机器,你可以在shell中调用adb命令,其它的Android工具比如ADT插件和DDMS也包含adb client。

2、 server,作为后台进程同样运行于开发机器,server负责管理client和运行于目标机器或者emulator的守护进程之间的通信,就像一座桥一样。

3、 daemon,运行于目标机或者emulator的守护进程。

       上面这段话是SDK里面翻译过来的,我是看adb的代码看的有点迷糊,才去看sdk的,再返回来看代码的时候思路清晰很多。

        adb的功能强大,而且支持多平台,但是它的代码却非常精简,只有1.5万行左右,代价就是比较晦涩难懂(看懂以前),代码里面随处可见的各种宏让人眼花缭乱,其中一个重要的宏ADB_HOST,是用来区分本地主机和目标机器的。

client和server调用的是adb

[cpp] view plaincopy
  1. LOCAL_CFLAGS += -O2 -g -DADB_HOST=1  -Wall -Wno-unused-parameter  
  2. LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE -DSH_HISTORY  
  3. LOCAL_MODULE := adb  

而emulator/device调用adbd

[cpp] view plaincopy
  1. LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -Wall -Wno-unused-parameter  
  2. LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE  
  3. LOCAL_MODULE := adbd  

1、 在HOST端,adb会fork出一个守护进程(不是adbd),即server,而父进程继续处理client请求,所有的client通过TCP端口号5037进行与server通信,而server创建local socket与remote socket,前者用于和client通信,后者用与远端进行通信,emulator通过TCP,real device则通过usb。

2、在emulator/device端,adbd也创建local socket和remote socket,前者与通过jdwp与Java虚拟机进层通信,后者通过TCP/USB与HOST通信。

因此整个流程应该是这样的,

1、client调用某个adb命令

2、adb进程fork出一个子进程作为server

3、server查找当前连接的emulator/device

4、server接收到来自client请求

5、server处理请求,将本地处理不了的请求发给emulator/device

6、位于emulator/device的adbd拿到请求后交给对应的java虚拟机进程。

7、adbd将结果发回给server

8、server讲结果发回给client

如下图:

                               ___________________________________
                               |                                                                                |
                               |                          ADB Server (host)                      |
                               |                                                                                 |
        Debugger <---> LocalSocket <-------------> RemoteSocket   |
                               |                                                              ^^                |
                               |___________________________||_______|
                                                                                               ||
                                                                            Transport ||
                              (TCP for emulator - USB for device) ||
                                                                                               ||
                                ___________________________||_______
                                |                                                              ||                |
                                |                                ADBD  (device)   ||                |
                                |                                                             VV               |
         JDWP <======> LocalSocket <------------> RemoteSocket |
                                |                                                                                 |
                                |___________________________________|



 <二>HOST端

         我分析代码的喜欢从main函数开始,因为还不知道代码结构的情况下,这是最直接的方法。所以先看adb.c的main函数

[cpp] view plaincopy
  1. int main(int argc, char **argv)  
  2. {  
  3.     adb_trace_init();  
  4. #if ADB_HOST  
  5.     adb_sysdeps_init();  
  6.     return adb_commandline(argc - 1, argv + 1);  
  7. #else  
  8.     if((argc > 1) && (!strcmp(argv[1],"recovery"))) {  
  9.         adb_device_banner = "recovery";  
  10.         recovery_mode = 1;  
  11.     }  
  12.   
  13.     start_device_log();  
  14.     return adb_main(0);  
  15. #endif  
  16. }  

宏ADB_HOST用来区别编译adb和adbd,参见上一篇博客http://blog.csdn.net/yinlijun2004/article/details/7008952。

现在用一个常用命令“adb devices”用来捋顺代码流程,adb_trace_init用于log tag初始化,在host端,输入命令"adb devices"之后,进入adb_commandline函数。

adb_commandline首先解析参数,判断有没有指定transport type,即指定与哪个设备通信,emulator 或者 device,指定设备的方法是

[cpp] view plaincopy
  1. -d  
  2. -e  
  3. -s <serial number>   

然后调用adb_set_transport将type,serial赋值给全局变量,

[cpp] view plaincopy
  1.  void adb_set_transport(transport_type type, const char* serial)  
  2. {  
  3.     __adb_transport = type;  
  4.     __adb_serial = serial;  
  5. }  

这两个全局变量由client保存,将用来告诉server,与何种设备通信,用何种方式传输通信。

接下来,adb_commandline用来判断server守护进程是否已经启动,

[cpp] view plaincopy
  1. if ((argc > 0) && (!strcmp(argv[0],"server"))) {  
  2.     if (no_daemon || is_daemon) {  
  3.         r = adb_main(is_daemon);  
  4.     } else {  
  5.         r = launch_server();  
  6.     }  
  7.     if(r) {  
  8.         fprintf(stderr,"* could not start server *\n");  
  9.     }  
  10.     return r;  
  11. }  
no_daemon和is_daemon初始化为0,当读到nodaemon参数时,no_daemon为1,这种情况用户显式的不用server进行通信;读到fork-server时is_daemon为1,这是标识当前进程已经是server进程。adb_main函数的is_daemon参数是用来决定是否回送一个应答“OK”给client的。

在这里我们的client第一次执行“adb device”,因此会去启动server,在launch_server中,执行fork()操作,生成一对管道用于父子进程的通信。子进程调用execl,执行adb fork-server server,父进程等待来自子进程的OK应答。

[cpp] view plaincopy
  1. // child side of the fork  
  2.   
  3.  // redirect stderr to the pipe  
  4.  // we use stderr instead of stdout due to stdout's buffering behavior.  
  5.  adb_close(fd[0]);  
  6.  dup2(fd[1], STDERR_FILENO);  
  7.  adb_close(fd[1]);  
  8.   
  9.  // child process  
  10.  int result = execl(path, "adb""fork-server""server", NULL);  
  11.  // this should not return  
  12.  fprintf(stderr, "OOPS! execl returned %d, errno: %d\n", result, errno);  

这里子进程将STDERR_FILENO重定向到管道的写端fd[1];然后讲管道关闭,这样所有对stderr的操作都将写入父进程,fprintf语句只有在execl执行失败时执行。

[cpp] view plaincopy
  1. // parent side of the fork  
  2.   
  3. char  temp[3];  
  4.   
  5. temp[0] = 'A'; temp[1] = 'B'; temp[2] = 'C';  
  6. // wait for the "OK\n" message  
  7. adb_close(fd[1]);  
  8. int ret = adb_read(fd[0], temp, 3);  
  9. adb_close(fd[0]);  
  10. if (ret < 0) {  
  11.     fprintf(stderr, "could not read ok from ADB Server, errno = %d\n", errno);  
  12.     return -1;  
  13. }  
  14. if (ret != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {  
  15.     fprintf(stderr, "ADB server didn't ACK\n" );  
  16.     return -1;  
  17. }  
  18.   
  19. setsid();  

父进程从管道的读端读取子进程发过来的应答,如果非“OK”,代表创建server失败,返回,setsid用于避免父进程退出时子进程也退出,即server真正成为一个守护进程。

花开两朵各表一只,先看fork出来的子进程,即守护进程server,前面说到,它的启动command是adb fork-server server,我们在回到adb的main函数,它用走到了adb_commandline里面来,这时候它解析参数以后,is_daemon就变成1了,因此执行adb_daemon(is_daemon)。 

[cpp] view plaincopy
  1. init_transport_registration();  
  2.   
  3.   
  4. ADB_HOST  
  5. HOST = 1;  
  6. usb_vendors_init();  
  7. usb_init();  
  8. local_init(ADB_LOCAL_TRANSPORT_PORT);  
  9.   
  10. if(install_listener("tcp:5037""*smartsocket*", NULL)) {  
  11.     exit(1);  
  12. }  
  13. e  


adb_daemon首先初始化transport registrantion,等待注册transport时间的到来,transport是用来与远端设备进行通信的,对HOST来说远端设备就是device/emulator,反之亦然。注册信息本身,是用通过一个socket对transport_registration_send,transport_registration_recv来传递的,这属于线程之间的通信。

首先初始化本地USB,监听本地usb的情况,如果有用于ADB的USB设备,则注册一个type为kTransportUsb的transport,

具体调用流程:usb_init->client_socket_thread出一个device_poll_thread线程,在device_poll_thread中:

[cpp] view plaincopy
  1. for (;;) {   
  2.     sleep(5);  
  3.     kick_disconnected();  
  4.     scan_usb_devices();  
  5. }  
通过scan_usb_devices查找用于adb的usb设备

scan_usb_devices->check_device->register_device->register_usb_transport->init_usb_transport->register_transport

在init_usb_transport中,

[cpp] view plaincopy
  1. void init_usb_transport(atransport *t, usb_handle *h, int state)  
  2. {     
  3.     D("transport: usb\n");  
  4.     t->close = remote_close;  
  5.     t->kick = remote_kick;  
  6.     t->read_from_remote = remote_read;  
  7.     t->write_to_remote = remote_write;  
  8.     t->sync_token = 1;  
  9.     t->connection_state = state;  
  10.     t->type = kTransportUsb;  
  11.     t->usb = h;  
  12.   
  13. #if ADB_HOST  
  14.     HOST = 1;  
  15. #else  
  16.     HOST = 0;  
  17. #endif    
  18. }            
可以看到,不管在host端,还是在device端,都会去注册usb的transport


接着然后试图连接5555-55585之间的端口,这个时候如果已经有emulator在运行,即调用socket_network_client成功,则注册一个type为kTransportLocal的transport,

调用流程:local_init->adb_thread_create出一个client_socket_thread线程,在client_socket_thread中,尝试连接5555-55585的本地端口

client_socket_thread->socket_loopback_client

如果socket_loopback_client返回值大于0,说明已连接上emulator,

则调用:register_socket_transport->init_socket_transport->register_transport

在init_socket_transport中

[cpp] view plaincopy
  1. int init_socket_transport(atransport *t, int s, int port, int local)  
  2. {         
  3.     int  fail = 0;  
  4.   
  5.     t->kick = remote_kick;  
  6.     t->close = remote_close;  
  7.     t->read_from_remote = remote_read;  
  8.     t->write_to_remote = remote_write;  
  9.     t->sfd = s;  
  10.     t->sync_token = 1;  
  11.     t->connection_state = CS_OFFLINE;  
  12.     t->type = kTransportLocal;  
  13.           
  14. #if ADB_HOST  
  15.     if (HOST && local) {  
  16.         adb_mutex_lock( &local_transports_lock );  
  17.         {   
  18.             int  index = (port - ADB_LOCAL_TRANSPORT_PORT)/2;  
  19.       
  20.             if (!(port & 1) || index < 0 || index >= ADB_LOCAL_TRANSPORT_MAX) {  
  21.                 D("bad local transport port number: %d\n", port);  
  22.                 fail = -1;  
  23.             }  
  24.             else if (local_transports[index] != NULL) {  
  25.                 D("local transport for port %d already registered (%p)?\n",  
  26.                 port, local_transports[index]);  
  27.                 fail = -1;  
  28.             }  
  29.             else  
  30.                 local_transports[index] = t;  
  31.         }  
  32.         adb_mutex_unlock( &local_transports_lock );  
  33.     }  
  34. #endif  
  35.     return fail;  
  36. }  

注意看ADB_HOST里面的东西,如果是在HOST端,则将transport添加到列表里面,因为adb device就是从这个列表里面读信息的。

再看register_transport,它将transport信息,一个tmsp的结构体,写入transport_registration_send

[cpp] view plaincopy
  1. struct tmsg   
  2. {  
  3.     atransport *transport;  
  4.     int         action;  
  5. };    

action为0表示移除该transport,1表示添加。

则接收端的描述符transport_registration_recv会收到对应的信息,它的处理回调函数是transport_registration_func,在transport_registration_func中,首先读取出待注册的transport的地址,在这里创建套接字对,一个是fd,负责从远端读入,或者写入远端。transport_socket负责跟本地(emulator或者device)交互,同时启动两个线程output_thread,调用read_from_remote从远端读入,还有input_thread,调用write_to_remote写入远端。

以output_thread为例,

[cpp] view plaincopy
  1. p = get_apacket();  
  2. p->msg.command = A_SYNC;                                                    
  3. p->msg.arg0 = 1;  
  4. p->msg.arg1 = ++(t->sync_token);  
  5. p->msg.magic = A_SYNC ^ 0xffffffff;                                         
  6. if(write_packet(t->fd, &p)) {                                               
  7.     put_apacket(p);  
  8.     D("from_remote: failed to write SYNC apacket to transport %p", t);      
  9.     goto oops;                                                              
  10. }      

首先向fd写入一个包含A_SYNC命令的信息包,用于同步,transport_socket的处理回调函数transport_socket_events会执行,继而调用handle_packet处理信息包

[cpp] view plaincopy
  1. case A_SYNC:                                                                
  2.     if(p->msg.arg0){                                                        
  3.         send_packet(p, t);                                                  
  4.         if(HOST) send_connect(t);                                           
  5.     } else {                                                                
  6.         t->connection_state = CS_OFFLINE;                                   
  7.         handle_offline(t);                                                  
  8.         send_packet(p, t);                                                  
  9.     }                                                                       
  10.     return;      

handle_packet判断是A_SYNC同步命令,则同时将信息包发送给远端,并发送一个连接请求给远端,里面包含adb版本,最大载荷等信息。send_package讲信息包写回给transport_socket。

回过头来output_thread线程回收到这些信息包,并将这些包写入远端。


写的太深入了,回到adb_main函数,初始化完可能USB和emulator的transport之后,执行下面这段代码

[cpp] view plaincopy
  1. if(install_listener("tcp:5037""*smartsocket*", NULL)) {  
  2.     exit(1);  
  3. }  

listener是一个很重要的概念,它绑定到一个本地端口,即local socket,负责与client通信(稍候将看到),并且创建一个连接到远端的remote socket,smartsocket是一个特殊的socket,它其实类似一个接线员的角色,它分析后看你要连接到哪个remote socket,然后帮你连上。注意这里的第三个参数NULL,因为接线员还来不及分析你的adb命令参数,不知道你要往哪个remote上连,所以这里为NULL,等分析好了,确定要连接那个remote socket,smartsocket的任务也完成了。

[cpp] view plaincopy
  1. struct alistener  
  2. {  
  3.     alistener *next;  
  4.     alistener *prev;  
  5.   
  6.     fdevent fde;  
  7.     int fd;  
  8.   
  9.     const char *local_name;  
  10.     const char *connect_to;  
  11.     atransport *transport;  
  12.     adisconnect  disconnect;  
  13. };  
在install_listener里面

[cpp] view plaincopy
  1. l->fd = local_name_to_fd(local_name);  
  2. close_on_exec(l->fd);  
  3. if(!strcmp(l->connect_to, "*smartsocket*")) {  
  4.     fdevent_install(&l->fde, l->fd, ss_listener_event_func, l);  
  5. }   
这样,client来消息的时候,就可以调用ss_listener_event_func进行处理了。

接下来,adb_main执行下面代码,

[cpp] view plaincopy
  1. if (is_daemon)  
  2. {  
  3.     // inform our parent that we are up and running.  
  4. f defined(HAVE_FORKEXEC)  
  5.     fprintf(stderr, "OK\n");  
  6. if  
  7.     start_logging();  
  8. }  
这段代码,告诉父进程adb server已经跑起来了,因此,往stderr里面写一个OK,还记得刚刚server已经将stderr重定向到fd[1]了,所以父进程能接收到这个OK消息。

接下来,server调用fdevent_loop进入事件循环。

[cpp] view plaincopy
  1. for(;;) {  
  2.     fdevent_process();  
  3.   
  4.     while((fde = fdevent_plist_dequeue())) {  
  5.         unsigned events = fde->events;  
  6.         fde->events = 0;  
  7.         fde->state &= (~FDE_PENDING);  
  8.         dump_fde(fde, "callback");  
  9.         fde->func(fde->fd, events, fde->arg);  
  10.     }  
  11. }  
因此adb是事件驱动型,所有的事件调用fdevent_register进行注册,该函数讲事件保存到全局事件数组fd_table里面,

[cpp] view plaincopy
  1. struct fdevent  
  2. {  
  3.     fdevent *next;  
  4.     fdevent *prev;  
  5.   
  6.     int fd;  
  7.     unsigned short state;  
  8.     unsigned short events;  
  9.   
  10.     fd_func func;  
  11.     void *arg;  
  12. };  

如果有相关事件的到达则调用fun进行处理。


adb_main,即server已经启动完成,再回到client的adb_commandline函数,我们继续adb device命令的解析,

[cpp] view plaincopy
  1. if(!strcmp(argv[0], "devices")) {  
  2.     char *tmp;  
  3.     snprintf(buf, sizeof buf, "host:%s", argv[0]);  
  4.     tmp = adb_query(buf);  
  5.     if(tmp) {  
  6.         printf("List of devices attached \n");  
  7.         printf("%s\n", tmp);  
  8.         return 0;  
  9.     } else {  
  10.         return 1;  
  11.     }  
  12. }  

它调用adb_query函数,参数是"host:devices“,它表示需要发往server的请求,这些请求分两种query型和command型,分别调用adb_query和adb_command

[cpp] view plaincopy
  1. char *adb_query(const char *service)  
  2. {         
  3.     char buf[5];  
  4.     unsigned n;  
  5.     char *tmp;  
  6.   
  7.     D("adb_query: %s\n", service);   
  8.     int fd = adb_connect(service);  
  9.   
  10.     if(readx(fd, buf, 4)) goto oops;  
  11.   
  12.     if(readx(fd, tmp, n) == 0) {  
  13.   
  14.     }  
  15. }  

可以看到,它连接到server,返回一个描述符,然后直接从该描述符里面读取结果就可以了。看起来很简单,adb_connect把下面很复杂的东西都包装起来了。

adb_connect包装了_adb_connect函数,包装了一些adb server是否已经成功启动,查询adb server版本信息的工作,在_adb_connect中

调用socket_loopback_client(ADB_PORT, SOCK_STREAM);尝试连接ADB_PORT,也就是5037,记住刚才adb server已经调用socket_loopback_server(port, SOCK_STREAM);这样,client和service之间就可以开始通信了。请求信息“host:devices”将写入adb server,来看adb server的处理函数ss_listener_event_func

ss_listener_event_func创建一个local socket读取该信息,

[cpp] view plaincopy
  1. fd = adb_socket_accept(_fd, &addr, &alen);  
  2. if(fd < 0) return;  
  3.   
  4. adb_socket_setbufsize(fd, CHUNK_SIZE);  
  5.   
  6. s = create_local_socket(fd);  
  7. if(s) {  
  8.     connect_to_smartsocket(s);  
  9.     return;  
  10. }  

先看create_local_socket,这个socket负责与client通信,回调处理函数是local_socket_event_func。

[cpp] view plaincopy
  1. asocket *create_local_socket(int fd)  
  2. {         
  3.     asocket *s = calloc(1, sizeof(asocket));  
  4.     if(s == 0) fatal("cannot allocate socket");  
  5.     install_local_socket(s);  
  6.     s->fd = fd;  
  7.     s->enqueue = local_socket_enqueue;  
  8.     s->ready = local_socket_ready;  
  9.     s->close = local_socket_close;  
  10.           
  11.     fdevent_install(&s->fde, fd, local_socket_event_func, s);  
  12.     return s;  
  13. }  

也就是由local_socket_event_func来读取“host:devices”串,然后调用s->peer->enqueue(s->peer, p);交给对断处理。

那local socket的对端是谁,看connect_to_smartsocket

[cpp] view plaincopy
  1. void connect_to_smartsocket(asocket *s)  
  2. {  
  3.     D("Connecting to smart socket \n");  
  4.     asocket *ss = create_smart_socket(smart_socket_action);  
  5.     s->peer = ss;  
  6.     ss->peer = s;  
  7.     s->ready(s);  
  8. }  

这里明白了local socket的对端就是smart socket(remote socket的一种),与local socket交互。

[cpp] view plaincopy
  1. asocket *create_smart_socket(void (*action_cb)(asocket *s, const char *act))  
  2. {         
  3.     asocket *s = calloc(1, sizeof(asocket));  
  4.     if(s == 0) fatal("cannot allocate socket");  
  5.     s->id = 0;  
  6.     s->enqueue = smart_socket_enqueue;  
  7.     s->ready = smart_socket_ready;  
  8.     s->close = smart_socket_close;  
  9.     s->extra = action_cb;  
  10.   
  11.     return s;   
  12. }     


这两个socket结对以后,调用local socket的ready回调函数,也就是local_socket_ready

[cpp] view plaincopy
  1. static void local_socket_ready(asocket *s)  
  2. {  
  3.     fdevent_add(&s->fde, FDE_READ);  
  4. }  
意思是说,我(local socket)已经准备好接收你smart socket发过来的数据了。

那local socket调用的s->peer->enqueue(s->peer, p);就是smart_socket_enqueue

在smart_socket_enqueue中,将刚刚读取到的package插入到package列表中,然后解析service,即发过来的“host:devices”

[cpp] view plaincopy
  1. #if ADB_HOST  
  2.     service = (char *)p->data + 4;  
  3.     if(!strncmp(service, "host-serial:", strlen("host-serial:"))) {  
  4.         char* serial_end;  
  5.         service += strlen("host-serial:");  
  6.   
  7.         // serial number should follow "host:"  
  8.         serial_end = strchr(service, ':');  
  9.         if (serial_end) {  
  10.             *serial_end = 0; // terminate string  
  11.             serial = service;  
  12.             service = serial_end + 1;  
  13.         }  
  14.     } else if (!strncmp(service, "host-usb:", strlen("host-usb:"))) {  
  15.         ttype = kTransportUsb;  
  16.         service += strlen("host-usb:");  
  17.     } else if (!strncmp(service, "host-local:", strlen("host-local:"))) {  
  18.         ttype = kTransportLocal;  
  19.         service += strlen("host-local:");  
  20.     } else if (!strncmp(service, "host:", strlen("host:"))) {  
  21.         ttype = kTransportAny;  
  22.         service += strlen("host:");  
  23.     } else {  
  24.         service = NULL;  
  25.     }  
这里将client发过来的请求,跟去前缀转化为各种transport type,接着解析具体的service名称,接着,调用handle_host_request处理一些可以立即响应的消息,然后直接返回(adb devices请求就是属于这一种),,否则调用create_host_service_socket创建另外一个service socket作为local service的对段,而smart socket就没什么事了,可以关闭了,如下代码。

[cpp] view plaincopy
  1. s2 = create_host_service_socket(service, serial);  
  2. if(s2 == 0) {  
  3.     D( "SS(%d): couldn't create host service '%s'\n", s->id, service );  
  4.     sendfailmsg(s->peer->fd, "unknown host service");  
  5.     goto fail;  
  6. }  
  7.   
  8. adb_write(s->peer->fd, "OKAY", 4);  
  9.   
  10. s->peer->ready = local_socket_ready;  
  11. s->peer->close = local_socket_close;  
  12. s->peer->peer = s2;  
  13. s2->peer = s->peer;  
  14. s->peer = 0;  
  15. D( "SS(%d): okay\n", s->id );  
  16. s->close(s);  

先来看可以用handle_host_request的部分,处理devices部分请求的代码如下

[cpp] view plaincopy
  1. // return a list of all connected devices  
  2. if (!strcmp(service, "devices")) {  
  3.     char buffer[4096];  
  4.     memset(buf, 0, sizeof(buf));  
  5.     memset(buffer, 0, sizeof(buffer));  
  6.     D("Getting device list \n");  
  7.     list_transports(buffer, sizeof(buffer));  
  8.     snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer),buffer);  
  9.     D("Wrote device list \n");  
  10.     writex(reply_fd, buf, strlen(buf));  
  11.     return 0;  
  12. }  

它讲transport列表里面的信息读取出来,然后写入reply_fd里面,其实这里猜也猜到了,它就是local socket的fd,也就是将信息写入port5037里面,这样我们的client端就能将当前连接的设备信息打印到屏幕上了。

整个过程的如下,

                               ___________________________________
                               |                                                                                |
                               |                          ADB Server (host)                      |
                               |                                                                                 |
        Client   <-------> LocalSocket <-------------> RemoteSocket   |
                               |                                                              ^^                |
                               |___________________________||_______|
                                                                                               ||



<三>DalvikVM之jdwp线程

jdwp(java debug wire protocol)是dalvik VM的一个线程,可以建立在adb或者tcp基础上,与DDMS或debugger进行通信。

代码位置

dalvik/vm/jdwp

frameworks/base/core/jni

java虚拟机初始化后,或者每次“zygote fork”出一个新进程时,会启动jdwp线程。关于虚拟机的初始化参考我的博客http://blog.csdn.net/yinlijun2004/article/details/6065979

主要调用路径:dvmStartup->dvmInitAfterZygote->dvmInitJDWP

dvmInitJDWP线程启动之前会可能会阻塞VM,依赖于配置suspend=n,所以dvmInitJDWP放在dvmStartup的最后步骤来执行。
dvmInitJDWP首先判断jdwp是否允许并且已经配置好,如果是,则读取jdwp的配置,这些配置是AndroidRuntime::startVm中配置的,
[cpp] view plaincopy
  1.     /* enable debugging; set suspend=y to pause during VM init */  
  2. #ifdef HAVE_ANDROID_OS  
  3.     /* use android ADB transport */  
  4.     opt.optionString =  
  5.         "-agentlib:jdwp=transport=dt_android_adb,suspend=n,server=y";  
  6. #else  
  7.     /* use TCP socket; address=0 means start at port 8000 and probe up */  
  8.     LOGI("Using TCP socket for JDWP\n");  
  9.     opt.optionString =  
  10.         "-agentlib:jdwp=transport=dt_socket,suspend=n,server=y,address=0";  
  11. #endif  


这些配置保存在虚拟机全局变量gDvm中,gDvm是DvmGlobals变量,需要读取的配置包括transport,负责与ADB或TCP交换数据,
[cpp] view plaincopy
  1. if (gDvm.jdwpAllowed && gDvm.jdwpConfigured) {  
  2.     JdwpStartupParams params;  
  3.   
  4.   
  5.     if (gDvm.jdwpHost != NULL) {  
  6.         if (strlen(gDvm.jdwpHost) >= sizeof(params.host)-1) {  
  7.             LOGE("ERROR: hostname too long: '%s'\n", gDvm.jdwpHost);  
  8.             return false;  
  9.         }  
  10.         strcpy(params.host, gDvm.jdwpHost);  
  11.     } else {  
  12.         params.host[0] = '\0';  
  13.     }  
  14.     params.transport = gDvm.jdwpTransport;  
  15.     params.server = gDvm.jdwpServer;  
  16.     params.suspend = gDvm.jdwpSuspend;  
  17.     params.port = gDvm.jdwpPort;  
  18.   
  19.   
  20.     gDvm.jdwpState = dvmJdwpStartup(&params);  
  21.     if (gDvm.jdwpState == NULL) {  
  22.         LOGW("WARNING: debugger thread failed to initialize\n");  
  23.         /* TODO: ignore? fail? need to mimic "expected" behavior */  
  24.     }  
  25. }  


其中gDvm.jdwpAllowed在dalvik_system_Zygote.c中配置
        gDvm.jdwpAllowed = ((debugFlags & DEBUG_ENABLE_DEBUGGER) != 0);
gDvm.jdwpConfigured在调用dvmStartup->dvmProcessOptions->parseJdwpOptions时配置。

参考上面的参数,对照Init.c的handleJdwpOption的函数,可知gDvm.jdwpTransport为kJdwpTransportAndroidAdb,gDvm.jdwpServer为true,gDvm.jdwpSuspend为false,gDvm.jdwpPort没有配置,这些参数保存到dvmJdwpStartup的参数里面。

再看dvmJdwpStartup,在里面,创建jdwp相关的结构体JdwpState,是先初始化一些互斥锁和条件锁,初始化transport
[cpp] view plaincopy
  1. switch (pParams->transport) {  
  2. case kJdwpTransportSocket:  
  3.     // LOGD("prepping for JDWP over TCP\n");  
  4.     state->transport = dvmJdwpSocketTransport();  
  5.     break;  
  6. case kJdwpTransportAndroidAdb:  
  7.     // LOGD("prepping for JDWP over ADB\n");  
  8.     state->transport = dvmJdwpAndroidAdbTransport();  
  9.     /* TODO */  
  10.     break;  
  11. default:  
  12.     LOGE("Unknown transport %d\n", pParams->transport);  
  13.     assert(false);  
  14.     goto fail;  
  15. }  


由上文可知,这里执行dvmJdwpAndroidAdbTransport,返回一个JdwpTransport的接口指针结构体,这些在ADB和TCP上各有一套实现方法,对应不同类型的transport。
[cpp] view plaincopy
  1. typedef struct JdwpTransport {  
  2.     bool (*startup)(struct JdwpState* state, const JdwpStartupParams* pParams);  
  3.     bool (*accept)(struct JdwpState* state);  
  4.     bool (*establish)(struct JdwpState* state);  
  5.     void (*close)(struct JdwpState* state);  
  6.     void (*shutdown)(struct JdwpState* state);  
  7.     void (*free)(struct JdwpState* state);  
  8.     bool (*isConnected)(struct JdwpState* state);  
  9.     bool (*awaitingHandshake)(struct JdwpState* state);  
  10.     bool (*processIncoming)(struct JdwpState* state);  
  11.     bool (*sendRequest)(struct JdwpState* state, ExpandBuf* pReq);  
  12.     bool (*sendBufferedRequest)(struct JdwpState* state,  
  13.         const struct iovec* iov, int iovcnt);  
  14. } JdwpTransport;  


然后,调用dvmJdwpNetStartup,在里面实际执行JdwpTransport在ADB上的startup接口。在JdwpADB.c的start函数内,初始化与adb有关的一些网络参数,比如socket名称
[cpp] view plaincopy
  1. #define kJdwpControlName    "\0jdwp-control"    

这个socket名称已经被adbd绑定。
然后,调用dvmCreateInternalThread启动jdwp线程,dvmCreateInternalThread是pthread_create的包装,最终线程的执行函数是jdwpThreadStart,
在jdwpThreadStart中,会调用dvmJdwpEstablishConnection与adbd建立连接。在dvmJdwpEstablishConnection中,会一直等待与adbd的连接,直到连接成功
[cpp] view plaincopy
  1. int  ret = connect(netState->controlSock,                           
  2.                    &netState->controlAddr.controlAddrPlain,         
  3.                    netState->controlAddrLen);             

如果执行connect成功,则将pid发送给adbd,
[cpp] view plaincopy
  1. snprintf(buff, sizeof(buff), "%04x", getpid());  
  2. buff[4] = 0;  
  3.         do {                                                            
  4.             ret = send( netState->controlSock, buff, 4, 0 );            
  5.         } while (ret < 0 && errno == EINTR);       


接着,jdwp等待adbd返回一个客户文件描述符,
[cpp] view plaincopy
  1. netState->clientSock = receiveClientFd(netState);  

如果返回成功,这个clientSock将用来直接与debugger或DDMS通信。可以想象,这里的clientSock就是TCP:5037对应的client描述符。
这样acceptConnection也成功返回了,回到jdwp线程处理函数jdwpThreadStart,接着进入一个while循环从adbd读取并处理握手消息。
[cpp] view plaincopy
  1. while (true) {  
  2.     // sanity check -- shouldn't happen?  
  3.     if (dvmThreadSelf()->status != THREAD_VMWAIT) {  
  4.         LOGE("JDWP thread no longer in VMWAIT (now %d); resetting\n",  
  5.             dvmThreadSelf()->status);  
  6.         dvmDbgThreadWaiting();  
  7.     }  
  8.   
  9.   
  10.     if (!dvmJdwpProcessIncoming(state))     /* blocking read */  
  11.         break;  
  12.   
  13.   
  14.     if (first && !dvmJdwpAwaitingHandshake(state)) {  
  15.         /* handshake worked, tell the interpreter that we're active */  
  16.         first = false;  
  17.   
  18.   
  19.         /* set thread ID; requires object registry to be active */  
  20.         state->debugThreadId = dvmDbgGetThreadSelfId();  
  21.   
  22.   
  23.         /* wake anybody who's waiting for us */  
  24.         dvmDbgLockMutex(&state->attachLock);  
  25.         dvmDbgCondBroadcast(&state->attachCond);  
  26.         dvmDbgUnlockMutex(&state->attachLock);  
  27.     }  
  28. }  


先看dvmJdwpProcessIncoming函数,在里面执行select,可能会收到三种数据,对应三个文件描述被set,其中wakeFds是定时唤醒作用,丢弃,controlSock的set也忽略,因为不需要接收第二个debugger文件描述服。之后收到debugger的数据,也就是clientSock被set的时候调用read读取数据,如果不一个单位数据包长度,则dvmJdwpProcessIncoming返回。否则,调用handlePacket处理数据包,
handlePacket->dvmJdwpProcessRequest->write
handlePacket从讲包中的数据还原成JdwpReqHeader和数据起始指针,送给dvmJdwpProcessRequest处理,dvmJdwpProcessRequest从gHandlerMap调出处理函数func
[cpp] view plaincopy
  1. typedef struct {                                                                
  2.     u1  cmdSet;                                                                 
  3.     u1  cmd;  
  4.     JdwpRequestHandler  func;                                                   
  5.     const char* descr;                                                          
  6. } JdwpHandlerMap;    

write讲结果,写回给adbd,adbd处理之后在发回给HOST端。



<四>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请求,数据包内容如下

[cpp] view plaincopy
  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 plaincopy
  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 plaincopy
  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 plaincopy
  1. int fd = _adb_connect("host:version");  

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

[cpp] view plaincopy
  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 plaincopy
  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 plaincopy
  1. if(adb_status(fd)) {  
  2.     adb_close(fd);  
  3.     return -1;  
  4. }  
在里面判断返回结果是否为“OK”
[cpp] view plaincopy
  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 plaincopy
  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 plaincopy
  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 plaincopy
  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 plaincopy
  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 plaincopy
  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 plaincopy
  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 plaincopy
  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 plaincopy
  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 plaincopy
  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 plaincopy
  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 plaincopy
  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 plaincopy
  1. s->ready(s);  

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

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

[cpp] view plaincopy
  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  
因此,流程应该大致如图所示,具体的步骤太复杂,只能粗略表示一下。




原创粉丝点击