adb 协议

adb通信分为两部分:adb client和adb server,以及adb server和adb daemon。

 client和server之间的通信协议

adb server对本地的tcp 5037号端口进行监听,等待adb client的命令。client的每个命令都会包含两个部分,前一部分固定4个字节,以十六进制方式指定命令部分的长度。后一部分是真正的内容。发送命令的接口为writex,并最终调用_fh_socket_write,通过send发送出去。因此这两部分至少需要发送两个tcp包。

例如想要获取adb server的版本号,client首先连接本机的tcp 5037端口,然后发送“000C”和“host:version”。

server对client回复,分为如下情况

1、 成功,回复四字节串“OKAY”,后面跟的内容根据不同的命令而不同。

2、 失败,回复四字节串“FAIL”,然后跟四字节的十六进制长度,以及失败原因。

3、 对于host:version,回复4个字节的十六进制字串,代表server的内部版本号。

具体的命令如下。

命令

解释

host:version

 

host:kill

停止server

host:devices

 

host:track-devies

 

host:emulator:<port>

 

host:transport:<serial-number>

连接指定serial-number的设备或者模拟器

host:transport-usb

连接usb上的设备,如果usb上有不止一个设备,会失败。

host:transport-local

通过tcp方式连接模拟器,如果有多个模拟器在运行,会失败。

host:transport-any

连接usb设备或者模拟器都可以,但是如果有超过一个设备或模拟器,会失败。

host-serial:<serial-number>:<request>

host-usb:<request>

host-local:<request>

向指定的设备发送特定的请求。同样如果存在多个设备的冲突,会失败。

host:<request>

向当前连接的设备发送请求

<host-prefix>:get-serialno

获取设备的serial-number

<host-prefix>:get-state

获取设备状态

<host-prefix>:forward:<local>;<remote>

 

下面这些命令仅仅用于已经连接到某个设备,即在上面命令使用成功,连接到特定设备后,向特定设备发送命令,操作特定设备。

 

命令

解释

shell:command arg1 arg2 ...

在设备上执行命令行操作

shell:

参见commandline.c中的interactive_shell()

remount:

以读/写模式加载设备的文件系统

dev:<path>

为client打开设备上的特定路径,用于读写问题。有可能由于权限问题而失败。

tcp:<port>

尝试从设备连接本主机的某个tcp端口

tcp:<port>:<server-name>

尝试从设备连接特定主机名的某个tcp端口

local:<path>

尝试连接设备上的特定路径,路径是UNIX域名形式

localreserved:<path>

localabstract:<path>

localfilesystem:<path>

尝试连接设备上的特定路径。

log:<name>

打开设备上的特定日志文件,以便读取日志

framebuffer:

尝试获取framebuffer的快照。即涉笔的屏幕快照

dns:<server-name>

由serer执行来解析特定设备名

recover:<size>

更新设备的恢复镜像

jdwp:<pid>

连接特定VM进程上面的JDWP线程

track-jdwp

 

sync:

同步设备和主机上的文件

 

 

关于命令内容以及回复信息的更详细说明,参见adb源码文件夹下的SERVICES.TXT。

 

 Transports

这个名词用于代表server和设备或者模拟器之间的通信协议。包含如下两种情况:

1、 USB transports。通过USB方式和物理设备通信。

2、 Local transports。通过本机的TCP连接方式和模拟器通信。

由此可以想到,其实可以通过TCP方式和其他机器上面的模拟器或者设备进行通信,但是这点还没有实现。

transport层用于处理消息,每个消息包含24个字节的头部,定义如下。

struct message {

   unsigned command;

   unsigned arg0;

   unsigned arg1;

   unsigned data_length;

   unsigned data_crc32;

   unsigned magic;

};

此部分具体内容参见protocol.txt。

参考文献:

1、 adb源码文件夹下OVERVIEW.TXT

2、 adb源码文件夹下SERVICES.TXT

3、 adb源码文件夹下protocol.txt

