Loading adb/adb.cpp +4 −0 Original line number Original line Diff line number Diff line Loading @@ -1257,6 +1257,10 @@ void update_transport_status() { void adb_notify_device_scan_complete() { void adb_notify_device_scan_complete() { { { std::lock_guard<std::mutex> lock(init_mutex); std::lock_guard<std::mutex> lock(init_mutex); if (device_scan_complete) { return; } device_scan_complete = true; device_scan_complete = true; } } Loading adb/adb_utils.h +31 −0 Original line number Original line Diff line number Diff line Loading @@ -17,7 +17,10 @@ #ifndef _ADB_UTILS_H_ #ifndef _ADB_UTILS_H_ #define _ADB_UTILS_H_ #define _ADB_UTILS_H_ #include <condition_variable> #include <mutex> #include <string> #include <string> #include <vector> #include <android-base/macros.h> #include <android-base/macros.h> Loading Loading @@ -53,4 +56,32 @@ extern int adb_close(int fd); bool forward_targets_are_valid(const std::string& source, const std::string& dest, bool forward_targets_are_valid(const std::string& source, const std::string& dest, std::string* error); 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 #endif adb/client/usb_libusb.cpp +31 −20 Original line number Original line Diff line number Diff line Loading @@ -37,6 +37,7 @@ #include <android-base/strings.h> #include <android-base/strings.h> #include "adb.h" #include "adb.h" #include "adb_utils.h" #include "transport.h" #include "transport.h" #include "usb.h" #include "usb.h" Loading Loading @@ -387,10 +388,9 @@ static std::atomic<int> connecting_devices(0); static void device_connected(libusb_device* device) { static void device_connected(libusb_device* device) { #if defined(__linux__) #if defined(__linux__) // Android's host linux libusb uses netlink instead of udev for device hotplug notification, // 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 // which means we can get hotplug notifications before udev has updated ownership/perms on // device. Since we're not going to be able to link against the system's libudev any time soon, // the device. Since we're not going to be able to link against the system's libudev any // hack around this by checking for accessibility in a loop. // time soon, hack around this by checking for accessibility in a loop. ++connecting_devices; auto thread = std::thread([device]() { auto thread = std::thread([device]() { std::string device_path = get_device_dev_path(device); std::string device_path = get_device_dev_path(device); auto start = std::chrono::steady_clock::now(); auto start = std::chrono::steady_clock::now(); Loading @@ -402,7 +402,9 @@ static void device_connected(libusb_device* device) { } } process_device(device); process_device(device); --connecting_devices; if (--connecting_devices == 0) { adb_notify_device_scan_complete(); } }); }); thread.detach(); thread.detach(); #else #else Loading @@ -425,17 +427,33 @@ static void device_disconnected(libusb_device* device) { } } } } static int hotplug_callback(libusb_context*, libusb_device* device, libusb_hotplug_event event, static auto& hotplug_queue = *new BlockingQueue<std::pair<libusb_hotplug_event, libusb_device*>>(); void*) { static void hotplug_thread() { // We're called with the libusb lock taken. Call these on the main thread outside of this adb_thread_setname("libusb hotplug"); // function so that the usb_handle mutex is always taken before the libusb mutex. while (true) { fdevent_run_on_main_thread([device, event]() { 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) { if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) { device_connected(device); device_connected(device); } else if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) { } else if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) { device_disconnected(device); 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 a separate thread outside of this // function so that the usb_handle mutex is always taken before the libusb mutex. 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; return 0; } } Loading @@ -457,13 +475,6 @@ void usb_init() { LOG(FATAL) << "failed to register libusb hotplug callback"; 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. // Spawn a thread for libusb_handle_events. std::thread([]() { std::thread([]() { adb_thread_setname("libusb"); adb_thread_setname("libusb"); Loading Loading
adb/adb.cpp +4 −0 Original line number Original line Diff line number Diff line Loading @@ -1257,6 +1257,10 @@ void update_transport_status() { void adb_notify_device_scan_complete() { void adb_notify_device_scan_complete() { { { std::lock_guard<std::mutex> lock(init_mutex); std::lock_guard<std::mutex> lock(init_mutex); if (device_scan_complete) { return; } device_scan_complete = true; device_scan_complete = true; } } Loading
adb/adb_utils.h +31 −0 Original line number Original line Diff line number Diff line Loading @@ -17,7 +17,10 @@ #ifndef _ADB_UTILS_H_ #ifndef _ADB_UTILS_H_ #define _ADB_UTILS_H_ #define _ADB_UTILS_H_ #include <condition_variable> #include <mutex> #include <string> #include <string> #include <vector> #include <android-base/macros.h> #include <android-base/macros.h> Loading Loading @@ -53,4 +56,32 @@ extern int adb_close(int fd); bool forward_targets_are_valid(const std::string& source, const std::string& dest, bool forward_targets_are_valid(const std::string& source, const std::string& dest, std::string* error); 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 #endif
adb/client/usb_libusb.cpp +31 −20 Original line number Original line Diff line number Diff line Loading @@ -37,6 +37,7 @@ #include <android-base/strings.h> #include <android-base/strings.h> #include "adb.h" #include "adb.h" #include "adb_utils.h" #include "transport.h" #include "transport.h" #include "usb.h" #include "usb.h" Loading Loading @@ -387,10 +388,9 @@ static std::atomic<int> connecting_devices(0); static void device_connected(libusb_device* device) { static void device_connected(libusb_device* device) { #if defined(__linux__) #if defined(__linux__) // Android's host linux libusb uses netlink instead of udev for device hotplug notification, // 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 // which means we can get hotplug notifications before udev has updated ownership/perms on // device. Since we're not going to be able to link against the system's libudev any time soon, // the device. Since we're not going to be able to link against the system's libudev any // hack around this by checking for accessibility in a loop. // time soon, hack around this by checking for accessibility in a loop. ++connecting_devices; auto thread = std::thread([device]() { auto thread = std::thread([device]() { std::string device_path = get_device_dev_path(device); std::string device_path = get_device_dev_path(device); auto start = std::chrono::steady_clock::now(); auto start = std::chrono::steady_clock::now(); Loading @@ -402,7 +402,9 @@ static void device_connected(libusb_device* device) { } } process_device(device); process_device(device); --connecting_devices; if (--connecting_devices == 0) { adb_notify_device_scan_complete(); } }); }); thread.detach(); thread.detach(); #else #else Loading @@ -425,17 +427,33 @@ static void device_disconnected(libusb_device* device) { } } } } static int hotplug_callback(libusb_context*, libusb_device* device, libusb_hotplug_event event, static auto& hotplug_queue = *new BlockingQueue<std::pair<libusb_hotplug_event, libusb_device*>>(); void*) { static void hotplug_thread() { // We're called with the libusb lock taken. Call these on the main thread outside of this adb_thread_setname("libusb hotplug"); // function so that the usb_handle mutex is always taken before the libusb mutex. while (true) { fdevent_run_on_main_thread([device, event]() { 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) { if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) { device_connected(device); device_connected(device); } else if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) { } else if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) { device_disconnected(device); 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 a separate thread outside of this // function so that the usb_handle mutex is always taken before the libusb mutex. 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; return 0; } } Loading @@ -457,13 +475,6 @@ void usb_init() { LOG(FATAL) << "failed to register libusb hotplug callback"; 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. // Spawn a thread for libusb_handle_events. std::thread([]() { std::thread([]() { adb_thread_setname("libusb"); adb_thread_setname("libusb"); Loading