注冊完三個通信函數(shù)和連個線程之后,就調(diào)用函數(shù)install_listener在5037端口進(jìn)行監(jiān)聽,然后將這個服務(wù)添加到鏈表中(可提供多個服務(wù),這個我不關(guān)注),并將輸入流重定向到/dev/null,打印 adb start ,向之前打開的管道寫端寫入 OK\N,通知服務(wù)已經(jīng)啟動。進(jìn)入fdevent_loop,fdevent_process進(jìn)行處理,這兩個函數(shù)后面進(jìn)行分析?;剡^頭來看adb command發(fā)送的adb shell命令。
前文講到子進(jìn)程execl了adb命令,我們回過頭來看看父進(jìn)程做什么
chartemp[3];
temp[0] = 'A'; temp[1] = 'B'; temp[2] = 'C';
// wait for the "OK\n" message
adb_close(fd[1]);
intret = adb_read(fd[0], temp, 3);
intsaved_errno = errno;
adb_close(fd[0]);
if(ret < 0) {
fprintf(stderr, "could not read ok from ADB Server, errno = %d\n", saved_errno);
return-1;
}
if(ret != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
fprintf(stderr, "ADB server didn't ACK\n" );
return-1;
}
首先父進(jìn)程關(guān)閉了管道寫端,準(zhǔn)備從管道讀端讀取數(shù)據(jù),當(dāng)adb-server啟動后向?qū)懚藢懭隣K\n 讀端從阻塞返回,launch_server返回。再次進(jìn)行__adb_connect 之后調(diào)用SendProtocolString 發(fā)送 000dhost:features,成功返回文件描述符,adb_connect返回到adb_query,
, 之后讀取四個字節(jié)長度,然后根據(jù)長度讀取數(shù)據(jù)z,這里返回000c也就是12, 后面返回的是shell_v2,cmd
協(xié)議版本和命令類型。adb_query返回之后adb_get_feature_set返回, FeatureSet
為 shell_v2,cmd.
之后調(diào)用CanUseFeature 對一下版本是否匹配。 最后解析參數(shù)調(diào)用RemoteShell函數(shù)進(jìn)行處理。
然后發(fā)送RemoteShell :shell,v2,TERM=xterm:
之后就是從STDIN中讀取數(shù)據(jù) 寫入到5037端口的鏈接。 這部分看完了,再回來看adb-server收到接到adb的鏈接請求后如何處理。
if(ev &FDE_READ) {
sockaddr_storagess;
sockaddr* addrp =reinterpret_cast(&ss);
socklen_talen =sizeof(ss);
intfd = adb_socket_accept(_fd,addrp,&alen);
if(fd <0)return;
intrcv_buf_size =CHUNK_SIZE;
adb_setsockopt(fd,SOL_SOCKET,SO_RCVBUF,&rcv_buf_size,sizeof(rcv_buf_size));
asocket* s = create_local_socket(fd);
if(s) {
connect_to_smartsocket(s);
return;
}
adb_close(fd);
}
adb-server在ss_listener_event_func觀察可讀事件,當(dāng)鏈接建立后進(jìn)入這個函數(shù),講請求接進(jìn)來后 重新設(shè)置緩沖區(qū)。
創(chuàng)建一對asocket一個代表服務(wù)端,一個代表客戶端(其實是一個從接進(jìn)來的鏈接中讀取數(shù)據(jù),一個寫入數(shù)據(jù))。
我們來看看怎么處理的,這個流程各種回調(diào),響應(yīng)式變成,好無聊
create_local_socket 創(chuàng)建客戶端asocket 設(shè)置回調(diào)函數(shù)local_socket_enqueue? local_socket_ready local_socket_close 鏈入local_socket_list
connect_to_smartsocket 創(chuàng)建服務(wù)端asocket,設(shè)置回調(diào)函數(shù)smart_socket_enqueue smart_socket_ready? smart_socket_close,設(shè)置local和smatrserver互為對端。
下面稱服務(wù)端asocket和客戶端socket分別為local_asocket,server_asocket,
最后執(zhí)行l(wèi)ocal_asocket.ready(local_asocket),
static voidlocal_socket_ready(asocket* s) {
/* far side is ready for data, pay attention to
readable events */
fdevent_add(&s->fde,FDE_READ);
}
其實就是觀察這個socket可寫狀態(tài)(可寫回調(diào)local_socket_event_func),因為客戶端馬上寫了個000dhost:features(前邊是長度,后邊是命令)。所以該函數(shù)會馬上回調(diào)。
這時候關(guān)注讀事件部分
if(ev &FDE_READ) {
這時候還沒有設(shè)置transport 當(dāng)前的max_payload= 256*1024,從客戶端套接字讀取數(shù)據(jù)到apacket->data,執(zhí)行server_asocket.enqueue
(server_asocket,p),注意這里p存了從套接字中讀取的數(shù)據(jù),server_asocket.enqueue函數(shù)就是smart_socket_enqueue函數(shù),可以猜測smart_socket_enqueue是寫入數(shù)據(jù)到usb,然后返回數(shù)據(jù)后寫出到fd,這里稍后分析,再看smart_socket_enqueue 返回后,就卸載了可讀事件的回調(diào),因為之后要寫入數(shù)據(jù)了。
現(xiàn)在分析smart_socket_enqueue函數(shù):獲取數(shù)據(jù)前四位長度。解析命令,之后對不同命令進(jìn)行處理,這里的命令是host:features,這里將
type設(shè)置成kTransportAny,server設(shè)置成features,調(diào)用handle_host_request處理請求,在adb.cpp中,
if(!strncmp(service, "transport", strlen("transport"))) {
TransportType type = kTransportAny;
atransport* t = acquire_one_transport(type, serial,nullptr, &error);
。。。
s->transport = t;
SendOkay(reply_fd);
通過acquire_one_transport獲取一個transport, 從transport_list中找出合適的atransport,根據(jù)類型(還記得我們之前打開的套接字對用于和usb通信的那套通信框架嗎,atransport就描述了該結(jié)構(gòu))對于不同的類型還有寫限制。 返回到handle_host_request
,獲取了atransport后,設(shè)置server_asocke的transport為 (選定通信通道),調(diào)用SendOkay(reply_fd);這里的reply_fd就是鏈接如5037端口的套接字,SendOkay就是向套接字中寫入OKAY.
這里我們不在關(guān)心協(xié)議細(xì)節(jié)的東西,我們來查看如何通信。假如命令是transport直接返回,由此可見transport是用于找到通信介質(zhì)。這種命令不需要寫入usb,就直接返回了。再看features命令,調(diào)用SendOkay(reply_fd, FeatureSetToString(t->features()));函數(shù)。
static intSendOkay(intfd,conststd::string& s) {
SendOkay(fd);
SendProtocolString(fd, s);
return0;
}
除了發(fā)送ok以為,還發(fā)送了 SendProtocolString 發(fā)送協(xié)議信息。到這里還沒有看到如何和adbd通信。 整個流程還沒有跑通,
關(guān)鍵點就在transport初始化的時候,會初始化一些信息 feure也是其中初始化的數(shù)據(jù)。 所以features 也是不需要和手機通信的,處理完成這些不用和手機進(jìn)行通信的請求后就是handle_forward_request 轉(zhuǎn)發(fā)請求, 也是獲取相應(yīng)的atransport 然后install_listeren,
以RemoteShell :shell,v2,TERM=xterm:這條命令為例子 第一個參數(shù)是RemoteShell,第二個參數(shù)是shell,v2,TERM=xterm: 三個參數(shù)是transport
創(chuàng)建新的 alistener
connect_to=shell,v2,TERM=xterm:
name = RemoteShell