本文為大家梳理Device端adbd的運作原理。在此之前最好是已經看了前三篇文章:ADB概論、HOST端和Dalvik虛擬機之jdwp線程。
在adbd起來時,也會監聽TCP:5037端口(好像沒有使用),掃描當前USB設備,注冊好usb transport,等待遠端的連接,同時啟動jdwp服務,與虛擬機的jdwp線程進行握手通信。
先看HOST和DEVICE的連接過程。
HOST首先發出connect請求,數據包內容如下:
C++代碼
- 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請求後,解析。
C++代碼
- 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端的。
C++代碼
- 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”之前,先調用:
C++代碼
- int fd = _adb_connect("host:version");
校驗,adb版本。_adb_connect中,如果碰到“host”打頭的請求,則切換transport。
C++代碼
- if (memcmp(service,"host",4) != 0 && switch_socket_transport(fd)) {
- return -1;
- }
在switch_socket_transport中,如果剛開始在adb命令中未指定serial 和transport type, 則,將“host:transport-any”發往5037端口。
C++代碼
- if(writex(fd, tmp, 4) || writex(fd, service, len)) {
- strcpy(__adb_error, "write failure during connection");
- adb_close(fd);
- return -1;
- }
等待返回一個“OKAY”。
C++代碼
- if(adb_status(fd)) {
- adb_close(fd);
- return -1;
- }
在裡面判斷返回結果是否為“OK”。
C++代碼
- 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”。
C++代碼
- 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函數,執行下面語句:
C++代碼
- // 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繼續執行下面語句,
C++代碼
- 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
C++代碼
- 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進行處理。
C++代碼
- 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裡面去。
C++代碼
- 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,回調:
C++代碼
- 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。
C++代碼
- s->id = id;
- s->enqueue = remote_socket_enqueue;
- s->ready = remote_socket_ready;
- s->close = remote_socket_close;
- s->transport = t;
然後調用:
C++代碼
- send_ready(s->id, s->peer->id, t);
- s->ready(s);
這裡的s->id是DEVICE端local socket的id,s->peer->是HOST端的local socket的id。
C++代碼
- 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接收到以後,
C++代碼
- 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,還調用
C++代碼
- s->ready(s);
這裡的s是local jdwp service socket,來看它的ready函數jdwp_socket_ready
C++代碼
- 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:
C++代碼
- 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收到以後
C++代碼
- 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裡面,調用
C++代碼
- int r = adb_write(s->fd, p->ptr, p->len);
寫入端口5037,這樣,client就能看到jdwp的進程信息了。就像下面這樣。
C++代碼
- [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
因此,流程應該大致如圖所示,具體的步驟太復雜,只能粗略表示一下。