Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 關於android開發 >> android6.0 adbd深入分析(二)adb驅動數據的處理、寫數據到adb驅動節點

android6.0 adbd深入分析(二)adb驅動數據的處理、寫數據到adb驅動節點

編輯:關於android開發

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(_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 read packet from transport socket on fd %d\n", 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, ) */
        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\n");
                    send_ready(s->id, rid, t);
                }
                return;
            }
        }
        break;

    default:
        printf("handle_packet: what is %08x?!\n", 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\n", 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\n", 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\n");
        return -1;
    }
    D("socketpair: (%d,%d)", s[0], s[1]);

    stinfo* sti = reinterpret_cast(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\n");
        return -1;
    }

    D("service thread started, %d:%d\n",s[0], s[1]);
    return s[0];//返回一端的socketpair
}

我們再來看看service_bootstrap_func函數:

void *service_bootstrap_func(void *x)
{
    stinfo* sti = reinterpret_cast(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\n");
        adb_close(fd);
    } else {
    	D("kangchen restart_root_service.\n");
        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\n");
            adb_close(fd);
            return;
        }

        property_set("service.adb.root", "1");//設置root
        WriteFdExactly(fd, "restarting adbd as root\n");//這是寫入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\n", 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\n", s->id);
        s->exit_on_close = 1;
    }
#endif

    return s;
}

我們再來看看create_local_socket函數

asocket *create_local_socket(int fd)
{
    asocket *s = reinterpret_cast(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)\n", 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(_s);
    D("LS(%d): event_func(fd=%d(==%d), ev=%04x)\n", 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\n",
              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\n",
          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\n", 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\n",
              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(calloc(1, sizeof(aremotesocket)));
    adisconnect* dis = &reinterpret_cast(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\n", 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\n",
      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 \n");
        // 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就比較清楚了。

 

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\n", mode);
        return -1;
    }
    D("create_subproc ret_fd=%d pid=%d\n", ret_fd, pid);

    stinfo* sti = reinterpret_cast(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\n");
        return -1;
    }

    D("service thread started, fd=%d pid=%d\n", 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 ]\n",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 ]\n", strerror(errno));
        adb_close(ptm);
        return -1;
    }

    *pid = fork();//fork進程
    if(*pid < 0) {
        printf("- fork failed: %s -\n", 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\n", 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)\n", cmd, arg0, arg1);
        fprintf(stderr, "- exec '%s' failed: %s (%d) -\n",
                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\n", 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\n", fd, p, status);
            if (WIFSIGNALED(status)) {
                D("*** Killed by signal %d\n", WTERMSIG(status));
                break;
            } else if (!WIFEXITED(status)) {
                D("*** Didn't exit!!. status %d\n", status);
                break;
            } else if (WEXITSTATUS(status) >= 0) {
                D("*** Exit code %d\n", WEXITSTATUS(status));
                break;
            }
         }
    }
    D("shell exited fd=%d of pid=%d err=%d\n", 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\n",
        SHELL_EXIT_NOTIFY_FD, pid, res, errno);
    }
}

這個函數開啟了一線線程,只是在一直waitpid的出錯信號。

當adb shell有命令進來比如“ls”,它先到handle_packet函數的A_WRTE命令

    case A_WRTE: /* WRITE(local-id, remote-id, ) */
        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\n");
                    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\n", 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\n", 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)\n", cmd, arg0, arg1);
#if defined(_WIN32)
    fprintf(stderr, "error: create_subproc_raw not implemented on Win32 (%s %s %s)\n", 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 ]\n", strerror(errno));
        return -1;
    }
    D("socketpair: (%d,%d)", sv[0], sv[1]);

    *pid = fork();
    if (*pid < 0) {
        printf("- fork failed: %s -\n", 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)\n", cmd, arg0, arg1);
		
        fprintf(stderr, "- exec '%s' failed: %s (%d) -\n",
                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 \n");
        // 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(_t);
    apacket *p;
    int active = 0;

    D("%s: starting transport input thread, reading from fd %d\n",
       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\n",
               t->serial, t->fd );//出錯直接跳出循環,線程結束
            break;
        }
        if(p->msg.command == A_SYNC){
            if(p->msg.arg0 == 0) {
                D("%s: transport SYNC offline\n", t->serial);
                put_apacket(p);
                break;
            } else {
                if(p->msg.arg1 == t->sync_token) {
                    D("%s: transport SYNC online\n", t->serial);
                    active = 1;
                } else {
                    D("%s: transport ignoring SYNC %d != %d\n",
                      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\n", 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\n", 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\n");
        return -1;
    }
    if(p->msg.data_length == 0) return 0;

    if(usb_write(t->usb, &p->data, size)) {
        D("remote usb: 2 - write terminated\n");
        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)\n", h->fd, len);
    n = adb_write(h->fd, data, len);
    if(n != len) {
        D("ERROR: fd = %d, n = %d, errno = %d (%s)\n",
            h->fd, n, errno, strerror(errno));
        return -1;
    }
    D("[ done fd=%d ]\n", h->fd);
    return 0;
}

最終就寫入的adb節點的驅動中去了。

三、總結

這篇博客分析了,處理pc端過來的數據,adb驅動中的數據,以及adb root 、adb shell這兩個過程,最後再由input_thread寫入adb 驅動發送到pc端。
 

 

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved