哎! 最近接USB, 還真有點難搞~~

http://blog.csdn.net/sfrysh/archive/2011/02/16/6187544.aspx

淺析linux開發工具adb具體實現

淺析linux開發工具adb具體實現
《再次淺析adb shell,pc daemon和手機daemon三者之間的數據交互流程
《淺析adb創建流程》
//===============================

adb啟動shell用到的命令
export ADBHOST=192.168.100.2
adb kill-server
adb start-server11:31:27
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;
}
arrow
arrow
    全站熱搜

    三原online 發表在 痞客邦 留言(0) 人氣()