这篇博客梳理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请求,数据包内容如下
apacket *cp = get_apacket(); cp->msg.command = A_CNXN; cp->msg.arg0 = A_VERSION; cp->msg.arg1 = MAX_PAYLOAD; snprintf((char*) cp->data, sizeof cp->data, "%s::", HOST ? "host" : adb_device_banner); DEVICE端收到以后,解析后设置transport的状态为HOST,然后给host回一个同样的connect请求,只不过data由"host::"变成了"device::",
HOST收到DEVICE的connect请求后,解析,
if(!strcmp(type, "device")) { D("setting connection_state to CS_DEVICE\n"); t->connection_state = CS_DEVICE; update_transports(); return; }
update_transports供client发送adb track-devices命令时有用。因此到此时为止,HOST和DEVICE已经处于online状态,准备好其它的通信了。
这里以adb jdwp命令为例说明,jdwp是获取当前device中注册了jdwp传输的进程列表。看看jdwp是怎么从HOST到DEVICE端的。
if (!strcmp(argv[0], "jdwp")) { int fd = adb_connect("jdwp"); if (fd >= 0) { read_and_dump(fd); adb_close(fd); return 0; } else { fprintf(stderr, "error: %s\n", adb_error()); return -1; } }
这是调用adb_connect,然后直接从里面读取结果,在发送“jdwp”之前,先调用int fd = _adb_connect("host:version");
校验,adb版本。_adb_connect中,如果碰到“host”打头的请求,则切换transport。if (memcmp(service,"host",4) != 0 && switch_socket_transport(fd)) { return -1; }
在switch_socket_transport中,如果刚开始在adb命令中未指定serial 和transport type, 则,将“host:transport-any‘发往5037端口
if(writex(fd, tmp, 4) || writex(fd, service, len)) { strcpy(__adb_error, "write failure during connection"); adb_close(fd); return -1; } 等待返回一个“OKAY”
if(adb_status(fd)) { adb_close(fd); return -1; }
在里面判断返回结果是否为“OK”
int adb_status(int fd) { unsigned char buf[5]; unsigned len; if(!memcmp(buf, "OKAY", 4)) { return 0; } }
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”
transport = acquire_one_transport(CS_ANY, type, serial, &error_string); if (transport) { s->transport = transport; adb_write(reply_fd, "OKAY", 4); } else { sendfailmsg(reply_fd, error_string); } 由此可知,切换transport后,才将"host:version"请求发送到TCP:5037端口,同样经过smart_socket_enqueue->handle_host_request函数,执行下面语句
// returns our value for ADB_SERVER_VERSION if (!strcmp(service, "version")) { char version[12]; snprintf(version, sizeof version, "%04x", ADB_SERVER_VERSION); snprintf(buf, sizeof buf, "OKAY%04x%s", (unsigned)strlen(version), version); writex(reply_fd, buf, strlen(buf)); return 0; } 返回结果的先导也有一个OKAY。TCP:5037的另一端,也就是service,它的读写处理函数是local_socket_event_func,讲"host:version"结果
再来看“jdwp”请求,smart_socket_enqueue->handle_host_request,handle_host_request发现处理不了,所以回到smart_socket_enqueue继续执行下面语句,
s->peer->ready = local_socket_ready_notify; s->peer->close = local_socket_close_notify; s->peer->peer = 0; /* give him our transport and upref it */ s->peer->transport = s->transport; connect_to_remote(s->peer, (char*) (p->data + 4)); s->peer = 0; s->close(s);
这段语句,将smart soeckt关闭,然后将transport交给local socket,这样,connect_to_remote的参数就是local socket, “jdwp”,在connect_to_remote
p->msg.command = A_OPEN; p->msg.arg0 = s->id; p->msg.data_length = len; strcpy((char*) p->data, destination); send_packet(p, s->transport);
把A_OPEN命令发给DEVICE端,id是socket的唯一标识,在初始化local socket的时候就确定,便于远端回复数据过来时,在socket list中能查找到该socket进行处理
void install_local_socket(asocket *s) { adb_mutex_lock(&socket_list_lock); s->id = local_socket_next_id++; insert_local_socket(s, &local_socket_list); adb_mutex_unlock(&socket_list_lock); } 在DEVICE端的output_thread线程,读取到消息,写到transport_socket里面去
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; } } 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,回调:
s->socket.ready = jdwp_socket_ready; s->socket.enqueue = jdwp_socket_enqueue; s->socket.close = jdwp_socket_close; s->pass = 0;
create_remote_socket的回调:这里的id是HOST端的local socket的id。
s->id = id; s->enqueue = remote_socket_enqueue; s->ready = remote_socket_ready; s->close = remote_socket_close; s->transport = t;
然后调用
send_ready(s->id, s->peer->id, t); s->ready(s);
这里的s->id是DEVICE端local socket的id, s->peer->是HOST端的local socket的id。
static void send_ready(unsigned local, unsigned remote, atransport *t) { D("Calling send_ready \n"); apacket *p = get_apacket(); p->msg.command = A_OKAY; p->msg.arg0 = local; p->msg.arg1 = remote; send_packet(p, t); }
这样,表示HOST端发送的A_OPEN命令成功了,DEVICE端的output_thread接收到以后,
case A_OKAY: /* READY(local-id, remote-id, "") */ if(t->connection_state != CS_OFFLINE) { if((s = find_local_socket(p->msg.arg1))) { if(s->peer == 0) { s->peer = create_remote_socket(p->msg.arg0, t); s->peer->peer = s; } s->ready(s); } } break;
根据id,找回local socket,同时创建remote socket。
前面看到,DEVICE端创建好local socket和remote socket之后,除了往HOST发一个OKAY,还调用
s->ready(s);
这里的s是local jdwp service socket,来看它的ready函数jdwp_socket_ready
apacket* p = get_apacket(); p->len = jdwp_process_list((char*)p->data, MAX_PAYLOAD); peer->enqueue(peer, p); jdwp->pass = 1;
将jdwp服务中的进程号,写入packet,调用remote socket的enqueue,也就是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,HOST的output_thread收到以后
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; 它调用local socket的enqueue函数local_socket_enqueue,在local_socket_enqueue里面,调用
int r = adb_write(s->fd, p->ptr, p->len); 写入端口5037,这样,client就能看到jdwp的进程信息了。就像下面这样。
[yinlijun@localhost adb]$ adb jdwp 228 277 111 176 185 188 180 208 212 330 339 351 361 370 378 407 416 427 438 446 455 因此,流程应该大致如图所示,具体的步骤太复杂,只能粗略表示一下。