本文为大家梳理Device端adbd的运作原理。在此之前最好是已经看了前三篇文章:ADB概论、HOST端和Dalvik虚拟机之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
因此,流程应该大致如图所示,具体的步骤太复杂,只能粗略表示一下。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。