static void handle_output_oops(atransport * t, bool(*close_handle_func)(ADBAPIHANDLE)) { D("%s: transport output thread is exiting\n", t->serial); kick_transport(t, close_handle_func); D("After kick, before unref\n"); transport_unref(t); D("After unref\n"); }
// TODO: BUG: The Peak on Windows rarely doesn't close the input thread. // This causes the UI thread to hang on exit. void *input_thread(void *_t, struct dll_io_bridge * _io_bridge) { i_bridge = _io_bridge; atransport *t = (atransport *)_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 ); 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) { D("%s: transport got packet %d, sending to remote\n", t->serial, p->msg.command); 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. D("Pre-close sockets input-thread\n"); close_all_sockets(t); D("%s: transport input thread is exiting, fd %d\n", t->serial, t->fd); #ifdef WIN32 kick_transport(t, i_bridge->AdbCloseHandle); #else kick_transport(t, NULL); #endif D("Post-kick transport input-thread\n"); transport_unref(t); D("Post-unref transport input-thread\n"); return 0; }
static void *output_thread(void *_t) { atransport *t = reinterpret_cast<atransport*>(_t); apacket *p; ADB_LOGD(ADB_TSPT, "%s: starting transport output thread on fd %d, SYNC online (%d)", 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); ADB_LOGE(ADB_TSPT, "%s: failed to write SYNC packet", t->serial); goto oops; } ADB_LOGD(ADB_TSPT, "%s: data pump started", t->serial); for (;;) { p = get_apacket(); if (t->read_from_remote(p, t) == 0) { ADB_LOGD(ADB_TSPT, "%s: received remote packet, sending to transport", t->serial); if (write_packet(t->fd, t->serial, &p)) { put_apacket(p); ADB_LOGE(ADB_TSPT, "%s: failed to write apacket to transport", t->serial); goto oops; } } else { ADB_LOGE(ADB_TSPT, "%s: remote read failed for transport", t->serial); put_apacket(p); break; } } ADB_LOGD(ADB_TSPT, "%s: SYNC offline for transport", 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)) { put_apacket(p); ADB_LOGW(ADB_TSPT, "%s: failed to write SYNC apacket to transport", t->serial); } oops: ADB_LOGD(ADB_TSPT, "%s: transport output thread is exiting", t->serial); kick_transport(t); transport_unref(t); return 0; }
static void *input_thread(void *_t) { atransport *t = reinterpret_cast<atransport*>(_t); apacket *p; int active = 0; ADB_LOGD(ADB_TSPT, "%s: starting transport input thread, reading from fd %d", t->serial, t->fd); for (;;) { if (read_packet(t->fd, t->serial, &p)) { ADB_LOGE(ADB_TSPT, "%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) { ADB_LOGE(ADB_TSPT, "%s: transport SYNC offline", t->serial); put_apacket(p); break; } else { if (p->msg.arg1 == t->sync_token) { ADB_LOGD(ADB_TSPT, "%s: transport SYNC online", t->serial); active = 1; } else { ADB_LOGD(ADB_TSPT, "%s: transport ignoring SYNC %d != %d", t->serial, p->msg.arg1, t->sync_token); } } } else { if (active) { ADB_LOGD(ADB_TSPT, "%s: transport got packet, sending to remote", t->serial); t->write_to_remote(p, t); } else { ADB_LOGD(ADB_TSPT, "%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); ADB_LOGD(ADB_TSPT, "%s: transport input thread is exiting, fd %d", t->serial, t->fd); kick_transport(t); transport_unref(t); return 0; }
// The transport is opened by transport_register_func before // the read_transport and write_transport threads are started. // // The read_transport thread issues a SYNC(1, token) message to let // the write_transport thread know to start things up. In the event // of transport IO failure, the read_transport thread will post a // SYNC(0,0) message to ensure shutdown. // // The transport will not actually be closed until both threads exit, but the threads // will kick the transport on their way out to disconnect the underlying device. // // read_transport thread reads data from a transport (representing a usb/tcp connection), // and makes the main thread call handle_packet(). static void *read_transport_thread(void *_t) { atransport *t = reinterpret_cast<atransport*>(_t); apacket *p; adb_thread_setname(android::base::StringPrintf("<-%s", (t->serial != nullptr ? t->serial : "transport"))); D("%s: starting read_transport thread on fd %d, SYNC online (%d)", 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", t->serial); goto oops; } D("%s: data pump started", t->serial); for(;;) { p = get_apacket(); if(t->read_from_remote(p, t) == 0){ D("%s: received remote packet, sending to transport", t->serial); if(write_packet(t->fd, t->serial, &p)){ put_apacket(p); D("%s: failed to write apacket to transport", t->serial); goto oops; } } else { D("%s: remote read failed for transport", t->serial); put_apacket(p); break; } } D("%s: SYNC offline for transport", 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)) { put_apacket(p); D("%s: failed to write SYNC apacket to transport", t->serial); } oops: D("%s: read_transport thread is exiting", t->serial); kick_transport(t); transport_unref(t); return 0; }
void unregister_transport(atransport *t) { adb_mutex_lock(&transport_lock); t->next->prev = t->prev; t->prev->next = t->next; adb_mutex_unlock(&transport_lock); kick_transport(t); transport_unref(t); }
static void *output_thread(void *_t) { atransport *t = _t; apacket *p; D("from_remote: starting thread for transport %p, on fd %d\n", t, t->fd ); D("from_remote: transport %p SYNC online (%d)\n", t, 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, &p)) { put_apacket(p); D("from_remote: failed to write SYNC apacket to transport %p", t); goto oops; } D("from_remote: data pump for transport %p\n", t); for(;;) { p = get_apacket(); if(t->read_from_remote(p, t) == 0){ D("from_remote: received remote packet, sending to transport %p\n", t); if(write_packet(t->fd, &p)){ put_apacket(p); D("from_remote: failed to write apacket to transport %p", t); goto oops; } } else { D("from_remote: remote read failed for transport %p\n", p); put_apacket(p); break; } } D("from_remote: SYNC offline for transport %p\n", t); 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, &p)) { put_apacket(p); D("from_remote: failed to write SYNC apacket to transport %p", t); } oops: D("from_remote: thread is exiting for transport %p\n", t); kick_transport(t); transport_unref(t); return 0; }
static void *input_thread(void *_t) { atransport *t = _t; apacket *p; int active = 0; D("to_remote: starting input_thread for %p, reading from fd %d\n", t, t->fd); for(;;){ if(read_packet(t->fd, &p)) { D("to_remote: failed to read apacket from transport %p on fd %d\n", t, t->fd ); break; } if(p->msg.command == A_SYNC){ if(p->msg.arg0 == 0) { D("to_remote: transport %p SYNC offline\n", t); put_apacket(p); break; } else { if(p->msg.arg1 == t->sync_token) { D("to_remote: transport %p SYNC online\n", t); active = 1; } else { D("to_remote: trandport %p ignoring SYNC %d != %d\n", t, p->msg.arg1, t->sync_token); } } } else { if(active) { D("to_remote: transport %p got packet, sending to remote\n", t); t->write_to_remote(p, t); } else { D("to_remote: transport %p ignoring packet while offline\n", t); } } 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("to_remote: thread is exiting for transport %p, fd %d\n", t, t->fd); kick_transport(t); transport_unref(t); return 0; }
// write_transport thread gets packets sent by the main thread (through send_packet()), // and writes to a transport (representing a usb/tcp connection). static void *write_transport_thread(void *_t) { atransport *t = reinterpret_cast<atransport*>(_t); apacket *p; int active = 0; adb_thread_setname(android::base::StringPrintf("->%s", (t->serial != nullptr ? t->serial : "transport"))); D("%s: starting write_transport thread, reading from fd %d", t->serial, t->fd); for(;;){ if(read_packet(t->fd, t->serial, &p)) { 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) { D("%s: transport got packet, sending to remote", t->serial); t->write_to_remote(p, t); } else { D("%s: transport ignoring packet while offline", t->serial); } } put_apacket(p); } D("%s: write_transport thread is exiting, fd %d", t->serial, t->fd); kick_transport(t); transport_unref(t); return 0; }