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

你可能感兴趣的:(Android Debug Bridge(ADB)学习总结)