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

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

Merge "Reland "adbd: don't close ep0 until we receive FUNCTIONFS_UNBIND."" am: 2a6ec6c3

am: 5c7c698a

Change-Id: I94222297a504954ddca5f6ec9b3f7a077e4d0647
parents b317df3c 5c7c698a
Loading
Loading
Loading
Loading
+6 −0
Original line number Original line Diff line number Diff line
@@ -16,6 +16,8 @@
 * limitations under the License.
 * limitations under the License.
 */
 */


#include <linux/usb/functionfs.h>

#include <atomic>
#include <atomic>
#include <condition_variable>
#include <condition_variable>
#include <mutex>
#include <mutex>
@@ -62,5 +64,9 @@ struct usb_handle {
};
};


usb_handle *create_usb_handle(unsigned num_bufs, unsigned io_size);
usb_handle *create_usb_handle(unsigned num_bufs, unsigned io_size);

struct usb_functionfs_event;
const char* ffs_event_to_string(enum usb_functionfs_event_type type);
bool read_functionfs_setup(android::base::borrowed_fd fd, usb_functionfs_event* event);
bool open_functionfs(android::base::unique_fd* control, android::base::unique_fd* bulk_out,
bool open_functionfs(android::base::unique_fd* control, android::base::unique_fd* bulk_out,
                     android::base::unique_fd* bulk_in);
                     android::base::unique_fd* bulk_in);
+28 −111
Original line number Original line Diff line number Diff line
@@ -66,25 +66,6 @@ static constexpr size_t kUsbReadSize = 4 * PAGE_SIZE;
static constexpr size_t kUsbWriteQueueDepth = 8;
static constexpr size_t kUsbWriteQueueDepth = 8;
static constexpr size_t kUsbWriteSize = 4 * PAGE_SIZE;
static constexpr size_t kUsbWriteSize = 4 * PAGE_SIZE;


static const char* to_string(enum usb_functionfs_event_type type) {
    switch (type) {
        case FUNCTIONFS_BIND:
            return "FUNCTIONFS_BIND";
        case FUNCTIONFS_UNBIND:
            return "FUNCTIONFS_UNBIND";
        case FUNCTIONFS_ENABLE:
            return "FUNCTIONFS_ENABLE";
        case FUNCTIONFS_DISABLE:
            return "FUNCTIONFS_DISABLE";
        case FUNCTIONFS_SETUP:
            return "FUNCTIONFS_SETUP";
        case FUNCTIONFS_SUSPEND:
            return "FUNCTIONFS_SUSPEND";
        case FUNCTIONFS_RESUME:
            return "FUNCTIONFS_RESUME";
    }
}

enum class TransferDirection : uint64_t {
enum class TransferDirection : uint64_t {
    READ = 0,
    READ = 0,
    WRITE = 1,
    WRITE = 1,
@@ -169,12 +150,12 @@ struct ScopedAioContext {
};
};


struct UsbFfsConnection : public Connection {
struct UsbFfsConnection : public Connection {
    UsbFfsConnection(unique_fd control, unique_fd read, unique_fd write,
    UsbFfsConnection(unique_fd* control, unique_fd read, unique_fd write,
                     std::promise<void> destruction_notifier)
                     std::promise<void> destruction_notifier)
        : worker_started_(false),
        : worker_started_(false),
          stopped_(false),
          stopped_(false),
          destruction_notifier_(std::move(destruction_notifier)),
          destruction_notifier_(std::move(destruction_notifier)),
          control_fd_(std::move(control)),
          control_fd_(control),
          read_fd_(std::move(read)),
          read_fd_(std::move(read)),
          write_fd_(std::move(write)) {
          write_fd_(std::move(write)) {
        LOG(INFO) << "UsbFfsConnection constructed";
        LOG(INFO) << "UsbFfsConnection constructed";
@@ -183,11 +164,6 @@ struct UsbFfsConnection : public Connection {
            PLOG(FATAL) << "failed to create eventfd";
            PLOG(FATAL) << "failed to create eventfd";
        }
        }


        monitor_event_fd_.reset(eventfd(0, EFD_CLOEXEC));
        if (monitor_event_fd_ == -1) {
            PLOG(FATAL) << "failed to create eventfd";
        }

        aio_context_ = ScopedAioContext::Create(kUsbReadQueueDepth + kUsbWriteQueueDepth);
        aio_context_ = ScopedAioContext::Create(kUsbReadQueueDepth + kUsbWriteQueueDepth);
    }
    }


@@ -199,7 +175,6 @@ struct UsbFfsConnection : public Connection {
        // We need to explicitly close our file descriptors before we notify our destruction,
        // We need to explicitly close our file descriptors before we notify our destruction,
        // because the thread listening on the future will immediately try to reopen the endpoint.
        // because the thread listening on the future will immediately try to reopen the endpoint.
        aio_context_.reset();
        aio_context_.reset();
        control_fd_.reset();
        read_fd_.reset();
        read_fd_.reset();
        write_fd_.reset();
        write_fd_.reset();


@@ -246,13 +221,6 @@ struct UsbFfsConnection : public Connection {
            PLOG(FATAL) << "failed to notify worker eventfd to stop UsbFfsConnection";
            PLOG(FATAL) << "failed to notify worker eventfd to stop UsbFfsConnection";
        }
        }
        CHECK_EQ(static_cast<size_t>(rc), sizeof(notify));
        CHECK_EQ(static_cast<size_t>(rc), sizeof(notify));

