您的位置:首页 > 移动开发 > Android开发

Android Debug Bridge(ADB)学习总结

2013-04-23 23:00 246 查看
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: