adbd: Check USB disabled property after opening FFS am: db01bd2944
Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/modules/adb/+/15130281
Change-Id: Iece3ff0a29ace0e8f767feae8b8b7e6ca070b0a7
diff --git a/OWNERS b/OWNERS
index 6f1a311..2108ae5 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,3 +1,4 @@
jmgao@google.com
+enh@google.com
include platform/packages/modules/common:/MODULES_OWNERS # see go/mainline-owners-policy
diff --git a/adb.cpp b/adb.cpp
index d692a0b..3b860c0 100644
--- a/adb.cpp
+++ b/adb.cpp
@@ -1360,6 +1360,52 @@
return HostRequestResult::Handled;
}
+ if (service == "attach") {
+ std::string error;
+ atransport* t = s->transport ? s->transport
+ : acquire_one_transport(type, serial, transport_id, nullptr,
+ &error, true);
+ if (!t) {
+ SendFail(reply_fd, error);
+ return HostRequestResult::Handled;
+ }
+
+ if (t->Attach(&error)) {
+ SendOkay(reply_fd,
+ android::base::StringPrintf("%s attached", t->serial_name().c_str()));
+ } else {
+ SendFail(reply_fd, error);
+ }
+ return HostRequestResult::Handled;
+ }
+
+ if (service == "detach") {
+ std::string error;
+ atransport* t = s->transport ? s->transport
+ : acquire_one_transport(type, serial, transport_id, nullptr,
+ &error, true);
+ if (!t) {
+ SendFail(reply_fd, error);
+ return HostRequestResult::Handled;
+ }
+
+ // HACK:
+ // Detaching the transport will lead to all of its sockets being closed,
+ // but we're handling one of those sockets right now!
+ //
+ // Mark the socket as not having a transport, knowing that it'll be cleaned up by the
+ // function that called us.
+ s->transport = nullptr;
+
+ if (t->Detach(&error)) {
+ SendOkay(reply_fd,
+ android::base::StringPrintf("%s detached", t->serial_name().c_str()));
+ } else {
+ SendFail(reply_fd, error);
+ }
+ return HostRequestResult::Handled;
+ }
+
// TODO: Switch handle_forward_request to string_view.
std::string service_str(service);
auto transport_acquirer = [=](std::string* error) {
diff --git a/adb.h b/adb.h
index 476ed9b..437a207 100644
--- a/adb.h
+++ b/adb.h
@@ -104,6 +104,7 @@
kCsAuthorizing, // Authorizing with keys from ADB_VENDOR_KEYS.
kCsUnauthorized, // ADB_VENDOR_KEYS exhausted, fell back to user prompt.
kCsNoPerm, // Insufficient permissions to communicate with the device.
+ kCsDetached, // USB device that's detached from the adb server.
kCsOffline,
kCsBootloader,
diff --git a/apex/Android.bp b/apex/Android.bp
index 3c9f13e..e018565 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -28,6 +28,7 @@
manifest: "apex_manifest.json",
key: "com.android.adbd.key",
certificate: ":com.android.adbd.certificate",
+ compressible: true,
}
soong_config_module_type_import {
diff --git a/client/adb_client.cpp b/client/adb_client.cpp
index a308732..60dd38f 100644
--- a/client/adb_client.cpp
+++ b/client/adb_client.cpp
@@ -383,9 +383,10 @@
return true;
}
-bool adb_query(const std::string& service, std::string* result, std::string* error) {
+bool adb_query(const std::string& service, std::string* result, std::string* error,
+ bool force_switch_device) {
D("adb_query: %s", service.c_str());
- unique_fd fd(adb_connect(service, error));
+ unique_fd fd(adb_connect(nullptr, service, error, force_switch_device));
if (fd < 0) {
return false;
}
diff --git a/client/adb_client.h b/client/adb_client.h
index d0a4c4e..ab559b2 100644
--- a/client/adb_client.h
+++ b/client/adb_client.h
@@ -51,7 +51,7 @@
// Connects to the named adb service and fills 'result' with the response.
// Returns true on success; returns false and fills 'error' on failure.
bool adb_query(const std::string& service, std::string* _Nonnull result,
- std::string* _Nonnull error);
+ std::string* _Nonnull error, bool force_switch_device = false);
// Set the preferred transport to connect to.
void adb_set_transport(TransportType type, const char* _Nullable serial, TransportId transport_id);
diff --git a/client/commandline.cpp b/client/commandline.cpp
index 0caf9e2..bfb7f25 100644
--- a/client/commandline.cpp
+++ b/client/commandline.cpp
@@ -234,6 +234,10 @@
" reconnect device kick connection from device side to force reconnect\n"
" reconnect offline reset offline/unauthorized devices to force reconnect\n"
"\n"
+ "usb:\n"
+ " attach attach a detached USB device\n"
+ " detach detach from a USB device to allow use by other processes\n"
+ ""
"environment variables:\n"
" $ADB_TRACE\n"
" comma-separated list of debug info to log:\n"
@@ -2162,6 +2166,15 @@
output_fd = adb_register_socket(output_fd);
close_on_exec(output_fd);
return incremental::serve(connection_fd, output_fd, argc - 3, argv + 3);
+ } else if (!strcmp(argv[0], "attach") || !strcmp(argv[0], "detach")) {
+ const char* service = strcmp(argv[0], "attach") == 0 ? "host:attach" : "host:detach";
+ std::string result;
+ std::string error;
+ if (!adb_query(service, &result, &error, true)) {
+ error_exit("failed to %s: %s", argv[0], error.c_str());
+ }
+ printf("%s\n", result.c_str());
+ return 0;
}
error_exit("unknown command %s", argv[0]);
diff --git a/client/usb_libusb.cpp b/client/usb_libusb.cpp
index a877610..b9ce1d1 100644
--- a/client/usb_libusb.cpp
+++ b/client/usb_libusb.cpp
@@ -47,6 +47,13 @@
using android::base::ScopedLockAssertion;
using android::base::StringPrintf;
+#define LOG_ERR(out, fmt, ...) \
+ do { \
+ std::string __err = android::base::StringPrintf(fmt, ##__VA_ARGS__); \
+ LOG(ERROR) << __err; \
+ *out = std::move(__err); \
+ } while (0)
+
// RAII wrappers for libusb.
struct ConfigDescriptorDeleter {
void operator()(libusb_config_descriptor* desc) { libusb_free_config_descriptor(desc); }
@@ -69,22 +76,22 @@
static void process_device(libusb_device* device_raw);
static std::string get_device_address(libusb_device* device) {
- return StringPrintf("usb:%d:%d", libusb_get_bus_number(device),
- libusb_get_device_address(device));
-}
-
-#if defined(__linux__)
-static std::string get_device_serial_path(libusb_device* device) {
uint8_t ports[7];
int port_count = libusb_get_port_numbers(device, ports, 7);
if (port_count < 0) return "";
- std::string path =
- StringPrintf("/sys/bus/usb/devices/%d-%d", libusb_get_bus_number(device), ports[0]);
+ std::string address = StringPrintf("%d-%d", libusb_get_bus_number(device), ports[0]);
for (int port = 1; port < port_count; ++port) {
- path += StringPrintf(".%d", ports[port]);
+ address += StringPrintf(".%d", ports[port]);
}
- path += "/serial";
+
+ return address;
+}
+
+#if defined(__linux__)
+static std::string get_device_serial_path(libusb_device* device) {
+ std::string address = get_device_address(device);
+ std::string path = StringPrintf("/sys/bus/usb/devices/%s/serial", address.c_str());
return path;
}
#endif
@@ -123,24 +130,26 @@
if (payload) {
packet->payload = std::move(*payload);
}
- read_callback_(this, std::move(packet));
+ transport_->HandleRead(std::move(packet));
}
void Cleanup(ReadBlock* read_block) REQUIRES(read_mutex_) {
libusb_free_transfer(read_block->transfer);
read_block->active = false;
read_block->transfer = nullptr;
- if (terminating_) {
+ if (terminated_) {
destruction_cv_.notify_one();
}
}
bool MaybeCleanup(ReadBlock* read_block) REQUIRES(read_mutex_) {
+ CHECK(read_block);
+ CHECK(read_block->transfer);
if (read_block->transfer->status == LIBUSB_TRANSFER_CANCELLED) {
- CHECK(terminating_);
+ CHECK(terminated_);
}
- if (terminating_) {
+ if (terminated_) {
Cleanup(read_block);
return true;
}
@@ -161,7 +170,9 @@
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
std::string msg = StringPrintf("usb read failed: status = %d", transfer->status);
LOG(ERROR) << msg;
- self->OnError(msg);
+ if (!self->detached_) {
+ self->OnError(msg);
+ }
self->Cleanup(read_block);
return;
}
@@ -208,7 +219,9 @@
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
std::string msg = StringPrintf("usb read failed: status = %d", transfer->status);
LOG(ERROR) << msg;
- self->OnError(msg);
+ if (!self->detached_) {
+ self->OnError(msg);
+ }
self->Cleanup(&self->payload_read_);
return;
}
@@ -242,12 +255,12 @@
libusb_free_transfer(transfer);
self->writes_.erase(write_block->id);
- if (self->terminating_ && self->writes_.empty()) {
+ if (self->terminated_ && self->writes_.empty()) {
self->destruction_cv_.notify_one();
}
}
- if (!succeeded) {
+ if (!succeeded && !self->detached_) {
self->OnError("libusb write failed");
}
}
@@ -304,10 +317,14 @@
memcpy(header.data(), &packet->msg, sizeof(packet->msg));
std::lock_guard<std::mutex> lock(write_mutex_);
- if (terminating_) {
+ if (terminated_) {
return false;
}
+ if (detached_) {
+ return true;
+ }
+
SubmitWrite(std::move(header));
if (!packet->payload.empty()) {
size_t payload_length = packet->payload.size();
@@ -463,37 +480,15 @@
bool OpenDevice(std::string* error) {
if (device_handle_) {
- return true;
+ LOG_ERR(error, "device already open");
+ return false;
}
libusb_device_handle* handle_raw;
int rc = libusb_open(device_.get(), &handle_raw);
if (rc != 0) {
- std::string err = StringPrintf("failed to open device: %s", libusb_strerror(rc));
- LOG(ERROR) << err;
-
-#if defined(__linux__)
- std::string device_serial;
- // libusb doesn't think we should be messing around with devices we don't have
- // write access to, but Linux at least lets us get the serial number anyway.
- if (!android::base::ReadFileToString(get_device_serial_path(device_.get()),
- &device_serial)) {
- // We don't actually want to treat an unknown serial as an error because
- // devices aren't able to communicate a serial number in early bringup.
- // http://b/20883914
- serial_ = "<unknown>";
- } else {
- serial_ = android::base::Trim(device_serial);
- }
-#else
- // On Mac OS and Windows, we're screwed. But I don't think this situation actually
- // happens on those OSes.
-#endif
-
- if (error) {
- *error = std::move(err);
- }
-
+ // TODO: Handle no permissions.
+ LOG_ERR(error, "failed to open device: %s", libusb_strerror(rc));
return false;
}
@@ -502,84 +497,47 @@
auto device_desc = GetDeviceDescriptor();
if (!device_desc) {
+ LOG_ERR(error, "failed to get device descriptor");
device_handle_.reset();
return false;
}
if (!FindInterface(&device_desc.value())) {
+ LOG_ERR(error, "failed to find adb interface");
device_handle_.reset();
return false;
}
serial_ = GetSerial();
- return true;
- }
-
- bool StartImpl(std::string* error) {
- if (!OpenDevice(error)) {
- return false;
- }
LOG(DEBUG) << "successfully opened adb device at " << device_address_ << ", "
<< StringPrintf("bulk_in = %#x, bulk_out = %#x", read_endpoint_,
write_endpoint_);
// WARNING: this isn't released via RAII.
- int rc = libusb_claim_interface(device_handle_.get(), interface_num_);
+ rc = libusb_claim_interface(device_handle_.get(), interface_num_);
if (rc != 0) {
- LOG(WARNING) << "failed to claim adb interface for device '" << serial_ << "'"
- << libusb_error_name(rc);
+ LOG_ERR(error, "failed to claim adb interface for device '%s': %s", serial_.c_str(),
+ libusb_error_name(rc));
+ device_handle_.reset();
return false;
}
for (uint8_t endpoint : {read_endpoint_, write_endpoint_}) {
rc = libusb_clear_halt(device_handle_.get(), endpoint);
if (rc != 0) {
- LOG(WARNING) << "failed to clear halt on device '" << serial_ << "' endpoint 0x"
- << std::hex << endpoint << ": " << libusb_error_name(rc);
+ LOG_ERR(error, "failed to clear halt on device '%s' endpoint %#02x: %s",
+ serial_.c_str(), endpoint, libusb_error_name(rc));
libusb_release_interface(device_handle_.get(), interface_num_);
+ device_handle_.reset();
return false;
}
}
- LOG(INFO) << "registered new usb device '" << serial_ << "'";
- std::lock_guard lock(read_mutex_);
- CreateRead(&header_read_, true);
- CreateRead(&payload_read_, false);
- SubmitRead(&header_read_, sizeof(amessage));
-
return true;
}
- void OnError(const std::string& error) {
- std::call_once(error_flag_, [this, &error]() {
- if (error_callback_) {
- error_callback_(this, error);
- }
- });
- }
-
- virtual void Reset() override final {
- Stop();
-
- if (libusb_reset_device(device_handle_.get()) == 0) {
- libusb_device* device = libusb_ref_device(device_.get());
- fdevent_run_on_main_thread([device]() {
- process_device(device);
- libusb_unref_device(device);
- });
- }
- }
-
- virtual void Start() override final {
- std::string error;
- if (!StartImpl(&error)) {
- OnError(error);
- return;
- }
- }
-
- virtual void Stop() override final {
+ void CloseDevice() {
// This is rather messy, because of the lifecyle of libusb_transfers.
//
// We can't call libusb_free_transfer for a submitted transfer, we have to cancel it
@@ -591,11 +549,11 @@
// Resolve this by setting an atomic flag before we lock to cancel transfers, and take the
// lock in the callbacks before checking the flag.
- if (terminating_) {
+ if (terminated_) {
return;
}
- terminating_ = true;
+ terminated_ = true;
{
std::unique_lock<std::mutex> lock(write_mutex_);
@@ -616,11 +574,12 @@
{
std::unique_lock<std::mutex> lock(read_mutex_);
ScopedLockAssertion assumed_locked(read_mutex_);
+
if (header_read_.transfer) {
if (header_read_.active) {
libusb_cancel_transfer(header_read_.transfer);
} else {
- libusb_free_transfer(header_read_.transfer);
+ Cleanup(&header_read_);
}
}
@@ -628,7 +587,7 @@
if (payload_read_.active) {
libusb_cancel_transfer(payload_read_.transfer);
} else {
- libusb_free_transfer(payload_read_.transfer);
+ Cleanup(&payload_read_);
}
}
@@ -636,12 +595,85 @@
ScopedLockAssertion assumed_locked(read_mutex_);
return !header_read_.active && !payload_read_.active;
});
+
+ incoming_header_.reset();
+ incoming_payload_.clear();
}
if (device_handle_) {
libusb_release_interface(device_handle_.get(), interface_num_);
+ device_handle_.reset();
+ }
+ }
+
+ bool StartImpl(std::string* error) {
+ if (!device_handle_) {
+ *error = "device not opened";
+ return false;
}
+ LOG(INFO) << "registered new usb device '" << serial_ << "'";
+ std::lock_guard lock(read_mutex_);
+ CreateRead(&header_read_, true);
+ CreateRead(&payload_read_, false);
+ SubmitRead(&header_read_, sizeof(amessage));
+
+ return true;
+ }
+
+ void OnError(const std::string& error) {
+ std::call_once(error_flag_, [this, &error]() {
+ if (transport_) {
+ transport_->HandleError(error);
+ }
+ });
+ }
+
+ virtual bool Attach(std::string* error) override final {
+ terminated_ = false;
+ detached_ = false;
+
+ if (!OpenDevice(error)) {
+ return false;
+ }
+
+ if (!StartImpl(error)) {
+ CloseDevice();
+ return false;
+ }
+
+ return true;
+ }
+
+ virtual bool Detach(std::string* error) override final {
+ detached_ = true;
+ CloseDevice();
+ return true;
+ }
+
+ virtual void Reset() override final {
+ LOG(INFO) << "resetting " << transport_->serial_name();
+ if (libusb_reset_device(device_handle_.get()) == 0) {
+ libusb_device* device = libusb_ref_device(device_.get());
+
+ Stop();
+
+ fdevent_run_on_main_thread([device]() {
+ process_device(device);
+ libusb_unref_device(device);
+ });
+ }
+ }
+
+ virtual void Start() override final {
+ std::string error;
+ if (!Attach(&error)) {
+ OnError(error);
+ }
+ }
+
+ virtual void Stop() override final {
+ CloseDevice();
OnError("requested stop");
}
@@ -660,9 +692,25 @@
return {};
}
+#if defined(__linux__)
+ std::string device_serial;
+ if (android::base::ReadFileToString(get_device_serial_path(connection->device_.get()),
+ &device_serial)) {
+ connection->serial_ = android::base::Trim(device_serial);
+ } else {
+ // We don't actually want to treat an unknown serial as an error because
+ // devices aren't able to communicate a serial number in early bringup.
+ // http://b/20883914
+ connection->serial_ = "<unknown>";
+ }
+#else
+ // We need to open the device to get its serial on Windows and OS X.
if (!connection->OpenDevice(nullptr)) {
return {};
}
+ connection->serial_ = connection->GetSerial();
+ connection->CloseDevice();
+#endif
return connection;
}
@@ -687,7 +735,8 @@
std::atomic<size_t> next_write_id_ = 0;
std::once_flag error_flag_;
- std::atomic<bool> terminating_ = false;
+ std::atomic<bool> terminated_ = false;
+ std::atomic<bool> detached_ = false;
std::condition_variable destruction_cv_;
size_t zero_mask_ = 0;
@@ -711,6 +760,12 @@
}
auto connection = *connection_opt;
+
+ {
+ std::lock_guard<std::mutex> lock(usb_handles_mutex);
+ usb_handles.emplace(libusb_ref_device(device_raw), connection);
+ }
+
LOG(INFO) << "constructed LibusbConnection for device " << connection->serial_ << " ("
<< device_address << ")";
@@ -744,6 +799,7 @@
if (it != usb_handles.end()) {
// We need to ensure that we don't destroy the LibusbConnection on this thread,
// as we're in a context with internal libusb mutexes held.
+ libusb_device* device = it->first;
std::weak_ptr<LibusbConnection> connection_weak = it->second;
usb_handles.erase(it);
fdevent_run_on_main_thread([connection_weak]() {
@@ -755,6 +811,7 @@
LOG(INFO) << "libusb_hotplug: device disconnected: (destroyed)";
}
});
+ libusb_unref_device(device);
}
usb_handles_mutex.unlock();
}
@@ -768,9 +825,13 @@
libusb_hotplug_event event = pair.first;
libusb_device* device = pair.second;
if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) {
+ LOG(INFO) << "libusb hotplug: device arrived";
device_connected(device);
} else if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) {
+ LOG(INFO) << "libusb hotplug: device left";
device_disconnected(device);
+ } else {
+ LOG(WARNING) << "unknown libusb hotplug event: " << event;
}
});
}
diff --git a/daemon/usb.cpp b/daemon/usb.cpp
index 4366ea9..6c3f735 100644
--- a/daemon/usb.cpp
+++ b/daemon/usb.cpp
@@ -582,7 +582,7 @@
// TODO: Make apacket contain an IOVector so we don't have to coalesce.
packet->payload = std::move(incoming_payload_).coalesce();
- read_callback_(this, std::move(packet));
+ transport_->HandleRead(std::move(packet));
incoming_header_.reset();
// reuse the capacity of the incoming payload while we can.
@@ -678,7 +678,10 @@
void HandleError(const std::string& error) {
std::call_once(error_flag_, [&]() {
- error_callback_(this, error);
+ if (transport_) {
+ transport_->HandleError(error);
+ }
+
if (!stopped_) {
Stop();
}
diff --git a/transport.cpp b/transport.cpp
index fbcf79b..1e13655 100644
--- a/transport.cpp
+++ b/transport.cpp
@@ -55,6 +55,10 @@
#include "fdevent/fdevent.h"
#include "sysdeps/chrono.h"
+#if ADB_HOST
+#include "client/usb.h"
+#endif
+
using namespace adb::crypto;
using namespace adb::tls;
using android::base::ScopedLockAssertion;
@@ -278,25 +282,28 @@
Stop();
}
+std::string Connection::Serial() const {
+ return transport_ ? transport_->serial_name() : "<unknown>";
+}
+
BlockingConnectionAdapter::BlockingConnectionAdapter(std::unique_ptr<BlockingConnection> connection)
: underlying_(std::move(connection)) {}
BlockingConnectionAdapter::~BlockingConnectionAdapter() {
- LOG(INFO) << "BlockingConnectionAdapter(" << this->transport_name_ << "): destructing";
+ LOG(INFO) << "BlockingConnectionAdapter(" << Serial() << "): destructing";
Stop();
}
void BlockingConnectionAdapter::Start() {
std::lock_guard<std::mutex> lock(mutex_);
if (started_) {
- LOG(FATAL) << "BlockingConnectionAdapter(" << this->transport_name_
- << "): started multiple times";
+ LOG(FATAL) << "BlockingConnectionAdapter(" << Serial() << "): started multiple times";
}
StartReadThread();
write_thread_ = std::thread([this]() {
- LOG(INFO) << this->transport_name_ << ": write thread spawning";
+ LOG(INFO) << Serial() << ": write thread spawning";
while (true) {
std::unique_lock<std::mutex> lock(mutex_);
ScopedLockAssertion assume_locked(mutex_);
@@ -316,7 +323,7 @@
break;
}
}
- std::call_once(this->error_flag_, [this]() { this->error_callback_(this, "write failed"); });
+ std::call_once(this->error_flag_, [this]() { transport_->HandleError("write failed"); });
});
started_ = true;
@@ -324,11 +331,11 @@
void BlockingConnectionAdapter::StartReadThread() {
read_thread_ = std::thread([this]() {
- LOG(INFO) << this->transport_name_ << ": read thread spawning";
+ LOG(INFO) << Serial() << ": read thread spawning";
while (true) {
auto packet = std::make_unique<apacket>();
if (!underlying_->Read(packet.get())) {
- PLOG(INFO) << this->transport_name_ << ": read failed";
+ PLOG(INFO) << Serial() << ": read failed";
break;
}
@@ -337,18 +344,17 @@
got_stls_cmd = true;
}
- read_callback_(this, std::move(packet));
+ transport_->HandleRead(std::move(packet));
// If we received the STLS packet, we are about to perform the TLS
// handshake. So this read thread must stop and resume after the
// handshake completes otherwise this will interfere in the process.
if (got_stls_cmd) {
- LOG(INFO) << this->transport_name_
- << ": Received STLS packet. Stopping read thread.";
+ LOG(INFO) << Serial() << ": Received STLS packet. Stopping read thread.";
return;
}
}
- std::call_once(this->error_flag_, [this]() { this->error_callback_(this, "read failed"); });
+ std::call_once(this->error_flag_, [this]() { transport_->HandleError("read failed"); });
});
}
@@ -366,18 +372,17 @@
{
std::lock_guard<std::mutex> lock(mutex_);
if (!started_) {
- LOG(INFO) << "BlockingConnectionAdapter(" << this->transport_name_ << "): not started";
+ LOG(INFO) << "BlockingConnectionAdapter(" << Serial() << "): not started";
return;
}
if (stopped_) {
- LOG(INFO) << "BlockingConnectionAdapter(" << this->transport_name_
- << "): already stopped";
+ LOG(INFO) << "BlockingConnectionAdapter(" << Serial() << "): already stopped";
return;
}
}
- LOG(INFO) << "BlockingConnectionAdapter(" << this->transport_name_ << "): resetting";
+ LOG(INFO) << "BlockingConnectionAdapter(" << Serial() << "): resetting";
this->underlying_->Reset();
Stop();
}
@@ -386,20 +391,19 @@
{
std::lock_guard<std::mutex> lock(mutex_);
if (!started_) {
- LOG(INFO) << "BlockingConnectionAdapter(" << this->transport_name_ << "): not started";
+ LOG(INFO) << "BlockingConnectionAdapter(" << Serial() << "): not started";
return;
}
if (stopped_) {
- LOG(INFO) << "BlockingConnectionAdapter(" << this->transport_name_
- << "): already stopped";
+ LOG(INFO) << "BlockingConnectionAdapter(" << Serial() << "): already stopped";
return;
}
stopped_ = true;
}
- LOG(INFO) << "BlockingConnectionAdapter(" << this->transport_name_ << "): stopping";
+ LOG(INFO) << "BlockingConnectionAdapter(" << Serial() << "): stopping";
this->underlying_->Close();
this->cv_.notify_one();
@@ -417,8 +421,8 @@
read_thread.join();
write_thread.join();
- LOG(INFO) << "BlockingConnectionAdapter(" << this->transport_name_ << "): stopped";
- std::call_once(this->error_flag_, [this]() { this->error_callback_(this, "requested stop"); });
+ LOG(INFO) << "BlockingConnectionAdapter(" << Serial() << "): stopped";
+ std::call_once(this->error_flag_, [this]() { transport_->HandleError("requested stop"); });
}
bool BlockingConnectionAdapter::Write(std::unique_ptr<apacket> packet) {
@@ -762,6 +766,16 @@
return 0;
}
+static bool usb_devices_start_detached() {
+#if ADB_HOST
+ static const char* env = getenv("ADB_LIBUSB_START_DETACHED");
+ static bool result = env && strcmp("1", env) == 0;
+ return should_use_libusb() && result;
+#else
+ return false;
+#endif
+}
+
static void transport_registration_func(int _fd, unsigned ev, void*) {
tmsg m;
atransport* t;
@@ -792,34 +806,16 @@
/* don't create transport threads for inaccessible devices */
if (t->GetConnectionState() != kCsNoPerm) {
- // The connection gets a reference to the atransport. It will release it
- // upon a read/write error.
- t->connection()->SetTransportName(t->serial_name());
- t->connection()->SetReadCallback([t](Connection*, std::unique_ptr<apacket> p) {
- if (!check_header(p.get(), t)) {
- D("%s: remote read: bad header", t->serial.c_str());
- return false;
- }
+ t->connection()->SetTransport(t);
- VLOG(TRANSPORT) << dump_packet(t->serial.c_str(), "from remote", p.get());
- apacket* packet = p.release();
-
- // TODO: Does this need to run on the main thread?
- fdevent_run_on_main_thread([packet, t]() { handle_packet(packet, t); });
- return true;
- });
- t->connection()->SetErrorCallback([t](Connection*, const std::string& error) {
- LOG(INFO) << t->serial_name() << ": connection terminated: " << error;
- fdevent_run_on_main_thread([t]() {
- handle_offline(t);
- transport_destroy(t);
- });
- });
-
- t->connection()->Start();
+ if (t->type == kTransportUsb && usb_devices_start_detached()) {
+ t->SetConnectionState(kCsDetached);
+ } else {
+ t->connection()->Start();
#if ADB_HOST
- send_connect(t);
+ send_connect(t);
#endif
+ }
}
{
@@ -852,7 +848,7 @@
transport_registration_recv = s[1];
transport_registration_fde =
- fdevent_create(transport_registration_recv, transport_registration_func, nullptr);
+ fdevent_create(transport_registration_recv, transport_registration_func, nullptr);
fdevent_set(transport_registration_fde, FDE_READ);
}
@@ -961,8 +957,8 @@
atransport* result = nullptr;
if (transport_id != 0) {
- *error_out =
- android::base::StringPrintf("no device with transport id '%" PRIu64 "'", transport_id);
+ *error_out = android::base::StringPrintf("no device with transport id '%" PRIu64 "'",
+ transport_id);
} else if (serial) {
*error_out = android::base::StringPrintf("device '%s' not found", serial);
} else if (type == kTransportLocal) {
@@ -1124,11 +1120,89 @@
update_transports();
}
+#if ADB_HOST
+bool atransport::Attach(std::string* error) {
+ D("%s: attach", serial.c_str());
+ check_main_thread();
+
+ if (!should_use_libusb()) {
+ *error = "attach/detach only implemented for libusb backend";
+ return false;
+ }
+
+ if (GetConnectionState() != ConnectionState::kCsDetached) {
+ *error = android::base::StringPrintf("transport %s is not detached", serial.c_str());
+ return false;
+ }
+
+ ResetKeys();
+
+ {
+ std::lock_guard<std::mutex> lock(mutex_);
+ if (!connection_->Attach(error)) {
+ return false;
+ }
+ }
+
+ send_connect(this);
+ return true;
+}
+
+bool atransport::Detach(std::string* error) {
+ D("%s: detach", serial.c_str());
+ check_main_thread();
+
+ if (!should_use_libusb()) {
+ *error = "attach/detach only implemented for libusb backend";
+ return false;
+ }
+
+ if (GetConnectionState() == ConnectionState::kCsDetached) {
+ *error = android::base::StringPrintf("transport %s is already detached", serial.c_str());
+ return false;
+ }
+
+ handle_offline(this);
+
+ {
+ std::lock_guard<std::mutex> lock(mutex_);
+ if (!connection_->Detach(error)) {
+ return false;
+ }
+ }
+
+ this->SetConnectionState(kCsDetached);
+ return true;
+}
+#endif
+
void atransport::SetConnection(std::shared_ptr<Connection> connection) {
std::lock_guard<std::mutex> lock(mutex_);
connection_ = std::shared_ptr<Connection>(std::move(connection));
}
+bool atransport::HandleRead(std::unique_ptr<apacket> p) {
+ if (!check_header(p.get(), this)) {
+ D("%s: remote read: bad header", serial.c_str());
+ return false;
+ }
+
+ VLOG(TRANSPORT) << dump_packet(serial.c_str(), "from remote", p.get());
+ apacket* packet = p.release();
+
+ // TODO: Does this need to run on the main thread?
+ fdevent_run_on_main_thread([packet, this]() { handle_packet(packet, this); });
+ return true;
+}
+
+void atransport::HandleError(const std::string& error) {
+ LOG(INFO) << serial_name() << ": connection terminated: " << error;
+ fdevent_run_on_main_thread([this]() {
+ handle_offline(this);
+ transport_destroy(this);
+ });
+}
+
std::string atransport::connection_state_name() const {
ConnectionState state = GetConnectionState();
switch (state) {
@@ -1154,6 +1228,8 @@
return "authorizing";
case kCsConnecting:
return "connecting";
+ case kCsDetached:
+ return "detached";
default:
return "unknown";
}
@@ -1268,7 +1344,8 @@
// Parse our |serial| and the given |target| to check if the hostnames and ports match.
std::string serial_host, error;
int serial_port = -1;
- if (android::base::ParseNetAddress(serial, &serial_host, &serial_port, nullptr, &error)) {
+ if (android::base::ParseNetAddress(serial, &serial_host, &serial_port, nullptr,
+ &error)) {
// |target| may omit the port to default to ours.
std::string target_host;
int target_port = serial_port;
diff --git a/transport.h b/transport.h
index d098b7c..20c47a1 100644
--- a/transport.h
+++ b/transport.h
@@ -106,22 +106,7 @@
Connection() = default;
virtual ~Connection() = default;
- void SetTransportName(std::string transport_name) {
- transport_name_ = std::move(transport_name);
- }
-
- using ReadCallback = std::function<bool(Connection*, std::unique_ptr<apacket>)>;
- void SetReadCallback(ReadCallback callback) {
- CHECK(!read_callback_);
- read_callback_ = callback;
- }
-
- // Called after the Connection has terminated, either by an error or because Stop was called.
- using ErrorCallback = std::function<void(Connection*, const std::string&)>;
- void SetErrorCallback(ErrorCallback callback) {
- CHECK(!error_callback_);
- error_callback_ = callback;
- }
+ void SetTransport(atransport* transport) { transport_ = transport; }
virtual bool Write(std::unique_ptr<apacket> packet) = 0;
@@ -133,9 +118,19 @@
// Stop, and reset the device if it's a USB connection.
virtual void Reset();
- std::string transport_name_;
- ReadCallback read_callback_;
- ErrorCallback error_callback_;
+ virtual bool Attach(std::string* error) {
+ *error = "transport type doesn't support attach";
+ return false;
+ }
+
+ virtual bool Detach(std::string* error) {
+ *error = "transport type doesn't support detach";
+ return false;
+ }
+
+ std::string Serial() const;
+
+ atransport* transport_ = nullptr;
static std::unique_ptr<Connection> FromFd(unique_fd fd);
};
@@ -295,6 +290,9 @@
return connection_;
}
+ bool HandleRead(std::unique_ptr<apacket> p);
+ void HandleError(const std::string& error);
+
#if ADB_HOST
void SetUsbHandle(usb_handle* h) { usb_handle_ = h; }
usb_handle* GetUsbHandle() { return usb_handle_; }
@@ -355,6 +353,11 @@
void RunDisconnects();
#if ADB_HOST
+ bool Attach(std::string* error);
+ bool Detach(std::string* error);
+#endif
+
+#if ADB_HOST
// Returns true if |target| matches this transport. A matching |target| can be any of:
// * <serial>
// * <devpath>
diff --git a/transport_fd.cpp b/transport_fd.cpp
index b9b4f42..d88d57d 100644
--- a/transport_fd.cpp
+++ b/transport_fd.cpp
@@ -121,7 +121,7 @@
packet->msg = *read_header_;
packet->payload = std::move(payload);
read_header_ = nullptr;
- read_callback_(this, std::move(packet));
+ transport_->HandleRead(std::move(packet));
}
}
}
@@ -145,7 +145,7 @@
thread_ = std::thread([this]() {
std::string error = "connection closed";
Run(&error);
- this->error_callback_(this, error);
+ transport_->HandleError(error);
});
}