adb: allow selection of a specific transport.
Extend device selection to allow selecting a specific transport via
monotonically increasing identifier (visible in devices -l).
This is useful when using multiple devices (like hikey960...) that
have identical bogus serial numbers like 0123456789ABCDEF.
Bug: http://b/37043226
Test: adb -t {1, 2, 9999999} {get-serialno, shell, features}
Change-Id: I55e5dc5a406a4eeee0012e39b52e8cd232e608a6
diff --git a/transport.cpp b/transport.cpp
index c26252e..91d708f 100644
--- a/transport.cpp
+++ b/transport.cpp
@@ -21,6 +21,7 @@
#include <ctype.h>
#include <errno.h>
+#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -36,6 +37,7 @@
#include <android-base/quick_exit.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
+#include <android-base/thread_annotations.h>
#include "adb.h"
#include "adb_auth.h"
@@ -46,6 +48,7 @@
static void transport_unref(atransport *t);
+// TODO: unordered_map<TransportId, atransport*>
static auto& transport_list = *new std::list<atransport*>();
static auto& pending_list = *new std::list<atransport*>();
@@ -57,6 +60,11 @@
const char* const kFeatureLibusb = "libusb";
const char* const kFeaturePushSync = "push_sync";
+TransportId NextTransportId() {
+ static std::atomic<TransportId> next(1);
+ return next++;
+}
+
static std::string dump_packet(const char* name, const char* func, apacket* p) {
unsigned command = p->msg.command;
int len = p->msg.data_length;
@@ -301,6 +309,8 @@
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();
}
@@ -638,11 +648,15 @@
return !*to_test;
}
-atransport* acquire_one_transport(TransportType type, const char* serial, bool* is_ambiguous,
- std::string* error_out, bool accept_any_state) {
+atransport* acquire_one_transport(TransportType type, const char* serial, TransportId transport_id,
+ bool* is_ambiguous, std::string* error_out,
+ bool accept_any_state) {
atransport* result = nullptr;
- if (serial) {
+ if (transport_id != 0) {
+ *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) {
*error_out = "no emulators found";
@@ -661,8 +675,12 @@
continue;
}
- // Check for matching serial number.
- if (serial) {
+ if (transport_id) {
+ if (t->id == transport_id) {
+ result = t;
+ break;
+ }
+ } else if (serial) {
if (t->MatchesTarget(serial)) {
if (result) {
*error_out = "more than one device";
@@ -889,18 +907,23 @@
#if ADB_HOST
+// We use newline as our delimiter, make sure to never output it.
+static std::string sanitize(std::string str, bool alphanumeric) {
+ auto pred = alphanumeric ? [](const char c) { return !isalnum(c); }
+ : [](const char c) { return c == '\n'; };
+ std::replace_if(str.begin(), str.end(), pred, '_');
+ return str;
+}
+
static void append_transport_info(std::string* result, const char* key, const char* value,
- bool sanitize) {
+ bool alphanumeric) {
if (value == nullptr || *value == '\0') {
return;
}
*result += ' ';
*result += key;
-
- for (const char* p = value; *p; ++p) {
- result->push_back((!sanitize || isalnum(*p)) ? *p : '_');
- }
+ *result += sanitize(value, alphanumeric);
}
static void append_transport(const atransport* t, std::string* result, bool long_listing) {
@@ -920,6 +943,11 @@
append_transport_info(result, "product:", t->product, false);
append_transport_info(result, "model:", t->model, true);
append_transport_info(result, "device:", t->device, false);
+
+ // Put id at the end, so that anyone parsing the output here can always find it by scanning
+ // backwards from newlines, even with hypothetical devices named 'transport_id:1'.
+ *result += " transport_id:";
+ *result += std::to_string(t->id);
}
*result += '\n';
}