我分析代码的喜欢从main函数开始,因为还不知道代码结构的情况下,这是最直接的方法。所以先看adb.c的main函数
int main(int argc, char **argv) { adb_trace_init(); #if ADB_HOST adb_sysdeps_init(); return adb_commandline(argc - 1, argv + 1); #else if((argc > 1) && (!strcmp(argv[1],"recovery"))) { adb_device_banner = "recovery"; recovery_mode = 1; } start_device_log(); return adb_main(0); #endif }
宏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,指定设备的方法是
-d -e -s <serial number>
然后调用adb_set_transport将type,serial赋值给全局变量,
void adb_set_transport(transport_type type, const char* serial) { __adb_transport = type; __adb_serial = serial; }
这两个全局变量由client保存,将用来告诉server,与何种设备通信,用何种方式传输通信。
接下来,adb_commandline用来判断server守护进程是否已经启动,
if ((argc > 0) && (!strcmp(argv[0],"server"))) { if (no_daemon || is_daemon) { r = adb_main(is_daemon); } else { r = launch_server(); } if(r) { fprintf(stderr,"* could not start server *\n"); } return r; }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应答。
// child side of the fork // redirect stderr to the pipe // we use stderr instead of stdout due to stdout's buffering behavior. adb_close(fd[0]); dup2(fd[1], STDERR_FILENO); adb_close(fd[1]); // child process int result = execl(path, "adb", "fork-server", "server", NULL); // this should not return fprintf(stderr, "OOPS! execl returned %d, errno: %d\n", result, errno);
// parent side of the fork char temp[3]; temp[0] = 'A'; temp[1] = 'B'; temp[2] = 'C'; // wait for the "OK\n" message adb_close(fd[1]); int ret = adb_read(fd[0], temp, 3); adb_close(fd[0]); if (ret < 0) { fprintf(stderr, "could not read ok from ADB Server, errno = %d\n", errno); return -1; } if (ret != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') { fprintf(stderr, "ADB server didn't ACK\n" ); return -1; } setsid();
花开两朵各表一只,先看fork出来的子进程,即守护进程server,前面说到,它的启动command是adb fork-server server,我们在回到adb的main函数,它用走到了adb_commandline里面来,这时候它解析参数以后,is_daemon就变成1了,因此执行adb_daemon(is_daemon)。
init_transport_registration(); #if ADB_HOST HOST = 1; usb_vendors_init(); usb_init(); local_init(ADB_LOCAL_TRANSPORT_PORT); if(install_listener("tcp:5037", "*smartsocket*", NULL)) { exit(1); } #else
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中:
for (;;) { sleep(5); kick_disconnected(); scan_usb_devices(); }通过scan_usb_devices查找用于adb的usb设备
scan_usb_devices->check_device->register_device->register_usb_transport->init_usb_transport->register_transport
在init_usb_transport中,
void init_usb_transport(atransport *t, usb_handle *h, int state) { D("transport: usb\n"); t->close = remote_close; t->kick = remote_kick; t->read_from_remote = remote_read; t->write_to_remote = remote_write; t->sync_token = 1; t->connection_state = state; t->type = kTransportUsb; t->usb = h; #if ADB_HOST HOST = 1; #else HOST = 0; #endif }可以看到,不管在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中
int init_socket_transport(atransport *t, int s, int port, int local) { int fail = 0; t->kick = remote_kick; t->close = remote_close; t->read_from_remote = remote_read; t->write_to_remote = remote_write; t->sfd = s; t->sync_token = 1; t->connection_state = CS_OFFLINE; t->type = kTransportLocal; #if ADB_HOST if (HOST && local) { adb_mutex_lock( &local_transports_lock ); { int index = (port - ADB_LOCAL_TRANSPORT_PORT)/2; if (!(port & 1) || index < 0 || index >= ADB_LOCAL_TRANSPORT_MAX) { D("bad local transport port number: %d\n", port); fail = -1; } else if (local_transports[index] != NULL) { D("local transport for port %d already registered (%p)?\n", port, local_transports[index]); fail = -1; } else local_transports[index] = t; } adb_mutex_unlock( &local_transports_lock ); } #endif return fail; }
再看register_transport,它将transport信息,一个tmsp的结构体,写入transport_registration_send
struct tmsg { atransport *transport; int action; };
则接收端的描述符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为例,
p = get_apacket(); p->msg.command = A_SYNC; p->msg.arg0 = 1; p->msg.arg1 = ++(t->sync_token); p->msg.magic = A_SYNC ^ 0xffffffff; if(write_packet(t->fd, &p)) { put_apacket(p); D("from_remote: failed to write SYNC apacket to transport %p", t); goto oops; }
case A_SYNC: if(p->msg.arg0){ send_packet(p, t); if(HOST) send_connect(t); } else { t->connection_state = CS_OFFLINE; handle_offline(t); send_packet(p, t); } return;
回过头来output_thread线程回收到这些信息包,并将这些包写入远端。
写的太深入了,回到adb_main函数,初始化完可能USB和emulator的transport之后,执行下面这段代码
if(install_listener("tcp:5037", "*smartsocket*", NULL)) { exit(1); }
struct alistener { alistener *next; alistener *prev; fdevent fde; int fd; const char *local_name; const char *connect_to; atransport *transport; adisconnect disconnect; };在install_listener里面
l->fd = local_name_to_fd(local_name); close_on_exec(l->fd); if(!strcmp(l->connect_to, "*smartsocket*")) { fdevent_install(&l->fde, l->fd, ss_listener_event_func, l); }这样,client来消息的时候,就可以调用ss_listener_event_func进行处理了。
接下来,adb_main执行下面代码,
if (is_daemon) { // inform our parent that we are up and running. #elif defined(HAVE_FORKEXEC) fprintf(stderr, "OK\n"); #endif start_logging(); }这段代码,告诉父进程adb server已经跑起来了,因此,往stderr里面写一个OK,还记得刚刚server已经将stderr重定向到fd[1]了,所以父进程能接收到这个OK消息。
接下来,server调用fdevent_loop进入事件循环。
for(;;) { fdevent_process(); while((fde = fdevent_plist_dequeue())) { unsigned events = fde->events; fde->events = 0; fde->state &= (~FDE_PENDING); dump_fde(fde, "callback"); fde->func(fde->fd, events, fde->arg); } }因此adb是事件驱动型,所有的事件调用fdevent_register进行注册,该函数讲事件保存到全局事件数组fd_table里面,
struct fdevent { fdevent *next; fdevent *prev; int fd; unsigned short state; unsigned short events; fd_func func; void *arg; };
adb_main,即server已经启动完成,再回到client的adb_commandline函数,我们继续adb device命令的解析,
if(!strcmp(argv[0], "devices")) { char *tmp; snprintf(buf, sizeof buf, "host:%s", argv[0]); tmp = adb_query(buf); if(tmp) { printf("List of devices attached \n"); printf("%s\n", tmp); return 0; } else { return 1; } }
char *adb_query(const char *service) { char buf[5]; unsigned n; char *tmp; D("adb_query: %s\n", service); int fd = adb_connect(service); if(readx(fd, buf, 4)) goto oops; if(readx(fd, tmp, n) == 0) { } }
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读取该信息,
fd = adb_socket_accept(_fd, &addr, &alen); if(fd < 0) return; adb_socket_setbufsize(fd, CHUNK_SIZE); s = create_local_socket(fd); if(s) { connect_to_smartsocket(s); return; }
先看create_local_socket,这个socket负责与client通信,回调处理函数是local_socket_event_func。
asocket *create_local_socket(int fd) { asocket *s = calloc(1, sizeof(asocket)); if(s == 0) fatal("cannot allocate socket"); install_local_socket(s); s->fd = fd; s->enqueue = local_socket_enqueue; s->ready = local_socket_ready; s->close = local_socket_close; fdevent_install(&s->fde, fd, local_socket_event_func, s); return s; }
也就是由local_socket_event_func来读取“host:devices”串,然后调用s->peer->enqueue(s->peer, p);交给对断处理。
那local socket的对端是谁,看connect_to_smartsocket
void connect_to_smartsocket(asocket *s) { D("Connecting to smart socket \n"); asocket *ss = create_smart_socket(smart_socket_action); s->peer = ss; ss->peer = s; s->ready(s); }
这里明白了local socket的对端就是smart socket(remote socket的一种),与local socket交互。
asocket *create_smart_socket(void (*action_cb)(asocket *s, const char *act)) { asocket *s = calloc(1, sizeof(asocket)); if(s == 0) fatal("cannot allocate socket"); s->id = 0; s->enqueue = smart_socket_enqueue; s->ready = smart_socket_ready; s->close = smart_socket_close; s->extra = action_cb; return s; }
这两个socket结对以后,调用local socket的ready回调函数,也就是local_socket_ready
static void local_socket_ready(asocket *s) { fdevent_add(&s->fde, FDE_READ); }意思是说,我(local socket)已经准备好接收你smart socket发过来的数据了。
那local socket调用的s->peer->enqueue(s->peer, p);就是smart_socket_enqueue
在smart_socket_enqueue中,将刚刚读取到的package插入到package列表中,然后解析service,即发过来的“host:devices”
#if ADB_HOST service = (char *)p->data + 4; if(!strncmp(service, "host-serial:", strlen("host-serial:"))) { char* serial_end; service += strlen("host-serial:"); // serial number should follow "host:" serial_end = strchr(service, ':'); if (serial_end) { *serial_end = 0; // terminate string serial = service; service = serial_end + 1; } } else if (!strncmp(service, "host-usb:", strlen("host-usb:"))) { ttype = kTransportUsb; service += strlen("host-usb:"); } else if (!strncmp(service, "host-local:", strlen("host-local:"))) { ttype = kTransportLocal; service += strlen("host-local:"); } else if (!strncmp(service, "host:", strlen("host:"))) { ttype = kTransportAny; service += strlen("host:"); } else { service = NULL; }这里将client发过来的请求,跟去前缀转化为各种transport type,接着解析具体的service名称,接着,调用handle_host_request处理一些可以立即响应的消息,然后直接返回(adb devices请求就是属于这一种),,否则调用create_host_service_socket创建另外一个service socket作为local service的对段,而smart socket就没什么事了,可以关闭了,如下代码。
s2 = create_host_service_socket(service, serial); if(s2 == 0) { D( "SS(%d): couldn't create host service '%s'\n", s->id, service ); sendfailmsg(s->peer->fd, "unknown host service"); goto fail; } adb_write(s->peer->fd, "OKAY", 4); s->peer->ready = local_socket_ready; s->peer->close = local_socket_close; s->peer->peer = s2; s2->peer = s->peer; s->peer = 0; D( "SS(%d): okay\n", s->id ); s->close(s);
// return a list of all connected devices if (!strcmp(service, "devices")) { char buffer[4096]; memset(buf, 0, sizeof(buf)); memset(buffer, 0, sizeof(buffer)); D("Getting device list \n"); list_transports(buffer, sizeof(buffer)); snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer),buffer); D("Wrote device list \n"); writex(reply_fd, buf, strlen(buf)); return 0; }
整个过程的如下,
___________________________________
| |
| ADB Server (host) |
| |
Client <-------> LocalSocket <-------------> RemoteSocket |
| ^^ |
|___________________________||_______|
||