adbd: don't close ep0 until we receive FUNCTIONFS_UNBIND.

Rework the functionfs logic to avoid rebinding the USB interface
repeatedly.

Bug: http://b/133132986
Test: treehugger
Change-Id: I7f75874efd197764d40b66800a117ff4726d793b
diff --git a/adb/daemon/usb.cpp b/adb/daemon/usb.cpp
index 1abae87..ac739c4 100644
--- a/adb/daemon/usb.cpp
+++ b/adb/daemon/usb.cpp
@@ -169,12 +169,12 @@
 };
 
 struct UsbFfsConnection : public Connection {
-    UsbFfsConnection(unique_fd control, unique_fd read, unique_fd write,
+    UsbFfsConnection(unique_fd* control, unique_fd read, unique_fd write,
                      std::promise<void> destruction_notifier)
         : worker_started_(false),
           stopped_(false),
           destruction_notifier_(std::move(destruction_notifier)),
-          control_fd_(std::move(control)),
+          control_fd_(control),
           read_fd_(std::move(read)),
           write_fd_(std::move(write)) {
         LOG(INFO) << "UsbFfsConnection constructed";
@@ -183,11 +183,6 @@
             PLOG(FATAL) << "failed to create eventfd";
         }
 
-        monitor_event_fd_.reset(eventfd(0, EFD_CLOEXEC));
-        if (monitor_event_fd_ == -1) {
-            PLOG(FATAL) << "failed to create eventfd";
-        }
-
         aio_context_ = ScopedAioContext::Create(kUsbReadQueueDepth + kUsbWriteQueueDepth);
     }
 
@@ -199,7 +194,6 @@
         // We need to explicitly close our file descriptors before we notify our destruction,
         // because the thread listening on the future will immediately try to reopen the endpoint.
         aio_context_.reset();
-        control_fd_.reset();
         read_fd_.reset();
         write_fd_.reset();
 
@@ -246,13 +240,6 @@
             PLOG(FATAL) << "failed to notify worker eventfd to stop UsbFfsConnection";
         }
         CHECK_EQ(static_cast<size_t>(rc), sizeof(notify));
-
-        rc = adb_write(monitor_event_fd_.get(), &notify, sizeof(notify));
-        if (rc < 0) {
-            PLOG(FATAL) << "failed to notify monitor eventfd to stop UsbFfsConnection";
-        }
-
-        CHECK_EQ(static_cast<size_t>(rc), sizeof(notify));
     }
 
   private:
