Merge "adb: reunregress waiting for device on start-server." am: 72076d1aa7 am: 08a70ac6e5
am: 986ba5bbbb
Change-Id: I5db3903d12a686394f8ce94078b202a3a52d2d71
diff --git a/adb.cpp b/adb.cpp
index a7706a0..bfb1144 100644
--- a/adb.cpp
+++ b/adb.cpp
@@ -1257,6 +1257,10 @@
void adb_notify_device_scan_complete() {
{
std::lock_guard<std::mutex> lock(init_mutex);
+ if (device_scan_complete) {
+ return;
+ }
+
device_scan_complete = true;
}
diff --git a/adb_utils.h b/adb_utils.h
index c1d5549..20c63b3 100644
--- a/adb_utils.h
+++ b/adb_utils.h
@@ -17,7 +17,10 @@
#ifndef _ADB_UTILS_H_
#define _ADB_UTILS_H_
+#include <condition_variable>
+#include <mutex>
#include <string>
+#include <vector>
#include <android-base/macros.h>
@@ -53,4 +56,32 @@
bool forward_targets_are_valid(const std::string& source, const std::string& dest,
std::string* error);
+// A thread-safe blocking queue.
+template <typename T>
+class BlockingQueue {
+ std::mutex mutex;
+ std::condition_variable cv;
+ std::vector<T> queue;
+
+ public:
+ void Push(const T& t) {
+ {
+ std::unique_lock<std::mutex> lock(mutex);
+ queue.push_back(t);
+ }
+ cv.notify_one();
+ }
+
+ template <typename Fn>
+ void PopAll(Fn fn) {
+ std::unique_lock<std::mutex> lock(mutex);
+ cv.wait(lock, [this]() { return !queue.empty(); });
+
+ for (const T& t : queue) {
+ fn(t);
+ }
+ queue.clear();
+ }
+};
+
#endif
diff --git a/client/usb_libusb.cpp b/client/usb_libusb.cpp
index 9477c56..7e77b5e 100644
--- a/client/usb_libusb.cpp
+++ b/client/usb_libusb.cpp
@@ -37,6 +37,7 @@
#include <android-base/strings.h>
#include "adb.h"
+#include "adb_utils.h"
#include "transport.h"
#include "usb.h"
@@ -387,10 +388,9 @@
static void device_connected(libusb_device* device) {
#if defined(__linux__)
// Android's host linux libusb uses netlink instead of udev for device hotplug notification,
- // which means we can get hotplug notifications before udev has updated ownership/perms on the
- // device. Since we're not going to be able to link against the system's libudev any time soon,
- // hack around this by checking for accessibility in a loop.
- ++connecting_devices;
+ // which means we can get hotplug notifications before udev has updated ownership/perms on
+ // the device. Since we're not going to be able to link against the system's libudev any
+ // time soon, hack around this by checking for accessibility in a loop.
auto thread = std::thread([device]() {
std::string device_path = get_device_dev_path(device);
auto start = std::chrono::steady_clock::now();
@@ -402,7 +402,9 @@
}
process_device(device);
- --connecting_devices;
+ if (--connecting_devices == 0) {
+ adb_notify_device_scan_complete();
+ }
});
thread.detach();
#else
@@ -425,17 +427,33 @@
}
}
+static auto& hotplug_queue = *new BlockingQueue<std::pair<libusb_hotplug_event, libusb_device*>>();
+static void hotplug_thread() {
+ adb_thread_setname("libusb hotplug");
+ while (true) {
+ hotplug_queue.PopAll([](std::pair<libusb_hotplug_event, libusb_device*> pair) {
+ libusb_hotplug_event event = pair.first;
+ libusb_device* device = pair.second;
+ if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) {
+ device_connected(device);
+ } else if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) {
+ device_disconnected(device);
+ }
+ });
+ }
+}
+
static int hotplug_callback(libusb_context*, libusb_device* device, libusb_hotplug_event event,
void*) {
- // We're called with the libusb lock taken. Call these on the main thread outside of this
+ // We're called with the libusb lock taken. Call these on a separate thread outside of this
// function so that the usb_handle mutex is always taken before the libusb mutex.
- fdevent_run_on_main_thread([device, event]() {
- if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) {
- device_connected(device);
- } else if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) {
- device_disconnected(device);
- }
- });
+ static std::once_flag once;
+ std::call_once(once, []() { std::thread(hotplug_thread).detach(); });
+
+ if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) {
+ ++connecting_devices;
+ }
+ hotplug_queue.Push({event, device});
return 0;
}
@@ -457,13 +475,6 @@
LOG(FATAL) << "failed to register libusb hotplug callback";
}
- // Wait for all of the connecting devices to finish.
- while (connecting_devices != 0) {
- std::this_thread::sleep_for(10ms);
- }
-
- adb_notify_device_scan_complete();
-
// Spawn a thread for libusb_handle_events.
std::thread([]() {
adb_thread_setname("libusb");