Loading adb/adb.cpp +0 −6 Original line number Original line Diff line number Diff line Loading @@ -1241,10 +1241,7 @@ void update_transport_status() { return true; return true; }); }); D("update_transport_status: transports_ready = %s", result ? "true" : "false"); bool ready; bool ready; { { std::lock_guard<std::mutex> lock(init_mutex); std::lock_guard<std::mutex> lock(init_mutex); transports_ready = result; transports_ready = result; Loading @@ -1252,14 +1249,11 @@ void update_transport_status() { } } if (ready) { if (ready) { D("update_transport_status: notifying"); init_cv.notify_all(); init_cv.notify_all(); } } } } void adb_notify_device_scan_complete() { void adb_notify_device_scan_complete() { D("device scan complete"); { { std::lock_guard<std::mutex> lock(init_mutex); std::lock_guard<std::mutex> lock(init_mutex); device_scan_complete = true; device_scan_complete = true; Loading adb/client/usb_libusb.cpp +78 −37 Original line number Original line Diff line number Diff line Loading @@ -151,10 +151,7 @@ struct usb_handle : public ::usb_handle { static auto& usb_handles = *new std::unordered_map<std::string, std::unique_ptr<usb_handle>>(); static auto& usb_handles = *new std::unordered_map<std::string, std::unique_ptr<usb_handle>>(); static auto& usb_handles_mutex = *new std::mutex(); static auto& usb_handles_mutex = *new std::mutex(); static std::thread* device_poll_thread = nullptr; static libusb_hotplug_callback_handle hotplug_handle; static bool terminate_device_poll_thread = false; static auto& device_poll_mutex = *new std::mutex(); static auto& device_poll_cv = *new std::condition_variable(); static std::string get_device_address(libusb_device* device) { static std::string get_device_address(libusb_device* device) { return StringPrintf("usb:%d:%d", libusb_get_bus_number(device), return StringPrintf("usb:%d:%d", libusb_get_bus_number(device), Loading @@ -175,6 +172,17 @@ static std::string get_device_serial_path(libusb_device* device) { path += "/serial"; path += "/serial"; return path; return path; } } static std::string get_device_dev_path(libusb_device* device) { uint8_t ports[7]; int port_count = libusb_get_port_numbers(device, ports, 7); if (port_count < 0) return ""; return StringPrintf("/dev/bus/usb/%03u/%03u", libusb_get_bus_number(device), ports[0]); } static bool is_device_accessible(libusb_device* device) { return access(get_device_dev_path(device).c_str(), R_OK | W_OK) == 0; } #endif #endif static bool endpoint_is_output(uint8_t endpoint) { static bool endpoint_is_output(uint8_t endpoint) { Loading Loading @@ -229,7 +237,7 @@ static void process_device(libusb_device* device) { // TODO: Is this assumption valid? // TODO: Is this assumption valid? LOG(VERBOSE) << "skipping interface with incorrect num_altsetting at " << device_address LOG(VERBOSE) << "skipping interface with incorrect num_altsetting at " << device_address << " (interface " << interface_num << ")"; << " (interface " << interface_num << ")"; return; continue; } } const libusb_interface_descriptor& interface_desc = interface.altsetting[0]; const libusb_interface_descriptor& interface_desc = interface.altsetting[0]; Loading @@ -237,7 +245,7 @@ static void process_device(libusb_device* device) { interface_desc.bInterfaceProtocol)) { interface_desc.bInterfaceProtocol)) { LOG(VERBOSE) << "skipping non-adb interface at " << device_address << " (interface " LOG(VERBOSE) << "skipping non-adb interface at " << device_address << " (interface " << interface_num << ")"; << interface_num << ")"; return; continue; } } LOG(VERBOSE) << "found potential adb interface at " << device_address << " (interface " LOG(VERBOSE) << "found potential adb interface at " << device_address << " (interface " Loading @@ -253,7 +261,7 @@ static void process_device(libusb_device* device) { const uint8_t transfer_type = endpoint_attr & LIBUSB_TRANSFER_TYPE_MASK; const uint8_t transfer_type = endpoint_attr & LIBUSB_TRANSFER_TYPE_MASK; if (transfer_type != LIBUSB_TRANSFER_TYPE_BULK) { if (transfer_type != LIBUSB_TRANSFER_TYPE_BULK) { return; continue; } } if (endpoint_is_output(endpoint_addr) && !found_out) { if (endpoint_is_output(endpoint_addr) && !found_out) { Loading Loading @@ -371,31 +379,60 @@ static void process_device(libusb_device* device) { } } register_usb_transport(usb_handle_raw, device_serial.c_str(), device_address.c_str(), writable); register_usb_transport(usb_handle_raw, device_serial.c_str(), device_address.c_str(), writable); LOG(INFO) << "registered new usb device '" << device_serial << "'"; LOG(INFO) << "registered new usb device '" << device_serial << "'"; } } static void poll_for_devices() { static std::atomic<int> connecting_devices(0); libusb_device** list; adb_thread_setname("device poll"); while (true) { const ssize_t device_count = libusb_get_device_list(nullptr, &list); LOG(VERBOSE) << "found " << device_count << " attached devices"; for (ssize_t i = 0; i < device_count; ++i) { static void device_connected(libusb_device* device) { process_device(list[i]); #if defined(__linux__) // 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. Since we're not going to be able to link against the system's libudev any time soon, // hack around this by checking for accessibility in a loop. ++connecting_devices; auto thread = std::thread([device]() { std::string device_path = get_device_dev_path(device); auto start = std::chrono::steady_clock::now(); while (std::chrono::steady_clock::now() - start < 500ms) { if (is_device_accessible(device)) { break; } std::this_thread::sleep_for(10ms); } } libusb_free_device_list(list, 1); process_device(device); --connecting_devices; }); thread.detach(); #else process_device(device); #endif } adb_notify_device_scan_complete(); static void device_disconnected(libusb_device* device) { std::string device_address = get_device_address(device); std::unique_lock<std::mutex> lock(device_poll_mutex); LOG(INFO) << "device disconnected: " << device_address; if (device_poll_cv.wait_for(lock, 500ms, []() { return terminate_device_poll_thread; })) { std::unique_lock<std::mutex> lock(usb_handles_mutex); return; auto it = usb_handles.find(device_address); if (it != usb_handles.end()) { if (!it->second->device_handle) { // If the handle is null, we were never able to open the device. unregister_usb_transport(it->second.get()); } usb_handles.erase(it); } } } static int hotplug_callback(libusb_context*, libusb_device* device, libusb_hotplug_event event, void*) { if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) { device_connected(device); } else if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) { device_disconnected(device); } } return 0; } } void usb_init() { void usb_init() { Loading @@ -405,6 +442,24 @@ void usb_init() { LOG(FATAL) << "failed to initialize libusb: " << libusb_error_name(rc); LOG(FATAL) << "failed to initialize libusb: " << libusb_error_name(rc); } } // Register the hotplug callback. rc = libusb_hotplug_register_callback( nullptr, static_cast<libusb_hotplug_event>(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT), LIBUSB_HOTPLUG_ENUMERATE, LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_CLASS_PER_INTERFACE, hotplug_callback, nullptr, &hotplug_handle); if (rc != LIBUSB_SUCCESS) { 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 @@ -412,24 +467,10 @@ void usb_init() { libusb_handle_events(nullptr); libusb_handle_events(nullptr); } } }).detach(); }).detach(); // Spawn a thread to do device enumeration. // TODO: Use libusb_hotplug_* instead? std::unique_lock<std::mutex> lock(device_poll_mutex); device_poll_thread = new std::thread(poll_for_devices); } } void usb_cleanup() { void usb_cleanup() { { libusb_hotplug_deregister_callback(nullptr, hotplug_handle); std::unique_lock<std::mutex> lock(device_poll_mutex); terminate_device_poll_thread = true; if (!device_poll_thread) { return; } } device_poll_cv.notify_all(); device_poll_thread->join(); } } // Dispatch a libusb transfer, unlock |device_lock|, and then wait for the result. // Dispatch a libusb transfer, unlock |device_lock|, and then wait for the result. Loading Loading
adb/adb.cpp +0 −6 Original line number Original line Diff line number Diff line Loading @@ -1241,10 +1241,7 @@ void update_transport_status() { return true; return true; }); }); D("update_transport_status: transports_ready = %s", result ? "true" : "false"); bool ready; bool ready; { { std::lock_guard<std::mutex> lock(init_mutex); std::lock_guard<std::mutex> lock(init_mutex); transports_ready = result; transports_ready = result; Loading @@ -1252,14 +1249,11 @@ void update_transport_status() { } } if (ready) { if (ready) { D("update_transport_status: notifying"); init_cv.notify_all(); init_cv.notify_all(); } } } } void adb_notify_device_scan_complete() { void adb_notify_device_scan_complete() { D("device scan complete"); { { std::lock_guard<std::mutex> lock(init_mutex); std::lock_guard<std::mutex> lock(init_mutex); device_scan_complete = true; device_scan_complete = true; Loading
adb/client/usb_libusb.cpp +78 −37 Original line number Original line Diff line number Diff line Loading @@ -151,10 +151,7 @@ struct usb_handle : public ::usb_handle { static auto& usb_handles = *new std::unordered_map<std::string, std::unique_ptr<usb_handle>>(); static auto& usb_handles = *new std::unordered_map<std::string, std::unique_ptr<usb_handle>>(); static auto& usb_handles_mutex = *new std::mutex(); static auto& usb_handles_mutex = *new std::mutex(); static std::thread* device_poll_thread = nullptr; static libusb_hotplug_callback_handle hotplug_handle; static bool terminate_device_poll_thread = false; static auto& device_poll_mutex = *new std::mutex(); static auto& device_poll_cv = *new std::condition_variable(); static std::string get_device_address(libusb_device* device) { static std::string get_device_address(libusb_device* device) { return StringPrintf("usb:%d:%d", libusb_get_bus_number(device), return StringPrintf("usb:%d:%d", libusb_get_bus_number(device), Loading @@ -175,6 +172,17 @@ static std::string get_device_serial_path(libusb_device* device) { path += "/serial"; path += "/serial"; return path; return path; } } static std::string get_device_dev_path(libusb_device* device) { uint8_t ports[7]; int port_count = libusb_get_port_numbers(device, ports, 7); if (port_count < 0) return ""; return StringPrintf("/dev/bus/usb/%03u/%03u", libusb_get_bus_number(device), ports[0]); } static bool is_device_accessible(libusb_device* device) { return access(get_device_dev_path(device).c_str(), R_OK | W_OK) == 0; } #endif #endif static bool endpoint_is_output(uint8_t endpoint) { static bool endpoint_is_output(uint8_t endpoint) { Loading Loading @@ -229,7 +237,7 @@ static void process_device(libusb_device* device) { // TODO: Is this assumption valid? // TODO: Is this assumption valid? LOG(VERBOSE) << "skipping interface with incorrect num_altsetting at " << device_address LOG(VERBOSE) << "skipping interface with incorrect num_altsetting at " << device_address << " (interface " << interface_num << ")"; << " (interface " << interface_num << ")"; return; continue; } } const libusb_interface_descriptor& interface_desc = interface.altsetting[0]; const libusb_interface_descriptor& interface_desc = interface.altsetting[0]; Loading @@ -237,7 +245,7 @@ static void process_device(libusb_device* device) { interface_desc.bInterfaceProtocol)) { interface_desc.bInterfaceProtocol)) { LOG(VERBOSE) << "skipping non-adb interface at " << device_address << " (interface " LOG(VERBOSE) << "skipping non-adb interface at " << device_address << " (interface " << interface_num << ")"; << interface_num << ")"; return; continue; } } LOG(VERBOSE) << "found potential adb interface at " << device_address << " (interface " LOG(VERBOSE) << "found potential adb interface at " << device_address << " (interface " Loading @@ -253,7 +261,7 @@ static void process_device(libusb_device* device) { const uint8_t transfer_type = endpoint_attr & LIBUSB_TRANSFER_TYPE_MASK; const uint8_t transfer_type = endpoint_attr & LIBUSB_TRANSFER_TYPE_MASK; if (transfer_type != LIBUSB_TRANSFER_TYPE_BULK) { if (transfer_type != LIBUSB_TRANSFER_TYPE_BULK) { return; continue; } } if (endpoint_is_output(endpoint_addr) && !found_out) { if (endpoint_is_output(endpoint_addr) && !found_out) { Loading Loading @@ -371,31 +379,60 @@ static void process_device(libusb_device* device) { } } register_usb_transport(usb_handle_raw, device_serial.c_str(), device_address.c_str(), writable); register_usb_transport(usb_handle_raw, device_serial.c_str(), device_address.c_str(), writable); LOG(INFO) << "registered new usb device '" << device_serial << "'"; LOG(INFO) << "registered new usb device '" << device_serial << "'"; } } static void poll_for_devices() { static std::atomic<int> connecting_devices(0); libusb_device** list; adb_thread_setname("device poll"); while (true) { const ssize_t device_count = libusb_get_device_list(nullptr, &list); LOG(VERBOSE) << "found " << device_count << " attached devices"; for (ssize_t i = 0; i < device_count; ++i) { static void device_connected(libusb_device* device) { process_device(list[i]); #if defined(__linux__) // 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. Since we're not going to be able to link against the system's libudev any time soon, // hack around this by checking for accessibility in a loop. ++connecting_devices; auto thread = std::thread([device]() { std::string device_path = get_device_dev_path(device); auto start = std::chrono::steady_clock::now(); while (std::chrono::steady_clock::now() - start < 500ms) { if (is_device_accessible(device)) { break; } std::this_thread::sleep_for(10ms); } } libusb_free_device_list(list, 1); process_device(device); --connecting_devices; }); thread.detach(); #else process_device(device); #endif } adb_notify_device_scan_complete(); static void device_disconnected(libusb_device* device) { std::string device_address = get_device_address(device); std::unique_lock<std::mutex> lock(device_poll_mutex); LOG(INFO) << "device disconnected: " << device_address; if (device_poll_cv.wait_for(lock, 500ms, []() { return terminate_device_poll_thread; })) { std::unique_lock<std::mutex> lock(usb_handles_mutex); return; auto it = usb_handles.find(device_address); if (it != usb_handles.end()) { if (!it->second->device_handle) { // If the handle is null, we were never able to open the device. unregister_usb_transport(it->second.get()); } usb_handles.erase(it); } } } static int hotplug_callback(libusb_context*, libusb_device* device, libusb_hotplug_event event, void*) { if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) { device_connected(device); } else if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) { device_disconnected(device); } } return 0; } } void usb_init() { void usb_init() { Loading @@ -405,6 +442,24 @@ void usb_init() { LOG(FATAL) << "failed to initialize libusb: " << libusb_error_name(rc); LOG(FATAL) << "failed to initialize libusb: " << libusb_error_name(rc); } } // Register the hotplug callback. rc = libusb_hotplug_register_callback( nullptr, static_cast<libusb_hotplug_event>(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT), LIBUSB_HOTPLUG_ENUMERATE, LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_CLASS_PER_INTERFACE, hotplug_callback, nullptr, &hotplug_handle); if (rc != LIBUSB_SUCCESS) { 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 @@ -412,24 +467,10 @@ void usb_init() { libusb_handle_events(nullptr); libusb_handle_events(nullptr); } } }).detach(); }).detach(); // Spawn a thread to do device enumeration. // TODO: Use libusb_hotplug_* instead? std::unique_lock<std::mutex> lock(device_poll_mutex); device_poll_thread = new std::thread(poll_for_devices); } } void usb_cleanup() { void usb_cleanup() { { libusb_hotplug_deregister_callback(nullptr, hotplug_handle); std::unique_lock<std::mutex> lock(device_poll_mutex); terminate_device_poll_thread = true; if (!device_poll_thread) { return; } } device_poll_cv.notify_all(); device_poll_thread->join(); } } // Dispatch a libusb transfer, unlock |device_lock|, and then wait for the result. // Dispatch a libusb transfer, unlock |device_lock|, and then wait for the result. Loading