天地会珠海分舵注:本来这一系列是准备出一本书的,详情请见早前博文“寻求合作伙伴编写《深入理解 MonkeyRunner》书籍“。但因为诸多原因,没有如愿。所以这里把草稿分享出来,所以错误在所难免。有需要的就参考下吧,转发的话还请保留每篇文章结尾的出处等信息。
ADB服务器端在接受到ADB客户端发送过来的命令后会进行相应的处理,如果是主机服务就在ADB服务器内部进行处理,如果是本地服务就会发送给Android目标机器端的adbd守护进程进行处理。
因为ADB相关的源代码不在我们源码分析的范围之内,所以我们很有必要把官方提供的ADB服务器支持的所有服务在这里描述下。虽然本人对自己的英语水平相当有信心,但总担心有词不达意的时候,所以翻译的过程中把英文也保留了下来以供大家参考。
主机服务:
host:version
向ADB服务器请求其内部版本号。作为一个协议中的例外(请查看OVERVIEW.txt来查看ADB具体协议规则),服务器会返回一个代表其内部版本号的4字节的十六进制字符串,而不会像标准协议中会返回OKAY或者FAIL
host:kill
请求ADB服务器立刻退出。当ADB升级完成后,如果ADB客户端检测到之前已经过时的ADB服务器还在运行的时候会发送这个请求。
host:devices host:devices -l
这两个服务请求是类似的,都是请求ADB服务器返回一系列有效的安卓设备以及对应的状态信息,只是devices -l会在状态信息中包含该设备更多的信息,比如产品型号等。在正常返回OKAY之后,会紧跟着一个代表数据长度的4字节长的十六进制数,以及对应的如我们通过命令adb devices -l命令能看到的输出,然后连接请求就会关闭。
host:track-devices
这个服务是以上的host:devices的一个变种,客户端和ADB服务器的连接会一直保持,当有增加/移除设备或者设备状态改变的时候会主动的往连接上的客户端发送新的设备列表信息(4字节16进制长度+内容)。这样做的话就可以允许DDMS这些工具来实时跟踪所有连接上来的设备的状态,而不需要客户端每次都去连接ADB服务器获取对应信息。
host:emulator:<port>
这是一个特殊的请求,当一个新的模拟器启动的时候这个请求将会发送到ADB服务器。<port>对应的是模拟器的控制端口的一个十进制数字,例如本机转发到正在运行的模拟器的adbd的对应的那个TCP转发端口。这个机制让ADB服务器可以清楚知道有哪个模拟器被启动起来了。
host:transport:<serial-number>
请求ADB服务器切换当前连接到<serial-number>指定的设备/模拟器。在OKAY应答之后,客户端的所有请求都会重定向到该设备的adbd这个守护进程。(用来实现ADB命令行客户端的-s选项)
host:transport-usb
请求ADB服务器切换当前连接到通过USB连接到主机的设备。如果多于一个设备通过USB连接到主机,调用将会失败。(用来实现ADB命令行客户端的-d这个方便使用的选项)
host:transport-local
请求ADB服务器切换当前连接到一个通过TCP协议连接上来的模拟器。如果多于一个模拟器在运行的话,调用将会失败。(用来实现-e这个方便使用的选项)
host:transport-any
另外一个host:transport的变种。请求ADB服务器切换当前连接到已经连接上主机的设备或者正在主机中运行的中模拟器。如果有多于一个这类设备存在,调用将会失败。(在-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的变种,这次指定的是一个在主机运行的模拟器。如果没有或者有多于一个这种设备的话调用将会失败。相当于直接执行" adb get-product"或者“adb get-serilano"等
host:request
当通过ADB服务器向一个相关设备请求信息的时候,'host:' 在这种情况下也可以指‘任意一个连接上主机的的设备或者正在主机上运行的模拟器'。
(以下”host-prefix:”开始的描述的就是上面4种特殊服务请求的参数)
host-prefix:get-product
XXX
官方就提供了上面的XXX,没有更多的信息。本人在尝试"adb get-product"时发现并没有支持。
host-prefix:get-serialno
返回对应的设备/模拟器的序列号。"host-prefix:"指的是上面4种特殊信息请求命令。注意模拟器的序列号的格式形如"emulator-5554"。类似于命令行执行"adb get-serialno"
host-prefix:get-devpath
返回对应设备/模拟器的设备路径,这里的设备路径指的是"adb device -l"列出的最后一部分,如"device product:OPPO_12025 model:X909 device:X909"。 "host-prefix:"指的是上面三种特殊信息请求命令。类似于命令行执行"adb get-devpath"。
host-prefix:get-state
返回一个代表指定设备状态的字串,"host-prefix:"指的是上面三种特殊信息请求命令。类似于命令行执行"adb get-stat"。
host-prefix:forward:local;remote
请求ADB服务器把本地local指定的连接重定向到指定设备的remote地址。在这里,"host-prefix"可以是以上描述的用来指定目标设备/模拟器的
其中local的格式可以是以下任一种:
-
tcp:port -> 本地主机的port端口的TCP连接
-
local:path -> 基于地址path的本地主机的Unix域套接字连接(UNIX Domain Socket的地址是一个socket类型的文件在文件系统中的路径)
remote的格式如下:
-
tcp: port ->目标设备的localhost:port
-
local:path -> 目标设备的本地Unix Domain Socket
-
jdwp:pid -> 目标设备中进程号<PID>指定的JAVA虚拟机内部的JDWP线程
甚至还支持下面描述的任一个本地服务
host-prefix:forward:norebind:local;remote
类似host-prefix:forward:local;remote ,有一点区别是如果已经存在local的一个转发的话调用会失败。用来实现"adb forward --no-rebind local remote"
host-prefix:killforward:local
移除所有<local>指定的本地重定向连接。用来实现"adb forward --remove local"命令
host-prefix:killforward-all
移除所有的重定向连接。用来实现"adb forward --remove-all"命令
host-prefix:list-forward
列出本机所有存在的转发连接。返回格式如下:
-
hex4: 返回结果长度,由4字节16进制字符组成
-
payload: 一连串以下格式的行:
- serial " " local " " remote "\n":serial代表设备序列号。local代表主机端的的连接点(比如tcp:90000)。remote代表设备端的连接点。
这是用来实现"adb forward --list"命令的。
本地服务:
下面的所有请求是建立在你已经把传输切换到一个真实设备上,或者你使用了以上描述的一个query前缀的服务请求。
shell:command arg1 arg2 ...
在设备的shell中运行'command arg1 arg2 ...',并且返回对应输出和错误流。
注意参数必须空格隔开。如果一个参数本身包含空格,那么它必须要用双引号引起来。参数内部不能包含双引号,否则命令执行结果将无法控制。
注意这是"adb shell"的一个非交互式版本
shell:
开启设备的一个交互shell会话。合理的重定向了标准输入/标准输出/标注错误。
注意ADB服务器就是使用这个协议来实现命令行客户端的"adb shell"请求的,但当然它会先包装整理好输入的信息再发送到目标设备(请查看commandline.c的interactive_shell())
remount:
请求adbd去重新把设备只读文件系统挂载成可读写模式的文件系统。这个在执行"adb sync"或者"adb push"请求之前通常是很有必要先执行的。这个请求在一些版本中也许因为不支持而会失败
dev:path
打开一个设备文件并通过客户端连接上该设备来进行读写操作。通常这是用来调试用的,但可能不可以在所有设备上运行,因为它需要特殊的权限才能执行。path指的是从文件系统根开始的全路径。
tcp:port
尝试连接上本机的tcp端口port
tcp:port:server-name
尝试连接上server-name指定的设备的tcp端口port。这对调试只能在设备上显示的网络/代理问题很有用。
local:path
尝试连接上设备上的path地址指定的Unix域套接字
localreserved:path | localabstract: path | localfilesystem: path
local:path的几个变种,用来访问安卓其他命名空间指定的套接字。
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 高度(像素)
在当前的实现中,宽度永远是16,大小也永远是宽度高度2
每次客户端想要一个截屏快照时,它将会通过Socket通道发送一个字节,这会触发本服务去把framebuffer数据按其大小指定的字节数发送给客户端。如果adbd守护进程没有足够的权限打开framebuffer设备,那么连接会立即关闭。
jdwp:pid
连接目标设备中由进程号<PID>指定的JAVA虚拟机进程内部的JDWP线程
track-jdwp
这个服务是用来周期性的往客户端发送有启用JDWP的进程的进程号列表。
The format of the returned data is the following:
返回数据格式如下:
-
hex4: 代表返回数据长度的一个4字节16进制字串
-
content: 一系列的ASCLL字串行,每行的格式如下: <pid> "\n"
这个服务被DDMS用来知悉有哪些可调式的进程正在真实设备/模拟器上运行。
注意并不存在另外一个服务来只获取一次这个列表。
sync:
开启文件同步服务,用来实现"adb push"和" adb pull" 这两个命令。因为这个服务相当复杂,更详细的信息请查看相关的SYNC.TXT文档。
官方英文版: https://android.googlesource.com/platform/system/core/+/master/adb/SERVICES.TXT
——— 未完待续———
作者:天地会珠海分舵
微信公众号:TechGoGoGo
微博:http://weibo.com/techgogogo
CSDN:http://blog.csdn.net/zhubaitian
网友评论