淺析linux開發工具adb具體實現
淺析linux開發工具adb具體實現 《再次淺析adb shell,pc daemon和手機daemon三者之間的數據交互流程》 《淺析adb創建流程》 //=============================== adb啟動shell用到的命令 export ADBHOST=192.168.100.2 adb kill-server adb start-server11:31:27 adb shell //=============================== 讓我們來分析一下對應的代碼 adb start-server ==>main ==>adb_commandline ==>do_cmd ==>adb_connect("host:start-server");如果是adb start-server命令 ==>fd = _adb_connect("host:version"); _adb_connect fd = socket_loopback_client(ADB_PORT, SOCK_STREAM);//嘗試連接127.0.0.1本機ip地址對應的ADB_PORT端口server 如果fd小於0,那么函數返回-2,否則在ADB_PORT端口打開server成功, snprintf(tmp, sizeof tmp, "%04x", len); if (writex(fd, tmp, 4) || writex(fd, service, len)) //先將4字節長度發送給server,然后發送命令數據"host:start-server" adb_status(fd); readx(fd, buf, 4);//讀取server對該命令的反饋信息 if (!memcmp(buf, "OKAY", 4))//server成功處理 if (memcmp(buf, "FAIL", 4))//server返回了非FAIL值,那么說明server出現協議數據異常,直接退出 ==>如果沒有啟動server,那么fd將等於-2 if(fd == -2) { fprintf(stdout,"* daemon not running. starting it now */n"); start_server: if(launch_server(0)) { fprintf(stderr,"* failed to start daemon */n"); return -1; } else { fprintf(stdout,"* daemon started successfully */n"); } /* give the server some time to start properly and detect devices */ adb_sleep_ms(2000); // fall through to _adb_connect } ==>launch_server ==> pipe(fd); pid_t pid = fork(); if (pid == 0) { //子線程[luther.gliethttp] adb_close(fd[0]); dup2(fd[1], STDERR_FILENO);//將pipe[1]的描述符dup2到stderr上, //因為execl操作只會裝入新的執行程序代碼,然后取代調用execl的child子進程繼續在用戶空間執行, //並不會改變內核空間的fd_tables[],所以execl運行的程序送往stderr上的數據就是送到parent的pipe[0]管道. adb_close(fd[1]); int result = execl(path, "adb", "fork-server", "server", NULL); // this should not return //永遠不會返回到這里,因為位於用戶空間的這里的代碼,已經被execl操作替換成adb fork-server server程序了, //這里的代碼已經被覆蓋,不存在了,所以當然不會返回到這里了[luther.gliethttp] fprintf(stderr, "OOPS! execl returned %d, errno: %d/n", result, errno); } else { char temp[3]; temp[0] = 'A'; temp[1] = 'B'; temp[2] = 'C'; // wait for the "OK/n" message adb_close(fd[1]); int ret = adb_read(fd[0], temp, 3);//等待管道數據的到來 /* static __inline__ int adb_read(int fd, void* buf, size_t len) { return read(fd, buf, len); } */ adb_close(fd[0]); if (ret < 0) { fprintf(stderr, "could not read ok from ADB Server, errno = %d/n", 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; } // run a program in a new session setsid();//之前parent和child運行在同一個session里,而且parent是session頭,所以, //所以作為session頭的parent如果exit結束執行的話,那么會話session組中的所有進程將都被殺死, //所以執行setsid()之后,parent將重新獲得一個新的會話session組id,child將仍持有原有的會話session組, //這時parent退出之后,將不會影響到child了[luther.gliethttp]. } 來看看fork之后execl執行的過程[luther.gliethttp] adb fork-server server ==>main ==>adb_commandline if (!strcmp(argv[0], "fork-server")) { /* this is a special flag used only when the ADB client launches the ADB Server */ is_daemon = 1; } if ((argc > 0) && (!strcmp(argv[0],"server"))) { if (no_daemon || is_daemon) { r = adb_main(is_daemon);//完成daemon啟動 } else { r = launch_server(); } if(r) { fprintf(stderr,"* could not start server */n"); } return r; } ==>adb_main init_transport_registration HOST = 1; usb_init(); local_init(); if(install_listener("tcp:5037", "*smartsocket*", NULL)) { exit(1); } if (is_daemon) { fprintf(stderr, "OK/n");//將OK傳遞給上面parent執行adb_read(fd[0], temp, 3);管道接收函數. start_logging();//打開log文件,然后dup2到stdout和stderr, } fdevent_loop(); usb_cleanup(); //================================ void start_logging(void) { int fd; fd = unix_open("/dev/null", O_RDONLY); dup2(fd, 0);//取消輸入通道stdin fd = unix_open("/tmp/adb.log", O_WRONLY | O_CREAT | O_APPEND, 0640);//創建/tmp/adb.log文件 if(fd < 0) { fd = unix_open("/dev/null", O_WRONLY);//如果不成功,那么執行/dev/null } dup2(fd, 1);//將文件句柄dup2到stdout dup2(fd, 2);//將文件句柄dup2到stderr fprintf(stderr,"--- adb starting (pid %d) ---/n", getpid());//向/tmp/adb.log文件寫入log數據[luther.gliethttp] } //================================ void fdevent_loop() { fdevent *fde; for(;;) { fdevent_process(); while((fde = fdevent_plist_dequeue())) { unsigned events = fde->events; fde->events = 0; fde->state &= (~FDE_PENDING); dump_fde(fde, "callback"); fde->func(fde->fd, events, fde->arg); } } } //================================ ==>install_listener fdevent_install(&l->fde, l->fd, ss_listener_event_func, l); ==>fdevent_install fde->func = func; fdevent_connect(fde); ==>ss_listener_event_func ==>connect_to_smartsocket asocket *ss = create_smart_socket(smart_socket_action); ==>create_smart_socket s->enqueue = smart_socket_enqueue; ==>smart_socket_enqueue ==>handle_host_request ==>local_connect ... fd = socket_loopback_client(port, SOCK_STREAM); #if ADB_HOST if(fd < 0) { const char *host = getenv("ADBHOST"); if(host) { fd = socket_network_client(host, port, SOCK_STREAM); } } #endif //================================ init_transport_registration void init_transport_registration(void) { int s[2]; if(adb_socketpair(s)){//創建一對unix通信socket fatal_errno("cannot open transport registration socketpair"); } transport_registration_send = s[0];//用來發送 transport_registration_recv = s[1];//用來接收 fdevent_install(&transport_registration_fde, transport_registration_recv,//注冊接收socket作為epoll等待信息來源 transport_registration_func,//對接收到的數據執行處理操作的func 0); fdevent_set(&transport_registration_fde, FDE_READ);//登記為READ類型 } fdevent_install==>fdevent_register ==>fd_table[fde->fd] = fde;//這里fd_table是模擬kernel實現方式,因為fde->fd由內核獲取,所以可以保證其值的唯一性. ==>fde->state |= FDE_ACTIVE;//置state為激活 fdevent_set(&transport_registration_fde, FDE_READ); ==> void fdevent_set(fdevent *fde, unsigned events) { ... if(fde->state & FDE_ACTIVE) { fdevent_update(fde, events);//刷新該fde->fd到epoll中 dump_fde(fde, "update"); } fde->state = (fde->state & FDE_STATEMASK) | events;//保存信息 ... } static void fdevent_update(fdevent *fde, unsigned events) { struct epoll_event ev; int active; active = (fde->state & FDE_EVENTMASK) != 0; memset(&ev, 0, sizeof(ev)); ev.events = 0;//清0 ev.data.ptr = fde;//置數據指針 if(events & FDE_READ) ev.events |= EPOLLIN;//置in事件 if(events & FDE_WRITE) ev.events |= EPOLLOUT;//置out事件 if(events & FDE_ERROR) ev.events |= (EPOLLERR | EPOLLHUP); fde->state = (fde->state & FDE_STATEMASK) | events; if(active) { ... } else { /* we're not active. if we're watching events, we need ** to add, otherwise we can just do nothing */ if(ev.events) { if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fde->fd, &ev)) {//添加到epoll_fd中 perror("epoll_ctl() failed/n"); exit(1); } } } } static int epoll_fd = -1; static void fdevent_init() { /* XXX: what's a good size for the passed in hint? */ epoll_fd = epoll_create(256); if(epoll_fd < 0) { perror("epoll_create() failed"); exit(1); } /* mark for close-on-exec */ fcntl(epoll_fd, F_SETFD, FD_CLOEXEC); } static void fdevent_process() { struct epoll_event events[256]; fdevent *fde; int i, n; n = epoll_wait(epoll_fd, events, 256, -1);//等待添加到epoll_fd中的各個fd對應event事件發生[luther.gliethttp] ... for(i = 0; i < n; i++) { struct epoll_event *ev = events + i; fde = ev->data.ptr; if(ev->events & EPOLLIN) { fde->events |= FDE_READ; } if(ev->events & EPOLLOUT) { fde->events |= FDE_WRITE; } if(ev->events & (EPOLLERR | EPOLLHUP)) { fde->events |= FDE_ERROR; } if(fde->events) { if(fde->state & FDE_PENDING) continue;//正在處理前一條信息 fde->state |= FDE_PENDING; fdevent_plist_enqueue(fde);//放入待處理的list鏈表上 } } } static void fdevent_plist_enqueue(fdevent *node) { fdevent *list = &list_pending;//需要處理所有pending任務的鏈表 node->next = list; node->prev = list->prev; node->prev->next = node; list->prev = node; } static fdevent *fdevent_plist_dequeue(void)//從pending任務鏈表摘下一個node來處理 { fdevent *list = &list_pending; fdevent *node = list->next; if(node == list) return 0; list->next = node->next; list->next->prev = list; node->next = 0; node->prev = 0; return node; } void fdevent_loop() { fdevent *fde; for(;;) { fdevent_process(); while((fde = fdevent_plist_dequeue())) { unsigned events = fde->events; fde->events = 0;//復位成0 fde->state &= (~FDE_PENDING);//事件檢查和前期處理完成,之后將執行事件對應的func,所以清除pending標志,允許該sock接受下一個event的添加[luther.gliethttp] dump_fde(fde, "callback"); fde->func(fde->fd, events, fde->arg); } } } adb_main ==>init_transport_registration ==>usb_init adb_thread_create(&tid, device_poll_thread, NULL)//創建thread ==>local_init adb_thread_create(&thr, client_socket_thread, 0)//host對應的處理函數,對於client,對應server_socket_thread transport_registration_send === transport_registration_recv [FDE_READ]=== transport_registration_func "tcp:5037" === local_name_to_fd("tcp:5037") [FDE_READ]=== ss_listener_event_func //處理來自loopback端口5037的sock數據 === 嘗試連接到"tcp:5037"上的client們 === local_socket_event_func 並將"tcp:5037"這個sock添加到listener_list鏈表上 好了,我們的server已經成功起來了,來看一個命令交互:adb shell 1.本地執行adb shell adb shell ==>main ==>adb_commandline ==>interactive_shell ==>fd = adb_connect("shell:"); int fd = _adb_connect("host:version");//因為server在上面已經打開,所以將成功鏈接 fd = socket_loopback_client(ADB_PORT, SOCK_STREAM);//打開127.0.0.1本地機tcp:5037端口 //對於server端,fdevent_process()==>epoll_wait(epoll_fd, events, 256, -1);將返回,觸發server啟動時install_listener("tcp:5037", "*smartsocket*", NULL);注冊登記的 //回調函數ss_listener_event_func在fdevent_loop中被執行. if (memcmp(service,"host",4) != 0 && switch_socket_transport(fd))//非host命令, //發送"host:transport-any"命令給server adb_status(fd);//讀取"host:version"命令的返回,對於host就是調用 //handle_host_request()==> //#define ADB_SERVER_VERSION 20 //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; //} //在OKAY00040014 switch_socket_transport對於server端來說對應==> ==>handle_host_request if (!strncmp(service, "transport", strlen("transport"))) { ... } else if (!strncmp(service, "transport-any", strlen("transport-any"))) { type = kTransportAny; } ... transport = acquire_one_transport(CS_ANY, type, serial, &error_string); //就是從transport_list鏈表上摘下一個登記了的transport,對於我們分析的adb shell就是 //init_transport_registration==>transport_registration_func==>會追加transport_list鏈表 //fdevent_install(&transport_registration_fde, // transport_registration_recv, // transport_registration_func, // 0); if (transport) { s->transport = transport; adb_write(reply_fd, "OKAY", 4); } int adb_status(int fd) { unsigned char buf[5]; unsigned len; if(readx(fd, buf, 4)) { strcpy(__adb_error, "protocol fault (no status)"); return -1; } if(!memcmp(buf, "OKAY", 4)) { return 0;//ok,server正常返回數據,退出,進一步處理 } if(memcmp(buf, "FAIL", 4)) { sprintf(__adb_error, "protocol fault (status %02x %02x %02x %02x?!)", buf[0], buf[1], buf[2], buf[3]); return -1; } if(readx(fd, buf, 4)) {//錯誤:讀取返回數據長度 strcpy(__adb_error, "protocol fault (status len)"); return -1; } buf[4] = 0; len = strtoul((char*)buf, 0, 16);//錯誤:轉換長度數據 if(len > 255) len = 255; if(readx(fd, __adb_error, len)) {//錯誤:讀取數據 strcpy(__adb_error, "protocol fault (status read)"); return -1; } __adb_error[len] = 0; return -1; } |