adb: add `adb reconnect offline` to reconnect offline devices.

Add a command to reconnect offline/unauthorized devices, mainly for use
with the inotify-monitoring of vendor key directories added by 2e671202.

Bug: http://b/29273531
Test: manually tested with a sailfish + copying vendor keys
Change-Id: If34cccee4ae553ada65d128b57d03cba8c0d7c46
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 29d6e65..8b6b2b5 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -1089,6 +1089,31 @@
         return 1;
     }
 
+    if (!strcmp(service, "reconnect-offline")) {
+        std::string response;
+        close_usb_devices([&response](const atransport* transport) {
+            switch (transport->connection_state) {
+                case kCsOffline:
+                case kCsUnauthorized:
+                    response += "reconnecting ";
+                    if (transport->serial) {
+                        response += transport->serial;
+                    } else {
+                        response += "<unknown>";
+                    }
+                    response += "\n";
+                    return true;
+                default:
+                    return false;
+            }
+        });
+        if (!response.empty()) {
+            response.resize(response.size() - 1);
+        }
+        SendOkay(reply_fd, response);
+        return 0;
+    }
+
     if (!strcmp(service, "features")) {
         std::string error;
         atransport* t = acquire_one_transport(type, serial, nullptr, &error);
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index 1f03c1a..e15bcad 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -1950,10 +1950,17 @@
     } else if (!strcmp(argv[0], "reconnect")) {
         if (argc == 1) {
             return adb_query_command("host:reconnect");
-        } else if (argc == 2 && !strcmp(argv[1], "device")) {
-            std::string err;
-            adb_connect("reconnect", &err);
-            return 0;
+        } else if (argc == 2) {
+            if (!strcmp(argv[1], "device")) {
+                std::string err;
+                adb_connect("reconnect", &err);
+                return 0;
+            } else if (!strcmp(argv[1], "offline")) {
+                std::string err;
+                return adb_query_command("host:reconnect-offline");
+            } else {
+                return usage();
+            }
         }
     }
 
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index 3a57174..c05903f 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -791,11 +791,14 @@
     }
 #endif
 
-    if (!(s->transport) || (s->transport->connection_state == kCsOffline)) {
+    if (!s->transport) {
+        SendFail(s->peer->fd, "device offline (no transport)");
+        goto fail;
+    } else if (s->transport->connection_state == kCsOffline) {
         /* if there's no remote we fail the connection
          ** right here and terminate it
          */
-        SendFail(s->peer->fd, "device offline (x)");
+        SendFail(s->peer->fd, "device offline (transport offline)");
         goto fail;
     }
 
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 7b4bb1c..132702d 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -908,12 +908,18 @@
     return result;
 }
 
+void close_usb_devices(std::function<bool(const atransport*)> predicate) {
+    std::lock_guard<std::mutex> lock(transport_lock);
+    for (auto& t : transport_list) {
+        if (predicate(t)) {
+            t->Kick();
+        }
+    }
+}
+
 /* hack for osx */
 void close_usb_devices() {
-    std::lock_guard<std::mutex> lock(transport_lock);
-    for (const auto& t : transport_list) {
-        t->Kick();
-    }
+    close_usb_devices([](const atransport*) { return true; });
 }
 #endif // ADB_HOST
 
diff --git a/adb/transport.h b/adb/transport.h
index 621516c..b2df838 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -20,6 +20,7 @@
 #include <sys/types.h>
 
 #include <deque>
+#include <functional>
 #include <list>
 #include <memory>
 #include <string>
@@ -199,8 +200,8 @@
 int check_header(apacket* p, atransport* t);
 int check_data(apacket* p);
 
-/* for MacOS X cleanup */
 void close_usb_devices();
+void close_usb_devices(std::function<bool(const atransport*)> predicate);
 
 void send_packet(apacket* p, atransport* t);