adb: make disconnect stop reconnection immediately.

Make `adb disconnect` remove transports immediately, instead of on
their next reconnection cycle.

Test: adb connect unreachable:12345; adb devices; adb disconnect; adb devices
Change-Id: I35c8b57344e847575596d09216fc636be47dde64
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 4cd19f9..332e0f8 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -97,6 +97,9 @@
     // Adds the atransport* to the queue of reconnect attempts.
     void TrackTransport(atransport* transport);
 
+    // Wake up the ReconnectHandler thread to have it check for kicked transports.
+    void CheckForKicked();
+
   private:
     // The main thread loop.
     void Run();
@@ -166,6 +169,10 @@
     reconnect_cv_.notify_one();
 }
 
+void ReconnectHandler::CheckForKicked() {
+    reconnect_cv_.notify_one();
+}
+
 void ReconnectHandler::Run() {
     while (true) {
         ReconnectAttempt attempt;
@@ -184,10 +191,25 @@
             }
 
             if (!running_) return;
+
+            // Scan the whole list for kicked transports, so that we immediately handle an explicit
+            // disconnect request.
+            bool kicked = false;
+            for (auto it = reconnect_queue_.begin(); it != reconnect_queue_.end();) {
+                if (it->transport->kicked()) {
+                    D("transport %s was kicked. giving up on it.", it->transport->serial.c_str());
+                    remove_transport(it->transport);
+                    it = reconnect_queue_.erase(it);
+                } else {
+                    ++it;
+                }
+                kicked = true;
+            }
+
             if (reconnect_queue_.empty()) continue;
 
-            // Go back to sleep in case |reconnect_cv_| woke up spuriously and we still
-            // have more time to wait for the current attempt.
+            // Go back to sleep if we either woke up spuriously, or we were woken up to remove
+            // a kicked transport, and the first transport isn't ready for reconnection yet.
             auto now = std::chrono::steady_clock::now();
             if (reconnect_queue_.begin()->reconnect_time > now) {
                 continue;
@@ -195,11 +217,6 @@
 
             attempt = *reconnect_queue_.begin();
             reconnect_queue_.erase(reconnect_queue_.begin());
-            if (attempt.transport->kicked()) {
-                D("transport %s was kicked. giving up on it.", attempt.transport->serial.c_str());
-                remove_transport(attempt.transport);
-                continue;
-            }
         }
         D("attempting to reconnect %s", attempt.transport->serial.c_str());
 
@@ -448,6 +465,10 @@
     if (std::find(transport_list.begin(), transport_list.end(), t) != transport_list.end()) {
         t->Kick();
     }
+
+#if ADB_HOST
+    reconnect_handler.CheckForKicked();
+#endif
 }
 
 static int transport_registration_send = -1;
@@ -1276,6 +1297,9 @@
             t->Kick();
         }
     }
+#if ADB_HOST
+    reconnect_handler.CheckForKicked();
+#endif
 }
 
 #endif