ADB 分析
让我们来分析一下对应的代码
adbstart-server
==>main
==>adb_commandline
==>do_cmd
==>adb_connect("host:start-server");如果是adbstart-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 serversome 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 shouldnot return
//永远不会返回到这里,因为位于用户空间的这里的代码,已经被execl操作替换成adbfork-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]
adbfork-server server
==>main
==>adb_commandline
if (!strcmp(argv[0], "fork-server")) {
/* this is a special flag used only when the ADB client launches theADB 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,"--- adbstarting (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
voidinit_transport_registration(void)
{
ints[2];
if(adb_socketpair(s)){//创建一对unix通信socket
fatal_errno("cannotopen 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, unsignedevents)
{
...
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, unsignedevents)
{
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已经成功起来了,来看一个命令交互:adbshell
1.本地执行adbshell
adbshell
==>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, sizeofversion, "%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,对于我们分析的adbshell就是
//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)) {
return0;//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)
==>intfd = _adb_connect("host:version");
==>
else {
// if server was running, check itsversion to make sure it is not out of date
charbuf[100];
intn;
int version =ADB_SERVER_VERSION - 1;//先置个非法值
// ifwe have a file descriptor, then parse version result
if(fd >=0) {
if(readx(fd, buf, 4)) gotoerror;//读取数据长度
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 notsupport the version command
if (strcmp(__adb_error, "unknown host service")!= 0)
return fd;
}
if(version!= ADB_SERVER_VERSION) {//版本不匹配
printf("adb server isout 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, "Createdlocal socket in create_local_socket /n");
D("LS(%d): created(fd=%d)/n", s->id, s->fd);
returns;
}
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);
returns;
}
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//如果是一个驻留服务
...
//对于我们的adbshell命令将执行到下面
s->peer->ready =local_socket_ready_notify;
s->peer->close= local_socket_close_notify;
s->peer->peer= 0;
/* give him ourtransport and upref it */
s->peer->transport= s->transport;
//对于我们的adbshell命令就是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_remotecall /n");
apacket *p = get_apacket();
int len = strlen(destination) + 1;
if(len > (MAX_PAYLOAD-1)){
fatal("destinationoversized");
}
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 ofrunning emulator instances */
/* this is onlydone 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(intport)
{
char buf[64];
int fd = -1;
fd = socket_loopback_client(port,SOCK_STREAM);
#if ADB_HOST
if(fd < 0){
const char *host =getenv("ADBHOST");//就是上面exportADBHOST=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]
return0;
}
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
staticvoid register_transport(atransport *transport)
{
tmsg m;
m.transport = transport;
m.action = 1;
D("transport: %pregistered/n", transport);
if(transport_write_action(transport_registration_send, &m)){
fatal_errno("cannotwrite transport registration socket/n");
}
}
这样与transport_registration_send配对的transport_registration_recv将接收到该数据,并且调用已经注册好的transport_registration_func()函数来进一步处理发送过去的数据,
==>transport_registration_func
==>transport_socket_events
==>voidhandle_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
} elseif(!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
#if0
} 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, constchar *arg0, const char *arg1)
{
#ifdef HAVE_WIN32_PROC
fprintf(stderr, "error: create_subprocess not implemented onWin32 (%s %s %s)/n", cmd, arg0, arg1);
return -1;
#else /* !HAVE_WIN32_PROC */
char*devname;
int ptm;
pid_tpid;
//这里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;
//子进程建立自己的新sessionid来和父进程完全独立开[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*/
}
手机上的clientadb执行server_socket_thread线程等待ADB_LOCAL_TRANSPORT_PORT端口发生连接请求,
pc机端执行
exportADBHOST=192.168.100.2
adb kill-server //杀死pc上的adbserver
adb start-server //重新启动adbserver,打开时,将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 //登录adbshell,打开/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的大体流程就是这个样子,当然还有很多细节,以后有时间再慢慢研究了
adb shell程序执行流程:
system/core/adb/adb.c
int adb_main(int is_daemon, intserver_port)
{
#if !ADB_HOST
int port;
char value[PROPERTY_VALUE_MAX];
umask(000);
#endif
atexit(adb_cleanup);
#ifdef HAVE_WIN32_PROC
SetConsoleCtrlHandler(ctrlc_handler, TRUE );
#elif defined(HAVE_FORKEXEC)
// No SIGCHLD. Let the servicesubproc handle its children.
signal(SIGPIPE, SIG_IGN);
#endif
init_transport_registration();
=====>system/core/adb/transport.c
void init_transport_registration(void)
{
int s[2];
if(adb_socketpair(s)){
fatal_errno("cannot opentransport registration socketpair");
}
transport_registration_send =s[0];
transport_registration_recv =s[1];
fdevent_install(&transport_registration_fde,
transport_registration_recv,
transport_registration_func,
0);
fdevent_set(&transport_registration_fde, FDE_READ);
}
====>system/core/adb/transport.c
static voidtransport_registration_func(int _fd, unsigned ev, void *data)
{
tmsg m;
adb_thread_t output_thread_ptr;
adb_thread_t input_thread_ptr;
int s[2];
atransport *t;
fdevent_install(&(t->transport_fde),
t->transport_socket,
transport_socket_events,
t);
=====>system/core/adb/transport.c
static void transport_socket_events(intfd, unsigned events, void *_t)
{
atransport *t = _t;
D("transport_socket_events(fd=%d,events=%04x,...)\n", fd, events);
if(events & FDE_READ){
apacket *p = 0;
if(read_packet(fd, t->serial,&p)){
D("%s: failed to readpacket from transport socket on fd %d\n", t->serial, fd);
} else {
handle_packet(p,(atransport *) _t);
}
}
}
=====>system/core/adb/adb.c
void handle_packet(apacket *p,atransport *t)
{
asocket *s;
D("handle_packet()%c%c%c%c\n", ((char*) (&(p->msg.command)))[0],
((char*)(&(p->msg.command)))[1],
((char*)(&(p->msg.command)))[2],
((char*)(&(p->msg.command)))[3]);
print_packet("recv", p);
case A_OPEN: /* OPEN(local-id, 0,"destination") */
if (t->online) {
char *name = (char*)p->data;
name[p->msg.data_length> 0 ? p->msg.data_length - 1 : 0] = 0;
s =create_local_service_socket(name);
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);
}
}
=====>system/core/adb/sockets.c
asocket*create_local_service_socket(const char *name)
{
asocket *s;
int fd;
#if !ADB_HOST
if (!strcmp(name,"jdwp")){
returncreate_jdwp_service_socket();
}
if (!strcmp(name,"track-jdwp")){
returncreate_jdwp_tracker_service_socket();
}
#endif
fd = service_to_fd(name);
if(fd < 0) return 0;
s = create_local_socket(fd);
D("LS(%d): bound to '%s' via%d\n", s->id, name, fd);
#if !ADB_HOST
if ((!strncmp(name, "root:",5) && getuid() != 0)
|| !strncmp(name, "usb:",4)
|| !strncmp(name, "tcpip:",6)) {
D("LS(%d): enablingexit_on_close\n", s->id);
s->exit_on_close = 1;
}
#endif
======>system/core/adb/services.c
int service_to_fd(const char *name)
{
int ret = -1;
} else if(!HOST &&!strncmp(name, "shell:", 6)) {
if(name[6]) {
ret =create_subproc_thread(name + 6);
} else {
ret =create_subproc_thread(0);
}
======>system/core/adb/services.c
static int create_subproc_thread(constchar *name)
{
stinfo *sti;
adb_thread_t t;
int ret_fd;
pid_t pid;
if(name) {
ret_fd =create_subprocess(SHELL_COMMAND, "-c", name, &pid);
} else {
ret_fd =create_subprocess(SHELL_COMMAND, "-", 0, &pid);
}
D("create_subprocess()ret_fd=%d pid=%d\n", ret_fd, pid);
sti = malloc(sizeof(stinfo));
if(sti == 0) fatal("cannotallocate stinfo");
sti->func =subproc_waiter_service;
sti->cookie = (void*)pid;
sti->fd = ret_fd;
======>system/core/adb/services.c
static int create_subprocess(const char*cmd, const char *arg0, const char *arg1, pid_t *pid)
{
#ifdef HAVE_WIN32_PROC
D("create_subprocess(cmd=%s,arg0=%s, arg1=%s)\n", cmd, arg0, arg1);
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;
ptm = unix_open("/dev/ptmx",O_RDWR); // | O_NOCTTY);
if(ptm < 0){
printf("[ cannot open/dev/ptmx - %s ]\n",strerror(errno));
return -1;
}