Android Debug Bridge(ADB)學習總結


Android Debug Bridge

Android調試橋(ADB)是一種多用途的命令行工具。通過它我們可以和模擬器或者設備通信。ADB是一個客戶端-服務器程序,包括三個組成部分:

  • 客戶端(Client),運行在你用於程序開發的電腦上。你可以通過shell端使用adb命令啟動客戶端。其他Android工具,例如ADT插件和DDMS同樣可以產生adb客戶端。
  • 服務器(Server),以后台進程的形式運行在你用於程序開發的電腦上。該服務器負責管理客戶端和運行於模擬器或設備上的adb守護進程(daemon)之間的通信。
  • 守護進程(Daemon),以后台進程的形式運行在模擬器或者設備上。

你可以在sdk/platform-tools下面找到adb工具。

當你啟動一個adb客戶端,客戶端首先檢測是否已有一個adb服務器進程正在運行。如果沒有,則啟動服務器進程。當服務器運行,adb服務器就會綁定本地的TCP端口5037並監聽adb客戶端發來的命令——所有的adb客戶端都是通過TCP端口5037與adb服務器進行通信。

接下來,服務器將所有運行中的模擬器或設備實例建立連接。它通過掃描所有5555到5585范圍內的奇數端口來定位所有的模擬器或設備。一旦服務器找到了adb守護進程,它將建立一個到該端口的連接。請注意每個模擬器或設備實例都會取得兩個連續的端口——偶數端口響應控制台連接,奇數端口響應adb連接。例如:

  Emulator 1, console: 5554

  Emulator 1, adb: 5555

  Emulator 2, console: 5556

  Emulator 2, adb: 5557

如上所示,通過5555端口連接adb的模擬器實例和通過5554端口連接控制台的實例是相同的。

一旦服務器與所有模擬器實例建立連接,就可以使用adb命令來訪問該實例。因為服務器管理模擬器或設備實例的連接,而且處理來自多個adb客戶端的命令,你可以通過任何客戶端(或腳本)來控制任何模擬器或設備實例。

你可以在PC的命令行或腳本上發布Android命令,使用方法:

語法

adb [-d|-e|-s <serialNumber>] <command>

如果僅有一個模擬器運行或一個設備連接,adb命令默認發送給這個設備。如果有多個模擬器運行或多個設備連接,你就需要使用-d, -e, -s選項來指定接收命令的目標設備。

ADB常用命令

  • adb start-server
  • adb kill-server
  • adb shell
  • adb devices
  • adb connect <serialNumber>
  • adb pull -s <serialNumber> <remote> <local>
  • adb push -s <serialNumber> <local> <remote>

實例演練

上面的學習總結都是鋪墊,或者說都是廢話,因為在其他技術博客也能看到相關的介紹。接下來才是文章的重點:"adb server is out of date. killing..."

這里我忍不住吐槽一下,網上關於"adb server is out of date. killing..."的介紹都是關於神馬“豌豆莢”之類的,沒有一篇文章從深層原理發出,解釋為什么會出現這種情況。吐槽完畢。。。

 

為了解決公司里多客戶端通過tftp公用adb server造成相互“殺死”對方的情況,我進行了如下測試:

場景:兩個DMP Board,三個tftp用戶。

1. 查看A,B,C三個用戶的adb路徑

macan@BG2BLT06:~$ which adb
/home/macan/Android_Eclipse/adt-bundle-linux-x86_64-20130219/sdk/platform-tools/adb
[~/macan/Honeycomb]which adb
/home/chenwei/macan/Honeycomb/out/host/linux-x86/bin/adb
cwen@BG2BLT06:~$ which adb
/home/cwen/android/android-sdk-linux_86/platform-tools/adb

細心的讀者可能會發現,三個用戶的adb路徑都不同啊,怎么說公用一個adb server呢?上面文章講過:“當你啟動一個adb客戶端,客戶端首先檢測是否已有一個adb服務器進程正在運行。如果沒有,則啟動服務器進程。”為了更好的理解,第二步讓我們看看進程情況。

2. 用戶B,C啟動adb server

 

[~/macan/Honeycomb]adb start-server
* daemon not running. starting it now on port 5037 *
* daemon started successfully *
cwen@BG2BLT06:~$ adb start-server

A,B,C用戶分別查看進程情況

