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