summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Gao2017-05-12 16:46:50 -0500
committerJosh Gao2017-05-12 19:08:50 -0500
commit3f60a968e35b051943249fb9ac70e349323a0590 (patch)
tree7935e195ad0585717952fcc07f19eb85182c0f25
parent6da1cd49b5eaeabb3febe584845de6bb3ae45873 (diff)
downloadplatform-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.cpp51
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
176static 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
183static 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
177static bool endpoint_is_output(uint8_t endpoint) { 188static 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
375static void remove_device(libusb_device* device) { 385static std::atomic<int> connecting_devices(0);
386
387static 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
413static 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) {
390static int hotplug_callback(libusb_context*, libusb_device* device, libusb_hotplug_event event, 428static 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.