浅析linux开发工具adb具体实现
《再次浅析adb shell,pc daemon和手机daemon三者之间的数据交互流程》
//===============================
adb启动shell用到的命令
export ADBHOST= 192. 168. 100. 2
adb kill - server
adb start- server
adb shell
//===============================
让我们来分析一下对应的代码
adb start- server
= = > main
= = > adb_commandline
= = > do_cmd
= = > adb_connect( "host:start-server" ) ; 如果是adb start- server命令
= = > fd = _adb_connect( "host:version" ) ;
_adb_connect
fd = socket_loopback_client( ADB_PORT, SOCK_STREAM ) ; //尝试连接127.0.0.1本机ip地址对应的ADB_PORT端口server
如果fd小于0, 那么函数返回- 2, 否则在ADB_PORT端口打开server成功,
snprintf( tmp, sizeof tmp, "%04x" , len) ;
if ( writex( fd, tmp, 4) | | writex( fd, service, len) ) //先将4字节长度发送给server,然后发送命令数据"host:start-server"
adb_status( fd) ;
readx( fd, buf, 4) ; //读取server对该命令的反馈信息
if ( ! memcmp ( buf, "OKAY" , 4) ) //server成功处理
if ( memcmp ( buf, "FAIL" , 4) ) //server返回了非FAIL值,那么说明server出现协议数据异常,直接退出
= = > 如果没有启动server, 那么fd将等于- 2
if ( fd = = - 2) {
fprintf ( stdout , "* daemon not running. starting it now */n" ) ;
start_server:
if ( launch_server( 0) ) {
fprintf ( stderr , "* failed to start daemon */n" ) ;
return - 1;
} else {
fprintf ( stdout , "* daemon started successfully */n" ) ;
}
/* give the server some time to start properly and detect devices */
adb_sleep_ms( 2000) ;
// fall through to _adb_connect
}
= = > launch_server
= = >
pipe( fd) ;
pid_t pid = fork( ) ;
if ( pid = = 0) {
//子线程[luther.gliethttp]
adb_close( fd[ 0] ) ;
dup2( fd[ 1] , STDERR_FILENO) ; //将pipe[1]的描述符dup2到stderr上,
//因为execl操作只会装入新的执行程序代码,然后取代调用execl的child子进程继续在用户空间执行,
//并不会改变内核空间的fd_tables[],所以execl运行的程序送往stderr上的数据就是送到parent的pipe[0]管道.
adb_close( fd[ 1] ) ;
int result = execl( path, "adb" , "fork-server" , "server" , NULL ) ;
// this should not return
//永远不会返回到这里,因为位于用户空间的这里的代码,已经被execl操作替换成adb fork-server server程序了,
//这里的代码已经被覆盖,不存在了,所以当然不会返回到这里了[luther.gliethttp]
fprintf ( stderr , "OOPS! execl returned %d, errno: %d/n" , result, errno ) ;
} else {
char temp[ 3] ;
temp[ 0] = 'A' ; temp[ 1] = 'B' ; temp[ 2] = 'C' ;
// wait for the "OK/n" message
adb_close( fd[ 1] ) ;
int ret = adb_read( fd[ 0] , temp, 3) ; //等待管道数据的到来
/*
static __inline__ int adb_read(int fd, void* buf, size_t len)
{
return read(fd, buf, len);
}
*/
adb_close( fd[ 0] ) ;
if ( ret < 0) {
fprintf ( stderr , "could not read ok from ADB Server, errno = %d/n" , errno ) ;
return - 1;
}
if ( ret ! = 3 | | temp[ 0] ! = 'O' | | temp[ 1] ! = 'K' | | temp[ 2] ! = '/n' ) {
fprintf ( stderr , "ADB server didn't ACK/n" ) ;
return - 1;
}
// run a program in a new session
setsid( ) ; //之前parent和child运行在同一个session里,而且parent是session头,所以,
//所以作为session头的parent如果exit结束执行的话,那么会话session组中的所有进程将都被杀死,
//所以执行setsid()之后,parent将重新获得一个新的会话session组id,child将仍持有原有的会话session组,
//这时parent退出之后,将不会影响到child了[luther.gliethttp].
}
来看看fork之后execl执行的过程[ luther. gliethttp]
adb fork- server server
= = > main
= = > adb_commandline
if ( ! strcmp ( argv[ 0] , "fork-server" ) ) {
/* this is a special flag used only when the ADB client launches the ADB Server */
is_daemon = 1;
}
if ( ( argc > 0) & & ( ! strcmp ( argv[ 0] , "server" ) ) ) {
if ( no_daemon | | is_daemon) {
r = adb_main( is_daemon) ; //完成daemon启动
} else {
r = launch_server( ) ;
}
if ( r) {
fprintf ( stderr , "* could not start server */n" ) ;
}
return r;
}
= = > adb_main
init_transport_registration
HOST = 1;
usb_init( ) ;
local_init( ) ;
if ( install_listener( "tcp:5037" , "*smartsocket*" , NULL ) ) {
exit ( 1) ;
}
if ( is_daemon) {
fprintf ( stderr , "OK/n" ) ; //将OK传递给上面parent执行adb_read(fd[0], temp, 3);管道接收函数.
start_logging( ) ; //打开log文件,然后dup2到stdout和stderr,
}
fdevent_loop( ) ;
usb_cleanup( ) ;
//================================
void start_logging( void )
{
int fd;
fd = unix_open( "/dev/null" , O_RDONLY) ;
dup2( fd, 0) ; //取消输入通道stdin
fd = unix_open( "/tmp/adb.log" , O_WRONLY | O_CREAT | O_APPEND, 0640) ; //创建/tmp/adb.log文件
if ( fd < 0) {
fd = unix_open( "/dev/null" , O_WRONLY) ; //如果不成功,那么执行/dev/null
}
dup2( fd, 1) ; //将文件句柄dup2到stdout
dup2( fd, 2) ; //将文件句柄dup2到stderr
fprintf ( stderr , "--- adb starting (pid %d) ---/n" , getpid( ) ) ; //向/tmp/adb.log文件写入log数据[luther.gliethttp]
}
//================================
void fdevent_loop( )
{
fdevent * fde;
for ( ; ; ) {
fdevent_process( ) ;
while ( ( fde = fdevent_plist_dequeue( ) ) ) {
unsigned events = fde- > events;
fde- > events = 0;
fde- > state & = ( ~ FDE_PENDING) ;
dump_fde( fde, "callback" ) ;
fde- > func( fde- > fd, events, fde- > arg ) ;
}
}
}
//================================
= = > install_listener
fdevent_install( & l- > fde, l- > fd, ss_listener_event_func, l) ;
= = > fdevent_install
fde- > func = func;
fdevent_connect( fde) ;
= = > ss_listener_event_func
= = > connect_to_smartsocket
asocket * ss = create_smart_socket( smart_socket_action) ;
= = > create_smart_socket
s- > enqueue = smart_socket_enqueue;
= = > smart_socket_enqueue
= = > handle_host_request
= = > local_connect
. . .
fd = socket_loopback_client( port, SOCK_STREAM ) ;
# if ADB_HOST
if ( fd < 0) {
const char * host = getenv ( "ADBHOST" ) ;
if ( host) {
fd = socket_network_client( host, port, SOCK_STREAM ) ;
}
}
# endif
//================================
init_transport_registration
void init_transport_registration( void )
{
int s[ 2] ;
if ( adb_socketpair( s) ) { //创建一对unix通信socket
fatal_errno( "cannot open transport registration socketpair" ) ;
}
transport_registration_send = s[ 0] ; //用来发送
transport_registration_recv = s[ 1] ; //用来接收
fdevent_install( & transport_registration_fde,
transport_registration_recv, //注册接收socket作为epoll等待信息来源
transport_registration_func, //对接收到的数据执行处理操作的func
0) ;
fdevent_set( & transport_registration_fde, FDE_READ) ; //登记为READ类型
}
fdevent_install= = > fdevent_register
= = > fd_table[ fde- > fd] = fde; //这里fd_table是模拟kernel实现方式,因为fde->fd由内核获取,所以可以保证其值的唯一性.
= = > fde- > state | = FDE_ACTIVE; //置state为激活
fdevent_set( & transport_registration_fde, FDE_READ) ;
= = >
void fdevent_set( fdevent * fde, unsigned events)
{
. . .
if ( fde- > state & FDE_ACTIVE) {
fdevent_update( fde, events) ; //刷新该fde->fd到epoll中
dump_fde( fde, "update" ) ;
}
fde- > state = ( fde- > state & FDE_STATEMASK) | events; //保存信息
. . .
}
static void fdevent_update( fdevent * fde, unsigned events)
{
struct epoll_event ev;
int active;
active = ( fde- > state & FDE_EVENTMASK) ! = 0;
memset ( & ev, 0, sizeof ( ev) ) ;
ev. events = 0; //清0
ev. data. ptr = fde; //置数据指针
if ( events & FDE_READ) ev. events | = EPOLLIN; //置in事件
if ( events & FDE_WRITE) ev. events | = EPOLLOUT; //置out事件
if ( events & FDE_ERROR) ev. events | = ( EPOLLERR | EPOLLHUP) ;
fde- > state = ( fde- > state & FDE_STATEMASK) | events;
if ( active) {
. . .
} else {
/* we're not active. if we're watching events, we need
** to add, otherwise we can just do nothing
*/
if ( ev. events) {
if ( epoll_ctl( epoll_fd, EPOLL_CTL_ADD, fde- > fd, & ev) ) { //添加到epoll_fd中
perror ( "epoll_ctl() failed/n" ) ;
exit ( 1) ;
}
}
}
}
static int epoll_fd = - 1;
static void fdevent_init( )
{
/* XXX: what's a good size for the passed in hint? */
epoll_fd = epoll_create( 256) ;
if ( epoll_fd < 0) {
perror ( "epoll_create() failed" ) ;
exit ( 1) ;
}
/* mark for close-on-exec */
fcntl( epoll_fd, F_SETFD, FD_CLOEXEC) ;
}
static void fdevent_process( )
{
struct epoll_event events[ 256] ;
fdevent * fde;
int i, n;
n = epoll_wait( epoll_fd, events, 256, - 1) ; //等待添加到epoll_fd中的各个fd对应event事件发生[luther.gliethttp]
. . .
for ( i = 0; i < n; i+ + ) {
struct epoll_event * ev = events + i;
fde = ev- > data. ptr;
if ( ev- > events & EPOLLIN) {
fde- > events | = FDE_READ;
}
if ( ev- > events & EPOLLOUT) {
fde- > events | = FDE_WRITE;
}
if ( ev- > events & ( EPOLLERR | EPOLLHUP) ) {
fde- > events | = FDE_ERROR;
}
if ( fde- > events) {
if ( fde- > state & FDE_PENDING) continue ; //正在处理前一条信息
fde- > state | = FDE_PENDING;
fdevent_plist_enqueue( fde) ; //放入待处理的list链表上
}
}
}
static void fdevent_plist_enqueue( fdevent * node)
{
fdevent * list = & list_pending; //需要处理所有pending任务的链表
node- > next = list ;
node- > prev = list - > prev;
node- > prev- > next = node;
list - > prev = node;
}
static fdevent * fdevent_plist_dequeue( void ) //从pending任务链表摘下一个node来处理
{
fdevent * list = & list_pending;
fdevent * node = list - > next;
if ( node = = list ) return 0;
list - > next = node- > next;
list - > next- > prev = list ;
node- > next = 0;
node- > prev = 0;
return node;
}
void fdevent_loop( )
{
fdevent * fde;
for ( ; ; ) {
fdevent_process( ) ;
while ( ( fde = fdevent_plist_dequeue( ) ) ) {
unsigned events = fde- > events;
fde- > events = 0; //复位成0
fde- > state & = ( ~ FDE_PENDING) ; //事件检查和前期处理完成,之后将执行事件对应的func,所以清除pending标志,允许该sock接受下一个event的添加[luther.gliethttp]
dump_fde( fde, "callback" ) ;
fde- > func( fde- > fd, events, fde- > arg ) ;
}
}
}
adb_main
= = > init_transport_registration
= = > usb_init
adb_thread_create( & tid, device_poll_thread, NULL ) //创建thread
= = > local_init
adb_thread_create( & thr, client_socket_thread, 0) //host对应的处理函数,对于client,对应server_socket_thread
transport_registration_send = = = transport_registration_recv [ FDE_READ] = = = transport_registration_func
"tcp:5037" = = = local_name_to_fd( "tcp:5037" ) [ FDE_READ] = = = ss_listener_event_func //处理来自loopback端口5037的sock数据
= = = 尝试连接到"tcp:5037" 上的client们 = = = local_socket_event_func
并将"tcp:5037" 这个sock添加到listener_list链表上
好了, 我们的server已经成功起来了, 来看一个命令交互: adb shell
1. 本地执行adb shell
adb shell
= = > main
= = > adb_commandline
= = > interactive_shell
= = > fd = adb_connect( "shell:" ) ;
int fd = _adb_connect( "host:version" ) ; //因为server在上面已经打开,所以将成功链接
fd = socket_loopback_client( ADB_PORT, SOCK_STREAM ) ; //打开127.0.0.1本地机tcp:5037端口
//对于server 端,fdevent_process()==>epoll_wait(epoll_fd, events, 256, -1);将返回,触发server启动时install_listener("tcp:5037", "*smartsocket*", NULL);注册登记的
//回调函数ss_listener_event_func在fdevent_loop中被执行.
if ( memcmp ( service, "host" , 4) ! = 0 & & switch_socket_transport( fd) ) //非host命令,
//发送"host:transport-any"命令给server
adb_status( fd) ; //读取"host:version"命令的返回,对于host就是调用
//handle_host_request()==>
//#define ADB_SERVER_VERSION 20
//if (!strcmp(service, "version")) {
// char version[12];
// snprintf(version, sizeof version, "%04x", ADB_SERVER_VERSION);
// snprintf(buf, sizeof buf, "OKAY%04x%s", (unsigned)strlen(version), version);
// writex(reply_fd, buf, strlen(buf));
// return 0;
//}
//在OKAY00040014
switch_socket_transport对于server端来说对应= = >
= = > handle_host_request
if ( ! strncmp ( service, "transport" , strlen ( "transport" ) ) ) {
. . .
} else if ( ! strncmp ( service, "transport-any" , strlen ( "transport-any" ) ) ) {
type = kTransportAny;
}
. . .
transport = acquire_one_transport( CS_ANY, type, serial, & error_string) ;
//就是从transport_list链表上摘下一个登记了的transport,对于我们分析的adb shell就是
//init_transport_registration==>transport_registration_func==>会追加transport_list链表
//fdevent_install(&transport_registration_fde,
// transport_registration_recv,
// transport_registration_func,
// 0);
if ( transport) {
s- > transport = transport;
adb_write( reply_fd, "OKAY" , 4) ;
}
int adb_status( int fd)
{
unsigned char buf[ 5] ;
unsigned len;
if ( readx( fd, buf, 4) ) {
strcpy ( __adb_error, "protocol fault (no status)" ) ;
return - 1;
}
if ( ! memcmp ( buf, "OKAY" , 4) ) {
return 0; //ok,server正常返回数据,退出,进一步处理
}
if ( memcmp ( buf, "FAIL" , 4) ) {
sprintf ( __adb_error,
"protocol fault (status %02x %02x %02x %02x?!)" ,
buf[ 0] , buf[ 1] , buf[ 2] , buf[ 3] ) ;
return - 1;
}
if ( readx( fd, buf, 4) ) { //错误:读取返回数据长度
strcpy ( __adb_error, "protocol fault (status len)" ) ;
return - 1;
}
buf[ 4] = 0;
len = strtoul ( ( char * ) buf, 0, 16) ; //错误:转换长度数据
if ( len > 255) len = 255;
if ( readx( fd, __adb_error, len) ) { //错误:读取数据
strcpy ( __adb_error, "protocol fault (status read)" ) ;
return - 1;
}
__adb_error[ len] = 0;
return - 1;
}
= = > int adb_connect( const char * service)
= = > int fd = _adb_connect( "host:version" ) ;
= = >
else {
// if server was running, check its version to make sure it is not out of date
char buf[ 100] ;
int n;
int version = ADB_SERVER_VERSION - 1; //先置个非法值
// if we have a file descriptor, then parse version result
if ( fd > = 0) {
if ( readx( fd, buf, 4) ) goto error ; //读取数据长度
buf[ 4] = 0;
n = strtoul ( buf, 0, 16) ; //转换长度数据
if ( n > ( int ) sizeof ( buf) ) goto error ;
if ( readx( fd, buf, n) ) goto error ; //读取server返回的数据
adb_close( fd) ; //关闭fd
if ( sscanf ( buf, "%04x" , & version) ! = 1) goto error ; //将server返回的version数据转储到version变量中
} else {
// if fd is -1, then check for "unknown host service",
// which would indicate a version of adb that does not support the version command
if ( strcmp ( __adb_error, "unknown host service" ) ! = 0)
return fd;
}
if ( version ! = ADB_SERVER_VERSION) { //版本不匹配
printf ( "adb server is out of date. killing.../n" ) ;
fd = _adb_connect( "host:kill" ) ;
adb_close( fd) ;
/* XXX can we better detect its death? */
adb_sleep_ms( 2000) ;
goto start_server;
}
}
// if the command is start-server, we are done.
if ( ! strcmp ( service, "host:start-server" ) )
return 0;
//好了,说明server正常返回了 _adb_connect("host:version");命令,所以我们可以放心的传送adb_connect命令需要传送的service命令了, 并为该service命令创建一个与server服务器连接句柄fd.,这里就是我们上面的fd = adb_connect("shell:");它不是host命令.
fd = _adb_connect( service) ;
if ( fd = = - 2) {
fprintf ( stderr , "** daemon still not running" ) ;
}
return fd;
2. 在server端
= = > fdevent_process
= = > fde = fdevent_plist_dequeue( )
= = > fde- > func( fde- > fd, events, fde- > arg )
= = > ss_listener_event_func//"tcp:5037"端口数据处理回调函数
= = > fd = adb_socket_accept( _fd, & addr, & alen) ; //接受client的socket_loopback_client(ADB_PORT, SOCK_STREAM);连接,并为该新连接建立fd处理句柄
= = > s = create_local_socket( fd) ; //登记新建立的套接字到fd_table[fde->fd] = fde;上,回调函数为local_socket_event_func
= = > connect_to_smartsocket( s) ; // 为该socket链接创建peer处理函数,然后调用ready==>local_socket_ready==> fdevent_add(&s->fde, FDE_READ);将本fde添加到epoll上[如果不明确调用epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fde->fd, &ev);执行删除操作,那么它将永远在epoll里]等待该client发送数据过来,然后执行 s->peer->enqueue(s->peer, p);数据函数,即:smart_socket_enqueue.
static void ss_listener_event_func( int _fd, unsigned ev, void * _l)
{
asocket * s;
if ( ev & FDE_READ) {
struct sockaddr addr;
socklen_t alen;
int fd;
alen = sizeof ( addr) ;
fd = adb_socket_accept( _fd, & addr, & alen) ; //接受client的socket_loopback_client(ADB_PORT, SOCK_STREAM);连接,并为该新连接建立fd处理句柄
if ( fd < 0) return ;
adb_socket_setbufsize( fd, CHUNK_SIZE) ; //设置新建立的套接字缓冲大小
s = create_local_socket( fd) ; //登记新建立的套接字到fd_table[fde->fd] = fde;上,回调函数为local_socket_event_func
if ( s) {
connect_to_smartsocket( s) ;
//创建peer处理函数,然后调用ready==>local_socket_ready==>fdevent_add(&s->fde, FDE_READ);将本fde添加到epoll上,等待该client数据的到来,
//当接收完数据之后,调用s->peer->enqueue(s->peer, p);函数,即:smart_socket_enqueue,对数据进一步深入处理
return ;
}
adb_close( fd) ;
}
}
asocket * create_local_socket( int fd)
{
asocket * s = calloc ( 1, sizeof ( asocket) ) ;
if ( s = = 0) fatal( "cannot allocate socket" ) ;
install_local_socket( s) ;
s- > fd = fd;
s- > enqueue = local_socket_enqueue;
s- > ready = local_socket_ready; //fdevent_add(&s->fde, FDE_READ);将本fde添加到epoll上
s- > close = local_socket_close;
fdevent_install( & s- > fde, fd, local_socket_event_func, s) ;
/* fdevent_add(&s->fde, FDE_ERROR); */
//fprintf(stderr, "Created local socket in create_local_socket /n");
D( "LS(%d): created (fd=%d)/n" , s- > id, s- > fd) ;
return s;
}
void connect_to_smartsocket( asocket * s)
{
D( "Connecting to smart socket /n" ) ;
asocket * ss = create_smart_socket( smart_socket_action) ;
s- > peer = ss; //创建对等的peer对象,这样彼此将互相转送数据[luther.gliethttp]
ss- > peer = s;
s- > ready( s) ; //调用ready==>local_socket_ready==>fdevent_add(&s->fde, FDE_READ);将本fde添加到epoll上.
}
asocket * create_smart_socket( void ( * action_cb) ( asocket * s, const char * act) )
{
D( "Creating smart socket /n" ) ;
asocket * s = calloc ( 1, sizeof ( asocket) ) ;
if ( s = = 0) fatal( "cannot allocate socket" ) ;
s- > id = 0;
s- > enqueue = smart_socket_enqueue; //数据处理函数
s- > ready = smart_socket_ready;
s- > close = smart_socket_close;
s- > extra = action_cb;
D( "SS(%d): created %p/n" , s- > id, action_cb) ;
return s;
}
3. 建立的连接socket处理流程
fdevent_loop
= = > local_socket_event_func//实现通过connect连接到127.0.0.1本地机tcp:5037端口上的一个client数据收发处理
if ( ev & FDE_READ) {
. . .
adb_read( fd, x, avail) ; //读取client发送过来的数据
. . .
s- > peer- > enqueue( s- > peer, p) ; //将接收到的client数据递交给peer,smart_socket_enqueue()函数完成数据处理[luther.gliethttp]
. . .
}
= = > smart_socket_enqueue
len = unhex( p- > data, 4) ; //解出长度
service = ( char * ) p- > data + 4; //读取服务命令字
//处理所有service服务命令,比如:_adb_connect("host:version");
handle_host_request( service, ttype, serial, s- > peer- > fd, s)
//返回给s->peer->fd
//这里s->peer就是上面s = create_local_socket(fd);创建的asocket,
//s->peer->fd就是上面fd = adb_socket_accept(_fd, &addr, &alen);由client打开的socket连接,所以
//对s->peer->fd的数据发送将,通过本地机tcp:5037端口socket发送到client.
create_host_service_socket//如果是一个驻留服务
. . .
//对于我们的adb shell命令将执行到下面
s- > peer- > ready = local_socket_ready_notify;
s- > peer- > close = local_socket_close_notify;
s- > peer- > peer = 0;
/* give him our transport and upref it */
s- > peer- > transport = s- > transport;
//对于我们的adb shell命令就是connect_to_remote(s->peer, "shell:");
connect_to_remote( s- > peer, ( char * ) ( p- > data + 4) ) ;
s- > peer = 0;
s- > close ( s) ;
return 1;
void connect_to_remote( asocket * s, const char * destination)
{
D( "Connect_to_remote call /n" ) ;
apacket * p = get_apacket( ) ;
int len = strlen ( destination) + 1;
if ( len > ( MAX_PAYLOAD- 1) ) {
fatal( "destination oversized" ) ;
}
D( "LS(%d): connect('%s')/n" , s- > id, destination) ;
p- > msg. command = A_OPEN;
p- > msg. arg0 = s- > id;
p- > msg. data_length = len;
strcpy ( ( char * ) p- > data, destination) ; //destination为"shell:"
send_packet( p, s- > transport) ; //发送remote连接命令
}
= = > init_transport_registration
= = > transport_registration_send = s[ 0] ;
transport_registration_recv = s[ 1] ; //等待transport_registration_send管道数据
= = > fdevent_install( & transport_registration_fde,
transport_registration_recv,
transport_registration_func,
0) ;
= = > transport_registration_func
= = > fdevent_install( & ( t- > transport_fde) ,
t- > transport_socket,
transport_socket_events,
t) ;
= = > register_socket_transport
= = > init_socket_transport
luther@gliethttp: ~ $ adb devices
* daemon not running. starting it now *
* daemon started successfully *
List of devices attached
emulator- 5554 device
对于host启动
adb_main
= = > local_init
= = > adb_thread_create( & thr, client_socket_thread, 0) //建立client_socket_thread线程
= = > client_socket_thread
static void * client_socket_thread( void * x)
{
# if ADB_HOST
# define ADB_LOCAL_TRANSPORT_PORT 5555
int port = ADB_LOCAL_TRANSPORT_PORT;
int count = ADB_LOCAL_TRANSPORT_MAX;
D( "transport: client_socket_thread() starting/n" ) ;
/* try to connect to any number of running emulator instances */
/* this is only done when ADB starts up. later, each new emulator */
/* will send a message to ADB to indicate that is is starting up */
for ( ; count > 0; count - - , port + = 2 ) {
( void ) local_connect( port) ; //扫描网络端口,尝试连接与本机pc连接的所有物理设备或者emulator设备
// Emulator 1, console: 5554
// Emulator 1, adb: 5555
// Emulator 2, console: 5556
// Emulator 2, adb: 5557 ...
}
# endif
return 0; //线程执行完毕,安全退出.
}
# define LOCAL_CLIENT_PREFIX "emulator-"
= = > local_connect
int local_connect( int port)
{
char buf[ 64] ;
int fd = - 1;
fd = socket_loopback_client( port, SOCK_STREAM ) ;
# if ADB_HOST
if ( fd < 0) {
const char * host = getenv ( "ADBHOST" ) ; //就是上面export ADBHOST=192.168.100.2设备地址
if ( host) {
fd = socket_network_client( host, port, SOCK_STREAM ) ; //连接192.168.100.2上的port端口,
//对于client端见后面分析
}
}
# endif
if ( fd > = 0) {
D( "client: connected on remote on fd %d/n" , fd) ;
close_on_exec( fd) ;
disable_tcp_nagle( fd) ;
snprintf( buf, sizeof buf, "%s%d" , LOCAL_CLIENT_PREFIX, port - 1) ;
register_socket_transport( fd, buf, port) ; //登记到transport_list链表,作为数据传输通道之一[luther.gliethttp]
return 0;
}
return - 1;
}
对于手机上client启动
adb_main
= = > local_init
= = > adb_thread_create( & thr, server_socket_thread, 0) //建立server_socket_thread线程
= = > server_socket_thread
if ( serverfd = = - 1) {
serverfd = socket_inaddr_any_server( ADB_LOCAL_TRANSPORT_PORT, SOCK_STREAM ) ; //等待ADB_LOCAL_TRANSPORT_PORT端口数据到来
if ( serverfd < 0) {
D( "server: cannot bind socket yet/n" ) ;
adb_sleep_ms( 1000) ;
continue ;
}
close_on_exec( serverfd) ;
}
fd = adb_socket_accept( serverfd, & addr, & alen) ; //接收到一个数据请求,
//由上面的
//==>local_connect
//==>socket_network_client(host, port, SOCK_STREAM);//连接192.168.100.2上的port端口
//发起该连接,进而执行register_socket_transport向client管理的transport_list链表登记注册
register_socket_transport( fd, "host" , ADB_LOCAL_TRANSPORT_PORT) ; //创建请求线程
= = > register_socket_transport
= = > register_transport
static void register_transport( atransport * transport)
{
tmsg m;
m. transport = transport;
m. action = 1;
D( "transport: %p registered/n" , transport) ;
if ( transport_write_action( transport_registration_send, & m) ) {
fatal_errno( "cannot write transport registration socket/n" ) ;
}
}
这样与transport_registration_send配对的transport_registration_recv将接收到该数据, 并且调用已经注册好的transport_registration_func( ) 函数来进一步处理发送过去的数据,
= = > transport_registration_func
= = > transport_socket_events
= = > void handle_packet( apacket * p, atransport * t)
switch ( p- > msg. command) {
case A_OPEN: /* OPEN(local-id, 0, "destination") */
if ( t- > connection_state ! = CS_OFFLINE) {
char * name = ( char * ) p- > data; //对于我们这里的分析就是"shell:"
name[ p- > msg. data_length > 0 ? p- > msg. data_length - 1 : 0] = 0;
s = create_local_service_socket( name) ; //根据name创建service
if ( s = = 0) {
send_close( 0, p- > msg. arg0, t) ;
} else {
s- > peer = create_remote_socket( p- > msg. arg0, t) ;
s- > peer- > peer = s;
send_ready( s- > id, s- > peer- > id, t) ;
s- > ready( s) ;
}
}
break ;
= = > asocket * create_local_service_socket( const char * name)
fd = service_to_fd( name) ; //就是ptm = unix_open("/dev/ptmx", O_RDWR);返回的主pty
s = create_local_socket( fd) ; // 这样sh通过pts从pty发出的数据都将通过ptm主pty发送到peer对应的fd,即pc连接到手机端的socket,然后通过网络转发到pc端, 相应的,由pc端下发过来的数据将通过建立的socket读取到,然后交由该socket对应的peer,即:ptmx主pty,进而将直接被传递到 pty从设备,也就是下面将要看到的/system/bin/sh程序[luther.gliethttp].
return s;
int service_to_fd( const char * name)
= = >
else if ( ! HOST & & ! strncmp ( name, "shell:" , 6) ) { //对于我们这里的分析就是"shell:"
# if ADB_HOST
# define SHELL_COMMAND "/bin/sh"
# else
# define SHELL_COMMAND "/system/bin/sh" //手机上的sh位置
# endif
if ( name[ 6] ) {
ret = create_subprocess( SHELL_COMMAND, "-c" , name + 6) ;
} else {
ret = create_subprocess( SHELL_COMMAND, "-" , 0) ;
}
//ret = ptm主pty句柄
# if ! ADB_HOST
} else if ( ! strncmp ( name, "sync:" , 5) ) {
ret = create_service_thread( file_sync_service, NULL ) ;
} else if ( ! strncmp ( name, "remount:" , 8) ) {
ret = create_service_thread( remount_service, NULL ) ;
# endif
# if 0
} else if ( ! strncmp ( name, "echo:" , 5) ) {
ret = create_service_thread( echo_service, 0) ;
# endif
}
//让我们看看create_subprocess创建sh的函数体
//使用pty虚拟终端对,来完成创建工作
static int create_subprocess( const char * cmd, const char * arg0, const char * arg1)
{
# ifdef HAVE_WIN32_PROC
fprintf ( stderr , "error: create_subprocess not implemented on Win32 (%s %s %s)/n" , cmd, arg0, arg1) ;
return - 1;
# else /* !HAVE_WIN32_PROC */
char * devname;
int ptm;
pid_t pid;
//这里cmd就是"/system/bin/sh"//手机上的sh位置
ptm = unix_open( "/dev/ptmx" , O_RDWR) ; // | O_NOCTTY);
if ( ptm < 0) {
printf ( "[ cannot open /dev/ptmx - %s ]/n" , strerror ( errno ) ) ;
return - 1;
}
fcntl( ptm, F_SETFD, FD_CLOEXEC) ;
if ( grantpt( ptm) | | unlockpt( ptm) | |
( ( devname = ( char * ) ptsname( ptm) ) = = 0) ) { //获取从pty的设备名
printf ( "[ trouble with /dev/ptmx - %s ]/n" , strerror ( errno ) ) ;
return - 1;
}
pid = fork( ) ;
if ( pid < 0) {
printf ( "- fork failed: %s -/n" , strerror ( errno ) ) ;
return - 1;
}
if ( pid = = 0) {
int pts;
//子进程建立自己的新session id来和父进程完全独立开[luther.gliethttp]
setsid( ) ;
pts = unix_open( devname, O_RDWR) ; //打开pty从设备
if ( pts < 0) exit ( - 1) ;
dup2( pts, 0) ; //stdin
dup2( pts, 1) ; //stdout
dup2( pts, 2) ; //stderr 都将被重定向到pts
adb_close( ptm) ;
execl( cmd, cmd, arg0, arg1, NULL ) ; //执行/system/bin/sh
fprintf ( stderr , "- exec '%s' failed: %s (%d) -/n" ,
cmd, strerror ( errno ) , errno ) ;
exit ( - 1) ;
} else {
return ptm;
}
# endif /* !HAVE_WIN32_PROC */
}
手机上的client adb执行server_socket_thread线程等待ADB_LOCAL_TRANSPORT_PORT端口发生连接请求,
pc机端执行
export ADBHOST= 192. 168. 100. 2
adb kill - server //杀死pc上的adb server
adb start- server // 重新启动adb server,打开时,将client_socket_thread==>local_connect连接192.168.100.2的 ADB_LOCAL_TRANSPORT_PORT端口,这样手机端的server_socket_thread线程将接收到 ADB_LOCAL_TRANSPORT_PORT端口上的socket数据,然后登记该port为transport端口到 transport_list链表上[luther.gliethttp]
adb shell //登录adb shell,打开/system/bin/sh在从pty上,该sh的0,1,2句柄都将dup2到pts从pty对应的子进程上,然后ptm主pty, 将作为ADB_LOCAL_TRANSPORT_PORT端口上收发到数据后的转发peer对应的fd目的句柄,所以这样pc端的数据将通过socket 发送到手机上的socket,手机上的socket处理函数local_socket_event_func==> local_socket_enqueue将从网络接收到的数据转发给peer,即:ptm主pty,进而被pts从pty接收,也就是传递给了将 0,1,2句柄dup2到pts从pty上的/system/bin/sh应用程序,由/system/bin/sh输出的结果通过pts从pty传递给 ptm主pty,然后ptm主pty,发送到peer对应的fd,即pc连接到手机端的socket,然后通过网络转发到pc端,adb的大体流程就是这 个样子,当然还有很多细节,以后有时间再慢慢研究了,嘿[luther.gliethttp]
Detail refer: http://blog.chinaunix.net/space.php?uid=20564848&do=blog&cuid=1807376