Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2115135
  • 博文数量: 374
  • 博客积分: 7276
  • 博客等级: 少将
  • 技术积分: 5668
  • 用 户 组: 普通用户
  • 注册时间: 2011-10-06 16:35
文章分类

全部博文(374)

文章存档

2013年(23)

2012年(153)

2011年(198)

分类:

2012-04-10 17:39:40


浅析linux开发工具adb具体实现

《再次浅析adb shell,pc daemon和手机daemon三者之间的数据交互流程》

《浅析adb创建流程》

//===============================

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]

阅读(4090) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

linux禅师2012-04-24 16:08:44

adb研究的很深刻。支持!
遇到了一个问题想请教大侠:
问题:怎样实现通过USB数据线就能进行Andriod设备和PC端通信?
-------可以通过adb来实现,我不知道如何实现?要修改哪些地方?小弟刚接受到Android系统,望大侠给予指点。