adb: implement wait-for-disconnect.

Bug: http://b/124244488
Test: manual
Change-Id: I316a87994924c51c785e46a4900380c58e726985
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index f70b480..1909de3 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -190,8 +190,8 @@
         "scripting:\n"
         " wait-for[-TRANSPORT]-STATE\n"
         "     wait for device to be in the given state\n"
-        "     State: device, recovery, sideload, or bootloader\n"
-        "     Transport: usb, local, or any [default=any]\n"
+        "     STATE: device, recovery, sideload, bootloader, or disconnect\n"
+        "     TRANSPORT: usb, local, or any [default=any]\n"
         " get-state                print offline | bootloader | device\n"
         " get-serialno             print <serial-number>\n"
         " get-devpath              print <device-path>\n"
@@ -1031,10 +1031,11 @@
     }
 
     if (components[3] != "any" && components[3] != "bootloader" && components[3] != "device" &&
-        components[3] != "recovery" && components[3] != "sideload") {
+        components[3] != "recovery" && components[3] != "sideload" &&
+        components[3] != "disconnect") {
         fprintf(stderr,
                 "adb: unknown state %s; "
-                "expected 'any', 'bootloader', 'device', 'recovery', or 'sideload'\n",
+                "expected 'any', 'bootloader', 'device', 'recovery', 'sideload', or 'disconnect'\n",
                 components[3].c_str());
         return false;
     }
diff --git a/adb/services.cpp b/adb/services.cpp
index 1ed7182..80f9f79 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -109,12 +109,21 @@
         const char* serial = sinfo->serial.length() ? sinfo->serial.c_str() : nullptr;
         atransport* t = acquire_one_transport(sinfo->transport_type, serial, sinfo->transport_id,
                                               &is_ambiguous, &error);
-        if (t != nullptr && (sinfo->state == kCsAny || sinfo->state == t->GetConnectionState())) {
+        if (sinfo->state == kCsOffline) {
+            // wait-for-disconnect uses kCsOffline, we don't actually want to wait for 'offline'.
+            if (t == nullptr) {
+                SendOkay(fd);
+                break;
+            }
+        } else if (t != nullptr &&
+                   (sinfo->state == kCsAny || sinfo->state == t->GetConnectionState())) {
             SendOkay(fd);
             break;
-        } else if (!is_ambiguous) {
+        }
+
+        if (!is_ambiguous) {
             adb_pollfd pfd = {.fd = fd, .events = POLLIN};
-            int rc = adb_poll(&pfd, 1, 1000);
+            int rc = adb_poll(&pfd, 1, 100);
             if (rc < 0) {
                 SendFail(fd, error);
                 break;
@@ -224,6 +233,8 @@
             sinfo->state = kCsBootloader;
         } else if (name == "-any") {
             sinfo->state = kCsAny;
+        } else if (name == "-disconnect") {
+            sinfo->state = kCsOffline;
         } else {
             return nullptr;
         }