本文尝试列举客户端能够发送给ADB服务器的所有请求。关于adb客户端、adb服务器、adbd守护进程、adb服务的概念,以及这些组件如何相互配合完成ADB工作的细节,请参考之前发的文章《Android Debug Bridge 技术实现》。
  
  ==============================
  主机服务
  ==============================
  
  host:version

    请求ADB服务器的内部版本号。作为一个特殊的例外,服务器将用4字节的十六进制字符串回应,返回服务器内部版本号,回应中没有“OKAY”和“FAIL”。
  
  host:kill
    请求ADB服务器立即退出。用于ADB客户端检测到在升级之后有废弃的ADB服务器仍在运行的情况。
  
  host:devices
    请求返回可用的Android设备及其状态的列表。在“OKAY”之后是4个字节的长度定义,然后是指定长度的表明当前设备状况的字符串,返回之后连接关闭。
  
  host:track-devices
    “host:devices”的一个变种,它不关闭连接;相反,每次添加或移除设备或者指定设备的状态发生变化,一个新的设备列表描述被发送。这就使得像DDMS这样的工具能够实时跟踪连接设备的状态,而不用重复轮训服务器。
  
  host:emulator:<port>
    这是一个特殊的请求,当启动一个新的模拟器时,该请求被发送到ADB服务器。<port>是一个十进制数字代表模拟器的ADB协议端口号,比如:模拟器将自动转发到adbd守护进程的TCP端口号。这个机制使得ADB服务器能够知道新的模拟器实例启动。
  
  host:transport:<serial-number>
    请求切换连接到<serial-number>指示的设备或模拟器。接到“OKAY”回应之后,所有的客户端请求将被直接发送给运行在指定设备上的adbd守护进程。(用来实现-s)
  
  host:transport-usb
    请求切换连接到通过USB连接到主机的设备上。如果存在多个这样的设备,请求将失败。(用来实现-d)
  
  host:transport-local
    请求切换连接到通过TCP连接的模拟器。如果有多个这样的模拟器实例在运行,请求将失败。(用来实现-e)
  
  host:transport-any
    另一个“host:transport”变种。请求切换连接到已连接的设备或正在运行的模拟器。如果可用的设备或模拟器多于一个,请求将失败。(用在-s、-d、-e都不被提供时)
  
  host-serial:<serial-number>:<request>
    这是一个特殊形式的请求,前缀“host-serial:<serial-number>:”表明客户端正在请求ADB服务器获得指定设备的信息。<request>可以是下述格式的一种。
  
  host-usb:<request>
    host-serial的一个变种,用于将连接到主机的唯一USB设备作为目标。如果没有这样的设备或有多个这样的设备,请求将失败。
  
  host-local:<request>
    host-serial的一个变种,用于将运行在主机上唯一的模拟器实例作为目标。如果没有这样的模拟器或有多个这样的模拟器,请求将失败。
  
  host:<request>
    当请求设备相关的信息时,“host:”也能被解释为“任何连接到主机的唯一设备或运行在主机上的唯一模拟器”。
  
  <host-prefix>:get-product
    暂无解释。
  
  <host-prefix>:get-serialno
    返回对应设备或模拟器的序列号。注意模拟器序列号是“emulator-5544”的形式。
  
  <host-prefix>:get-state
    返回指定设备的状态字符串。
  
  <host-prefix>:forward:<local>;<remote>
    请求ADB服务器将本地连接从<local>转移到指定设备上的<remote>地址。
    这里的<host-prefix>可以是上面描述的host-serial、host-usb、host-local、host的任意一个,它表明目标是哪个设备或模拟器。
    <local>的格式有以下几种:
      tcp:<port>      -> 在localhost:<port>上的TCP连接
      local:<path>    -> 在<path>上的Unix本地域套接字(Unix domain socket)
    <remote>的格式有以下几种:
      tcp:<port>      -> 在设备上localhost:<port>的TCP连接
      local:<path>    -> 在设备上的Unix本地域套接字
      jdwp:<pid>      -> 在虚拟机进程<pid>中的JDWP线程
    或者下面所描述的本地服务的任何一种。
  
  
  ==============================
  本地服务
  ==============================

  
