From 3705b346b9595c07e17efe8d0dcc88f287c05067 Mon Sep 17 00:00:00 2001 From: Josh Gao Date: Thu, 28 Mar 2019 15:47:44 -0700 Subject: adb: make `adb reconnect` perform a USB reset. Bug: http://b/128941083 Test: manual Change-Id: Iaf46d2c46cc82b590768004486d119244591c8e2 --- adb/adb.cpp | 4 ++-- adb/client/usb_dispatch.cpp | 5 +++++ adb/client/usb_libusb.cpp | 5 +++++ adb/client/usb_linux.cpp | 5 +++++ adb/client/usb_osx.cpp | 7 ++++++ adb/client/usb_windows.cpp | 5 +++++ adb/daemon/usb_dummy.cpp | 4 ++++ adb/daemon/usb_legacy.cpp | 4 ++++ adb/transport.cpp | 54 +++++++++++++++++++++++++++++++++++++++------ adb/transport.h | 17 +++++++++++--- adb/transport_usb.cpp | 5 +++++ adb/usb.h | 1 + 12 files changed, 104 insertions(+), 12 deletions(-) (limited to 'adb') diff --git a/adb/adb.cpp b/adb/adb.cpp index 3c0788254..e417f05e3 100644 --- a/adb/adb.cpp +++ b/adb/adb.cpp @@ -1114,7 +1114,7 @@ HostRequestResult handle_host_request(std::string_view service, TransportType ty return true; } return false; - }); + }, true); if (!response.empty()) { response.resize(response.size() - 1); } @@ -1229,7 +1229,7 @@ HostRequestResult handle_host_request(std::string_view service, TransportType ty std::string response; atransport* t = acquire_one_transport(type, serial, transport_id, nullptr, &response, true); if (t != nullptr) { - kick_transport(t); + kick_transport(t, true); response = "reconnecting " + t->serial_name() + " [" + t->connection_state_name() + "]\n"; } diff --git a/adb/client/usb_dispatch.cpp b/adb/client/usb_dispatch.cpp index ce5773175..f55ae9010 100644 --- a/adb/client/usb_dispatch.cpp +++ b/adb/client/usb_dispatch.cpp @@ -52,6 +52,11 @@ int usb_close(usb_handle* h) { : native::usb_close(reinterpret_cast(h)); } +void usb_reset(usb_handle* h) { + should_use_libusb() ? libusb::usb_reset(reinterpret_cast(h)) + : native::usb_reset(reinterpret_cast(h)); +} + void usb_kick(usb_handle* h) { should_use_libusb() ? libusb::usb_kick(reinterpret_cast(h)) : native::usb_kick(reinterpret_cast(h)); diff --git a/adb/client/usb_libusb.cpp b/adb/client/usb_libusb.cpp index f2ca63ba3..53f01a0ce 100644 --- a/adb/client/usb_libusb.cpp +++ b/adb/client/usb_libusb.cpp @@ -622,6 +622,11 @@ int usb_close(usb_handle* h) { return 0; } +void usb_reset(usb_handle* h) { + libusb_reset_device(h->device_handle); + usb_kick(h); +} + void usb_kick(usb_handle* h) { h->Close(); } diff --git a/adb/client/usb_linux.cpp b/adb/client/usb_linux.cpp index 116895894..81b830643 100644 --- a/adb/client/usb_linux.cpp +++ b/adb/client/usb_linux.cpp @@ -458,6 +458,11 @@ int usb_read(usb_handle *h, void *_data, int len) return orig_len - len; } +void usb_reset(usb_handle* h) { + ioctl(h->fd, USBDEVFS_RESET); + usb_kick(h); +} + void usb_kick(usb_handle* h) { std::lock_guard lock(h->mutex); D("[ kicking %p (fd = %d) ]", h, h->fd); diff --git a/adb/client/usb_osx.cpp b/adb/client/usb_osx.cpp index e380c8406..381ded4bb 100644 --- a/adb/client/usb_osx.cpp +++ b/adb/client/usb_osx.cpp @@ -556,6 +556,13 @@ int usb_close(usb_handle *handle) return 0; } +void usb_reset(usb_handle* handle) { + if (!handle->dead) { + (*handle->interface)->USBDeviceReEnumerate(handle->interface, 0); + } + usb_kick(handle); +} + static void usb_kick_locked(usb_handle *handle) { LOG(INFO) << "Kicking handle"; diff --git a/adb/client/usb_windows.cpp b/adb/client/usb_windows.cpp index cfa5cf40b..f23c3a5e6 100644 --- a/adb/client/usb_windows.cpp +++ b/adb/client/usb_windows.cpp @@ -448,6 +448,11 @@ void usb_cleanup_handle(usb_handle* handle) { } } +void usb_reset(usb_handle* handle) { + // Unimplemented on Windows. + usb_kick(handle); +} + static void usb_kick_locked(usb_handle* handle) { // The reason the lock must be acquired before calling this function is in // case multiple threads are trying to kick the same device at the same time. diff --git a/adb/daemon/usb_dummy.cpp b/adb/daemon/usb_dummy.cpp index 984bc25ef..c9bf79731 100644 --- a/adb/daemon/usb_dummy.cpp +++ b/adb/daemon/usb_dummy.cpp @@ -33,6 +33,10 @@ int usb_close(usb_handle*) { return -1; } +void usb_reset(usb_handle*) { + LOG(FATAL) << "unimplemented"; +} + void usb_kick(usb_handle*) { LOG(FATAL) << "unimplemented"; } diff --git a/adb/daemon/usb_legacy.cpp b/adb/daemon/usb_legacy.cpp index 7ace59d3e..b65727a0c 100644 --- a/adb/daemon/usb_legacy.cpp +++ b/adb/daemon/usb_legacy.cpp @@ -307,6 +307,10 @@ int usb_close(usb_handle* h) { return 0; } +void usb_reset(usb_handle* h) { + usb_close(h); +} + void usb_kick(usb_handle* h) { h->kick(h); } diff --git a/adb/transport.cpp b/adb/transport.cpp index 0b4e08431..15c3a9a32 100644 --- a/adb/transport.cpp +++ b/adb/transport.cpp @@ -257,6 +257,11 @@ TransportId NextTransportId() { return next++; } +void Connection::Reset() { + LOG(INFO) << "Connection::Reset(): stopping"; + Stop(); +} + BlockingConnectionAdapter::BlockingConnectionAdapter(std::unique_ptr connection) : underlying_(std::move(connection)) {} @@ -312,6 +317,26 @@ void BlockingConnectionAdapter::Start() { started_ = true; } +void BlockingConnectionAdapter::Reset() { + { + std::lock_guard lock(mutex_); + if (!started_) { + LOG(INFO) << "BlockingConnectionAdapter(" << this->transport_name_ << "): not started"; + return; + } + + if (stopped_) { + LOG(INFO) << "BlockingConnectionAdapter(" << this->transport_name_ + << "): already stopped"; + return; + } + } + + LOG(INFO) << "BlockingConnectionAdapter(" << this->transport_name_ << "): resetting"; + this->underlying_->Reset(); + Stop(); +} + void BlockingConnectionAdapter::Stop() { { std::lock_guard lock(mutex_); @@ -424,14 +449,18 @@ void send_packet(apacket* p, atransport* t) { } } -void kick_transport(atransport* t) { +void kick_transport(atransport* t, bool reset) { std::lock_guard lock(transport_lock); // As kick_transport() can be called from threads without guarantee that t is valid, // check if the transport is in transport_list first. // // TODO(jmgao): WTF? Is this actually true? if (std::find(transport_list.begin(), transport_list.end(), t) != transport_list.end()) { - t->Kick(); + if (reset) { + t->Reset(); + } else { + t->Kick(); + } } #if ADB_HOST @@ -942,9 +971,16 @@ int atransport::Write(apacket* p) { return this->connection()->Write(std::unique_ptr(p)) ? 0 : -1; } +void atransport::Reset() { + if (!kicked_.exchange(true)) { + LOG(INFO) << "resetting transport " << this << " " << this->serial; + this->connection()->Reset(); + } +} + void atransport::Kick() { if (!kicked_.exchange(true)) { - D("kicking transport %p %s", this, this->serial.c_str()); + LOG(INFO) << "kicking transport " << this << " " << this->serial; this->connection()->Stop(); } } @@ -1173,18 +1209,22 @@ std::string list_transports(bool long_listing) { return result; } -void close_usb_devices(std::function predicate) { +void close_usb_devices(std::function predicate, bool reset) { std::lock_guard lock(transport_lock); for (auto& t : transport_list) { if (predicate(t)) { - t->Kick(); + if (reset) { + t->Reset(); + } else { + t->Kick(); + } } } } /* hack for osx */ -void close_usb_devices() { - close_usb_devices([](const atransport*) { return true; }); +void close_usb_devices(bool reset) { + close_usb_devices([](const atransport*) { return true; }, reset); } #endif // ADB_HOST diff --git a/adb/transport.h b/adb/transport.h index a0174b8fc..f4490eded 100644 --- a/adb/transport.h +++ b/adb/transport.h @@ -99,6 +99,9 @@ struct Connection { virtual void Start() = 0; virtual void Stop() = 0; + // Stop, and reset the device if it's a USB connection. + virtual void Reset(); + std::string transport_name_; ReadCallback read_callback_; ErrorCallback error_callback_; @@ -124,6 +127,9 @@ struct BlockingConnection { // This method must be thread-safe, and must cause concurrent Reads/Writes to terminate. // Formerly known as 'Kick' in atransport. virtual void Close() = 0; + + // Terminate a connection, and reset it. + virtual void Reset() = 0; }; struct BlockingConnectionAdapter : public Connection { @@ -136,6 +142,8 @@ struct BlockingConnectionAdapter : public Connection { virtual void Start() override final; virtual void Stop() override final; + virtual void Reset() override final; + bool started_ GUARDED_BY(mutex_) = false; bool stopped_ GUARDED_BY(mutex_) = false; @@ -157,6 +165,7 @@ struct FdConnection : public BlockingConnection { bool Write(apacket* packet) override final; void Close() override; + virtual void Reset() override final { Close(); } private: unique_fd fd_; @@ -170,6 +179,7 @@ struct UsbConnection : public BlockingConnection { bool Write(apacket* packet) override final; void Close() override final; + virtual void Reset() override final; usb_handle* handle_; }; @@ -235,6 +245,7 @@ class atransport { virtual ~atransport(); int Write(apacket* p); + void Reset(); void Kick(); bool kicked() const { return kicked_; } @@ -364,7 +375,7 @@ class atransport { atransport* acquire_one_transport(TransportType type, const char* serial, TransportId transport_id, bool* is_ambiguous, std::string* error_out, bool accept_any_state = false); -void kick_transport(atransport* t); +void kick_transport(atransport* t, bool reset = false); void update_transports(void); // Iterates across all of the current and pending transports. @@ -395,8 +406,8 @@ void unregister_usb_transport(usb_handle* usb); bool check_header(apacket* p, atransport* t); -void close_usb_devices(); -void close_usb_devices(std::function predicate); +void close_usb_devices(bool reset = false); +void close_usb_devices(std::function predicate, bool reset = false); void send_packet(apacket* p, atransport* t); diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp index 2e5918ab6..3e87522e5 100644 --- a/adb/transport_usb.cpp +++ b/adb/transport_usb.cpp @@ -171,6 +171,11 @@ bool UsbConnection::Write(apacket* packet) { return true; } +void UsbConnection::Reset() { + usb_reset(handle_); + usb_kick(handle_); +} + void UsbConnection::Close() { usb_kick(handle_); } diff --git a/adb/usb.h b/adb/usb.h index cd83c42ae..eb8ca6cc0 100644 --- a/adb/usb.h +++ b/adb/usb.h @@ -26,6 +26,7 @@ int usb_write(handle_ref_type h, const void* data, int len); \ int usb_read(handle_ref_type h, void* data, int len); \ int usb_close(handle_ref_type h); \ + void usb_reset(handle_ref_type h); \ void usb_kick(handle_ref_type h); \ size_t usb_get_max_packet_size(handle_ref_type) -- cgit v1.2.3