Loading adb/daemon/include/adbd/usb.h +6 −0 Original line number Original line Diff line number Diff line Loading @@ -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> Loading Loading @@ -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); adb/daemon/usb.cpp +28 −111 Original line number Original line Diff line number Diff line Loading @@ -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, Loading Loading @@ -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"; Loading @@ -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); } } Loading @@ -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(); Loading Loading @@ -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(), ¬ify, 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: Loading @@ -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) { Loading @@ -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; Loading @@ -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?"; } } Loading @@ -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; } } } } } } Loading @@ -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"; Loading Loading @@ -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) { Loading Loading @@ -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_; Loading Loading @@ -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; Loading @@ -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(); Loading adb/daemon/usb_ffs.cpp +77 −1 Original line number Original line Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading
adb/daemon/include/adbd/usb.h +6 −0 Original line number Original line Diff line number Diff line Loading @@ -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> Loading Loading @@ -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);
adb/daemon/usb.cpp +28 −111 Original line number Original line Diff line number Diff line Loading @@ -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, Loading Loading @@ -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"; Loading @@ -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); } } Loading @@ -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(); Loading Loading @@ -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(), ¬ify, 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: Loading @@ -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) { Loading @@ -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; Loading @@ -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?"; } } Loading @@ -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; } } } } } } Loading @@ -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"; Loading Loading @@ -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) { Loading Loading @@ -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_; Loading Loading @@ -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; Loading @@ -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(); Loading
adb/daemon/usb_ffs.cpp +77 −1 Original line number Original line Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading