Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 關於android開發 >> android6.0 adbd深入分析(四)adbd usb線拔掉再連接的過程

android6.0 adbd深入分析(四)adbd usb線拔掉再連接的過程

編輯:關於android開發

android6.0 adbd深入分析(四)adbd usb線拔掉再連接的過程


一、log打印流程

我們先來看下自己調試的代碼打印:

由於顯示的問題,我把log的時間去除了,只顯示了pid 和tid

 

//拔去usb線
185   188 I adbd    : output_thread:(null): remote read failed for transport
185   188 I adbd    : output_thread:(null) SYNC offline for transport
185   185 I adbd    : handle_packet: A_SYNC
185   185 I adbd    : handle_packet: A_SYNC CS_OFFLINE
185   187 I adbd    : input_thread:(null): transport SYNC offline
185   187 I adbd    : input_thread:(null): transport input thread is exiting, fd 13
185   186 I usb_adb_open_thread: adbd usb_thread - opening device
185   186 I usb_adb_open_thread: adbd opening device succeeded
185   185 I adbd    : handle_packet: A_SYNC
185   185 I adbd    : handle_packet: A_SYNC send_packet
185  2164 I adbd    : input_thread:(null): transport SYNC online



//插上usb線
185  2165 I adbd    : output_thread: read_from_remote after
185   185 I adbd    : handle_packet: A_CNXN
185   185 I adbd    : handle_packet: A_CNXN handle_online
185   185 I adbd    : handle_packet: A_CNXN send_connect
185  2165 I adbd    : output_thread: read_from_remote after
185   185 I adbd    : adb command: 'shell:dumpsys iphonesubinfo'
185  2165 I adbd    : output_thread: read_from_remote after
185  2165 I adbd    : output_thread: read_from_remote after
185   185 I adbd    : adb command: 'shell:dumpsys battery'
185  2165 I adbd    : output_thread: read_from_remote after
185  2165 I adbd    : output_thread: read_from_remote after
185  2165 I adbd    : output_thread: read_from_remote after
185   185 I adbd    : handle_packet: A_CNXN
185   185 I adbd    : handle_packet: A_CNXN handle_offline
185   185 I adbd    : handle_packet: A_CNXN handle_online
185   185 I adbd    : handle_packet: A_CNXN send_connect

 

 

二、拔usb線流程

2.1 output_thread讀取adb驅動的數據出錯

我們按照log看,首先就是output_thread讀取adb驅動的數據出錯了

 

static void *output_thread(void *_t)
{
    atransport *t = reinterpret_cast(_t);
    apacket *p;

    D("%s: starting transport output thread on fd %d, SYNC online (%d)\n",
       t->serial, t->fd, t->sync_token + 1);
    p = get_apacket();
    p->msg.command = A_SYNC;
    p->msg.arg0 = 1;
    p->msg.arg1 = ++(t->sync_token);
    p->msg.magic = A_SYNC ^ 0xffffffff;
    if(write_packet(t->fd, t->serial, &p)) {
        put_apacket(p);
        D("%s: failed to write SYNC packet\n", t->serial);
        goto oops;
    }

    D("%s: data pump started\n", t->serial);
    for(;;) {
        p = get_apacket();

        if(t->read_from_remote(p, t) == 0){
            D("%s: received remote packet, sending to transport\n",
              t->serial);
            if(write_packet(t->fd, t->serial, &p)){
                put_apacket(p);
                D("%s: failed to write apacket to transport\n", t->serial);
		LOG("%s:%s: failed to write apacket to transport\n", __FUNCTION__, t->serial);
                goto oops;
            }
        } else {
            D("%s: remote read failed for transport\n", t->serial);
	    LOG("%s:%s: remote read failed for transport\n", __FUNCTION__, t->serial);//讀取adb驅動數據失敗
            put_apacket(p);
            break;
        }
    }

    D("%s: SYNC offline for transport\n", t->serial);
    LOG("%s:%s SYNC offline for transport\n", __FUNCTION__, t->serial);//線程退出
    p = get_apacket();
    p->msg.command = A_SYNC;
    p->msg.arg0 = 0;
    p->msg.arg1 = 0;
    p->msg.magic = A_SYNC ^ 0xffffffff;
    if(write_packet(t->fd, t->serial, &p)) {//往sockpair另一側寫信息
        put_apacket(p);
        D("%s: failed to write SYNC apacket to transport", t->serial);
    }
output_thread讀取adb驅動的數據出錯了,然後退出線程並發送sockpair的另一側數據

 

 

另一側的socketpair關聯的函數是transport_socket_events函數

        fdevent_install(&(t->transport_fde),
                        t->transport_socket,
                        transport_socket_events,
                        t);

transport_socket_events函數,接著調用了handle_packet函數

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);
        }
    }
}

 

