diff options
author | Josh Gao | 2017-05-12 13:21:30 -0500 |
---|---|---|
committer | Josh Gao | 2017-05-12 19:08:50 -0500 |
commit | 6da1cd49b5eaeabb3febe584845de6bb3ae45873 (patch) | |
tree | b689d4d06c2a80798155be31dd3c65e0dc6e94bd | |
parent | 723258a4c7d024473de8558c15a6db5437468681 (diff) | |
download | platform-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.cpp | 70 |
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 { | |||
151 | static auto& usb_handles = *new std::unordered_map<std::string, std::unique_ptr<usb_handle>>(); | 151 | static auto& usb_handles = *new std::unordered_map<std::string, std::unique_ptr<usb_handle>>(); |
152 | static auto& usb_handles_mutex = *new std::mutex(); | 152 | static auto& usb_handles_mutex = *new std::mutex(); |
153 | 153 | ||
154 | static std::thread* device_poll_thread = nullptr; | 154 | static libusb_hotplug_callback_handle hotplug_handle; |
155 | static bool terminate_device_poll_thread = false; | ||
156 | static auto& device_poll_mutex = *new std::mutex(); | ||
157 | static auto& device_poll_cv = *new std::condition_variable(); | ||
158 | 155 | ||
159 | static std::string get_device_address(libusb_device* device) { | 156 | static 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 | ||
378 | static void poll_for_devices() { | 375 | static 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); | 390 | static 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 | ||
401 | void usb_init() { | 400 | void 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 | ||
422 | void usb_cleanup() { | 429 | void 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. |