转自:http://blog.chinaunix.net/uid-20514606-id-375756.html
adb push 文件时host端(server+client)通讯的流程,分析如下:
绿色表示Cleint端
兰色表示Server端
红色表示Device端
------------------------------------------------------------------------------
(1) (server)
( socket_loopback_server(tcp:5037 loopback server 监听client连接)
------------------------------------------------------------------------------
(2) (目前为client)
( int fd = _adb_connect(service); )
执行socket_loopback_client 去连接server
------------------------------------------------------------------------------
(3) (server)
如果有client 连接交由ss_listener_event_func 处理
adb_socket_accept 接受连接后进行如下处理:
* 设置socket buff 大小
* 用create_local_socket 创建asocket 对象
并初始化enqueue,ready,close 函数指针local_socket_xxx
设置asocket 的id, 设置asocket 的fd 为accpeted socket fd
(使用该fd 与client 通讯)
* 设置epoll 等待该accepted socket fd 上FDE READ,WRITE事件
处理函数为local_socket_event_func
(注意这时并为设置等待FDE EVENT !!!)
* 用connect_to_smartsocket 创建一个smart asocket
( 注意是smart 不是remote!)
asocket id 为0 (这是个细节)
并设置enqueue ,ready ,close 函数为smart_socket_xxx
设置local ,smart asocket 互为对方peer
调用下local socket ready,这样local_socket_event_func
就可以等待到client 发数据过来的fde read event了
------------------------------------------------------------------------------
(4) (client)
(_adb_connect("sync:"))=>
* switch_socket_transport 发送:
'xxxx'(msglen)+ 'host:transport-any'
* 然后readx 读socket_loopback_client
返回的fd 来等待server 应答
------------------------------------------------------------------------------
(5) (server)
local_socket_event_func 的 fde read 分支读到client 发来的
'xxxx'(msglen)+ 'host:transport-any' ,调用
smart_socket_enqueue (不是remot socket 入队)
* 收完msg len 指定长度的msg
* 开始handle_host_request(service='transport-any'
, ttype=kTransportAny
, serial=nll
, s->peer->fd local socekt 's fd
, s smart asocket
通过acquire_one_transport(CS_ANY, type=kTransportAny,serial,error_string);
去从transport_list 上获得一个transport
transport_list 是在 usb_init =>device_poll_thread 中发现usb device
插入,或者local_init 通过client_socket_thread 通过ip+port 连上device 后
通过register_xxx_transport ,xxx指 usb 或socket,注册时link 到list上的
所以注意如果想用tcp 连接时 getenv("ADBHOST") ,要设置ip 地址
不过现在仍然假定使用usb transport 并且device 已经插入成功
获得一个atransport 成功后,给client 发OKAY
并把smart asocket 的atransport 设置为获得的atransport
* handle_host_request 返回时判断service 中用'transport' 字样就
return 0; 退出enqueue
-------------------------------------------------------------------------------------
(6) (client)
等到server 发来的okay ,开始通过
loopback client socket fd 发
'xxxx'(len)+ 'sync:'
-------------------------------------------------------------------------------------
(7) (server)
local_socket_event_func 中如果enqueue 返回>0 才会
delete FDE_READ,前面(5)楼enqueue 退出为return 0,
所以条件不满足, 仍然可以触发
又到了local_socket_event_func 的 fde read 分支!!!
收到'xxxx'(msglen)+ 'sync:' 调用
smart_socket_enqueue 入队
由于msg 中没有任何host 字样就直接去设置
local asocket 的ready ,改为local_socket_ready_notify,
主要为回应client OKAY 做个过度,所有又设回
local_socket_ready (notify 做了下二传手的作用)
close 设为local_socket_close_notify 重设为local_socket_close_notify
和上面一样主要是回应 client "closed",然后设回
s->peer->peer = 0; 将local asocket 的peer端由smart socket 改为0
(local asocket 与smart socket 现在断开了)
connect_to_remote(smart ascoket,'sync:'); 去向目前还挂在
smart asocket 上的usb transport 发6大message 之一个的
A_OPEN 去open sync service
(注意smart asocket 获得见5楼倒数第3行,虽然和loc sock断开了,不过还有利用价值)
-------------------------------------------------------------------------------------
(8)
(device)
device 收到open sycn 后打开sync service
然后给host 端发A_OKAY
(具体见ADB push 文件通讯包的device端分析 )
-------------------------------------------------------------------------------------
(9)
(server)
server 端 收到A_OKAY 后handle_packet 处理A_OKAY
(具体ADB push 文件通讯包的device端分析)
因为前面local asocket 与smart ascoket 断开时设置
* s->peer->peer = 0 ; (peer的peer 一定不要昏,见前面(7)楼解释)
* 所以create_remote_socket(device asocket id, usb atransport->transport register时获得)
* 设置 新创建的remote asocket 的enqueue,ready,close ,disconnet 等func pt
* 将刚才和smart asocket 断开的local asocket 连到remote asocket
(就是这句s->peer->peer = s;)
* 调ready (那个ready ??? ;) )
local_socket_ready_notify ,这个ready 2传下到
local_socket_ready(close) ,然后给client 回个OKAY ,
然后再s->ready(s); (那个ready???)
local_sokcet_ready ,设置fde_read, (这句很关键!!!)
回头看下client ,它发完sync 还挂着adb_status 等OKAY,
现在轮到client 了
-------------------------------------------------------------------------------------
(10) (目前为client)
adb connet sync:成功返回loopback
client socket fd 后开始发文件了
sync_send(fd=> loop back client sfd
* 发ID_SEND + filename +file mode 's len
* write_data_file
发ID_DATA + size + file data (最大64K)
(这里和下面是交叉执行)
-------------------------------------------------------------------------------------
(11)
(server)
(9)楼提到的关键句s->ready(s) 起作用了
加上client 的write ,激发了
local_socket_event_func 去处理分支FDE_READ
* 读loopbake server socket fd 获得client 发来的数据
* s->peer->enqueue =>现在enqueue 是remote 了, 不是smart
这就是前面local, smart 断开时做的
(见上面处理A_OKAY 时create_remote_socket 做的)
enqueue => remote_socket_enqueue
向device 发A_WRTE (通过usb transport
send_packet出去)
local_socket_event_func => FDE_READ => adb_read(fd, x, avail)
的avail 是4096,所以实际usb 上一次write max 4096
-------------------------------------------------------------------------------------
(12)
(device)
由于ADB push 文件通讯包的device 端分析中已经
讲过device 端,所以省略
但是每次device 处理A_write 后都回A_OKAY
-------------------------------------------------------------------------------------
(server)
又回到server 端处理A_OKAY,和上面(9)楼一样处理
一直又处理到(12)楼
直到文件内容发完
-------------------------------------------------------------------------------------
(13) (目前为client)
发ID_DONE + mtime
然后等server 回OKAY
-------------------------------------------------------------------------------------
(目前为server)
这部分和(11)楼处理过程一样,因为省略分析devcie 端
但也是由s->ready + client 写sfd 激发local_socket_event_func 开始的
最后server 通过local_socket_ready_notify 回应 client OKAY
-------------------------------------------------------------------------------------
(14) (client)
收到OKAY
sync_quit =>
发ID_QUIT
-------------------------------------------------------------------------------------
(15)
(server)
已经基本没client 的事情了
server local_socket_event_func 上最后一 次 去处理分支FDE_READ
r = adb_read(fd, x, avail); r 返回0
is_eof成立
执行 s->close(s); =>local_socket_close_notify
直接贴代码
- static void local_socket_close_notify(asocket *s)
- {
- s->ready = local_socket_ready;
- s->close = local_socket_close;
- sendfailmsg(s->fd, "closed");
- s->close(s); ===> local_socket_ready 发A_CLSE
- }
-------------------------------------------------------------------------------------
(16)
如device 端分析中最后收到A_CLSE
结束
其他
server 端对非host 命令的转发类似与一个单刀双掷开关
fd(loopback sfd) <----------------> (client)
|
fde (local_socket_event_func)
(2) |(1)
(device handle) \ (server handle)
(remote enqueue) <------> <----------------->(smart enqueue)
开始连着client ,接收到非host 命令,发A_OPEN 打开device service 后
开关连到(2)一头,以后enqueue 就是remote 了,就发给了device
两路 :一路client 经过(1) 到server handle
另一路client 经过(2)到device handle
比如push 一个文件, adb push '/xxx//xxxxx.xxx' mode 100644
从device 端分析下通讯过程中包的传输过程:
A_XXXX message 总是24byte长,结构如下:
- struct message {
- unsigned command; /* command identifier constant */
- unsigned arg0; /* first argument */
- unsigned arg1; /* second argument */
- unsigned data_length; /* length of payload (0 is allowed) */
- unsigned data_crc32; /* crc32 of data payload */
- unsigned magic; /* command ^ 0xffffffff */
- };
=>A_XXXX :表示从host 发过来
A_XXXX=> : 表示device 发出去
----------------------------------------------------------------------------
=>A_OPEN 24byte
DATA 6byte ==>(sync:\0)
(handle A_OPEN packet 的最后s->ready(s),来通
知device ,
自己可以接收,后续都是主动发A_OKAY来实现)
----------------------------------------------------------------------------
A_OKAY=> 24byte
(transport层发send_packet)
-----------------------------------------------------------------------------
=>A_WRTE
DATA 8byte ==>+size
struct {
unsigned id; ==>'STAT'
unsigned namelen;==>后续路径名长度'/xxx/' 5byte
} req;
------------------------------------------------------------------------------
A_OKAY=> 24byte
(transport层发send_packet)
----------------------------------------------------------------------------
(service 层writex发xxx目录的stat)
A_WRTE=>
DATA 16byte
struct {
('STAT')<== unsigned id;
unsigned mode;
unsigned size;
unsigned time;
} stat;
----------------------------------------------------------------------------
A_OKAY=> 24byte
(可以看出host ,devie 收到A_WRTE 后必须回A_OKAY)
----------------------------------------------------------------------------
(开始发文件)
=>A_WRTE 24byte
DATA 8byte
struct {
unsigned id; ==>'SEND' id
unsigned namelen; ==>file name size +mode size( 16+8=22byte)
} req;
------------------------------------------------------------------------------
A_OKAY=> 24byte
(transport层发send_packet)
------------------------------------------------------------------------------
(进入handle_send_file)
=>A_WRTE 24byte
DATA 4096byte (包括下面22byte+data struct + left data)
22byte namelen ==> file name+mode(include path)
struct { ==> syncmsg
unsigned id; ==>'DATA' id
unsigned size; ==>data size 65536byte
} data;
left data ==>4096-22-8 byte
------------------------------------------------------------------------------
A_OKAY=> 24byte
(transport层发send_packet)
-------------------------------------------------------------------------------
(下面开始是 纯data )
=>A_WRTE 24byte
DATA 4096byte
file data ==>4096
------------------------------------------------------------------------------
A_OKAY=> 24byte
(transport层发send_packet)
--------------------------------------------------------------------------------
..... (host重复发=>A_WRTE 纯data) (device 重复A_OKAY=>)
--------------------------------------------------------------------------------
(到msg过来时满了64k 注意最大64K 需要重新发DATA syncmsg)
=>A_WRTE 24byte
DATA 4096byte (同时一个消息最大4K data)
22byte data ==> file data
struct {
unsigned id; ==>'DATA' id
unsigned size; ==>data size 65536byte
} data;
left data ==>4096-22-8 byte
---------------------------------------------------------------------------------
.... (一直到文件内容发完)
---------------------------------------------------------------------------------
(收到DONE id msg ,跳出handle_send_file循环)
=>A_WRTE 24byte
DATA 8byte
struct {
unsigned id; ==>'DONE' id
unsigned size; ==>timestamp 4byte
} data;
---------------------------------------------------------------------------------
devie 发ID_OKAY (注意不是A_OKAY)
A_WRTE=> 24byte
DATA 8byte
struct {
unsigned id;==>'ID_OKAY'
unsigned msglen; ==>0
} status;
---------------------------------------------------------------------------------
=>A_OKAY 24byte 后面无DATA
---------------------------------------------------------------------------------
=>A_WRTE 24byte
DATA 8byte
struct {
unsigned id; ==>'QUIT' id
unsigned namelen; ==>0
} req;
----------------------------------------------------------------------------------
A_OKAY=> 24byte
(transport层发send_packet)
----------------------------------------------------------------------------------
=>A_CLSE 24byte
通讯发生在socket 层和transport 层 :
socket 是在service 层面的通讯
transport是在设备端口层面的通讯
第1层socket pair 用于 设备注册,注册过程在thread中,device kick 来触发
第2层socket pair 用于 设备通讯,主要是包的通讯,6大消息包的handle:
CONNECT(version, maxdata, "system-identity-string")
OPEN(local-id, 0, "destination")
READY(local-id, remote-id, "")
WRITE(0, remote-id, "data")
CLOSE(local-id, remote-id, "")
SYNC(online, sequence, "")
第3层socket pair 用于 service 通讯,是实际功能的通讯 ,不包含包头,打包过程在第2层socketpair 完成
local_socket_event_func 是由A_WRTE收到后enqueue 时驱动write,并且由收到A_OKAY 消息驱动read