2.2 handle_packet處理offline

handle_packet函數收到A_SYNC命令,然後處理offline

void handle_packet(apacket *p, atransport *t)
{
    asocket *s;

    D("handle_packet() %c%c%c%c\n", ((char*) (&(p->msg.command)))[0],
            ((char*) (&(p->msg.command)))[1],
            ((char*) (&(p->msg.command)))[2],
            ((char*) (&(p->msg.command)))[3]);
    print_packet("recv", p);

    switch(p->msg.command){
    case A_SYNC:
	LOG("%s: A_SYNC \n", __FUNCTION__);//進入sync
        if(p->msg.arg0){
            send_packet(p, t);
	    LOG("%s: A_SYNC send_packet\n", __FUNCTION__);
            if(HOST) send_connect(t);
        } else {
            t->connection_state = CS_OFFLINE;
	    LOG("%s: A_SYNC CS_OFFLINE\n", __FUNCTION__);//offline處理
            handle_offline(t);
            send_packet(p, t);
        }
        return;

hand_packet處理sync消息,我們先來看handle_offline函數,其實就是把狀態處理下

 

void handle_offline(atransport *t)
{
    D("adb: offline\n");
    //Close the associated usb
    t->online = 0;
    run_transport_disconnects(t);
}

 

2.3 Input_thread處理offline

處理offline的我們看send_packet也是往socketpair的另一側寫數據,這樣inputThread會有數據接收

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)) {
            D("%s: failed to read apacket from transport on fd %d\n",
               t->serial, t->fd );
	      LOG("%s:%s: failed to read apacket from transport on fd %d\n", __FUNCTION__, 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);
		LOG("%s:%s: transport SYNC offline\n", __FUNCTION__, t->serial);//收到handle_packet發來的offline的消息,跳出循環
                break;
            } else {
                if(p->msg.arg1 == t->sync_token) {
		    LOG("%s:%s: transport SYNC online\n", __FUNCTION__, t->serial);
                    active = 1;
                } else {
                    D("%s: transport ignoring SYNC %d != %d\n",
                      t->serial, p->msg.arg1, t->sync_token);
                }
            }
        } else {
            if(active) {
                D("%s: transport got packet, sending to remote\n", t->serial);
                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);
    LOG("%s:%s: transport input thread is exiting, fd %d\n", __FUNCTION__, t->serial, t->fd);//線程結束
    kick_transport(t);//調用了kick_transport函數
    transport_unref(t);
    return 0;

Input_thread收到handle_packet發來的offline消息,直接退出線程,並且調用了kick_transport函數

void kick_transport(atransport* t)
{
    if (t && !t->kicked)
    {
        int  kicked;

        adb_mutex_lock(&transport_lock);
        kicked = t->kicked;
        if (!kicked)
            t->kicked = 1;
        adb_mutex_unlock(&transport_lock);

        if (!kicked)
            t->kick(t);
    }
}

這裡調用了kick其實是remote_kick函數

void init_usb_transport(atransport *t, usb_handle *h, int state)
{
    D("transport: usb\n");
    t->close = remote_close;
    t->kick = remote_kick;
    t->read_from_remote = remote_read;
    t->write_to_remote = remote_write;
    t->sync_token = 1;
    t->connection_state = state;
    t->type = kTransportUsb;
    t->usb = h;

#if ADB_HOST
    HOST = 1;
#else
    HOST = 0;
#endif
}

remote_kick調用了usb_kick函數

 

static void remote_kick(atransport *t)
{
    usb_kick(t->usb);
}
然後才調用了usb_handle的kick函數

 

 

void usb_kick(usb_handle *h)
{
    h->kick(h);
}

 

在usb_adb_init初始化的時候kick為usb_adb_kick

static void usb_adb_init()
{
    usb_handle* h = reinterpret_cast(calloc(1, sizeof(usb_handle)));
    if (h == nullptr) fatal("couldn't allocate usb_handle");

    h->write = usb_adb_write;
    h->read = usb_adb_read;
    h->kick = usb_adb_kick;

我們再來看看這個函數,最終是發送了一個signal

static void usb_adb_kick(usb_handle *h)
{
    D("usb_kick\n");
    adb_mutex_lock(&h->lock);
    adb_close(h->fd);
    h->fd = -1;

    // notify usb_adb_open_thread that we are disconnected
    adb_cond_signal(&h->notify);
    adb_mutex_unlock(&h->lock);
}

而就是這個signal導致usb_adb_open_thread等待的狀態打破,重新打開了adb驅動,然後重新開啟input_thread output_thread

static void *usb_adb_open_thread(void *x)
{
    struct usb_handle *usb = (struct usb_handle *)x;
    int fd;

    while (true) {
        // wait until the USB device needs opening
        adb_mutex_lock(&usb->lock);
        while (usb->fd != -1)
            adb_cond_wait(&usb->notify, &usb->lock);// 等待信號
        adb_mutex_unlock(&usb->lock);

        D("[ usb_thread - opening device ]\n");//重新打開adb驅動
        __android_log_print(ANDROID_LOG_INFO, __FUNCTION__,
                   "adbd usb_thread - opening device\n");
        do {
            /* XXX use inotify? */
            fd = unix_open("/dev/android_adb", O_RDWR);
            if (fd < 0) {
                // to support older kernels
                fd = unix_open("/dev/android", O_RDWR);
            }
            if (fd < 0) {
                adb_sleep_ms(1000);
            }
        } while (fd < 0);
        D("[ opening device succeeded ]\n");
        __android_log_print(ANDROID_LOG_INFO, __FUNCTION__,
                   "adbd opening device succeeded\n");

        close_on_exec(fd);
        usb->fd = fd;

        D("[ usb_thread - registering device ]\n");
        register_usb_transport(usb, 0, 0, 1);//注冊usb通道,最好開啟input_thread和output_thread
    }

    // never gets here
    return 0;
}

 

2.3 重啟開啟output_thread input_thread線程

然後在output_thread打開後,先會往handle_packet發送一個A_SYNC命令

static void *output_thread(void *_t)
{
    atransport *t = reinterpret_cast(_t);
    apacket *p;

    D("%s: starting transport output thread on fd %d, SYNC online (%d)\n",
       t->serial, t->fd, t->sync_token + 1);
    p = get_apacket();
    p->msg.command = A_SYNC;
    p->msg.arg0 = 1;
    p->msg.arg1 = ++(t->sync_token);
    p->msg.magic = A_SYNC ^ 0xffffffff;
    if(write_packet(t->fd, t->serial, &p)) {
        put_apacket(p);
        D("%s: failed to write SYNC packet\n", t->serial);
        goto oops;
    }

然後到handle_packet如何處理這個sync命令的呢

void handle_packet(apacket *p, atransport *t)
{
    asocket *s;

    D("handle_packet() %c%c%c%c\n", ((char*) (&(p->msg.command)))[0],
            ((char*) (&(p->msg.command)))[1],
            ((char*) (&(p->msg.command)))[2],
            ((char*) (&(p->msg.command)))[3]);
    print_packet("recv", p);

    switch(p->msg.command){
    case A_SYNC:
	LOG("%s: A_SYNC \n", __FUNCTION__);
        if(p->msg.arg0){//為1
            send_packet(p, t);//就又往input_thread發送包了
	    LOG("%s: A_SYNC send_packet\n", __FUNCTION__);
            if(HOST) send_connect(t);
        } else {
            t->connection_state = CS_OFFLINE;
	    LOG("%s: A_SYNC CS_OFFLINE\n", __FUNCTION__);
            handle_offline(t);
            send_packet(p, t);
        }
        return;

而input_thread收到這sync命令後的處理如下:

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)) {
            D("%s: failed to read apacket from transport on fd %d\n",
               t->serial, t->fd );
			LOG("%s:%s: failed to read apacket from transport on fd %d\n", __FUNCTION__, 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);
		LOG("%s:%s: transport SYNC offline\n", __FUNCTION__, t->serial);
                break;
            } else {
                if(p->msg.arg1 == t->sync_token) {//收到sync命令後,將active置為1,代表下次就可以往adb驅動寫了
                    D("%s: transport SYNC online\n", t->serial);
		    LOG("%s:%s: transport SYNC online\n", __FUNCTION__, t->serial);
                    active = 1;
                } else {
                    D("%s: transport ignoring SYNC %d != %d\n",
                      t->serial, p->msg.arg1, t->sync_token);
					LOG("%s:%s: transport ignoring SYNC\n", __FUNCTION__, t->serial);
                }
            }
        } else {
            if(active) {
                D("%s: transport got packet, sending to remote\n", t->serial);
                t->write_to_remote(p, t);
            } else {
                D("%s: transport ignoring packet while offline\n", t->serial);
            }
        }

        put_apacket(p);
    }

input_thread收到sync命令後將active置為1,代表下次有數據過來可以往adb驅動裡面寫了。

 

但是是不是有個疑問,因為這個時候usb先拔了,而且沒有再插上,那為什麼這個時候input_thread可以往adb驅動寫數據呢?答案在這裡:

static void *output_thread(void *_t)
{
    atransport *t = reinterpret_cast(_t);
    apacket *p;

    D("%s: starting transport output thread on fd %d, SYNC online (%d)\n",
       t->serial, t->fd, t->sync_token + 1);
    p = get_apacket();
    p->msg.command = A_SYNC;
    p->msg.arg0 = 1;
    p->msg.arg1 = ++(t->sync_token);
    p->msg.magic = A_SYNC ^ 0xffffffff;
    if(write_packet(t->fd, t->serial, &p)) {
        put_apacket(p);
        D("%s: failed to write SYNC packet\n", t->serial);
        goto oops;
    }

    D("%s: data pump started\n", t->serial);
    for(;;) {
        p = get_apacket();
	//在這裡修改了代碼,本來沒有result變量的,這個函數直接在if判斷中,這裡我們把它分開,並且打log,就是為了驗證這個函數是否阻塞
	int result = t->read_from_remote(p, t);//沒有插上usb線,這個函數一直會阻塞
	LOG("%s: read_from_remote after\n", __FUNCTION__);

        if(result == 0){
            D("%s: received remote packet, sending to transport\n",
              t->serial);
            if(write_packet(t->fd, t->serial, &p)){
                put_apacket(p);
                D("%s: failed to write apacket to transport\n", t->serial);
		LOG("%s:%s: failed to write apacket to transport\n", __FUNCTION__, t->serial);
                goto oops;
            }
        } else {
            D("%s: remote read failed for transport\n", t->serial);
	    LOG("%s:%s: remote read failed for transport\n", __FUNCTION__, t->serial);
            put_apacket(p);
            break;
        }
    }
這個時候我們在output_thread裡面稍微修改了代碼,並且增加了log,發現沒有插上usb線的時候,這個時候output_thread在讀取adb驅動數據的時候會阻塞,這樣也就不會有數據傳到input_thread往adb驅動中寫了,當然就不會有問題了。


 

三、插上usb線流程

下面我們再來分析細插上usb線的代碼流程:

我們先看log,拔去usb線先打印了read_from_remote after這個log,說明這個時候output_thread從adb驅動讀取數據不再阻塞了,然後就把數據發送了handle_packet.

handle_packet這個時候直接收到adb驅動來的 A_CNXN命令:

    case A_CNXN: /* CONNECT(version, maxdata, "system-id-string") */
            /* XXX verify version, etc */
	LOG("%s: A_CNXN\n", __FUNCTION__);
        if(t->connection_state != CS_OFFLINE) {
            t->connection_state = CS_OFFLINE;
            handle_offline(t);
	    LOG("%s: A_CNXN handle_offline\n", __FUNCTION__);
        }

        parse_banner(reinterpret_cast(p->data), t);

        if (HOST || !auth_required) {
            handle_online(t);
	    LOG("%s: A_CNXN handle_online\n", __FUNCTION__);
            if (!HOST) {
		send_connect(t);
		LOG("%s: A_CNXN send_connect\n", __FUNCTION__);
            }
        } else {
            send_auth_request(t);
	    LOG("%s: A_CNXN send_auth_request\n", __FUNCTION__);
        }
        break;

由於一開始,transport的connection_state = CS_OFFLINE,所以先處理了handle_online, 然後調用了send_connect函數:

void handle_online(atransport *t)
{
    D("adb: online\n");
    t->online = 1;
}

send_connect就是往input_thread發送連接信息,最後就是往adb驅動發送, 這樣pc就知道和adbd連接上了。

void send_connect(atransport *t)
{
    D("Calling send_connect \n");
    apacket *cp = get_apacket();
    cp->msg.command = A_CNXN;
    cp->msg.arg0 = A_VERSION;
    cp->msg.arg1 = MAX_PAYLOAD;
    cp->msg.data_length = fill_connect_data((char *)cp->data,
                                            sizeof(cp->data));
    send_packet(cp, t);
}

還有就是,在parse_banner這個函數中對connection_state做了處理

 

void parse_banner(const char* banner, atransport* t) {
    D("parse_banner: %s\n", banner);

    // The format is something like:
    // "device::ro.product.name=x;ro.product.model=y;ro.product.device=z;".
    std::vector pieces = android::base::Split(banner, ":");

    if (pieces.size() > 2) {
        const std::string& props = pieces[2];
        for (auto& prop : android::base::Split(props, ";")) {
            // The list of properties was traditionally ;-terminated rather than ;-separated.
            if (prop.empty()) continue;

            std::vector key_value = android::base::Split(prop, "=");
            if (key_value.size() != 2) continue;

            const std::string& key = key_value[0];
            const std::string& value = key_value[1];
            if (key == "ro.product.name") {
                qual_overwrite(&t->product, value);
            } else if (key == "ro.product.model") {
                qual_overwrite(&t->model, value);
            } else if (key == "ro.product.device") {
                qual_overwrite(&t->device, value);
            }
        }
    }

    const std::string& type = pieces[0];
    if (type == "bootloader") {
        D("setting connection_state to CS_BOOTLOADER\n");
        t->connection_state = CS_BOOTLOADER;
        update_transports();
    } else if (type == "device") {
        D("setting connection_state to CS_DEVICE\n");
        t->connection_state = CS_DEVICE;
        update_transports();
    } else if (type == "recovery") {
        D("setting connection_state to CS_RECOVERY\n");
        t->connection_state = CS_RECOVERY;
        update_transports();
    } else if (type == "sideload") {
        D("setting connection_state to CS_SIDELOAD\n");
        t->connection_state = CS_SIDELOAD;
        update_transports();
    } else {
        D("setting connection_state to CS_HOST\n");
        t->connection_state = CS_HOST;
    }
}

 

因此我在處理A_CNXN的時候,在parse_banner前後打了log

 

   case A_CNXN: /* CONNECT(version, maxdata, "system-id-string") */
            /* XXX verify version, etc */
		LOG("%s: A_CNXN\n", __FUNCTION__);
        if(t->connection_state != CS_OFFLINE) {
            t->connection_state = CS_OFFLINE;
            handle_offline(t);
			LOG("%s: A_CNXN handle_offline\n", __FUNCTION__);
        }

	LOG("%s: A_CNXN parse_banner before: connection_state:%d\n", __FUNCTION__, t->connection_state);

        parse_banner(reinterpret_cast(p->data), t);

	LOG("%s: A_CNXN parse_banner after: connection_state:%d\n", __FUNCTION__, t->connection_state);

 

最後發現當插上usb線的時候,一開始connection_state:0也就是CS_OFFLINE, 後面變成了3也就是CS_HOST

 

185   185 I adbd    : handle_packet: A_CNXN
185   185 I adbd    : handle_packet: A_CNXN parse_banner before: connection_state:0
185   185 I adbd    : handle_packet: A_CNXN parse_banner after: connection_state:3
185   185 I adbd    : handle_packet: A_CNXN handle_online
185   185 I adbd    : handle_packet: A_CNXN send_connect

 

至於後面一些log,shell:dumpsys iphonesubinfo' shell:dumpsys battery'都是一些別的命令

//插上usb線
185   185 I adbd    : handle_packet: A_CNXN
185   185 I adbd    : handle_packet: A_CNXN parse_banner before: connection_state:0
185   185 I adbd    : handle_packet: A_CNXN parse_banner after: connection_state:3
185   185 I adbd    : handle_packet: A_CNXN handle_online
185   185 I adbd    : handle_packet: A_CNXN send_connect
185   185 I adbd    : adb command: 'shell:dumpsys iphonesubinfo'
185   185 I adbd    : adb command: 'shell:dumpsys battery'
185   185 I adbd    : handle_packet: A_CNXN
185   185 I adbd    : handle_packet: A_CNXN handle_offline
185   185 I adbd    : handle_packet: A_CNXN parse_banner before: connection_state:0
185   185 I adbd    : handle_packet: A_CNXN parse_banner after: connection_state:3
185   185 I adbd    : handle_packet: A_CNXN handle_online
185   185 I adbd    : handle_packet: A_CNXN send_connect

最後還有一個命令先處理handle_offline,狀態先為0,再改為3

    case A_CNXN: /* CONNECT(version, maxdata, "system-id-string") */
            /* XXX verify version, etc */
		LOG("%s: A_CNXN\n", __FUNCTION__);
        if(t->connection_state != CS_OFFLINE) {
            t->connection_state = CS_OFFLINE;// handleoffline了後connection_state = CS_OFFLINE就為0了
            handle_offline(t);
	    LOG("%s: A_CNXN handle_offline\n", __FUNCTION__);
        }

	LOG("%s: A_CNXN parse_banner before: connection_state:%d\n", __FUNCTION__, t->connection_state);

        parse_banner(reinterpret_cast(p->data), t);

	LOG("%s: A_CNXN parse_banner after: connection_state:%d\n", __FUNCTION__, t->connection_state);

        ......

至於最後為什麼會連接兩次,不是很明白,這應該是協議規定的。



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