前面有篇文章介绍了adb install的后面的流程,但前面的通信过程没有怎么介绍,这里主要介绍下adb 启动的流程,以及connect、install的前面流程,这里介绍的都是服务端的。
一、adb 启动流程:
首先看下服务端adb 启动的流程
adb_main主要 调用4个初始化函数:
1、init_transport_registration:初始化本地事务处理,每个client连接都会有一个专门的处理,对每个client都会在服务端有一对套接字对与该client相连的socket上的数据流进行处理。
2、install_listener(local_name, "*smartsocket*", NULL),这个函数 暂时还不知道做什么的;
3、local_init,初始化本地套接字,等待client的连接。
4、init_jdwp这个好像是跟dalvik中间的某个东东通讯的,没去研究。
5、fdevent_loop,事件处理,当相应的套接字上有数据到来时,调用注册的函数进行处理。
这里主要介绍下init_transport_registration,local_init,fdevent_loop这三个函数。
1)、init_transport_registration
void init_transport_registration(void) { int s[2]; if(adb_socketpair(s)){ fatal_errno("cannot open transport registration socketpair"); } transport_registration_send = s[0]; transport_registration_recv = s[1]; fdevent_install(&transport_registration_fde, transport_registration_recv, transport_registration_func, 0); fdevent_set(&transport_registration_fde, FDE_READ); }
2)、local_init
void local_init(int port) { adb_thread_t thr; void* (*func)(void *); if(HOST) { func = client_socket_thread; } else { func = server_socket_thread; } D("transport: local %s init\n", HOST ? "client" : "server"); if(adb_thread_create(&thr, func, (void *)port)) { fatal_errno("cannot create local socket %s thread", HOST ? "client" : "server"); } }这里是server端,所以这里func为server_socket_thread,这里创建了这个线程:
static void *server_socket_thread(void * arg) { int serverfd, fd; struct sockaddr addr; socklen_t alen; int port = (int)arg; D("transport: server_socket_thread() starting\n"); serverfd = -1; for(;;) { if(serverfd == -1) { serverfd = socket_inaddr_any_server(port, SOCK_STREAM); if(serverfd < 0) { D("server: cannot bind socket yet\n"); adb_sleep_ms(1000); continue; } close_on_exec(serverfd); } alen = sizeof(addr); D("server: trying to get new connection from %d\n", port); fd = adb_socket_accept(serverfd, &addr, &alen); if(fd >= 0) { D("server: new connection on fd %d\n", fd); close_on_exec(fd); disable_tcp_nagle(fd); register_socket_transport(fd, "host", port, 1); } } D("transport: server_socket_thread() exiting\n"); return 0; }这里调用socket_inaddr_any_server建立监听套接字,这里的port默认是5555,再调用adb_socket_accept等待客户连接的到来。
3)、fdevent_loop
void fdevent_loop() { fdevent *fde; for(;;) { #if DEBUG fprintf(stderr,"--- ---- waiting for events\n"); #endif 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); } } }这里先调用fdevent_process启动select或epoll检测机制,这里面会把有数据到来的套接字消息调用fdevent_plist_enqueue压入list_pending,调用fdevent_plist_dequeue从list_pending取出一条消息,并调用它的处理函数进行处理。
二、adb connect流程:
上面 我们讲server_socket_thread讲到创建了一个线程并监听等待客户连接的到来,当client连接过来的时候, 这里accept会返回,我们接着往下看,会调用register_socket_transport注册这个连接
void register_socket_transport(int s, const char *serial, int port, int local) { atransport *t = calloc(1, sizeof(atransport)); D("transport: %p init'ing for socket %d, on port %d\n", t, s, port); if ( init_socket_transport(t, s, port, local) < 0 ) { adb_close(s); free(t); return; } if(serial) { t->serial = strdup(serial); } register_transport(t); }
分配了一个atransport结构并调用init_socket_transport进行初始化
int init_socket_transport(atransport *t, int s, int adb_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; t->adb_port = 0; }注意这里的sdf是这个连接的套接字,还有remote_read及remote_write.
接着调用register_transport注册这个事务
static void register_transport(atransport *transport) { tmsg m; m.transport = transport; m.action = 1; D("transport: %p registered\n", transport); if(transport_write_action(transport_registration_send, &m)) { fatal_errno("cannot write transport registration socket\n"); } }注意这里transport_write_action的第一个参数是transport_registration_send,是否有点印象,对的,这个fd就是我们在init_transport_registration建立的一对已连接的匿名套接字中 的一个。这样在transport_registration_recv就会有数据到来。并调用transport_registration_func,
static void transport_registration_func(int _fd, unsigned ev, void *data) { tmsg m; adb_thread_t output_thread_ptr; adb_thread_t input_thread_ptr; int s[2]; atransport *t; if(!(ev & FDE_READ)) { return; } if(transport_read_action(_fd, &m)) { fatal_errno("cannot read transport registration socket"); } t = m.transport; if(m.action == 0){ D("transport: %p removing and free'ing %d\n", t, t->transport_socket); /* IMPORTANT: the remove closes one half of the ** socket pair. The close closes the other half. */ fdevent_remove(&(t->transport_fde)); adb_close(t->fd); adb_mutex_lock(&transport_lock); t->next->prev = t->prev; t->prev->next = t->next; adb_mutex_unlock(&transport_lock); run_transport_disconnects(t); if (t->product) free(t->product); if (t->serial) free(t->serial); memset(t,0xee,sizeof(atransport)); free(t); update_transports(); return; } /* don't create transport threads for inaccessible devices */ if (t->connection_state != CS_NOPERM) { /* initial references are the two threads */ t->ref_count = 2; if(adb_socketpair(s)) { fatal_errno("cannot open transport socketpair"); } D("transport: %p (%d,%d) starting\n", t, s[0], s[1]); t->transport_socket = s[0]; t->fd = s[1]; D("transport: %p install %d\n", t, t->transport_socket ); fdevent_install(&(t->transport_fde), t->transport_socket, transport_socket_events, t); fdevent_set(&(t->transport_fde), FDE_READ); if(adb_thread_create(&input_thread_ptr, input_thread, t)){ fatal_errno("cannot create input thread"); } if(adb_thread_create(&output_thread_ptr, output_thread, t)){ fatal_errno("cannot create output thread"); } } /* put us on the master device list */ adb_mutex_lock(&transport_lock); t->next = &transport_list; t->prev = transport_list.prev; t->next->prev = t; t->prev->next = t; adb_mutex_unlock(&transport_lock); t->disconnects.next = t->disconnects.prev = &t->disconnects; update_transports(); }
在这个函数中,先调用transport_read_action读取前面写入的tmsg数据,m.action =1,所以不执行,这里t->connection_state!= CS_NOPERM,前面赋值了为CS_OFFLINE。adb_socketpair又建立两个本地通信套接字,分别赋给t->transport_socket和t->fd,接着调用fdevent_install把t->transport_socket添加进去,创建input_thread 和output_thread两线程。
static void *input_thread(void *_t) { atransport *t = _t; apacket *p; int active = 0; D("to_remote: starting input_thread for %p, reading from fd %d\n", t, t->fd); for(;;){ if(read_packet(t->fd, &p)) { D("to_remote: failed to read apacket from transport %p on fd %d\n", t, t->fd ); break; } if(p->msg.command == A_SYNC){ if(p->msg.arg0 == 0) { D("to_remote: transport %p SYNC offline\n", t); put_apacket(p); break; } else { if(p->msg.arg1 == t->sync_token) { D("to_remote: transport %p SYNC online\n", t); active = 1; } else { D("to_remote: trandport %p ignoring SYNC %d != %d\n", t, p->msg.arg1, t->sync_token); } } } else { if(active) { D("to_remote: transport %p got packet, sending to remote\n", t); t->write_to_remote(p, t); } else { D("to_remote: transport %p ignoring packet while offline\n", t); } } put_apacket(p); } // this is necessary to avoid a race condition that occured when a transport closes // while a client socket is still active. close_all_sockets(t); D("to_remote: thread is exiting for transport %p, fd %d\n", t, t->fd); kick_transport(t); transport_unref(t); return 0; }input_thread就是从t->fd读数据,然后调用write_to_remote,write_to_remote中有一句writex(t->sfd,&p->msg, sizeof(amessage) + length)发给远端
再来看下output_thread
static void *output_thread(void *_t) { atransport *t = _t; apacket *p; D("from_remote: starting thread for transport %p, on fd %d\n", t, t->fd ); D("from_remote: transport %p SYNC online (%d)\n", t, t->sync_token + 1); 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; } D("from_remote: data pump for transport %p\n", t); for(;;) { p = get_apacket(); if(t->read_from_remote(p, t) == 0){ D("from_remote: received remote packet, sending to transport %p\n", t); if(write_packet(t->fd, &p)){ put_apacket(p); D("from_remote: failed to write apacket to transport %p", t); goto oops; } } else { D("from_remote: remote read failed for transport %p\n", p); put_apacket(p); break; } } D("from_remote: SYNC offline for transport %p\n", t); p = get_apacket(); p->msg.command = A_SYNC; p->msg.arg0 = 0; p->msg.arg1 = 0; 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); } oops: D("from_remote: thread is exiting for transport %p\n", t); kick_transport(t); transport_unref(t); return 0; }output_thread先往t->fd写一个A_SYNC命令,然后循环调用read_from_remote,remote_read 中有(readx(t->sfd,p->data, p->msg.data_length),然后write_packet把数据写到t->fd。上面output_thread中往t->fdk中写了一个A_SYNC命令,这样就触发了t->transport_socket上的读操作,并调用transport_socket_events
static void transport_socket_events(int fd, unsigned events, void *_t) { if(events & FDE_READ){ apacket *p = 0; if(read_packet(fd, &p)){ D("failed to read packet from transport socket on fd %d\n", fd); } else { handle_packet(p, (atransport *) _t); } } }这里先从fd读数据,然后调用handle_packet处理,对于A_SYNC,有相应的如下代码:
void handle_packet(apacket *p, atransport *t) { ... 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; ... }
void handle_packet(apacket *p, atransport *t) { ... case A_CNXN: /* CONNECT(version, maxdata, "system-id-string") */ /* XXX verify version, etc */ if(t->connection_state != CS_OFFLINE) { t->connection_state = CS_OFFLINE; handle_offline(t); } parse_banner((char*) p->data, t); handle_online(); if(!HOST) send_connect(t); break; .... }调用send_connect发送版本等信息到远端.
三、adb install 通讯过程
同样消息从远端的sfd送到t->fd,触发t->transport_socket执行handle_packet,这里Client先发送一条A_OPEN消息
void handle_packet(apacket *p, atransport *t) { ... case A_OPEN: /* OPEN(local-id, 0, "destination") */ if(t->connection_state != CS_OFFLINE) { char *name = (char*) p->data; name[p->msg.data_length > 0 ? p->msg.data_length - 1 : 0] = 0; s = create_local_service_socket(name); if(s == 0) { send_close(0, p->msg.arg0, t); } else { s->peer = create_remote_socket(p->msg.arg0, t); s->peer->peer = s; send_ready(s->id, s->peer->id, t); s->ready(s); } } break; ... }
这里的name 是”sync:”,用于通知服务端同步读取client发送过来的文件,调用create_local_service_socket创建一个本地服务的socket
asocket *create_local_service_socket(const char *name) { asocket *s; int fd; fd = service_to_fd(name); if(fd < 0) return 0; s = create_local_socket(fd); D("LS(%d): bound to '%s'\n", s->id, name); return s; }
static int create_service_thread(void (*func)(int, void *), void *cookie) { stinfo *sti; adb_thread_t t; int s[2]; if(adb_socketpair(s)) { printf("cannot create service socket pair\n"); return -1; } sti = malloc(sizeof(stinfo)); if(sti == 0) fatal("cannot allocate stinfo"); sti->func = func; sti->cookie = cookie; sti->fd = s[1]; if(adb_thread_create( &t, service_bootstrap_func, sti)){ free(sti); adb_close(s[0]); adb_close(s[1]); printf("cannot create service thread\n"); return -1; } D("service thread started, %d:%d\n",s[0], s[1]); return s[0]; }
void *service_bootstrap_func(void *x) { stinfo *sti = x; sti->func(sti->fd, sti->cookie); free(sti); return 0; }
void file_sync_service(int fd, void *cookie) { syncmsg msg; char name[1025]; unsigned namelen; char *buffer = malloc(SYNC_DATA_MAX); if(buffer == 0) goto fail; for(;;) { D("sync: waiting for command\n"); if(readx(fd, &msg.req, sizeof(msg.req))) { fail_message(fd, "command read failure"); break; } namelen = ltohl(msg.req.namelen); if(namelen > 1024) { fail_message(fd, "invalid namelen"); break; } if(readx(fd, name, namelen)) { fail_message(fd, "filename read failure"); break; } name[namelen] = 0; msg.req.namelen = 0; D("sync: '%s' '%s'\n", (char*) &msg.req, name); switch(msg.req.id) { case ID_STAT: if(do_stat(fd, name)) goto fail; break; case ID_LIST: if(do_list(fd, name)) goto fail; break; case ID_SEND: if(do_send(fd, name, buffer)) goto fail; break; case ID_RECV: if(do_recv(fd, name, buffer)) goto fail; break; case ID_QUIT: goto fail; default: fail_message(fd, "unknown command"); goto fail; } } fail: if(buffer != 0) free(buffer); D("sync: done\n"); adb_close(fd); }这里就阻塞在读上面了,等待套接字上数据的到来。
回到create_local_service_socket,继续调用create_local_socket,并把刚返回的s[0]传进来了
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); /* fdevent_add(&s->fde, FDE_ERROR); */ //fprintf(stderr, "Created local socket in create_local_socket \n"); D("LS(%d): created (fd=%d)\n", s->id, s->fd); return s; }
注意这里asocket类型变量t的enqueue为local_socket_enqueue,这里fd就是前面 返回的s[0],安装到fdevent,这里的处理函数是local_socket_event_func.,这里的local_socket_event_func函数是在s[1],即进行文件操作的那端需要往对端发送消息时触发的。
回到handle_packet,再调用create_remote_socket,创建一个asocket,初始化,把这个peer初始化为他的对端。
asocket *create_remote_socket(unsigned id, atransport *t) { asocket *s = calloc(1, sizeof(aremotesocket)); adisconnect* dis = &((aremotesocket*)s)->disconnect; if(s == 0) fatal("cannot allocate socket"); s->id = id; s->enqueue = remote_socket_enqueue; s->ready = remote_socket_ready; s->close = remote_socket_close; s->transport = t; dis->func = remote_socket_disconnect; dis->opaque = s; add_transport_disconnect( t, dis ); D("RS(%d): created\n", s->id); return s; }
赋值给s->peer;然后调用send_ready发送A_OKAY,最后调用s->ready把s->fd加入fdevent
A_OPEN处理完了,就会在与Client连接的套接字字上收到A_WRTE,
void handle_packet(apacket *p, atransport *t) { asocket *s; ... case A_WRTE: if(t->connection_state != CS_OFFLINE) { if((s = find_local_socket(p->msg.arg1))) { unsigned rid = p->msg.arg0; p->len = p->msg.data_length; if(s->enqueue(s, p) == 0) { D("Enqueue the socket\n"); send_ready(s->id, rid, t); } return; } } break; .... }
先调用find_local_socket找到前面建立的local_service_socket,调用s->enqueue,这里调用local_socket_enqueue
static int local_socket_enqueue(asocket *s, apacket *p) { ... while(p->len > 0) { int r = adb_write(s->fd, p->ptr, p->len); if(r > 0) { p->len -= r; p->ptr += r; continue; } if((r == 0) || (errno != EAGAIN)) { D( "LS(%d): not ready, errno=%d: %s\n", s->id, errno, strerror(errno) ); s->close(s); return 1; /* not ready (error) */ } else { break; } } ... }
这里把数据写到s->fd,也即前面的s[0],往s[0]写数据时候会触发file_sync_service读数据,这个函数阻塞在readx读数据,上面写了数据后,这里就会去读。所有数据都处理完了则发送send_ready
数据的发送过程:
先发送ID_STAT,查看文件是否存在,不存在的话再发送ID_SEND发送文件,文件发送完毕发送ID_QUIT退出,关关闭套接字
这里在client发送了ID_STAT时会回一个消息给client,就是通过往s[1]里面写,而s[0]是加到了select或poll中监听的,这个时候 s[0]就会触发,执行local_socket_event_func
static void local_socket_event_func(int fd, unsigned ev, void *_s) { .... if(ev & FDE_READ){ apacket *p = get_apacket(); unsigned char *x = p->data; size_t avail = MAX_PAYLOAD; int r; int is_eof = 0; while(avail > 0) { r = adb_read(fd, x, avail); if(r > 0) { avail -= r; x += r; continue; } if(r < 0) { if(errno == EAGAIN) break; if(errno == EINTR) continue; } /* r = 0 or unhandled error */ is_eof = 1; break; } if((avail == MAX_PAYLOAD) || (s->peer == 0)) { put_apacket(p); } else { p->len = MAX_PAYLOAD - avail; r = s->peer->enqueue(s->peer, p); if(r < 0) { /* error return means they closed us as a side-effect ** and we must return immediately. ** ** note that if we still have buffered packets, the ** socket will be placed on the closing socket list. ** this handler function will be called again ** to process FDE_WRITE events. */ return; } } .... }这里的s->peer->enpueue即是remote_socket_enqueue
static int remote_socket_enqueue(asocket *s, apacket *p) { D("Calling remote_socket_enqueue\n"); p->msg.command = A_WRTE; p->msg.arg0 = s->peer->id; p->msg.arg1 = s->id; p->msg.data_length = p->len; send_packet(p, s->transport); return 1; }这里往transport写数据又回到了前面的流程了,会在input_thread中会从t->fd读出数据并发给远端。
具体文件接收过程:
先接收消息头,判断是否为文件内容消息,以及是否发送完毕消息:
如果是文件内容消息,则接收数据并盘入文件
如果是发送完毕消息,则跳出循环,发送ID_OKAY消息。
文件接收完毕,Client会再发个A_OPEN消息name = shell:pm install /data/local/tmp/sipDemo.apk,这个时候会重新建立一个create_local_socket,最后调用create_subprocess,这里会打开伪终端/dev/ptmx。( 通过函数open()打开设备“/dev/ptmx”,可以得到一对伪终端的主从设备,得到的fd是主设备的文件描述符)在父进程里使用fd,子进程中打开从设备的设备名可以通过函数ptsname(),在子进程中重定位标准输出到伪终端,这样子进程中的有输出父进程就能得到,注意在pm.java runInstall函数中有这样几行代码
private void runInstall() { ..... PackageInstallObserver obs = new PackageInstallObserver(); try { mPm.installPackage(Uri.fromFile(new File(apkFilePath)), obs, installFlags, installerPackageName); synchronized (obs) { while (!obs.finished) { try { obs.wait(); } catch (InterruptedException e) { } } if (obs.result == PackageManager.INSTALL_SUCCEEDED) { System.out.println("Success"); } else { System.err.println("Failure [" + installFailureToString(obs.result) + "]"); } } } catch (RemoteException e) { System.err.println(e.toString()); System.err.println(PM_NOT_RUNNING_ERR); } ..., }这里用System.err.println就是打到标准输出设备,也就是伪终端了
安装完毕后,发送结果给Client,Client还会发一个A_OPEN消息,name = shell:rm /data/local/tmp/sipDemo.apk,删除这个apk最后发送A_CLSE删除这个连接
Adb处理install流程:参考:
http://blog.chinaunix.net/uid-20514606-id-375756.html
http://blog.csdn.net/yinlijun2004/article/details/7008952