adb: make adb reconnect perform a USB reset.

Bug: http://b/128941083
Test: manual
Change-Id: Iaf46d2c46cc82b590768004486d119244591c8e2
This commit is contained in:
Josh Gao 2019-03-28 15:47:44 -07:00
parent ee9ba3efe7
commit 3705b346b9
12 changed files with 104 additions and 12 deletions

View file

@ -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";
}

View file

@ -52,6 +52,11 @@ int usb_close(usb_handle* h) {
: native::usb_close(reinterpret_cast<native::usb_handle*>(h));
}
void usb_reset(usb_handle* h) {
should_use_libusb() ? libusb::usb_reset(reinterpret_cast<libusb::usb_handle*>(h))
: native::usb_reset(reinterpret_cast<native::usb_handle*>(h));
}
void usb_kick(usb_handle* h) {
should_use_libusb() ? libusb::usb_kick(reinterpret_cast<libusb::usb_handle*>(h))
: native::usb_kick(reinterpret_cast<native::usb_handle*>(h));

View file

@ -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();
}

View file

@ -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<std::mutex> lock(h->mutex);
D("[ kicking %p (fd = %d) ]", h, h->fd);

View file

@ -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";

View file

@ -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.

View file

@ -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";
}

View file

@ -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);
}

View file

@ -257,6 +257,11 @@ TransportId NextTransportId() {
return next++;
}
void Connection::Reset() {
LOG(INFO) << "Connection::Reset(): stopping";
Stop();
}
BlockingConnectionAdapter::BlockingConnectionAdapter(std::unique_ptr<BlockingConnection> connection)
: underlying_(std::move(connection)) {}
@ -312,6 +317,26 @@ void BlockingConnectionAdapter::Start() {
started_ = true;
}
void BlockingConnectionAdapter::Reset() {
{
std::lock_guard<std::mutex> 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<std::mutex> 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<std::recursive_mutex> 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<apacket>(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<bool(const atransport*)> predicate) {
void close_usb_devices(std::function<bool(const atransport*)> predicate, bool reset) {
std::lock_guard<std::recursive_mutex> 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

View file

@ -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<bool(const atransport*)> predicate);
void close_usb_devices(bool reset = false);
void close_usb_devices(std::function<bool(const atransport*)> predicate, bool reset = false);
void send_packet(apacket* p, atransport* t);

View file

@ -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_);
}

View file

@ -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)