macan@BG2BLT06:~$ ps aux | grep adb
chenwei  14873  0.0  0.0  19988   916 pts/10   Sl   13:38   0:00 adb fork-server server
macan    14891  0.0  0.0   8956   876 pts/12   R+   13:39   0:00 grep --color=auto adb
[~/macan/Honeycomb]ps axu | grep adb
chenwei  14873  0.0  0.0  19988   916 pts/10   Sl   13:38   0:00 adb fork-server server
chenwei  14918  0.0  0.0   8956   876 pts/10   S+   13:40   0:00 grep --color=auto adb
cwen@BG2BLT06:~$ ps aux | grep adb
chenwei  14873  0.0  0.0  19988   916 pts/10   Sl   13:38   0:00 adb fork-server server
cwen     14915  0.0  0.0   8952   876 pts/11   R+   13:40   0:00 grep --color=auto adb

到了這里大家應該就明白了“公用adb server”這句話的意思了。不過,我們還是沒有發現所謂的:"adb server is out of date. killing..."

3. 用戶A啟動adb server(關鍵)

在B已經啟動adb server的情況下,我們發現C執行"adb start-server"沒有反應,因為公用B的adb server。那么當A執行“adb start-server”呢?

macan@BG2BLT06:~$ adb start-server
adb server is out of date.  killing...
* daemon started successfully *

悲劇發生了。。。我們盼望已久的"adb server is out of date. killing..."出現了!這是為啥捏??? 

先別急,一步步分析。

4. 再次看看進程

macan@BG2BLT06:~$ ps aux |grep adb
macan    15062  0.0  0.0  20944  1404 pts/12   Sl   13:49   0:00 adb fork-server server
macan    15107  0.0  0.0   8956   872 pts/12   R+   13:52   0:00 grep --color=auto adb

很明顯,之前由B的Client fork出的adb server已經被kill,現在的adb server是由A的Client fork出的。。。

這個時候,我們的線索只有一個"adb server is out of date. killing..."!!!

一切都是浮雲,源碼才是王道!!!

/system/core/adb

通過定位找到了"adb server is out of date. killing..."所在位置

//adb_client.c

if(version != ADB_SERVER_VERSION) {
            printf("*Yagami* version: %d ADB_SERVER_VERSION: %d\n" ,version,ADB_SERVER_VERSION);
            printf("adb server is out of date.  killing...\n");
            fd = _adb_connect("host:kill");
            adb_close(fd);

            /* XXX can we better detect its death? */
            adb_sleep_ms(2000);
            goto start_server;
        }

我們發現了好東東:ADB_SERVER_VERSION!找到它的聲明!

#define ADB_SERVER_VERSION    26    // Increment this when we want to force users to start a new adb server

這就是版本號啊!我們離真相已經不遠了!!!

我在B用戶adb源碼adb_client.c中加入了一條打印,希望能發現更多信息。

繼續測試

5. 再次啟動B adb server

[~/macan/Honeycomb]adb start-server
*Yagami* version: 31 ADB_SERVER_VERSION: 26
adb server is out of date.  killing...
* daemon started successfully *

同樣,我們發現B又kill掉了A的server。不過此時的我們已經發現了原因,一個版本號是26,一個版本號是31。。。

6. 好吧,讓我們看看A,B,C分別都是神碼版本吧。。。

macan@BG2BLT06:~$ adb version
Android Debug Bridge version 1.0.31
[~/macan/Honeycomb]adb version
Android Debug Bridge version 1.0.26
cwen@BG2BLT06:~$ adb version
Android Debug Bridge version 1.0.26

怪不的B,C兩個能兼容,因為版本號一樣啊。。。

到這里還沒完呢,原因找到了,解決方法還木有給呢。。。

其實很簡單啦,統一版本號唄。

方法一:

在tftp的/usr/bin下面存放一個adb,保證每個用戶的$PATH里面/usr/bin的路徑在最前面,這樣大家就可以統一用這個adb,版本當然一樣。

方法二:

如果每個用戶想用自己的adb server,可能有時自己會修改源碼,那么大家就統一一個版本號,修改ADB_SERVER_VERSION這個宏即可。

 

ps:還有一點測試時候用的其他命令,就當看着玩吧。

進入DMP Board查看daemon進程

ps | grep adbd
root      735   1     7484   900   ffffffff 2ac1ec30 S /sbin/adbd

查看5037端口號

netstat -apn|grep 5037
tcp        0      0 127.0.0.1:5037          0.0.0.0:*               LISTEN      15861/adb

查看進程15861

ps aux | grep 15861
chenwei  15861  0.0  0.0  29144  1512 pts/27   Sl   11:37   0:00 adb fork-server server
chenwei  22605  0.0  0.0   8956   876 pts/0    S+   11:55   0:00 grep --color=auto 15861


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM