adb源碼分析2

注冊完三個通信函數(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









最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容