下面所有的请求都假设你已经切换传输到实际的设备,或者你使用上面所描述的请求前缀。
  
  shell:command arg1 arg2 ...
    在设备的shell中运行“command arg1 arg2 ...”,返回输出流及错误流。注意命令参数必须用空格分隔。如果一个参数包含空格,应该对它使用双引号。参数不能包含双引号和其他会导致错误的符号。
    这是“adb shell”的非交互版本。
  
  shell:
    在设备上启动一个交互的shell会话。恰当的重定向标准输入、标准输出和标准错误输出。ADB服务器使用这个服务来实现“adb shell”,但是在输入被发送到设备之前,ADB服务器也会对输入做加工。(参考commandline.c中的interactive_shell()函数)
  
  remount:
    请求adbd守护进程重新挂载设备的文件系统到读/写模式下,而不是只读模式。在执行“adb sync”或者“adb push”之前,通常都需要这个服务。
    在不允许该操作的特定的系统中,这个请求可能不成功。
  
  dev:<path>
    打开一个设备文件,直接将客户端连接到这个文件去执行读写。该服务对于调试除错很有用,但是需要特殊的权限,不能在所有的设备上运行。<path>是从文件系统根目录开始的全路径。
  
  tcp:<port>
    尝试连接到loclhost的tcp端口<port>上。
  
  tcp:<port>:<server-name>
    尝试从设备连接到<server-name>所指定机器的tcp端口<port>上。这个服务对调试只能在设备上显示的网络或代理问题很有用。
  
  local:<path>
    尝试连接到设备上的Unix域套接字<path>。
  
  localreserved:<path>
  localabstract:<path>
  localfilesystem:<path>

    几个local:<path>的变种,用来访问其他Android套接字命名空间。
  
  log:<name>
    打开一个系统日志(/dev/log/<name>),允许客户端直接读取。用来实现“adb logcat”。数据流对客户端是只读的。
  
  framebuffer:
    这个服务用来向客户端发送framebuffer的快照。它需要足够的权限,工作原理如下:
    在“OKAY”之后,服务发送包含下列字段的16字节的二进制结构(低位优先格式):
    depth:   uint32_t:    framebuffer深度
    size:    uint32_t:    framebuffer大小(单位:字节)
    width:   uint32_t:    framebuffer宽度(单位:像素)
    height:  uint32_t:    framebuffer高度(单位:像素)
    在当前的实现中,framebuffer深度总是16,大小总是:宽度*高度*2。
    每当客户端想要一个快照时,它应该通过通道发送一个字节,触发服务将framebuffer数据按framebuffer大小指定的字节数发送给它。
    如果adbd守护进程没有足够的权限打开framebuffer设备,那么连接会立即关闭。
  
  dns:<server-name>
    这个服务是个例外,因为它仅仅运行在ADB服务器中。它被用来实现USB联网,比如:通过主机为设备提供一个网络连接。
    它用来在主机上执行gethostbyname(<address>),IP地址以4个字节的字符串返回。
  
  recover:<size>
    这个服务上传一个recovery影像到设备中。<size>必须与recovery影像文件大小一样。工作原理如下:
    - 创建一个命名为/tmp/update的文件;
    - 从客户端读取<size>大小的字节数,将它们写入到/tmp/update;
    - 当影像文件成功读取之后,创建一个命名为/tmp/update.start的文件。
    只有当设备处于recovery模式时,这个服务才能工作。此外,如果/tmp目录不存在,连接会立即关闭。
  
  jdwp:<pid>
    连接到运行在虚拟机进程<pid>中的JDWP线程。
  
  track-jdwp
    用于周期性的向客户端发送JDWP pids列表。返回数据格式如下:
    <hex4>:        4个字符的十六进制字符串指定所有内容的长度
    <content>:   一连串的格式为<pid> "/n"的ASCII行
    DDMS使用这个服务知道设备或模拟器上正在运行哪些可以调试的进程。
    注意没有仅获取一次列表的单步服务。
  
  sync:
    这个请求启动文件系统同步服务,用来实现“adb push”和“adb pull”。因为这个服务相当复杂,需要专门的文章来解释说明,如果有朋友感兴趣,我们以后专门讨论。
  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值