@@ -271,33 +258,24 @@
         monitor_thread_ = std::thread([this]() {
             adb_thread_setname("UsbFfs-monitor");
 
-            bool bound = false;
             bool enabled = false;
             bool running = true;
             while (running) {
                 adb_pollfd pfd[2] = {
-                  { .fd = control_fd_.get(), .events = POLLIN, .revents = 0 },
-                  { .fd = monitor_event_fd_.get(), .events = POLLIN, .revents = 0 },
+                        {.fd = control_fd_->get(), .events = POLLIN, .revents = 0},
                 };
 
-                // If we don't see our first bind within a second, try again.
-                int timeout_ms = bound ? -1 : 1000;
-
-                int rc = TEMP_FAILURE_RETRY(adb_poll(pfd, 2, timeout_ms));
+                int rc = TEMP_FAILURE_RETRY(adb_poll(pfd, 2, -1));
                 if (rc == -1) {
                     PLOG(FATAL) << "poll on USB control fd failed";
-                } else if (rc == 0) {
-                    LOG(WARNING) << "timed out while waiting for FUNCTIONFS_BIND, trying again";
-                    break;
                 }
 
                 if (pfd[1].revents) {
-                    // We were told to die.
-                    break;
+                    // We were told to die, continue reading until FUNCTIONFS_UNBIND.
                 }
 
                 struct usb_functionfs_event event;
-                rc = TEMP_FAILURE_RETRY(adb_read(control_fd_.get(), &event, sizeof(event)));
+                rc = TEMP_FAILURE_RETRY(adb_read(control_fd_->get(), &event, sizeof(event)));
                 if (rc == -1) {
                     PLOG(FATAL) << "failed to read functionfs event";
                 } else if (rc == 0) {
@@ -313,28 +291,10 @@
 
                 switch (event.type) {
                     case FUNCTIONFS_BIND:
-                        if (bound) {
-                            LOG(WARNING) << "received FUNCTIONFS_BIND while already bound?";
-                            running = false;
-                            break;
-                        }
-
-                        if (enabled) {
-                            LOG(WARNING) << "received FUNCTIONFS_BIND while already enabled?";
-                            running = false;
-                            break;
-                        }
-
-                        bound = true;
+                        LOG(FATAL) << "received FUNCTIONFS_BIND after already opened?";
                         break;
 
                     case FUNCTIONFS_ENABLE:
-                        if (!bound) {
-                            LOG(WARNING) << "received FUNCTIONFS_ENABLE while not bound?";
-                            running = false;
-                            break;
-                        }
-
                         if (enabled) {
                             LOG(WARNING) << "received FUNCTIONFS_ENABLE while already enabled?";
                             running = false;
@@ -346,10 +306,6 @@
                         break;
 
                     case FUNCTIONFS_DISABLE:
-                        if (!bound) {
-                            LOG(WARNING) << "received FUNCTIONFS_DISABLE while not bound?";
-                        }
-
                         if (!enabled) {
                             LOG(WARNING) << "received FUNCTIONFS_DISABLE while not enabled?";
                         }
@@ -363,11 +319,6 @@
                             LOG(WARNING) << "received FUNCTIONFS_UNBIND while still enabled?";
                         }
 
-                        if (!bound) {
-                            LOG(WARNING) << "received FUNCTIONFS_UNBIND when not bound?";
-                        }
-
-                        bound = false;
                         running = false;
                         break;
 
@@ -381,7 +332,7 @@
 
                         if ((event.u.setup.bRequestType & USB_DIR_IN)) {
                             LOG(INFO) << "acking device-to-host control transfer";
-                            ssize_t rc = adb_write(control_fd_.get(), "", 0);
+                            ssize_t rc = adb_write(control_fd_->get(), "", 0);
                             if (rc != 0) {
                                 PLOG(ERROR) << "failed to write empty packet to host";
                                 break;
@@ -390,7 +341,7 @@
                             std::string buf;
                             buf.resize(event.u.setup.wLength + 1);
 
-                            ssize_t rc = adb_read(control_fd_.get(), buf.data(), buf.size());
+                            ssize_t rc = adb_read(control_fd_->get(), buf.data(), buf.size());
                             if (rc != event.u.setup.wLength) {
                                 LOG(ERROR)
                                         << "read " << rc
@@ -426,6 +377,12 @@
                 uint64_t dummy;
                 ssize_t rc = adb_read(worker_event_fd_.get(), &dummy, sizeof(dummy));
                 if (rc == -1) {
+                    if (errno == EINTR) {
+                        // We were interrupted either to stop, or because of a backtrace.
+                        // Check stopped_ again to see if we need to exit.
+                        continue;
+                    }
+
                     PLOG(FATAL) << "failed to read from eventfd";
                 } else if (rc == 0) {
                     LOG(FATAL) << "hit EOF on eventfd";
@@ -462,6 +419,7 @@
         }
 
         worker_thread_.join();
+        worker_started_ = false;
     }
 
     void PrepareReadBlock(IoBlock* block, uint64_t id) {
@@ -679,10 +637,13 @@
     std::once_flag error_flag_;
 
     unique_fd worker_event_fd_;
-    unique_fd monitor_event_fd_;
 
     ScopedAioContext aio_context_;
-    unique_fd control_fd_;
+
+    // We keep a pointer to the control fd, so that we can reuse it to avoid USB reconfiguration,
+    // and still be able to reset it to force a reopen after FUNCTIONFS_UNBIND or running into an
+    // unexpected situation.
+    unique_fd* control_fd_;
     unique_fd read_fd_;
     unique_fd write_fd_;
 
@@ -711,15 +672,16 @@
 static void usb_ffs_open_thread() {
     adb_thread_setname("usb ffs open");
 
+    unique_fd control;
+    unique_fd bulk_out;
+    unique_fd bulk_in;
+
     while (true) {
         if (gFfsAioSupported.has_value() && !gFfsAioSupported.value()) {
             LOG(INFO) << "failed to use nonblocking ffs, falling back to legacy";
             return usb_init_legacy();
         }
 
-        unique_fd control;
-        unique_fd bulk_out;
-        unique_fd bulk_in;
         if (!open_functionfs(&control, &bulk_out, &bulk_in)) {
             std::this_thread::sleep_for(1s);
             continue;
@@ -730,7 +692,7 @@
         std::promise<void> destruction_notifier;
         std::future<void> future = destruction_notifier.get_future();
         transport->SetConnection(std::make_unique<UsbFfsConnection>(
-                std::move(control), std::move(bulk_out), std::move(bulk_in),
+                &control, std::move(bulk_out), std::move(bulk_in),
                 std::move(destruction_notifier)));
         register_transport(transport);
         future.wait();
diff --git a/adb/daemon/usb_ffs.cpp b/adb/daemon/usb_ffs.cpp
index a64ce40..1b54022 100644
--- a/adb/daemon/usb_ffs.cpp
+++ b/adb/daemon/usb_ffs.cpp
@@ -297,8 +297,32 @@
             PLOG(ERROR) << "failed to write USB strings";
             return false;
         }
-        // Signal only when writing the descriptors to ffs
+
+        // Signal init after we've wwritten our descriptors.
         android::base::SetProperty("sys.usb.ffs.ready", "1");
+
+        // Read until we get FUNCTIONFS_BIND from the control endpoint.
+        while (true) {
+            struct usb_functionfs_event event;
+            ssize_t rc = TEMP_FAILURE_RETRY(adb_read(control.get(), &event, sizeof(event)));
+
+            if (rc == -1) {
+                PLOG(FATAL) << "failed to read from FFS control fd";
+            } else if (rc == 0) {
+                LOG(WARNING) << "hit EOF on functionfs control fd during initialization";
+            } else if (rc != sizeof(event)) {
+                LOG(FATAL) << "read functionfs event of unexpected size, expected " << sizeof(event)
+                           << ", got " << rc;
+            }
+
+            if (event.type != FUNCTIONFS_BIND) {
+                LOG(FATAL) << "first read on functionfs control fd returned non-bind: "
+                           << event.type;
+            } else {
+                break;
+            }
+        }
+
         *out_control = std::move(control);
     }