diff options
author | Josh Gao | 2017-05-12 16:46:50 -0500 |
---|---|---|
committer | Josh Gao | 2017-05-12 19:08:50 -0500 |
commit | 3f60a968e35b051943249fb9ac70e349323a0590 (patch) | |
tree | 7935e195ad0585717952fcc07f19eb85182c0f25 | |
parent | 6da1cd49b5eaeabb3febe584845de6bb3ae45873 (diff) | |
download | platform-system-core-3f60a968e35b051943249fb9ac70e349323a0590.tar.gz platform-system-core-3f60a968e35b051943249fb9ac70e349323a0590.tar.xz platform-system-core-3f60a968e35b051943249fb9ac70e349323a0590.zip |
adb: libusb: wait for devices to become accessible.
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.
When detecting a new device, poll the device file for a while until we
can access it, before trying to open it.
Bug: http://b/38170349
Test: manually incrased timeout and chmodded a device betwen 0 and 664
Change-Id: I3c714f630940df02b407442592301e2bbb3d9653
-rw-r--r-- | adb/client/usb_libusb.cpp | 51 |
1 files changed, 47 insertions, 4 deletions
diff --git a/adb/client/usb_libusb.cpp b/adb/client/usb_libusb.cpp index 0068e084b..2508fc12e 100644 --- a/adb/client/usb_libusb.cpp +++ b/adb/client/usb_libusb.cpp | |||
@@ -172,6 +172,17 @@ static std::string get_device_serial_path(libusb_device* device) { | |||
172 | path += "/serial"; | 172 | path += "/serial"; |
173 | return path; | 173 | return path; |
174 | } | 174 | } |
175 | |||
176 | static std::string get_device_dev_path(libusb_device* device) { | ||
177 | uint8_t ports[7]; | ||
178 | int port_count = libusb_get_port_numbers(device, ports, 7); | ||
179 | if (port_count < 0) return ""; | ||
180 | return StringPrintf("/dev/bus/usb/%03u/%03u", libusb_get_bus_number(device), ports[0]); | ||
181 | } | ||
182 | |||
183 | static bool is_device_accessible(libusb_device* device) { | ||
184 | return access(get_device_dev_path(device).c_str(), R_OK | W_OK) == 0; | ||
185 | } | ||
175 | #endif | 186 | #endif |
176 | 187 | ||
177 | static bool endpoint_is_output(uint8_t endpoint) { | 188 | static bool endpoint_is_output(uint8_t endpoint) { |
@@ -368,11 +379,38 @@ static void process_device(libusb_device* device) { | |||
368 | } | 379 | } |
369 | 380 | ||
370 | register_usb_transport(usb_handle_raw, device_serial.c_str(), device_address.c_str(), writable); | 381 | register_usb_transport(usb_handle_raw, device_serial.c_str(), device_address.c_str(), writable); |
371 | |||
372 | LOG(INFO) << "registered new usb device '" << device_serial << "'"; | 382 | LOG(INFO) << "registered new usb device '" << device_serial << "'"; |
373 | } | 383 | } |
374 | 384 | ||
375 | static void remove_device(libusb_device* device) { | 385 | static std::atomic<int> connecting_devices(0); |
386 | |||
387 | static void device_connected(libusb_device* device) { | ||
388 | #if defined(__linux__) | ||
389 | // Android's host linux libusb uses netlink instead of udev for device hotplug notification, | ||
390 | // which means we can get hotplug notifications before udev has updated ownership/perms on the | ||
391 | // device. Since we're not going to be able to link against the system's libudev any time soon, | ||
392 | // hack around this by checking for accessibility in a loop. | ||
393 | ++connecting_devices; | ||
394 | auto thread = std::thread([device]() { | ||
395 | std::string device_path = get_device_dev_path(device); | ||
396 | auto start = std::chrono::steady_clock::now(); | ||
397 | while (std::chrono::steady_clock::now() - start < 500ms) { | ||
398 | if (is_device_accessible(device)) { | ||
399 | break; | ||
400 | } | ||
401 | std::this_thread::sleep_for(10ms); | ||
402 | } | ||
403 | |||
404 | process_device(device); | ||
405 | --connecting_devices; | ||
406 | }); | ||
407 | thread.detach(); | ||
408 | #else | ||
409 | process_device(device); | ||
410 | #endif | ||
411 | } | ||
412 | |||
413 | static void device_disconnected(libusb_device* device) { | ||
376 | std::string device_address = get_device_address(device); | 414 | std::string device_address = get_device_address(device); |
377 | 415 | ||
378 | LOG(INFO) << "device disconnected: " << device_address; | 416 | LOG(INFO) << "device disconnected: " << device_address; |
@@ -390,9 +428,9 @@ static void remove_device(libusb_device* device) { | |||
390 | static int hotplug_callback(libusb_context*, libusb_device* device, libusb_hotplug_event event, | 428 | static int hotplug_callback(libusb_context*, libusb_device* device, libusb_hotplug_event event, |
391 | void*) { | 429 | void*) { |
392 | if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) { | 430 | if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) { |
393 | process_device(device); | 431 | device_connected(device); |
394 | } else if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) { | 432 | } else if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) { |
395 | remove_device(device); | 433 | device_disconnected(device); |
396 | } | 434 | } |
397 | return 0; | 435 | return 0; |
398 | } | 436 | } |
@@ -415,6 +453,11 @@ void usb_init() { | |||
415 | LOG(FATAL) << "failed to register libusb hotplug callback"; | 453 | LOG(FATAL) << "failed to register libusb hotplug callback"; |
416 | } | 454 | } |
417 | 455 | ||
456 | // Wait for all of the connecting devices to finish. | ||
457 | while (connecting_devices != 0) { | ||
458 | std::this_thread::sleep_for(10ms); | ||
459 | } | ||
460 | |||
418 | adb_notify_device_scan_complete(); | 461 | adb_notify_device_scan_complete(); |
419 | 462 | ||
420 | // Spawn a thread for libusb_handle_events. | 463 | // Spawn a thread for libusb_handle_events. |