前面有篇文章介绍了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);
}
这里调用adb_socketpair建立一对匿名的已经连接的套接字,分别赋给transport_registration_send和transport_registration_recv,之后调用fdevent_install把transport_registration_recv这个套接字注册到监听到套接字里面,并把相应的处理函数设置为transport_registration_func。
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;
...
}
p->msg.arg0= 1;所以直接send_packet,这里面会调用write_packet(t-> transport_socket,&p),这样与它相应的对端就可以收到数据,在input_thread中会从t->fd读出数据并发给远端,注意这里远端连接的套接字并没有加入fdevent,而是在output_thread中阻塞在read上面,直到Client端有数据到来。客户端收到A_SYNC命令后,会发送一个connect消息过来,收到数据后就转发给t->fd,触发t->transport_socket,执行transport_socket_events同样调用handle_packet处理收到的数据。
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;
}
在service_to_fd中这里对应于create_service_thread(file_sync_service, NULL);
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];
}
在这里面又调用adb_socketpair创建了两个本地通信套接字,并返回其中s[0],这里还创建一个线程:service_bootstrap_func,执行void *service_bootstrap_func(void *x)
void *service_bootstrap_func(void *x)
{
stinfo *sti = x;
sti->func(sti->fd, sti->cookie);
free(sti);
return 0;
}
这里的func是file_sync_service,sti->fd= s[1]。
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