(转)Android开发工具——ADB(Android Debug Bridge) <二>HOST端

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

[cpp]  view plain copy
  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 plain copy
  1. -d  
  2. -e  
  3. -s <serial number>   

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

[cpp]  view plain copy
  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 plain copy
  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 plain copy
  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 plain copy
  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 plain copy
  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 plain copy
  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 plain copy
  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 plain copy
  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 plain copy
  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 plain copy
  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 plain copy
  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 plain copy
  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 plain copy
  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 plain copy
  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 plain copy
  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 plain copy
  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 plain copy
  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 plain copy
  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 plain copy
  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 plain copy
  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 plain copy
  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 plain copy
  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 plain copy
  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 plain copy
  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 plain copy
  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 plain copy
  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 plain copy
  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   |
                               |                                                              ^^                |
                               |___________________________||_______|
                                                                                               ||


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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值