andoid adb server研究

答問題adb 1.0.39執行adb -a -P5037 fork-server server報錯求救大佬?時發現對adb啟動服務並不了解,於是簡單研究了adb的源碼。也非常感謝 @星空輕語 的幫助。

通常我們沒有必要去特意使用adb server命令。因為我們經常敲的adb devices命令一般會有如下提示:

List of devices attached* daemon not running. starting it now at tcp:5037 ** daemon started successfully *

如果有usb設備連著或者模擬器開著,會顯示名稱。

如果使用ps aux | grep adb,會發現多了一個後台進程:

adb -L tcp:5037 fork-server server --reply-fd 4

這估計就是我答題時最開始錯誤回答的原因了。後台會提到為啥是4。

先以adb devices為例介紹下調用流程。

1. main在adb/client/main.cpp,基本就是調用adb_commandline()解析命令行。(github.com/android/plat

int main(int argc, char** argv) { adb_trace_init(argv); return adb_commandline(argc - 1, const_cast<const char**>(argv + 1));}

2. 接著是devices命令的處理,就是調用adb_query_command。

github.com/android/plat

if (!strcmp(argv[0], "devices")) { const char *listopt; if (argc < 2) { listopt = ""; } else if (argc == 2 && !strcmp(argv[1], "-l")) { listopt = argv[1]; } else { return syntax_error("adb devices [-l]"); } std::string query = android::base::StringPrintf("host:%s%s", argv[0], listopt); printf("List of devices attached
"); return adb_query_command(query); }

3. adb_query_command還是在commandline.cpp中,就是adb_query的wrapper。

static int adb_query_command(const std::string& command) { std::string result; std::string error; if (!adb_query(command, &result, &error)) { fprintf(stderr, "error: %s
", error.c_str()); return 1; } printf("%s
", result.c_str()); return 0;}

4. adb_query見github.com/android/plat,走到了adb_connect。

bool adb_query(const std::string& service, std::string* result, std::string* error) { D("adb_query: %s", service.c_str()); int fd = adb_connect(service, error); if (fd < 0) { return false; } result->clear(); if (!ReadProtocolString(fd, result, error)) { adb_close(fd); return false; } ReadOrderlyShutdown(fd); adb_close(fd); return true;}

5. adb_connect還是在adb_client.cpp中,終於看到了主流程launch_server。

int adb_connect(const std::string& service, std::string* error) { // first query the adb servers version int fd = _adb_connect("host:version", error); D("adb_connect: service %s", service.c_str()); if (fd == -2 && !is_local_socket_spec(__adb_server_socket_spec)) { fprintf(stderr, "* cannot start server on remote host
"); // error is the original network connection error return fd; } else if (fd == -2) { fprintf(stderr, "* daemon not running; starting now at %s
", __adb_server_socket_spec); start_server: if (launch_server(__adb_server_socket_spec)) { fprintf(stderr, "* failed to start daemon
"); // launch_server() has already printed detailed error info, so just // return a generic error string about the overall adb_connect() // that the caller requested. *error = "cannot connect to daemon"; return -1; } else { fprintf(stderr, "* daemon started successfully
"); } // The server will wait until it detects all of its connected devices before acking. // Fall through to _adb_connect. } //...

6. 用launch_server中的linux/mac流程來介紹比較簡單。launch_server在github.com/android/plat

int launch_server(const std::string& socket_spec) {#if defined(_WIN32)#else /* !defined(_WIN32) */ // set up a pipe so the child can tell us when it is ready. // fd[0] will be parents end, and the child will write on fd[1] int fd[2]; if (pipe(fd)) { fprintf(stderr, "pipe failed in launch_server, errno: %d
", errno); return -1; } std::string path = android::base::GetExecutablePath(); pid_t pid = fork(); if (pid < 0) return -1; if (pid == 0) { // child side of the fork adb_close(fd[0]); char reply_fd[30]; snprintf(reply_fd, sizeof(reply_fd), "%d", fd[1]); // child process int result = execl(path.c_str(), "adb", "-L", socket_spec.c_str(), "fork-server", "server", "--reply-fd", reply_fd, NULL); // this should not return fprintf(stderr, "adb: execl returned %d: %s
", result, strerror(errno)); } else { // parent side of the fork char temp[3] = {}; // wait for the "OK
" message
adb_close(fd[1]); int ret = adb_read(fd[0], temp, 3); int saved_errno = errno; adb_close(fd[0]); if (ret < 0) { fprintf(stderr, "could not read ok from ADB Server, errno = %d
", saved_errno); return -1; } if (ret != 3 || temp[0] != O || temp[1] != K || temp[2] !=
) { ReportServerStartupFailure(pid); return -1; } }#endif /* !defined(_WIN32) */ return 0;}

首先創建一個pipe。因為linux默認打開了0、1、2三個文件句柄,一個pipe佔用兩個句柄,pipe[0] = 3,pipe[1] = 4。

然後進行了fork,接著父進程監聽pipe[0],進程將pipe[1]傳入execl,即執行命令adb -L $Socket fork-server server --reply-fd 4,其中4是pipe[1]。

所以fork-server和--reply-fd是用於程序編寫adb調用時需要使用的,我們通常使用不需要。

結合fish:adb 1.0.39執行adb -a -P5037 fork-server server報錯求救大佬?

進行總結:

1、單純的啟動server不需要刻意執行,直接使用adb devices或其他adb命令即可。

2、如果特意去啟動server,後台啟動可以使用adb server,前台啟動可以使用adb server nodaemon。

3、默認adb server使用的是localhost,如果需要遠程訪問,則要使用-a。

4、默認adb server使用的是5037埠,如果需要修改,則要使用-P5037或-P 5037的形式。

5、對於3和4,也可以使用-L tcp:ip:port的形式,默認是-L tcp:localhost:5037。


推薦閱讀:

BAT哪家Android的APP 水準最高?
完全急救指南- 應急 App 專題(二)
Jake Wharton 建議一個應用只使用一個 Activity
TCL並不是互聯網公司,為什麼也加入這場中端手機大混戰?
三星 Note7和iphone 7 plus的哪些差距會讓你選擇Note7?

TAG:Android | androidsdktools |