        rc = adb_write(monitor_event_fd_.get(), &notify, sizeof(notify));
        if (rc < 0) {
            PLOG(FATAL) << "failed to notify monitor eventfd to stop UsbFfsConnection";
        }

        CHECK_EQ(static_cast<size_t>(rc), sizeof(notify));
    }
    }


  private:
  private:
@@ -271,33 +239,24 @@ struct UsbFfsConnection : public Connection {
        monitor_thread_ = std::thread([this]() {
        monitor_thread_ = std::thread([this]() {
            adb_thread_setname("UsbFfs-monitor");
            adb_thread_setname("UsbFfs-monitor");


            bool bound = false;
            bool enabled = false;
            bool enabled = false;
            bool running = true;
            bool running = true;
            while (running) {
            while (running) {
                adb_pollfd pfd[2] = {
                adb_pollfd pfd[2] = {
                  { .fd = control_fd_.get(), .events = POLLIN, .revents = 0 },
                        {.fd = control_fd_->get(), .events = POLLIN, .revents = 0},
                  { .fd = monitor_event_fd_.get(), .events = POLLIN, .revents = 0 },
                };
                };


                // If we don't see our first bind within a second, try again.
                int rc = TEMP_FAILURE_RETRY(adb_poll(pfd, 2, -1));
                int timeout_ms = bound ? -1 : 1000;

                int rc = TEMP_FAILURE_RETRY(adb_poll(pfd, 2, timeout_ms));
                if (rc == -1) {
                if (rc == -1) {
                    PLOG(FATAL) << "poll on USB control fd failed";
                    PLOG(FATAL) << "poll on USB control fd failed";
                } else if (rc == 0) {
                    LOG(WARNING) << "timed out while waiting for FUNCTIONFS_BIND, trying again";
                    break;
                }
                }


                if (pfd[1].revents) {
                if (pfd[1].revents) {
                    // We were told to die.
                    // We were told to die, continue reading until FUNCTIONFS_UNBIND.
                    break;
                }
                }


                struct usb_functionfs_event event;
                struct usb_functionfs_event event;
                rc = TEMP_FAILURE_RETRY(adb_read(control_fd_.get(), &event, sizeof(event)));
                rc = TEMP_FAILURE_RETRY(adb_read(control_fd_->get(), &event, sizeof(event)));
                if (rc == -1) {
                if (rc == -1) {
                    PLOG(FATAL) << "failed to read functionfs event";
                    PLOG(FATAL) << "failed to read functionfs event";
                } else if (rc == 0) {
                } else if (rc == 0) {
@@ -309,32 +268,15 @@ struct UsbFfsConnection : public Connection {
                }
                }


                LOG(INFO) << "USB event: "
                LOG(INFO) << "USB event: "
                          << to_string(static_cast<usb_functionfs_event_type>(event.type));
                          << ffs_event_to_string(
                                     static_cast<usb_functionfs_event_type>(event.type));


                switch (event.type) {
                switch (event.type) {
                    case FUNCTIONFS_BIND:
                    case FUNCTIONFS_BIND:
                        if (bound) {
                        LOG(FATAL) << "received FUNCTIONFS_BIND after already opened?";
                            LOG(WARNING) << "received FUNCTIONFS_BIND while already bound?";
                            running = false;
                            break;
                        }

                        if (enabled) {
                            LOG(WARNING) << "received FUNCTIONFS_BIND while already enabled?";
                            running = false;
                            break;
                        }

                        bound = true;
                        break;
                        break;


                    case FUNCTIONFS_ENABLE:
                    case FUNCTIONFS_ENABLE:
                        if (!bound) {
                            LOG(WARNING) << "received FUNCTIONFS_ENABLE while not bound?";
                            running = false;
                            break;
                        }

                        if (enabled) {
                        if (enabled) {
                            LOG(WARNING) << "received FUNCTIONFS_ENABLE while already enabled?";
                            LOG(WARNING) << "received FUNCTIONFS_ENABLE while already enabled?";
                            running = false;
                            running = false;
@@ -346,10 +288,6 @@ struct UsbFfsConnection : public Connection {
                        break;
                        break;


                    case FUNCTIONFS_DISABLE:
                    case FUNCTIONFS_DISABLE:
                        if (!bound) {
                            LOG(WARNING) << "received FUNCTIONFS_DISABLE while not bound?";
                        }

                        if (!enabled) {
                        if (!enabled) {
                            LOG(WARNING) << "received FUNCTIONFS_DISABLE while not enabled?";
                            LOG(WARNING) << "received FUNCTIONFS_DISABLE while not enabled?";
                        }
                        }
@@ -363,45 +301,13 @@ struct UsbFfsConnection : public Connection {
                            LOG(WARNING) << "received FUNCTIONFS_UNBIND while still enabled?";
                            LOG(WARNING) << "received FUNCTIONFS_UNBIND while still enabled?";
                        }
                        }


                        if (!bound) {
                            LOG(WARNING) << "received FUNCTIONFS_UNBIND when not bound?";
                        }

                        bound = false;
                        running = false;
                        running = false;
                        break;
                        break;


                    case FUNCTIONFS_SETUP: {
                    case FUNCTIONFS_SETUP: {
                        LOG(INFO) << "received FUNCTIONFS_SETUP control transfer: bRequestType = "
                        read_functionfs_setup(*control_fd_, &event);
                                  << static_cast<int>(event.u.setup.bRequestType)
                                  << ", bRequest = " << static_cast<int>(event.u.setup.bRequest)
                                  << ", wValue = " << static_cast<int>(event.u.setup.wValue)
                                  << ", wIndex = " << static_cast<int>(event.u.setup.wIndex)
                                  << ", wLength = " << static_cast<int>(event.u.setup.wLength);

                        if ((event.u.setup.bRequestType & USB_DIR_IN)) {
                            LOG(INFO) << "acking device-to-host control transfer";
                            ssize_t rc = adb_write(control_fd_.get(), "", 0);
                            if (rc != 0) {
                                PLOG(ERROR) << "failed to write empty packet to host";
                        break;
                        break;
                    }
                    }
                        } else {
                            std::string buf;
                            buf.resize(event.u.setup.wLength + 1);

                            ssize_t rc = adb_read(control_fd_.get(), buf.data(), buf.size());
                            if (rc != event.u.setup.wLength) {
                                LOG(ERROR)
                                        << "read " << rc
                                        << " bytes when trying to read control request, expected "
                                        << event.u.setup.wLength;
                            }

                            LOG(INFO) << "control request contents: " << buf;
                            break;
                        }
                    }
                }
                }
            }
            }


@@ -426,6 +332,12 @@ struct UsbFfsConnection : public Connection {
                uint64_t dummy;
                uint64_t dummy;
                ssize_t rc = adb_read(worker_event_fd_.get(), &dummy, sizeof(dummy));
                ssize_t rc = adb_read(worker_event_fd_.get(), &dummy, sizeof(dummy));
                if (rc == -1) {
                if (rc == -1) {
                    if (errno == EINTR) {
                        // We were interrupted either to stop, or because of a backtrace.
                        // Check stopped_ again to see if we need to exit.
                        continue;
                    }

                    PLOG(FATAL) << "failed to read from eventfd";
                    PLOG(FATAL) << "failed to read from eventfd";
                } else if (rc == 0) {
                } else if (rc == 0) {
                    LOG(FATAL) << "hit EOF on eventfd";
                    LOG(FATAL) << "hit EOF on eventfd";
@@ -462,6 +374,7 @@ struct UsbFfsConnection : public Connection {
        }
        }


        worker_thread_.join();
        worker_thread_.join();
        worker_started_ = false;
    }
    }


    void PrepareReadBlock(IoBlock* block, uint64_t id) {
    void PrepareReadBlock(IoBlock* block, uint64_t id) {
@@ -692,10 +605,13 @@ struct UsbFfsConnection : public Connection {
    std::once_flag error_flag_;
    std::once_flag error_flag_;


    unique_fd worker_event_fd_;
    unique_fd worker_event_fd_;
    unique_fd monitor_event_fd_;


    ScopedAioContext aio_context_;
    ScopedAioContext aio_context_;
    unique_fd control_fd_;

    // We keep a pointer to the control fd, so that we can reuse it to avoid USB reconfiguration,
    // and still be able to reset it to force a reopen after FUNCTIONFS_UNBIND or running into an
    // unexpected situation.
    unique_fd* control_fd_;
    unique_fd read_fd_;
    unique_fd read_fd_;
    unique_fd write_fd_;
    unique_fd write_fd_;


@@ -724,15 +640,16 @@ void usb_init_legacy();
static void usb_ffs_open_thread() {
static void usb_ffs_open_thread() {
    adb_thread_setname("usb ffs open");
    adb_thread_setname("usb ffs open");


    unique_fd control;
    unique_fd bulk_out;
    unique_fd bulk_in;

    while (true) {
    while (true) {
        if (gFfsAioSupported.has_value() && !gFfsAioSupported.value()) {
        if (gFfsAioSupported.has_value() && !gFfsAioSupported.value()) {
            LOG(INFO) << "failed to use nonblocking ffs, falling back to legacy";
            LOG(INFO) << "failed to use nonblocking ffs, falling back to legacy";
            return usb_init_legacy();
            return usb_init_legacy();
        }
        }


        unique_fd control;
        unique_fd bulk_out;
        unique_fd bulk_in;
        if (!open_functionfs(&control, &bulk_out, &bulk_in)) {
        if (!open_functionfs(&control, &bulk_out, &bulk_in)) {
            std::this_thread::sleep_for(1s);
            std::this_thread::sleep_for(1s);
            continue;
            continue;
@@ -743,7 +660,7 @@ static void usb_ffs_open_thread() {
        std::promise<void> destruction_notifier;
        std::promise<void> destruction_notifier;
        std::future<void> future = destruction_notifier.get_future();
        std::future<void> future = destruction_notifier.get_future();
        transport->SetConnection(std::make_unique<UsbFfsConnection>(
        transport->SetConnection(std::make_unique<UsbFfsConnection>(
                std::move(control), std::move(bulk_out), std::move(bulk_in),
                &control, std::move(bulk_out), std::move(bulk_in),
                std::move(destruction_notifier)));
                std::move(destruction_notifier)));
        register_transport(transport);
        register_transport(transport);
        future.wait();
        future.wait();
+77 −1
Original line number Original line Diff line number Diff line
@@ -248,6 +248,56 @@ static const struct {
};
};
// clang-format on
// clang-format on


const char* ffs_event_to_string(enum usb_functionfs_event_type type) {
    switch (type) {
        case FUNCTIONFS_BIND:
            return "FUNCTIONFS_BIND";
        case FUNCTIONFS_UNBIND:
            return "FUNCTIONFS_UNBIND";
        case FUNCTIONFS_ENABLE:
            return "FUNCTIONFS_ENABLE";
        case FUNCTIONFS_DISABLE:
            return "FUNCTIONFS_DISABLE";
        case FUNCTIONFS_SETUP:
            return "FUNCTIONFS_SETUP";
        case FUNCTIONFS_SUSPEND:
            return "FUNCTIONFS_SUSPEND";
        case FUNCTIONFS_RESUME:
            return "FUNCTIONFS_RESUME";
    }
}

bool read_functionfs_setup(borrowed_fd fd, usb_functionfs_event* event) {
    LOG(INFO) << "received FUNCTIONFS_SETUP control transfer: bRequestType = "
              << static_cast<int>(event->u.setup.bRequestType)
              << ", bRequest = " << static_cast<int>(event->u.setup.bRequest)
              << ", wValue = " << static_cast<int>(event->u.setup.wValue)
              << ", wIndex = " << static_cast<int>(event->u.setup.wIndex)
              << ", wLength = " << static_cast<int>(event->u.setup.wLength);

    if ((event->u.setup.bRequestType & USB_DIR_IN)) {
        LOG(INFO) << "acking device-to-host control transfer";
        ssize_t rc = adb_write(fd.get(), "", 0);
        if (rc != 0) {
            PLOG(ERROR) << "failed to write empty packet to host";
            return false;
        }
    } else {
        std::string buf;
        buf.resize(event->u.setup.wLength + 1);

        ssize_t rc = adb_read(fd.get(), buf.data(), buf.size());
        if (rc != event->u.setup.wLength) {
            LOG(ERROR) << "read " << rc << " bytes when trying to read control request, expected "
                       << event->u.setup.wLength;
        }

        LOG(INFO) << "control request contents: " << buf;
    }

    return true;
}

bool open_functionfs(android::base::unique_fd* out_control, android::base::unique_fd* out_bulk_out,
bool open_functionfs(android::base::unique_fd* out_control, android::base::unique_fd* out_bulk_out,
                     android::base::unique_fd* out_bulk_in) {
                     android::base::unique_fd* out_bulk_in) {
    unique_fd control, bulk_out, bulk_in;
    unique_fd control, bulk_out, bulk_in;
@@ -297,11 +347,37 @@ bool open_functionfs(android::base::unique_fd* out_control, android::base::uniqu
            PLOG(ERROR) << "failed to write USB strings";
            PLOG(ERROR) << "failed to write USB strings";
            return false;
            return false;
        }
        }
        // Signal only when writing the descriptors to ffs

        // Signal init after we've written our descriptors.
        android::base::SetProperty("sys.usb.ffs.ready", "1");
        android::base::SetProperty("sys.usb.ffs.ready", "1");
        *out_control = std::move(control);
        *out_control = std::move(control);
    }
    }


    // Read until we get FUNCTIONFS_BIND from the control endpoint.
    while (true) {
        struct usb_functionfs_event event;
        ssize_t rc = TEMP_FAILURE_RETRY(adb_read(*out_control, &event, sizeof(event)));

        if (rc == -1) {
            PLOG(FATAL) << "failed to read from FFS control fd";
        } else if (rc == 0) {
            LOG(WARNING) << "hit EOF on functionfs control fd during initialization";
        } else if (rc != sizeof(event)) {
            LOG(FATAL) << "read functionfs event of unexpected size, expected " << sizeof(event)
                       << ", got " << rc;
        }

        LOG(INFO) << "USB event: "
                  << ffs_event_to_string(static_cast<usb_functionfs_event_type>(event.type));
        if (event.type == FUNCTIONFS_BIND) {
            break;
        } else if (event.type == FUNCTIONFS_SETUP) {
            read_functionfs_setup(*out_control, &event);
        } else {
            continue;
        }
    }

    bulk_out.reset(adb_open(USB_FFS_ADB_OUT, O_RDONLY));
    bulk_out.reset(adb_open(USB_FFS_ADB_OUT, O_RDONLY));
    if (bulk_out < 0) {
    if (bulk_out < 0) {
        PLOG(ERROR) << "cannot open bulk-out endpoint " << USB_FFS_ADB_OUT;
        PLOG(ERROR) << "cannot open bulk-out endpoint " << USB_FFS_ADB_OUT;