ADB简介
Android Debug Bridge (adb) 是一个Android的命令行工具。可以用来连接模拟器或实际的移动设备。比如 adb logcat, adb shell。Dalvik Debug Monitor Server(DDMS) 后台也是运行的adb来实现监控调试移动设备。
总体而言,adb有两个用途:
- 监控连接设备 :adb会监控所有已经连接设备(包括模拟器),譬如设备所处的状态:ONLINE,OFFLINE, BOOTLOADER或RECOVERY。
- 提供操作命令 :adb提供了很多命令(
adb shell
,adb pull
),来实现对设备的操控。这些操作命令在adb的体系里面,都称为“服务”。
ADB 实现原理
Adb的全称为 Android Debug Bridge:Android调试桥,下图为Android官方对adb的介绍:
Android Debug Bridge (adb) 是一个通用命令行工具,其允许我们与模拟器或连接的 Android 设备进行通信。它可为各种设备操作提供便利,如安装和调试应用,并提供对 Unix shell(可用来在模拟器或连接的设备上运行各种命令)的访问。该工具是一个C/S架构实现的程序,包括三个组件:
- ADB Client:运行在PC上,通过在命令行执行adb,就启动了ADB Client程序
- ADB Server:运行于PC的后台进程,用于管理ADB Client和Daemon间的通信
- ADB Daemon (即adbd) :运行在模拟器或移动设备上的后台服务。当Android系统启动时,由init程序启动adbd。如果adbd挂了,则adbd会由init重新启动。
您可以在 android_sdk/platform-tools/
中找到 adb
工具。
ADB 源码
adb的源码在 system/core/adb 目录下,adb和adbd两个二进制程序都是从这个目录下的代码中编译出来的,可以参考 Android.mk
文件,通过宏编译开关ADB_HOST来控制:
Client 和 Server 调用的是adb
ADB_HOST=1
1 | LOCAL_CFLAGS += \ |
而 emulator/device 调用adbd
ADB_HOST=0
1 | LOCAL_CFLAGS := \ |
1、 在PC HOST端,adb
会fork出一个守护进程(不是adbd),即ADB Server,而父进程(ADB Client)继续处理Client请求,所有的Client通过TCP端口号5037进行与Server通信,而Server创建 local socket 与 remote socket,前者用于和Client通信,后者用与远端进行通信,emulator通过TCP,real device则通过usb。
2、在emulator/device端,adbd
也创建 local socket 和 remote socket,前者与通过 jdwp 与Java虚拟机进程通信,后者通过 TCP/USB 与 PC HOST通信。
Client和Server虽然是同一个执行程序,但在命令行输入一条adb
命令后,实际上完成了一次通信。在Server启动的时候,会将自己绑定到本地的5037
端口,当Client有请求到来时,便通过TCP连接Server的5037端口。
通过以下命令,可以看到server的启动日志:
1 | $ adb kill-server && adb devices |
通过以下命令,可以看到TCP的5037端口,在侦听连接:
1 | $ netstat -l | grep 5037 |
当我们执行一些常用的adb命令时,譬如adb devices
、adb shell
,server就自动启动了,也可以通过adb start-server
来启动;如果想要停止server的运行,可以通过adb kill-server
来杀掉server进程。
PC上命令行输入adb命令后发生了什么
- Client 调用某个
adb
命令 - adb 进程 fork 出一个子进程作为 Server
- Server 查找当前连接的 emulator/device
- Server 接收到来自 Client 请求
- Server 处理请求,将本地处理不了的请求发给 emulator/device
- 位于 emulator/device 的
adbd
拿到请求后交给对应的java虚拟机进程。 - adbd 将结果发回给 Server
- Server 将结果发回给 Client
ADB Protocol 通信协议
1. ADB Client 和 ADB Server 间的通信
这个数据通道是一个本地TCP连接,ADB Server启动以后,在本地的5037端口侦听。ADB Client通过本地的随机端口与5037端口建立连接。
在这个通道上,Client向Server发送的命令都遵循如下格式:
- 命令的长度(Length),由四位的十六进制表示
- 实际的命令(Payload),通过ASCII编码
Client 和 Server 间传输的命令定义源码在 /system/core/adb/SERVICES.TXT 文件中,截取部分命令如下。
1 | This file tries to document all requests a client can make |
譬如,查看adb当前的版本,Client会发起如下命令:
1 | 000Chost:version |
000C:表示”host:version”这条命令的长度为12个字节;
host前缀:是为了区分其他类型的命令(后面还会看到shell前缀的命令);
Server收到Client的请求后,返回的数据遵循如下格式:
- 如果成功,则返回四个字节的字符串”OKAY“
- 如果失败,则返回四个字节的字符串”FAIL“和出错原因
- 如果异常,则返回错误码
当Client收到Server返回的”OKAY“后,就可以发继续发起其他操作命令了。
2. ADB Daemon 和 ADB Server 间的通信 — transport协议
Android 源码中关于 transport 协议的定义在 system/core/adb/protocol.txt 文件中。下面是 message header 的格式,共占用24字节,分为6个字段(即每个字段占用4字节):
1 | The transport layer deals in "messages", which consist of a 24 byte |
并且定义了7种 command,以及每种指令后携带的参数含义 :
1 | --- message command constants ------------------------------------------ |
几个问题
一、PC上为什么要有一个ADB Server,而不是ADB Client 和 ADB Daemon 直接通信呢?
因为 ADB 是一个需要支持多对多架构的工具,一个PC可以连接多台手机设备或虚拟机,一个手机也可以同时连接多台PC。就需要一个统一的Sever管理多个设备的连接。