summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Gao2017-05-12 13:21:30 -0500
committerJosh Gao2017-05-12 19:08:50 -0500
commit6da1cd49b5eaeabb3febe584845de6bb3ae45873 (patch)
treeb689d4d06c2a80798155be31dd3c65e0dc6e94bd
parent723258a4c7d024473de8558c15a6db5437468681 (diff)
downloadplatform-system-core-6da1cd49b5eaeabb3febe584845de6bb3ae45873.tar.gz
platform-system-core-6da1cd49b5eaeabb3febe584845de6bb3ae45873.tar.xz
platform-system-core-6da1cd49b5eaeabb3febe584845de6bb3ae45873.zip
adb: libusb: switch to hotplug for device detection.
Switch from polling in a loop to using libusb's hotplug API to detect when devices arrive and leave. Use this to remove devices that were inaccessible when they're unplugged. Bug: http://b/38170349 Test: plugged in device Change-Id: Id157412eb46834debecb0cd45b47b1ced50c2274
-rw-r--r--adb/client/usb_libusb.cpp70
1 files changed, 34 insertions, 36 deletions
diff --git a/adb/client/usb_libusb.cpp b/adb/client/usb_libusb.cpp
index 18a8ff23a..0068e084b 100644
--- a/adb/client/usb_libusb.cpp
+++ b/adb/client/usb_libusb.cpp
@@ -151,10 +151,7 @@ struct usb_handle : public ::usb_handle {
151static auto& usb_handles = *new std::unordered_map<std::string, std::unique_ptr<usb_handle>>(); 151static auto& usb_handles = *new std::unordered_map<std::string, std::unique_ptr<usb_handle>>();
152static auto& usb_handles_mutex = *new std::mutex(); 152static auto& usb_handles_mutex = *new std::mutex();
153 153
154static std::thread* device_poll_thread = nullptr; 154static libusb_hotplug_callback_handle hotplug_handle;
155static bool terminate_device_poll_thread = false;
156static auto& device_poll_mutex = *new std::mutex();
157static auto& device_poll_cv = *new std::condition_variable();
158 155
159static std::string get_device_address(libusb_device* device) { 156static std::string get_device_address(libusb_device* device) {
160 return StringPrintf("usb:%d:%d", libusb_get_bus_number(device), 157 return StringPrintf("usb:%d:%d", libusb_get_bus_number(device),
@@ -375,27 +372,29 @@ static void process_device(libusb_device* device) {
375 LOG(INFO) << "registered new usb device '" << device_serial << "'"; 372 LOG(INFO) << "registered new usb device '" << device_serial << "'";
376} 373}
377 374
378static void poll_for_devices() { 375static void remove_device(libusb_device* device) {
379 libusb_device** list; 376 std::string device_address = get_device_address(device);
380 adb_thread_setname("device poll");
381 while (true) {
382 const ssize_t device_count = libusb_get_device_list(nullptr, &list);
383
384 LOG(VERBOSE) << "found " << device_count << " attached devices";
385 377
386 for (ssize_t i = 0; i < device_count; ++i) { 378 LOG(INFO) << "device disconnected: " << device_address;
387 process_device(list[i]); 379 std::unique_lock<std::mutex> lock(usb_handles_mutex);
380 auto it = usb_handles.find(device_address);
381 if (it != usb_handles.end()) {
382 if (!it->second->device_handle) {
383 // If the handle is null, we were never able to open the device.
384 unregister_usb_transport(it->second.get());
388 } 385 }
386 usb_handles.erase(it);
387 }
388}
389 389
390 libusb_free_device_list(list, 1); 390static int hotplug_callback(libusb_context*, libusb_device* device, libusb_hotplug_event event,
391 391 void*) {
392 adb_notify_device_scan_complete(); 392 if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) {
393 393 process_device(device);
394 std::unique_lock<std::mutex> lock(device_poll_mutex); 394 } else if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) {
395 if (device_poll_cv.wait_for(lock, 500ms, []() { return terminate_device_poll_thread; })) { 395 remove_device(device);
396 return;
397 }
398 } 396 }
397 return 0;
399} 398}
400 399
401void usb_init() { 400void usb_init() {
@@ -405,6 +404,19 @@ void usb_init() {
405 LOG(FATAL) << "failed to initialize libusb: " << libusb_error_name(rc); 404 LOG(FATAL) << "failed to initialize libusb: " << libusb_error_name(rc);
406 } 405 }
407 406
407 // Register the hotplug callback.
408 rc = libusb_hotplug_register_callback(
409 nullptr, static_cast<libusb_hotplug_event>(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED |
410 LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT),
411 LIBUSB_HOTPLUG_ENUMERATE, LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY,
412 LIBUSB_CLASS_PER_INTERFACE, hotplug_callback, nullptr, &hotplug_handle);
413
414 if (rc != LIBUSB_SUCCESS) {
415 LOG(FATAL) << "failed to register libusb hotplug callback";
416 }
417
418 adb_notify_device_scan_complete();
419
408 // Spawn a thread for libusb_handle_events. 420 // Spawn a thread for libusb_handle_events.
409 std::thread([]() { 421 std::thread([]() {
410 adb_thread_setname("libusb"); 422 adb_thread_setname("libusb");
@@ -412,24 +424,10 @@ void usb_init() {
412 libusb_handle_events(nullptr); 424 libusb_handle_events(nullptr);
413 } 425 }
414 }).detach(); 426 }).detach();
415
416 // Spawn a thread to do device enumeration.
417 // TODO: Use libusb_hotplug_* instead?
418 std::unique_lock<std::mutex> lock(device_poll_mutex);
419 device_poll_thread = new std::thread(poll_for_devices);
420} 427}
421 428
422void usb_cleanup() { 429void usb_cleanup() {
423 { 430 libusb_hotplug_deregister_callback(nullptr, hotplug_handle);
424 std::unique_lock<std::mutex> lock(device_poll_mutex);
425 terminate_device_poll_thread = true;
426
427 if (!device_poll_thread) {
428 return;
429 }
430 }
431 device_poll_cv.notify_all();
432 device_poll_thread->join();
433} 431}
434 432
435// Dispatch a libusb transfer, unlock |device_lock|, and then wait for the result. 433// Dispatch a libusb transfer, unlock |device_lock|, and then wait for the result.