Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發環境 >> Android開發工具ADB教程之四:Device端

Android開發工具ADB教程之四:Device端

編輯:Android開發環境

       本文為大家梳理Device端adbd的運作原理。在此之前最好是已經看了前三篇文章:ADB概論、HOST端和Dalvik虛擬機之jdwp線程。

       在adbd起來時,也會監聽TCP:5037端口(好像沒有使用),掃描當前USB設備,注冊好usb transport,等待遠端的連接,同時啟動jdwp服務,與虛擬機的jdwp線程進行握手通信。

  先看HOST和DEVICE的連接過程。

  HOST首先發出connect請求,數據包內容如下:

C++代碼
  1. apacket *cp = get_apacket();   
  2. cp->msg.command = A_CNXN;   
  3. cp->msg.arg0 = A_VERSION;   
  4. cp->msg.arg1 = MAX_PAYLOAD;   
  5. snprintf((char*) cp->data, sizeof cp->data, "%s::",   
  6.         HOST ? "host" : adb_device_banner);  

       DEVICE端收到以後,解析後設置transport的狀態為HOST,然後給host回一個同樣的connect請求,只不過data由"host::"變成了"device::"。

       HOST收到DEVICE的connect請求後,解析。

C++代碼
  1. if(!strcmp(type, "device")) {   
  2.     D("setting connection_state to CS_DEVICE\n");   
  3.     t->connection_state = CS_DEVICE;   
  4.     update_transports();   
  5.     return;   
  6. }  

       update_transports供client發送adb track-devices命令時有用。

       因此到此時為止,HOST和DEVICE已經處於online狀態,准備好其它的通信了。

       這裡以adb jdwp命令為例說明,jdwp是獲取當前device中注冊了jdwp傳輸的進程列表。看看jdwp是怎麼從HOST到DEVICE端的。

C++代碼
  1. if (!strcmp(argv[0], "jdwp")) {   
  2.     int  fd = adb_connect("jdwp");   
  3.     if (fd >= 0) {   
  4.         read_and_dump(fd);   
  5.         adb_close(fd);   
  6.         return 0;   
  7.     } else {   
  8.         fprintf(stderr, "error: %s\n", adb_error());   
  9.         return -1;   
  10.     }   
  11. }  

       這是調用adb_connect,然後直接從裡面讀取結果,在發送“jdwp”之前,先調用:

C++代碼
  1. int fd = _adb_connect("host:version");  

       校驗,adb版本。_adb_connect中,如果碰到“host”打頭的請求,則切換transport。

C++代碼
  1. if (memcmp(service,"host",4) != 0 && switch_socket_transport(fd)) {   
  2.     return -1;   
  3. }  

       在switch_socket_transport中,如果剛開始在adb命令中未指定serial 和transport type, 則,將“host:transport-any”發往5037端口。

C++代碼
  1. if(writex(fd, tmp, 4) || writex(fd, service, len)) {   
  2.     strcpy(__adb_error, "write failure during connection");   
  3.     adb_close(fd);   
  4.     return -1;   
  5. }  

       等待返回一個“OKAY”。

C++代碼
  1. if(adb_status(fd)) {   
  2.     adb_close(fd);   
  3.     return -1;   
  4. }  

       在裡面判斷返回結果是否為“OK”。

C++代碼
  1. int adb_status(int fd)   
  2. {   
  3.     unsigned char buf[5];   
  4.     unsigned len;   
  5.   
  6.     if(!memcmp(buf, "OKAY", 4)) {   
  7.         return 0;   
  8.     }   
  9. }  

       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++代碼
  1. transport = acquire_one_transport(CS_ANY, type, serial, &error_string);   
  2.   
  3. if (transport) {   
  4.     s->transport = transport;   
  5.     adb_write(reply_fd, "OKAY", 4);   
  6. } else {   
  7.     sendfailmsg(reply_fd, error_string);   
  8. }  

       由此可知,切換transport後,才將"host:version"請求發送到TCP:5037端口,同樣經過smart_socket_enqueue->handle_host_request函數,執行下面語句:

C++代碼
  1. // returns our value for ADB_SERVER_VERSION   
  2. if (!strcmp(service, "version")) {   
  3.     char version[12];   
  4.     snprintf(version, sizeof version, "%04x", ADB_SERVER_VERSION);   
  5.     snprintf(buf, sizeof buf, "OKAY%04x%s", (unsigned)strlen(version), version);   
  6.     writex(reply_fd, buf, strlen(buf));   
  7.     return 0;   
  8. }  

       返回結果的先導也有一個OKAY。TCP:5037的另一端,也就是service,它的讀寫處理函數是local_socket_event_func,講"host:version"結果。

       再來看“jdwp”請求,smart_socket_enqueue->handle_host_request,handle_host_request發現處理不了,所以回到smart_socket_enqueue繼續執行下面語句,

C++代碼
  1. s->peer->ready = local_socket_ready_notify;   
  2. s->peer->close = local_socket_close_notify;   
  3. s->peer->peer = 0;   
  4.     /* give him our transport and upref it */  
  5. s->peer->transport = s->transport;   
  6.   
  7. connect_to_remote(s->peer, (char*) (p->data + 4));   
  8. s->peer = 0;   
  9. s->close(s);  

       這段語句,將smart soeckt關閉,然後將transport交給local socket,這樣,connect_to_remote的參數就是local socket, “jdwp”,在connect_to_remote

C++代碼
  1. p->msg.command = A_OPEN;   
  2. p->msg.arg0 = s->id;   
  3. p->msg.data_length = len;   
  4. strcpy((char*) p->data, destination);   
  5. send_packet(p, s->transport);  

       把A_OPEN命令發給DEVICE端,id是socket的唯一標識,在初始化local socket的時候就確定,便於遠端回復數據過來時,在socket list中能查找到該socket進行處理。

