Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 986ba5bb authored by Josh Gao's avatar Josh Gao Committed by android-build-merger
Browse files

Merge "adb: reunregress waiting for device on start-server." am: 72076d1a

am: 08a70ac6

Change-Id: Ie379f49929c8b11544328694fd1a438e63da453d
parents 1fc59234 08a70ac6
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -1257,6 +1257,10 @@ void update_transport_status() {
void adb_notify_device_scan_complete() {
    {
        std::lock_guard<std::mutex> lock(init_mutex);
        if (device_scan_complete) {
            return;
        }

        device_scan_complete = true;
    }

+31 −0
Original line number Diff line number Diff line
@@ -17,7 +17,10 @@
#ifndef _ADB_UTILS_H_
#define _ADB_UTILS_H_

#include <condition_variable>
#include <mutex>
#include <string>
#include <vector>

#include <android-base/macros.h>

@@ -53,4 +56,32 @@ extern int adb_close(int fd);
bool forward_targets_are_valid(const std::string& source, const std::string& dest,
                               std::string* error);

// A thread-safe blocking queue.
template <typename T>
class BlockingQueue {
    std::mutex mutex;
    std::condition_variable cv;
    std::vector<T> queue;

  public:
    void Push(const T& t) {
        {
            std::unique_lock<std::mutex> lock(mutex);
            queue.push_back(t);
        }
        cv.notify_one();
    }

    template <typename Fn>
    void PopAll(Fn fn) {
        std::unique_lock<std::mutex> lock(mutex);
        cv.wait(lock, [this]() { return !queue.empty(); });

        for (const T& t : queue) {
            fn(t);
        }
        queue.clear();
    }
};

#endif
+31 −20
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@
#include <android-base/strings.h>

#include "adb.h"
#include "adb_utils.h"
#include "transport.h"
#include "usb.h"

@@ -387,10 +388,9 @@ static std::atomic<int> connecting_devices(0);
static void device_connected(libusb_device* device) {
#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;
    // 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.
    auto thread = std::thread([device]() {
        std::string device_path = get_device_dev_path(device);
        auto start = std::chrono::steady_clock::now();
@@ -402,7 +402,9 @@ static void device_connected(libusb_device* device) {
        }

        process_device(device);
        --connecting_devices;
        if (--connecting_devices == 0) {
            adb_notify_device_scan_complete();
        }
    });
    thread.detach();
#else
@@ -425,17 +427,33 @@ static void device_disconnected(libusb_device* device) {
    }
}

static int hotplug_callback(libusb_context*, libusb_device* device, libusb_hotplug_event event,
                            void*) {
    // We're called with the libusb lock taken. Call these on the main thread outside of this
    // function so that the usb_handle mutex is always taken before the libusb mutex.
    fdevent_run_on_main_thread([device, event]() {
static auto& hotplug_queue = *new BlockingQueue<std::pair<libusb_hotplug_event, libusb_device*>>();
static void hotplug_thread() {
    adb_thread_setname("libusb hotplug");
    while (true) {
        hotplug_queue.PopAll([](std::pair<libusb_hotplug_event, libusb_device*> pair) {
            libusb_hotplug_event event = pair.first;
            libusb_device* device = pair.second;
            if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) {
                device_connected(device);
            } else if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) {
                device_disconnected(device);
            }
        });
    }
}

static int hotplug_callback(libusb_context*, libusb_device* device, libusb_hotplug_event event,
                            void*) {
    // We're called with the libusb lock taken. Call these on a separate thread outside of this
    // function so that the usb_handle mutex is always taken before the libusb mutex.
    static std::once_flag once;
    std::call_once(once, []() { std::thread(hotplug_thread).detach(); });

    if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) {
        ++connecting_devices;
    }
    hotplug_queue.Push({event, device});
    return 0;
}

@@ -457,13 +475,6 @@ void usb_init() {
        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.
    std::thread([]() {
        adb_thread_setname("libusb");