1.ADB Server,ADB Client, ADB Daemon的关系
ADB通信分为两部分:ADB Server和ADB Client;ADB Server和ADB Daemon。
ADB Server:运行在PC上的后台程序,目的是检测USB借口何时连接或者移除设备。ADB Server维护着一个“已连接的设备的链表”,并且为每一个设备标记了一个状态:offline,bootloader,recovery或者online;Server一直在做一些循环和等待,以协调client和Server还有daemon之间的通信。
ADBD(daemon):adbd作为后台进程运行在手机上,所用是连接到adb server(通过USB或者TCP/IP),并且为运行在PC上的client提供一些服务。当手机正确俩捏到PC上,并且adb server能够连接上daemon时,server将手机的状态标记为online,否则为offline,这意味着server发现了一个新设备,但是不能成功连接到daemon。
ADB Client:其实就是shell,用来发送命令给Server。发送命令时,首先检测PC上有没有启动Server,如果后台没有Server,则自动启动一个Server,然后将命令发送到Server,并不关心命令发送过去以后会怎样。目前一个adb就包含了client和server两部分。
三者之间的通信:两条通讯通道。Client<--->Server<---->Daemon。Client发送的命令分为三种:adb version和adb help不经过server处理就能够成功的;和Server通讯但是不需要和手机通讯的命令:adb devices;需要Daemon进行处理的命令。
ADB Server对本地的TCP5037端口进行监听,等待ADB Client的命令。ADB Client每个命令都包含两个部分,前一部分包含固定四个字节,以十六进制的方式指明指令的长度;后一部分才是真正的指令内容;发送命令的借口为writex,最终调用_fh_socket_write,通过send发送出去,因此这两部分至少需要发送两个tcp包。
2.pc端判断怎样和手机进行连接?手机adbd进入哪个模式?
PC端的其实只在server启动的时候有一步检测,检测有没有配置环境变量ADBHOST=192.168.100.2。当我们定义了这个环境变量的时候才可以通过TCP/IP来连通手机。server起来以后便不再进行检测,所以当我们定义了这个变量然后再启动server才能连接上手机。但这又牵扯出来一个问题,我们这个时候在运行 sudo adb devices 是找不到设备的,即使在root里面设置了环境变量ADBHOST这条命令也是无法找到设备的。在代码里面加上log可以发现并没有找到这个环境变量,所以还是系统环境变量的问题导致的ADB找不到设备,而不是ADB本身的问题。 其实在进行环境变量的检测以前就进行了usb设备的检测,而且这是fork了一个进程来轮询扫描的,当找到以后就建立连接。所以是可以同时发现物理设备和虚拟设备的。这里说明一下,usb设备是轮询来检测的,但是在发现网络设备的时候只进行了一次循环检测。所以当我们在ADB模式下拔掉手机然后在进入ADB模式还可以发现设备,但是NET模式下则不能发现了。
adbd起来以后进行检测,看/dev目录下有没有 android/android_adb 两个文件,如果有其中一个,则进行ADB模式,那么NET模式将不会进行初始化。注意这里的初始化和PC上是不一样的,PC上是一个顺序结构,而手机上则是一个选择的分支结构。(结尾有简单流程图)
但是这个时候 如果 touch android 或 android_adb. 将会怎么样?
i. NET 模式将不能进入。
ii. 创建以后,第一次进如ADB 模式,能够发现设备,但是设备状态是 offline
这是因为adbd在进行文件检测的时候,只进行文件是否存在的检测,而不关心文件的属性。所以当他看到我们touch出来的文件时,不管我们选择哪个模式都会进行adb的初始化,相当于adbd进入了ADB模式, 然而这个时候的ADB模式并不是我们选择ADB时进入的模式,他没有加载adb驱动,反而是加载的NET的驱动,PC设别的不出来USB设备,识别出来的是一个网络设备,这个时候PC端的ADB是废掉的。所以即使配置即使我们发现了usb0,并且配置好usb0和ADBHOST正确,也不能正常连接。这两个节点本应该是 加载 android adb driver时创建的(其实只创建android_adb一个),但是我们人为的创建以后,driver 就不会再次创建,这个空文件没有设备文件收发数据的功能,所以不能正常工作。但是在卸载驱动的时候, 会去删除这个设备文件,所一就把我们touch的文件给删除了,再次进入ADB模式的时候会正常创建。这个时候就又能正常使用ADB模式了。
来看一下这两个文件的一些信息:
-crw-rw---- adb adb android_adb ----> driver
-rw-rw-rw- root root android_adb ----> touch
Design:
a. 在进行检测文件是否存在的同时检测文件的属性和权限。
b. 驱动加载的时候进行检测看是否有同名文件,有则删除。
3.为什进行adb模式现相连接,第一次运行adb命令要sudo?
当我们执行adb命令的时候几乎都会进行server是否启动的一个检测,如果server没有起来,那么他会起server。这里的sudo其实是用来起server的。也就是说我们要让server拥有root权限。
这是因为server起来以后,要去读写系统创建在/dev/bus/usb下面的设备节点来和phone上的daemon进行通讯。但是这个节点是由root用户创建。普通用户的权限是受到限制的。
我们可以看一下。首先lsusb来看一下我们的设备。
Bus003 Device 042: ID 18d1:dddd
这就是系统给我们设备创建的节点了,然后找到设备节点进一步看他的一些属性
ls -l /dev/bus/usb/003/042
crw-rw-r-- 1 root root 189, 297 2009-11-18 17:15
普通用户运行的adb当然就不能去和设备进行通讯.
Design:
a. 用chmod 命令来改变节点的读写权限。(当让这是费事不讨好,还不如直接sudo。但是这至少证明是设备节点的读写权限导致的这个问题。
b. 修改系统配置文件,让系统在创建设备节点的时候就允许普通用户有读写权限。但是这个时候潜在一个任何人都能访问节的的安全问题。
c. 从上面可以看到,将本人加入root用户组也可以得到读写的权限。(实用,推荐)
4. adbd的启动。
现在在我们的手机里面只有选择ADB模式或者NET模式的时候mountd才会起 adbd 进程,当拔掉线的时候再杀掉adbd。如果在运行过程中adbd非正常的死掉了,init进程会重新启动adbd。
mountd会选择性的加载驱动,当加载 android adbdriver 以后才启动adbd,因为手机上的adbd起来以后要检测是否有驱动创建的android_adb节点,来判定是否执行usb_init()函数,如果没有就会进行local_init(),如果先启动的adb则不能检测到该节点,所以要这样设计。(下
有简单流程图)
Design:
a. 如果让adbd进程长期在系统驻留,不被mountd杀死也可以在加载驱动以后进入adb模式。让adb在作检测的时候不止检测有没有android_adb 节点,另外再进行本地IP有没有正确配置的检测,如果都没有则sleep 2000ms,然后在做检测。
b. 如过我们真的可以去掉NET模式。那么我们可以在先判断一下当前adbd是不是运行在虚拟机里面,如果是就进行NET的初始化,如果不是在虚拟机里面那么就进入ADB模式,这个时候还是要等待驱动的插入,当检测到有驱动节点创建的时候就进行初始化。(我已近在tiger上面进行了改动,测试结果证明是可行的。)
5. 安全问题
在我们没有选择 NET 模式,mountd 没有加载配置文件的时候 手机的IP 地址并不是192.168.100.2,即使用WIFI也是没法和手机的 adbd 进行连通的。因为在我们现在的版本中ADB通信是把两个连通的IP写死了的,只有192.168.100.1和192.168.100.2能够进行连同。这就只牵扯到选择NET模式以后的的安全性问题,理论上这个时候WIFI是可以伪造IP 通过 adb只关心数据链路层来连接手机。mountd的design只是保证了ADB模式的正常进入,主要意图并不是来解决安全问题。
Design:
a. 当我们连上线的时候当然是我们最先进入NET模式,黑客是后来进入的。可以让一部手机只让一台电脑连接,当建立连接以后,便不再接受其他的连接请求。是这样的手机上的adbd起来以后是一个等待PC连接的状态,当PC的数据过来以后才会进行连接,然后向管理的链表登记注册,这时候会对该PC 上的socket进行一个ID标识,手机的server就是根据这个来进行通讯的,我们可以设置这个ID标识的第一组,也就是我们连接的PC是合法值,其他为非法,不进行通讯。或者干脆就不对多出来的进行标识,这样就无法通讯。
6. ADB debug 方式。
在PC端的log默认下是开启的,但是并不是所有的log都打开的。
在没有更改代码的前提下只记录ADB的启动和关闭 以及PID。
sudo打开 /tmp/adb.log 可以看到
我们可以通过更改代码来查看更多log,但是更简单的方式就是设置一个环境变量我们就可以查看更多的log。
export ADB_TRACE=all或者等于ADB_TRACE= 1。
这个时候在运行adb命令就可以看到更多的log打在屏幕上,当然他们同时也打在了文件中。
Phone的log 默认情况下是关闭的。
如果打开的话,其记录在 /data/adb_<time>.txt 文件中。
7. 关于版本检测
大家都知道我们的系统中只能打开一个server,不管多少 Shell来运行adb都只是和同一个server来通迅,各shell通过连接本地lo的5037端口来和server通讯。所以当我们运行不同版本的时候都是杀的后台的server。
adb 进行版本检测是做的检测pc上的server的版本。只进行了版
是否一致的检测。只要版本不一致,则会先杀死server然后才提示:
adbserver is out of date. killing...
而不提示用户现在运行的版本是什么版本,是否真的低于想运行的版本。
Design:
a.做进一步的检测。
b. 提示用户现在运行版本和将要运行版本的版本号。
8. 还是版本检测
adb help 和 adb version 这两条命令是不会进行版本检测的,甚至根
本都不关心server是否启动。只实现 help和 version的输出。
9. merge adb 的新功能
donut并没有更改adb的整个框架,最明显是加了一个新的功能,更
改了一下log的记录方式。
以前的版本中是要输入 adb shellreboot才可以重启手机,现在新加一条命令--->adb reboot.这样就可以直接重启手机。
上面我没说了log的问题,现在donut把手机上的log稍微的改了一点,上面说的是记录在/data/log_<time>.txt中。这个time就是用time函数获得的。但是现在改成了这样。他首先在data下面建立了一个adb的文件夹,然后在其中写的log文件,现在的文件名格式改成了这样--->adb-%Y-%m-%d-%H-%M-%S.txt
Éclair里面有加了一些新的功能。
a..adb connect <host>:<port>
connectto a device via TCP/IP
b.adb disconnect <host>:<port>
disconnectfrom a TCP/IP device
c.adb usb
restarts the adbd daemon listening on USB
c. adb tcpip<port>
restartsthe adbd daemon listening on TCP on the specified port
(2-9本人也不太懂,资料不好找,所以就先放这了)
.