C++代碼
  1. void install_local_socket(asocket *s)   
  2. {   
  3.     adb_mutex_lock(&socket_list_lock);   
  4.   
  5.     s->id = local_socket_next_id++;   
  6.     insert_local_socket(s, &local_socket_list);   
  7.   
  8.     adb_mutex_unlock(&socket_list_lock);   
  9. }  

       在DEVICE端的output_thread線程,讀取到消息,寫到transport_socket裡面去。

C++代碼
  1. for(;;) {   
  2.     p = get_apacket();   
  3.   
  4.     if(t->read_from_remote(p, t) == 0){   
  5.         D("from_remote: received remote packet, sending to transport %p\n",   
  6.           t);   
  7.         if(write_packet(t->fd, &p)){   
  8.             put_apacket(p);   
  9.             D("from_remote: failed to write apacket to transport %p", t);   
  10.             goto oops;   
  11.         }   
  12.     } else {   
  13.         D("from_remote: remote read failed for transport %p\n", p);   
  14.         put_apacket(p);   
  15.         break;   
  16.     }   
  17. }  

       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++代碼
  1. s->socket.ready   = jdwp_socket_ready;   
  2. s->socket.enqueue = jdwp_socket_enqueue;   
  3. s->socket.close   = jdwp_socket_close;   
  4. s->pass           = 0;   

       create_remote_socket的回調:這裡的id是HOST端的local socket的id。

C++代碼
  1. s->id = id;   
  2. s->enqueue = remote_socket_enqueue;   
  3. s->ready = remote_socket_ready;   
  4. s->close = remote_socket_close;   
  5. s->transport = t;  

       然後調用:

C++代碼
  1. send_ready(s->id, s->peer->id, t);   
  2. s->ready(s);  

       這裡的s->id是DEVICE端local socket的id,s->peer->是HOST端的local socket的id。

C++代碼
  1. static void send_ready(unsigned local, unsigned remote, atransport *t)   
  2. {   
  3.     D("Calling send_ready \n");   
  4.     apacket *p = get_apacket();   
  5.     p->msg.command = A_OKAY;   
  6.     p->msg.arg0 = local;   
  7.     p->msg.arg1 = remote;   
  8.     send_packet(p, t);   
  9. }  

       這樣,表示HOST端發送的A_OPEN命令成功了,DEVICE端的output_thread接收到以後,

C++代碼
  1. case A_OKAY: /* READY(local-id, remote-id, "") */  
  2.     if(t->connection_state != CS_OFFLINE) {   
  3.         if((s = find_local_socket(p->msg.arg1))) {   
  4.             if(s->peer == 0) {   
  5.                 s->peer = create_remote_socket(p->msg.arg0, t);   
  6.                 s->peer->peer = s;   
  7.             }   
  8.             s->ready(s);   
  9.         }   
  10.     }   
  11.     break;  

       根據id,找回local socket,同時創建remote socket。

       前面看到,DEVICE端創建好local socket和remote socket之後,除了往HOST發一個OKAY,還調用

C++代碼
  1. s->ready(s);  

       這裡的s是local jdwp service socket,來看它的ready函數jdwp_socket_ready

C++代碼
  1. apacket*  p = get_apacket();   
  2. p->len = jdwp_process_list((char*)p->data, MAX_PAYLOAD);   
  3. peer->enqueue(peer, p);   
  4. jdwp->pass = 1;  

       將jdwp服務中的進程號,寫入packet,調用remote socket的enqueue,也就是remote_socket_enqueue:

C++代碼
  1. static int remote_socket_enqueue(asocket *s, apacket *p)   
  2. {   
  3.     D("Calling remote_socket_enqueue\n");   
  4.     p->msg.command = A_WRTE;   
  5.     p->msg.arg0 = s->peer->id;   
  6.     p->msg.arg1 = s->id;   
  7.     p->msg.data_length = p->len;   
  8.     send_packet(p, s->transport);   
  9.     return 1;   
  10. }  

       它進程信息,寫入transport,HOST的output_thread收到以後

C++代碼
  1. case A_WRTE:                                                                 
  2.     if(t->connection_state != CS_OFFLINE) {                                  
  3.         if((s = find_local_socket(p->msg.arg1))) {                           
  4.             unsigned rid = p->msg.arg0;                                      
  5.             p->len = p->msg.data_length;                                     
  6.                                                                              
  7.             if(s->enqueue(s, p) == 0) {                                      
  8.                 D("Enqueue the socket\n");                                   
  9.                 send_ready(s->id, rid, t);                                   
  10.             }                                                                
  11.             return;                                                          
  12.         }                                                                    
  13.     }                                                                        
  14.     break;      

       它調用local socket的enqueue函數local_socket_enqueue,在local_socket_enqueue裡面,調用

C++代碼
  1. int r = adb_write(s->fd, p->ptr, p->len);  

       寫入端口5037,這樣,client就能看到jdwp的進程信息了。就像下面這樣。

C++代碼
  1. [yinlijun@localhost adb]$ adb jdwp   
  2. 228   
  3. 277   
  4. 111   
  5. 176   
  6. 185   
  7. 188   
  8. 180   
  9. 208   
  10. 212   
  11. 330   
  12. 339   
  13. 351   
  14. 361   
  15. 370   
  16. 378   
  17. 407   
  18. 416   
  19. 427   
  20. 438   
  21. 446   
  22. 455  

       因此,流程應該大致如圖所示,具體的步驟太復雜,只能粗略表示一下。

Android開發工具ADB教程之四:Device端

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved