zoukankan      html  css  js  c++  java
  • android6.0 adbd深入分析(二)adb驱动数据的处理、写数据到adb驱动节点

    

    上篇博客最后讲到在output_thread中。读取了adb驱动的数据后。就调用write_packet(t->fd, t->serial, &p)函数,把数据网socketpair的一側写。

    这会导致socketpair的还有一側有数据,还有一側有数据会调用transport_socket_events函数来处理数据。


    一、处理驱动读取的数据

    我们如今来看看transport_socket_events函数:

    static void transport_socket_events(int fd, unsigned events, void *_t)
    {
        atransport *t = reinterpret_cast<atransport*>(_t);
        D("transport_socket_events(fd=%d, events=%04x,...)
    ", fd, events);
        if(events & FDE_READ){
            apacket *p = 0;
            if(read_packet(fd, t->serial, &p)){
                D("%s: failed to read packet from transport socket on fd %d
    ", t->serial, fd);
            } else {
                handle_packet(p, (atransport *) _t);
            }
        }
    }

    我们先把socketpair一端的数据读取出来,然后调用handle_packet来处理。

    void handle_packet(apacket *p, atransport *t)
    {
        asocket *s;
    
        switch(p->msg.command){//依据从驱动读取内容msg的命令
    	......
    
        case A_OPEN: /* OPEN(local-id, 0, "destination") */
            if (t->online && p->msg.arg0 != 0 && p->msg.arg1 == 0) {
                char *name = (char*) p->data;
                name[p->msg.data_length > 0 ? p->msg.data_length - 1 : 0] = 0;
                s = create_local_service_socket(name);//创建一个本地的socket
                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;
    	......
    
        case A_WRTE: /* WRITE(local-id, remote-id, <data>) */
            if (t->online && p->msg.arg0 != 0 && p->msg.arg1 != 0) {
                if((s = find_local_socket(p->msg.arg1, p->msg.arg0))) {
                    unsigned rid = p->msg.arg0;
                    p->len = p->msg.data_length;
    
                    if(s->enqueue(s, p) == 0) {
                        D("Enqueue the socket
    ");
                        send_ready(s->id, rid, t);
                    }
                    return;
                }
            }
            break;
    
        default:
            printf("handle_packet: what is %08x?

    ! ", p->msg.command); } put_apacket(p); }


    上面是处理驱动的数据。我们先来看下处理open命令中一个create_local_service_socket函数

    asocket *create_local_service_socket(const char *name)
    {
    #if !ADB_HOST
        if (!strcmp(name,"jdwp")) {
            return create_jdwp_service_socket();
        }
        if (!strcmp(name,"track-jdwp")) {
            return create_jdwp_tracker_service_socket();
        }
    #endif
        int fd = service_to_fd(name);//获取fd
        if(fd < 0) return 0;
    
        asocket* s = create_local_socket(fd);//创建socket
        D("LS(%d): bound to '%s' via %d
    ", s->id, name, fd);
    
    #if !ADB_HOST
        char debug[PROPERTY_VALUE_MAX];
        if (!strncmp(name, "root:", 5))
            property_get("ro.debuggable", debug, "");
    
        if ((!strncmp(name, "root:", 5) && getuid() != 0 && strcmp(debug, "1") == 0)
            || (!strncmp(name, "unroot:", 7) && getuid() == 0)
            || !strncmp(name, "usb:", 4)
            || !strncmp(name, "tcpip:", 6)) {
            D("LS(%d): enabling exit_on_close
    ", s->id);
            s->exit_on_close = 1;
        }
    #endif
    
        return s;
    }

    我们先来看看service_to_fd函数:

    int service_to_fd(const char *name)
    {
        int ret = -1;
    
        if(!strncmp(name, "tcp:", 4)) {
            int port = atoi(name + 4);
            name = strchr(name + 4, ':');
            if(name == 0) {
                ret = socket_loopback_client(port, SOCK_STREAM);
                if (ret >= 0)
                    disable_tcp_nagle(ret);
            } else {
    #if ADB_HOST
                ret = socket_network_client(name + 1, port, SOCK_STREAM);
    #else
                return -1;
    #endif
            }
    #ifndef HAVE_WINSOCK   /* winsock doesn't implement unix domain sockets */
        } else if(!strncmp(name, "local:", 6)) {
            ret = socket_local_client(name + 6,
                    ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
        } else if(!strncmp(name, "localreserved:", 14)) {
            ret = socket_local_client(name + 14,
                    ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
        } else if(!strncmp(name, "localabstract:", 14)) {
            ret = socket_local_client(name + 14,
                    ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
        } else if(!strncmp(name, "localfilesystem:", 16)) {
            ret = socket_local_client(name + 16,
                    ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
    #endif
    #if !ADB_HOST
        } else if(!strncmp("dev:", name, 4)) {
            ret = unix_open(name + 4, O_RDWR | O_CLOEXEC);
        } else if(!strncmp(name, "framebuffer:", 12)) {
            ret = create_service_thread(framebuffer_service, 0);
        } else if (!strncmp(name, "jdwp:", 5)) {
            ret = create_jdwp_connection_fd(atoi(name+5));
        } else if(!HOST && !strncmp(name, "shell:", 6)) {//adb shell
            ret = create_subproc_thread(name + 6, SUBPROC_PTY);
        } else if(!HOST && !strncmp(name, "exec:", 5)) {
            ret = create_subproc_thread(name + 5, SUBPROC_RAW);
        } else if(!strncmp(name, "sync:", 5)) {
        	D("kangchen service_to_fd file_sync_service");
            ret = create_service_thread(file_sync_service, NULL);
        } else if(!strncmp(name, "remount:", 8)) {
            ret = create_service_thread(remount_service, NULL);
        } else if(!strncmp(name, "reboot:", 7)) {
            void* arg = strdup(name + 7);
            if (arg == NULL) return -1;
            ret = create_service_thread(reboot_service, arg);
        } else if(!strncmp(name, "root:", 5)) {//adb root
            ret = create_service_thread(restart_root_service, NULL);
    这里我们主要看下adb root和adb shell,其它的以后自己慢慢研究:

    1.2 adb root的处理过程

    我们先来看下adb root的处理过程,serverice_to_fd函数先调用了create_service_thread函数:

    static int create_service_thread(void (*func)(int, void *), void *cookie)
    {
        int s[2];
        if (adb_socketpair(s)) {//建立一对socketpair
            printf("cannot create service socket pair
    ");
            return -1;
        }
        D("socketpair: (%d,%d)", s[0], s[1]);
    
        stinfo* sti = reinterpret_cast<stinfo*>(malloc(sizeof(stinfo)));
        if (sti == nullptr) {
            fatal("cannot allocate stinfo");
        }
        sti->func = func;
        sti->cookie = cookie;
        sti->fd = s[1];
    
        adb_thread_t t;
        if (adb_thread_create(&t, service_bootstrap_func, sti)) {
            free(sti);
            adb_close(s[0]);
            adb_close(s[1]);
            printf("cannot create service thread
    ");
            return -1;
        }
    
        D("service thread started, %d:%d
    ",s[0], s[1]);
        return s[0];//返回一端的socketpair
    }

    我们再来看看service_bootstrap_func函数:

    void *service_bootstrap_func(void *x)
    {
        stinfo* sti = reinterpret_cast<stinfo*>(x);
        sti->func(sti->fd, sti->cookie);
        free(sti);
        return 0;
    }

    终于还是调用了create_service_thread传进来的func函数
    而adb root传入的是restart_root_service函数:

    void restart_root_service(int fd, void *cookie) {
        if (getuid() == 0) {//已经root
            WriteFdExactly(fd, "adbd is already running as root
    ");
            adb_close(fd);
        } else {
        	D("kangchen restart_root_service.
    ");
            char value[PROPERTY_VALUE_MAX];
            property_get("ro.debuggable", value, "");
            if (strcmp(value, "1") != 0) {
                WriteFdExactly(fd, "adbd cannot run as root in production builds
    ");
                adb_close(fd);
                return;
            }
    
            property_set("service.adb.root", "1");//设置root
            WriteFdExactly(fd, "restarting adbd as root
    ");//这是写入pc端的数据
            adb_close(fd);
        }
    }

    由于前面是sockpair。那这边写入的数据,会在另外一端的sockpair有反应。

    而另外一端的sockpair终于是作为service_to_fd函数的返回值,那我们继续看下create_local_service_socket函数

    asocket *create_local_service_socket(const char *name)
    {
    #if !ADB_HOST
        if (!strcmp(name,"jdwp")) {
            return create_jdwp_service_socket();
        }
        if (!strcmp(name,"track-jdwp")) {
            return create_jdwp_tracker_service_socket();
        }
    #endif
        int fd = service_to_fd(name);//得到sockpair的一端
        if(fd < 0) return 0;
    
        asocket* s = create_local_socket(fd);//创建localsocket
        D("LS(%d): bound to '%s' via %d
    ", s->id, name, fd);
    
    #if !ADB_HOST
        char debug[PROPERTY_VALUE_MAX];
        if (!strncmp(name, "root:", 5))
            property_get("ro.debuggable", debug, "");
    
        if ((!strncmp(name, "root:", 5) && getuid() != 0 && strcmp(debug, "1") == 0)
            || (!strncmp(name, "unroot:", 7) && getuid() == 0)
            || !strncmp(name, "usb:", 4)
            || !strncmp(name, "tcpip:", 6)) {
            D("LS(%d): enabling exit_on_close
    ", s->id);
            s->exit_on_close = 1;
        }
    #endif
    
        return s;
    }
    

    我们再来看看create_local_socket函数

    asocket *create_local_socket(int fd)
    {
        asocket *s = reinterpret_cast<asocket*>(calloc(1, sizeof(asocket)));
        if (s == NULL) fatal("cannot allocate socket");
        s->fd = fd;
        s->enqueue = local_socket_enqueue;
        s->ready = local_socket_ready;
        s->shutdown = NULL;
        s->close = local_socket_close;
        install_local_socket(s);
    
        fdevent_install(&s->fde, fd, local_socket_event_func, s);
        D("LS(%d): created (fd=%d)
    ", s->id, s->fd);
        return s;
    }

    这个函数也是给socket赋各种函数等,然后当socket的这个fd有数据,这个fd就是前面service_to_fd返回的fd,当这个fd有数据会触发local_socket_func函数,我们来看下这个函数:

    static void local_socket_event_func(int fd, unsigned ev, void* _s)
    {
        asocket* s = reinterpret_cast<asocket*>(_s);
        D("LS(%d): event_func(fd=%d(==%d), ev=%04x)
    ", s->id, s->fd, fd, ev);
    
    .....
    
        if (ev & FDE_READ) {
            apacket *p = get_apacket();
            unsigned char *x = p->data;
            size_t avail = MAX_PAYLOAD;
            int r;
            int is_eof = 0;
    
            while (avail > 0) {
                r = adb_read(fd, x, avail);//获取从sockpair一側传来的数据
                D("LS(%d): post adb_read(fd=%d,...) r=%d (errno=%d) avail=%zu
    ",
                  s->id, s->fd, r, r < 0 ?

    errno : 0, avail); if (r == -1) { if (errno == EAGAIN) { break; } } else if (r > 0) { avail -= r; x += r; continue; } /* r = 0 or unhandled error */ is_eof = 1; break; } D("LS(%d): fd=%d post avail loop. r=%d is_eof=%d forced_eof=%d ", s->id, s->fd, r, is_eof, s->fde.force_eof); if ((avail == MAX_PAYLOAD) || (s->peer == 0)) { put_apacket(p); } else { p->len = MAX_PAYLOAD - avail; r = s->peer->enqueue(s->peer, p);//往t->transport_socket的一端写值,这样input_thread线程就有数据读取了 D("LS(%d): fd=%d post peer->enqueue(). r=%d ", s->id, s->fd, r); if (r < 0) { /* error return means they closed us as a side-effect ** and we must return immediately. ** ** note that if we still have buffered packets, the ** socket will be placed on the closing socket list. ** this handler function will be called again ** to process FDE_WRITE events. */ return; } if (r > 0) { /* if the remote cannot accept further events, ** we disable notification of READs. They'll ** be enabled again when we get a call to ready() */ fdevent_del(&s->fde, FDE_READ); } } /* Don't allow a forced eof if data is still there */ if ((s->fde.force_eof && !r) || is_eof) { D(" closing because is_eof=%d r=%d s->fde.force_eof=%d ", is_eof, r, s->fde.force_eof); s->close(s); } } ...... }

    比方当我们adb root 处理之后,会发送类似adb restart root之类的信息给adb 驱动,这时候就会触发local_socket_event_func函数。这个函数先去读取你要发的信息。然后往t->transport_socket的一端写值。这样input_thread线程就有数据读取了。而这个是通过s->peer->enqueue来实现的。

    我们再来看看这块。

    在处理open命令的之后,还创建了remotesocket

        case A_OPEN: /* OPEN(local-id, 0, "destination") */
            if (t->online && p->msg.arg0 != 0 && p->msg.arg1 == 0) {
                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);
                }
            }
            break;

    我们来看看create_remote_socket函数

    asocket *create_remote_socket(unsigned id, atransport *t)
    {
        if (id == 0) fatal("invalid remote socket id (0)");
        asocket* s = reinterpret_cast<asocket*>(calloc(1, sizeof(aremotesocket)));
        adisconnect* dis = &reinterpret_cast<aremotesocket*>(s)->disconnect;
    
        if (s == NULL) fatal("cannot allocate socket");
        s->id = id;
        s->enqueue = remote_socket_enqueue;
        s->ready = remote_socket_ready;
        s->shutdown = remote_socket_shutdown;
        s->close = remote_socket_close;
        s->transport = t;
    
        dis->func   = remote_socket_disconnect;
        dis->opaque = s;
        add_transport_disconnect( t, dis );
        D("RS(%d): created
    ", s->id);
        return s;
    }

    这里我们主要看下remote_socket_enqueue函数:

    static int remote_socket_enqueue(asocket *s, apacket *p)
    {
        D("kangchen entered remote_socket_enqueue RS(%d) WRITE fd=%d peer.fd=%d
    ",
          s->id, s->fd, s->peer->fd);
        p->msg.command = A_WRTE;
        p->msg.arg0 = s->peer->id;
        p->msg.arg1 = s->id;
        p->msg.data_length = p->len;
        send_packet(p, s->transport);
        return 1;
    }
    再来看看send_packet函数

    void send_packet(apacket *p, atransport *t)
    {
        unsigned char *x;
        unsigned sum;
        unsigned count;
    
        p->msg.magic = p->msg.command ^ 0xffffffff;
    
        count = p->msg.data_length;
        x = (unsigned char *) p->data;
        sum = 0;
        while(count-- > 0){
            sum += *x++;
        }
        p->msg.data_check = sum;
    
        print_packet("send", p);
    
        if (t == NULL) {
            D("Transport is null 
    ");
            // Zap errno because print_packet() and other stuff have errno effect.
            errno = 0;
            fatal_errno("Transport is null");
        }
        if(write_packet(t->transport_socket, t->serial, &p)){
            fatal_errno("cannot enqueue packet on transport socket");
        }
    }

    send_packet函数终于是往t->transport_socket写入,这也意味着input_thread会从socketpair的还有一側读取数据,最后再往adb驱动写入数据。

    这样整个adb root就比較清楚了。

    static void *input_thread(void *_t)
    {
        atransport *t = reinterpret_cast<atransport*>(_t);
        apacket *p;
        int active = 0;
    
        D("%s: starting transport input thread, reading from fd %d
    ",
           t->serial, t->fd);
    
        for(;;){
            if(read_packet(t->fd, t->serial, &p)) {//读取socket数据
                D("%s: failed to read apacket from transport on fd %d
    ",
                   t->serial, t->fd );
                LOG("%s:%s: failed to read apacket from transport on fd %d
    ", __FUNCTION__, t->serial, t->fd );
                break;
            }
            if(p->msg.command == A_SYNC){
                if(p->msg.arg0 == 0) {
                    D("%s: transport SYNC offline
    ", t->serial);
                    put_apacket(p);
                    LOG("%s:%s: transport SYNC offline
    ", __FUNCTION__, t->serial);
                    break;
                } else {
                    if(p->msg.arg1 == t->sync_token) {
                        D("%s: transport SYNC online
    ", t->serial);
                        LOG("%s:%s: transport SYNC online
    ", __FUNCTION__, t->serial);
                        active = 1;
                    } else {
                        D("%s: transport ignoring SYNC %d != %d
    ",
                          t->serial, p->msg.arg1, t->sync_token);
                        LOG("%s:%s: transport ignoring SYNC
    ", __FUNCTION__, t->serial);
                    }
                }
            } else {
                if(active) {
                    D("%s: transport got packet, sending to remote
    ", t->serial);
                    t->write_to_remote(p, t);//写入adb驱动
                } else {
                    D("%s: transport ignoring packet while offline
    ", t->serial);
                }
            }
    
            put_apacket(p);
        }


    1.2 adb shell 流程

    以下我们再来看下adb shell的流程,会和adb root有点不一样。也会更复杂些。

    相同adb shell的处理流程也是先到handle _packet函数:

        case A_OPEN: /* OPEN(local-id, 0, "destination") */
            if (t->online && p->msg.arg0 != 0 && p->msg.arg1 == 0) {
                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); } } break;

    一样的我们就直接看service_to_fd函数了,当中截取以下这段代码:

        } else if(!HOST && !strncmp(name, "shell:", 6)) {
            ret = create_subproc_thread(name + 6, SUBPROC_PTY);

    我们来看看create_subproc_thread函数:

    static int create_subproc_thread(const char *name, const subproc_mode mode)
    {
        adb_thread_t t;
        int ret_fd;
        pid_t pid = -1;
    
        const char *arg0, *arg1;
        if (name == 0 || *name == 0) {
            arg0 = "-"; arg1 = 0;
        } else {
            arg0 = "-c"; arg1 = name;
        }
    
        switch (mode) {
        case SUBPROC_PTY:
            ret_fd = create_subproc_pty(SHELL_COMMAND, arg0, arg1, &pid);//我们是调用了这函数
            break;
        case SUBPROC_RAW:
            ret_fd = create_subproc_raw(SHELL_COMMAND, arg0, arg1, &pid);
            break;
        default:
            fprintf(stderr, "invalid subproc_mode %d
    ", mode);
            return -1;
        }
        D("create_subproc ret_fd=%d pid=%d
    ", ret_fd, pid);
    
        stinfo* sti = reinterpret_cast<stinfo*>(malloc(sizeof(stinfo)));
        if(sti == 0) fatal("cannot allocate stinfo");
        sti->func = subproc_waiter_service;
        sti->cookie = (void*) (uintptr_t) pid;
        sti->fd = ret_fd;
    
        if (adb_thread_create(&t, service_bootstrap_func, sti)) {
            free(sti);
            adb_close(ret_fd);
            fprintf(stderr, "cannot create service thread
    ");
            return -1;
        }
    
        D("service thread started, fd=%d pid=%d
    ", ret_fd, pid);
        return ret_fd;
    }
    我们先来看看create_subproc_pty函数:

    static int create_subproc_pty(const char *cmd, const char *arg0, const char *arg1, pid_t *pid)
    {
        int ptm;
    
        ptm = unix_open("/dev/ptmx", O_RDWR | O_CLOEXEC); // | O_NOCTTY);//返回的fd
        if(ptm < 0){
            printf("[ cannot open /dev/ptmx - %s ]
    ",strerror(errno));
            return -1;
        }
    
        char devname[64];
        if(grantpt(ptm) || unlockpt(ptm) || ptsname_r(ptm, devname, sizeof(devname)) != 0) {
            printf("[ trouble with /dev/ptmx - %s ]
    ", strerror(errno));
            adb_close(ptm);
            return -1;
        }
    
        *pid = fork();//fork进程
        if(*pid < 0) {
            printf("- fork failed: %s -
    ", strerror(errno));
            adb_close(ptm);
            return -1;
        }
    
        if (*pid == 0) {//子进程
            init_subproc_child();
    
            int pts = unix_open(devname, O_RDWR | O_CLOEXEC);
            if (pts < 0) {
                fprintf(stderr, "child failed to open pseudo-term slave: %s
    ", devname);
                exit(-1);
            }
    
            dup2(pts, STDIN_FILENO);//标准输入、输出、错误都指向这个fd
            dup2(pts, STDOUT_FILENO);
            dup2(pts, STDERR_FILENO);
    
            adb_close(pts);
            adb_close(ptm);
    
            execl(cmd, cmd, arg0, arg1, NULL);//然后应该一直运行system/bin/shell命令
    		D("kangchen create_subproc_pty(cmd=%s, arg0=%s, arg1=%s)
    ", cmd, arg0, arg1);
            fprintf(stderr, "- exec '%s' failed: %s (%d) -
    ",
                    cmd, strerror(errno), errno);
            exit(-1);
        } else {
            return ptm;
        }
    #endif /* !defined(_WIN32) */
    }

    这个函数中,ptm和pts两个节点肯定有某种联系。pts然后把标准输入、输出、错误都指向了它。也就是当有输入、输出、错误数据都会到pts这个fd。终于肯定回到ptm这个fd。

    也就是当外面有数据来的时候,ptm这个fd会有值,然后到pts,再到标准输入。经过dup2后进程A的不论什么目标为STDOUT_FILENO的I/O操作如printf等。其数据都将流入pts这个fd中。

    而标准输入有值,会到pts。然后到ptm。最后数据就到input_thread了。事实上这个pts和ptm类似socketpair的一对。

    我们再来看看subproc_waiter_service

    static void subproc_waiter_service(int fd, void *cookie)
    {
        pid_t pid = (pid_t) (uintptr_t) cookie;
    
        D("entered. fd=%d of pid=%d
    ", fd, pid);
        while (true) {
            int status;
            pid_t p = waitpid(pid, &status, 0);
            if (p == pid) {
                D("fd=%d, post waitpid(pid=%d) status=%04x
    ", fd, p, status);
                if (WIFSIGNALED(status)) {
                    D("*** Killed by signal %d
    ", WTERMSIG(status));
                    break;
                } else if (!WIFEXITED(status)) {
                    D("*** Didn't exit!!. status %d
    ", status);
                    break;
                } else if (WEXITSTATUS(status) >= 0) {
                    D("*** Exit code %d
    ", WEXITSTATUS(status));
                    break;
                }
             }
        }
        D("shell exited fd=%d of pid=%d err=%d
    ", fd, pid, errno);
        if (SHELL_EXIT_NOTIFY_FD >=0) {
          int res;
          res = WriteFdExactly(SHELL_EXIT_NOTIFY_FD, &fd, sizeof(fd)) ?

    0 : -1; D("notified shell exit via fd=%d for pid=%d res=%d errno=%d ", SHELL_EXIT_NOTIFY_FD, pid, res, errno); } }

    这个函数开启了一线线程,仅仅是在一直waitpid的出错信号。

    当adb shell有命令进来比方“ls”,它先到handle_packet函数的A_WRTE命令

        case A_WRTE: /* WRITE(local-id, remote-id, <data>) */
            if (t->online && p->msg.arg0 != 0 && p->msg.arg1 != 0) {
                if((s = find_local_socket(p->msg.arg1, p->msg.arg0))) {//先找到local_socket
                    unsigned rid = p->msg.arg0;
                    p->len = p->msg.data_length;
    
                    if(s->enqueue(s, p) == 0) {//调用enqueue函数
                        D("Enqueue the socket
    ");
                        send_ready(s->id, rid, t);
                    }
                    return;
                }
            }
            break;

    enqueue函数就是local_socket_enqueue函数,这个函数就是往service_to_fd写数据

    static int local_socket_enqueue(asocket *s, apacket *p)
    {
        D("LS(%d): enqueue %d
    ", s->id, p->len);
    
        p->ptr = p->data;
    
            /* if there is already data queue'd, we will receive
            ** events when it's time to write.  just add this to
            ** the tail
            */
        if(s->pkt_first) {
            goto enqueue;
        }
    
            /* write as much as we can, until we
            ** would block or there is an error/eof
            */
        while(p->len > 0) {
            int r = adb_write(s->fd, p->ptr, p->len);
            if(r > 0) {
                p->len -= r;
                p->ptr += r;
                continue;
            }
            if((r == 0) || (errno != EAGAIN)) {
                D( "LS(%d): not ready, errno=%d: %s
    ", s->id, errno, strerror(errno) );
                s->close(s);
                return 1; /* not ready (error) */
            } else {
                break;
            }
        }
    
        if(p->len == 0) {
            put_apacket(p);
            return 0; /* ready for more data */
        }
    
    enqueue:
        p->next = 0;
        if(s->pkt_first) {
            s->pkt_last->next = p;
        } else {
            s->pkt_first = p;
        }
        s->pkt_last = p;
    
            /* make sure we are notified when we can drain the queue */
        fdevent_add(&s->fde, FDE_WRITE);
    
        return 1; /* not ready (backlog) */
    }

    比方"ls"命令就往service_to_fd写。这样create_subproc_pty函数的子进程就标准输入就有数据了,就能够运行cmd命令了

            dup2(pts, STDIN_FILENO);
            dup2(pts, STDOUT_FILENO);
            dup2(pts, STDERR_FILENO);
    
            adb_close(pts);
            adb_close(ptm);
    
            execl(cmd, cmd, arg0, arg1, NULL);

    运行命令后,又有输出。就到ptm的fd中,也就是service_to_fd中。最后再到Input_thread中读取。


    事实上create_subproc_raw函数,使用socketpair更好理解。

    static int create_subproc_raw(const char *cmd, const char *arg0, const char *arg1, pid_t *pid)
    {
        D("create_subproc_raw(cmd=%s, arg0=%s, arg1=%s)
    ", cmd, arg0, arg1);
    #if defined(_WIN32)
        fprintf(stderr, "error: create_subproc_raw not implemented on Win32 (%s %s %s)
    ", cmd, arg0, arg1);
        return -1;
    #else
    
        // 0 is parent socket, 1 is child socket
        int sv[2];
        if (adb_socketpair(sv) < 0) {
            printf("[ cannot create socket pair - %s ]
    ", strerror(errno));
            return -1;
        }
        D("socketpair: (%d,%d)", sv[0], sv[1]);
    
        *pid = fork();
        if (*pid < 0) {
            printf("- fork failed: %s -
    ", strerror(errno));
            adb_close(sv[0]);
            adb_close(sv[1]);
            return -1;
        }
    
        if (*pid == 0) {
            adb_close(sv[0]);
            init_subproc_child();
    
            dup2(sv[1], STDIN_FILENO);
            dup2(sv[1], STDOUT_FILENO);
            dup2(sv[1], STDERR_FILENO);
    
            adb_close(sv[1]);
    
            execl(cmd, cmd, arg0, arg1, NULL);
    
    		D("kangchen create_subproc_raw(cmd=%s, arg0=%s, arg1=%s)
    ", cmd, arg0, arg1);
    		
            fprintf(stderr, "- exec '%s' failed: %s (%d) -
    ",
                    cmd, strerror(errno), errno);
            exit(-1);
        } else {
            adb_close(sv[1]);
            return sv[0];
        }
    #endif /* !defined(_WIN32) */
    }


    二、Input_thread读取local socket的数据,再写入adb驱动


    service_to_fd有数据后,会触发函数local_socket_event_func。在这个函数中调用了s->peer->enqueue。然后调用remote_socket_enqueue函数

    static int remote_socket_enqueue(asocket *s, apacket *p)
    {
        p->msg.command = A_WRTE;
        p->msg.arg0 = s->peer->id;
        p->msg.arg1 = s->id;
        p->msg.data_length = p->len;
        send_packet(p, s->transport);
        return 1;
    }

    终于调用send_packet函数

    void send_packet(apacket *p, atransport *t)
    {
        unsigned char *x;
        unsigned sum;
        unsigned count;
    
        p->msg.magic = p->msg.command ^ 0xffffffff;
    
        count = p->msg.data_length;
        x = (unsigned char *) p->data;
        sum = 0;
        while(count-- > 0){
            sum += *x++;
        }
        p->msg.data_check = sum;
    
        print_packet("send", p);
    
        if (t == NULL) {
            D("Transport is null 
    ");
            // Zap errno because print_packet() and other stuff have errno effect.
            errno = 0;
            fatal_errno("Transport is null");
        }
        if(write_packet(t->transport_socket, t->serial, &p)){
            fatal_errno("cannot enqueue packet on transport socket");
        }
    }

    终于还是往transport_socket写数据,然后我们再来看看input_thread线程。

    static void *input_thread(void *_t)
    {
        atransport *t = reinterpret_cast<atransport*>(_t);
        apacket *p;
        int active = 0;
    
        D("%s: starting transport input thread, reading from fd %d
    ",
           t->serial, t->fd);
    
        for(;;){
            if(read_packet(t->fd, t->serial, &p)) {//transport_socket的还有一端读取数据
                D("%s: failed to read apacket from transport on fd %d
    ",
                   t->serial, t->fd );//出错直接跳出循环,线程结束
                break;
            }
            if(p->msg.command == A_SYNC){
                if(p->msg.arg0 == 0) {
                    D("%s: transport SYNC offline
    ", t->serial);
                    put_apacket(p);
                    break;
                } else {
                    if(p->msg.arg1 == t->sync_token) {
                        D("%s: transport SYNC online
    ", t->serial);
                        active = 1;
                    } else {
                        D("%s: transport ignoring SYNC %d != %d
    ",
                          t->serial, p->msg.arg1, t->sync_token);
                    }
                }
            } else {
                if(active) {
                    t->write_to_remote(p, t);//往驱动写
                } else {
                    D("%s: transport ignoring packet while offline
    ", t->serial);
                }
            }
    
            put_apacket(p);
        }
    
        // this is necessary to avoid a race condition that occured when a transport closes
        // while a client socket is still active.
        close_all_sockets(t);
    
        D("%s: transport input thread is exiting, fd %d
    ", t->serial, t->fd);
        kick_transport(t);
        transport_unref(t);
        return 0;
    }

    write_to_remote调用的是remote_write函数。来看下remote_write函数:

    static int remote_write(apacket *p, atransport *t)
    {
        unsigned size = p->msg.data_length;
    	
        if(usb_write(t->usb, &p->msg, sizeof(amessage))) {
            D("remote usb: 1 - write terminated
    ");
            return -1;
        }
        if(p->msg.data_length == 0) return 0;
    
        if(usb_write(t->usb, &p->data, size)) {
            D("remote usb: 2 - write terminated
    ");
            return -1;
        }
    
        return 0;
    }

    usb_write函数

    int usb_write(usb_handle *h, const void *data, int len)
    {
        return h->write(h, data, len);
    }

    然后调用的是usb_adb_write函数:

    static int usb_adb_write(usb_handle *h, const void *data, int len)
    {
        int n;
    
        D("about to write (fd=%d, len=%d)
    ", h->fd, len);
        n = adb_write(h->fd, data, len);
        if(n != len) {
            D("ERROR: fd = %d, n = %d, errno = %d (%s)
    ",
                h->fd, n, errno, strerror(errno));
            return -1;
        }
        D("[ done fd=%d ]
    ", h->fd);
        return 0;
    }

    终于就写入的adb节点的驱动中去了。


    三、总结

    这篇博客分析了,处理pc端过来的数据,adb驱动中的数据。以及adb root 、adb shell这两个过程。最后再由input_thread写入adb 驱动发送到pc端。


  • 相关阅读:
    adb、monkey常用命令
    震惊!90%的程序员不知道的Java知识!
    Android,重新出发!
    Fiddler 手机抓包 手机联网异常解决方案
    技术贴汇总
    Android开发日常-listview滚动方法梳理
    JavaScript基本语法
    Spring Boot Profile
    Spring Boot配置文件占位符
    @PropertySource和@ImportSource
  • 原文地址:https://www.cnblogs.com/wzjhoutai/p/7275765.html
Copyright © 2011-2022 走看看