aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-12-14 00:21:32 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-12-14 00:21:32 +0000
commit239f50475f08dcfcbe60a36ede2531d95f955ecc (patch)
tree91fe78d0f3ff0afcf63e748e452a71280184895e
parent16a4667d519096859c6cdc596aafed227b17c0cc (diff)
parent123fe0d6e21c1d80781dc525220016afb55a4690 (diff)
downloadadb-android14-qpr2-s1-release.tar.gz
Change-Id: I500cfef72ccc114e78e6424c4dfc16f42bfceef5
-rw-r--r--Android.bp13
-rw-r--r--SERVICES.TXT10
-rw-r--r--adb.cpp9
-rw-r--r--client/commandline.cpp18
-rw-r--r--client/usb_libusb.cpp76
-rw-r--r--proto/Android.bp44
-rw-r--r--proto/devices.proto61
-rw-r--r--services.cpp8
-rw-r--r--sockets.cpp3
-rwxr-xr-xtest_device.py105
-rw-r--r--transport.cpp95
-rw-r--r--transport.h21
12 files changed, 432 insertions, 31 deletions
diff --git a/Android.bp b/Android.bp
index 34270798..2a0a6a8e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -310,6 +310,7 @@ cc_library_host_static {
"libcrypto_utils",
"libcutils",
"libdiagnose_usb",
+ "libdevices_protos",
"liblog",
"libmdnssd",
"libopenscreen-discovery",
@@ -379,12 +380,13 @@ cc_test_host {
"libcrypto",
"libcrypto_utils",
"libcutils",
+ "libdevices_protos",
"libdiagnose_usb",
"liblog",
"libmdnssd",
"libopenscreen-discovery",
"libopenscreen-platform-impl",
- "libprotobuf-cpp-lite",
+ "libprotobuf-cpp-full",
"libssl",
"libusb",
],
@@ -447,6 +449,7 @@ cc_binary_host {
"libcrypto_utils",
"libcutils",
"libdiagnose_usb",
+ "libdevices_protos",
"libfastdeploy_host",
"liblog",
"liblog",
@@ -889,10 +892,15 @@ python_test_host {
name: "adb_integration_test_device",
main: "test_device.py",
srcs: [
+ "proto/devices.proto",
"test_device.py",
],
+ proto: {
+ canonical_path_from_root: false,
+ },
libs: [
"adb_py",
+ "libprotobuf-python",
],
test_config: "adb_integration_test_device.xml",
test_suites: ["general-tests"],
@@ -974,13 +982,14 @@ cc_test_host {
"libcrypto",
"libcrypto_utils",
"libcutils",
+ "libdevices_protos",
"libdiagnose_usb",
"libfastdeploy_host",
"liblog",
"libmdnssd",
"libopenscreen-discovery",
"libopenscreen-platform-impl",
- "libprotobuf-cpp-lite",
+ "libprotobuf-cpp-full",
"libssl",
"libusb",
"libutils",
diff --git a/SERVICES.TXT b/SERVICES.TXT
index c8d06a32..380f2cf0 100644
--- a/SERVICES.TXT
+++ b/SERVICES.TXT
@@ -21,12 +21,14 @@ host:devices-l
the connection is closed
host:track-devices
- This is a variant of host:devices which doesn't close the
+host:track-devices-proto-binary
+host:track-devices-proto-text
+ These are variants of host:devices which doesn't close the
connection. Instead, a new device list description is sent
each time a device is added/removed or the state of a given
- device changes (hex4 + content). This allows tools like DDMS
- to track the state of connected devices in real-time without
- polling the server repeatedly.
+ device changes.
+ Variant [-proto-binary] is binary protobuf format.
+ Variant [-proto-text] is text protobuf format.
host:emulator:<port>
This is a special query that is sent to the ADB server when a
diff --git a/adb.cpp b/adb.cpp
index bb077a0e..f2cf8fc7 100644
--- a/adb.cpp
+++ b/adb.cpp
@@ -1326,9 +1326,14 @@ HostRequestResult handle_host_request(std::string_view service, TransportType ty
// return a list of all connected devices
if (service == "devices" || service == "devices-l") {
- bool long_listing = service == "devices-l";
+ TrackerOutputType output_type;
+ if (service == "devices-l") {
+ output_type = LONG_TEXT;
+ } else {
+ output_type = SHORT_TEXT;
+ }
D("Getting device list...");
- std::string device_list = list_transports(long_listing);
+ std::string device_list = list_transports(output_type);
D("Sending device list...");
SendOkay(reply_fd, device_list);
return HostRequestResult::Handled;
diff --git a/client/commandline.cpp b/client/commandline.cpp
index 8d3af7a8..781c6d5a 100644
--- a/client/commandline.cpp
+++ b/client/commandline.cpp
@@ -2068,10 +2068,22 @@ int adb_commandline(int argc, const char** argv) {
TrackAppStreamsCallback callback;
return adb_connect_command("track-app", nullptr, &callback);
} else if (!strcmp(argv[0], "track-devices")) {
- if (argc > 2 || (argc == 2 && strcmp(argv[1], "-l"))) {
- error_exit("usage: adb track-devices [-l]");
+ const char* listopt;
+ if (argc < 2) {
+ listopt = "";
+ } else {
+ if (!strcmp(argv[1], "-l")) {
+ listopt = argv[1];
+ } else if (!strcmp(argv[1], "--proto-text")) {
+ listopt = "-proto-text";
+ } else if (!strcmp(argv[1], "--proto-binary")) {
+ listopt = "-proto-binary";
+ } else {
+ error_exit("usage: adb track-devices [-l][--proto-text][--proto-binary]");
+ }
}
- return adb_connect_command(argc == 2 ? "host:track-devices-l" : "host:track-devices");
+ std::string query = android::base::StringPrintf("host:track-devices%s", listopt);
+ return adb_connect_command(query);
} else if (!strcmp(argv[0], "raw")) {
if (argc != 2) {
error_exit("usage: adb raw SERVICE");
diff --git a/client/usb_libusb.cpp b/client/usb_libusb.cpp
index 2f3a4265..4244225c 100644
--- a/client/usb_libusb.cpp
+++ b/client/usb_libusb.cpp
@@ -490,6 +490,74 @@ struct LibusbConnection : public Connection {
return serial;
}
+ // libusb gives us an int which is a value from 'enum libusb_speed'
+ static ConnectionSpeed ToConnectionSpeed(int speed) {
+ switch (speed) {
+ case LIBUSB_SPEED_LOW:
+ return USB1_0;
+ case LIBUSB_SPEED_FULL:
+ return USB2_0_FULL;
+ case LIBUSB_SPEED_HIGH:
+ return USB2_0_HIGH;
+ case LIBUSB_SPEED_SUPER:
+ return USB3_0;
+ case LIBUSB_SPEED_SUPER_PLUS:
+ return USB3_1;
+ case LIBUSB_SPEED_UNKNOWN:
+ default:
+ return UNKNOWN;
+ }
+ }
+
+ // libusb gives us a bitfield made of 'enum libusb_supported_speed' values
+ static ConnectionSpeed ExtractMaxSpeed(uint16_t wSpeedSupported) {
+ if (wSpeedSupported == 0) {
+ return UNKNOWN;
+ }
+
+ int msb = 0;
+ while (wSpeedSupported >>= 1) {
+ msb++;
+ }
+
+ switch (1 << msb) {
+ case LIBUSB_LOW_SPEED_OPERATION:
+ return USB1_0;
+ case LIBUSB_FULL_SPEED_OPERATION:
+ return USB2_0_FULL;
+ case LIBUSB_HIGH_SPEED_OPERATION:
+ return USB2_0_HIGH;
+ case LIBUSB_SUPER_SPEED_OPERATION:
+ return USB3_0;
+ default:
+ return UNKNOWN;
+ }
+ }
+
+ void RetrieveSpeeds() {
+ negotiated_speed_ = ToConnectionSpeed(libusb_get_device_speed(device_.get()));
+
+ // The set of supported speed is in a SuperSpeed capability
+ struct libusb_bos_descriptor* bos = nullptr;
+ if (!libusb_get_bos_descriptor(device_handle_.get(), &bos)) {
+ for (int i = 0; i < bos->bNumDeviceCaps; i++) {
+ if (bos->dev_capability[i]->bDevCapabilityType !=
+ LIBUSB_BT_SS_USB_DEVICE_CAPABILITY) {
+ continue;
+ }
+
+ libusb_ss_usb_device_capability_descriptor* ss_usb_device_cap = nullptr;
+ int r = libusb_get_ss_usb_device_capability_descriptor(
+ nullptr, bos->dev_capability[i], &ss_usb_device_cap);
+ if (!r) {
+ max_speed_ = ExtractMaxSpeed(ss_usb_device_cap->wSpeedSupported);
+ libusb_free_ss_usb_device_capability_descriptor(ss_usb_device_cap);
+ }
+ }
+ libusb_free_bos_descriptor(bos);
+ }
+ }
+
bool OpenDevice(std::string* error) {
if (device_handle_) {
LOG_ERR(error, "device already open");
@@ -545,6 +613,7 @@ struct LibusbConnection : public Connection {
}
}
+ RetrieveSpeeds();
return true;
}
@@ -763,6 +832,10 @@ struct LibusbConnection : public Connection {
return connection;
}
+ virtual ConnectionSpeed MaxSpeedMbps() override final { return max_speed_; }
+
+ virtual ConnectionSpeed NegotiatedSpeedMbps() override final { return negotiated_speed_; }
+
unique_device device_;
unique_device_handle device_handle_;
std::string device_address_;
@@ -788,6 +861,9 @@ struct LibusbConnection : public Connection {
std::condition_variable destruction_cv_;
size_t zero_mask_ = 0;
+
+ ConnectionSpeed negotiated_speed_ = UNKNOWN;
+ ConnectionSpeed max_speed_ = UNKNOWN;
};
static std::mutex usb_handles_mutex [[clang::no_destroy]];
diff --git a/proto/Android.bp b/proto/Android.bp
index fae321f2..383e4a70 100644
--- a/proto/Android.bp
+++ b/proto/Android.bp
@@ -143,3 +143,47 @@ cc_library_host_static {
type: "full",
},
}
+
+cc_defaults {
+ name: "libdevices_protos_defaults",
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Wthread-safety",
+ "-Werror",
+ ],
+
+ compile_multilib: "both",
+
+ srcs: [
+ "devices.proto",
+ ],
+ target: {
+ windows: {
+ compile_multilib: "first",
+ enabled: true,
+ },
+ },
+
+ visibility: [
+ "//packages/modules/adb:__subpackages__",
+ ],
+
+ stl: "libc++_static",
+
+ apex_available: [
+ "com.android.adbd",
+ "test_com.android.adbd",
+ ],
+}
+
+cc_library_host_static {
+ name: "libdevices_protos",
+ defaults: ["libdevices_protos_defaults"],
+
+ proto: {
+ export_proto_headers: true,
+ type: "full",
+ },
+}
+
diff --git a/proto/devices.proto b/proto/devices.proto
new file mode 100644
index 00000000..48ebadf8
--- /dev/null
+++ b/proto/devices.proto
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto3";
+
+option java_package = "com.android.server.adb.protos";
+option java_outer_classname = "DevicesProto";
+
+package adb.proto;
+
+// This mirrors adb.h's "enum ConnectionState"
+enum ConnectionState {
+ ANY = 0;
+ CONNECTING = 1;
+ AUTHORIZING = 2;
+ UNAUTHORIZED = 3;
+ NOPERMISSION = 4;
+ DETACHED = 5;
+ OFFLINE = 6;
+ BOOTLOADER = 7;
+ DEVICE = 8;
+ HOST = 9;
+ RECOVERY = 10;
+ SIDELOAD = 11;
+ RESCUE = 12;
+}
+
+enum ConnectionType {
+ UNKNOWN = 0;
+ USB = 1;
+ SOCKET = 2;
+}
+
+message Device {
+ string serial = 1;
+ ConnectionState state = 2;
+ string bus_address = 3;
+ string product = 4;
+ string model = 5;
+ string device = 6;
+ ConnectionType connection_type = 7;
+ int64 negotiated_speed = 8;
+ int64 max_speed = 9;
+}
+
+message Devices {
+ repeated Device device = 1;
+}
diff --git a/services.cpp b/services.cpp
index 0c3d061d..2e9499f4 100644
--- a/services.cpp
+++ b/services.cpp
@@ -250,9 +250,13 @@ static void wait_service(unique_fd fd, std::string serial, TransportId transport
asocket* host_service_to_socket(std::string_view name, std::string_view serial,
TransportId transport_id) {
if (name == "track-devices") {
- return create_device_tracker(false);
+ return create_device_tracker(SHORT_TEXT);
} else if (name == "track-devices-l") {
- return create_device_tracker(true);
+ return create_device_tracker(LONG_TEXT);
+ } else if (name == "track-devices-proto-binary") {
+ return create_device_tracker(PROTOBUF);
+ } else if (name == "track-devices-proto-text") {
+ return create_device_tracker(TEXT_PROTOBUF);
} else if (android::base::ConsumePrefix(&name, "wait-for-")) {
std::string spec(name);
unique_fd fd =
diff --git a/sockets.cpp b/sockets.cpp
index 87905cdb..e10f710e 100644
--- a/sockets.cpp
+++ b/sockets.cpp
@@ -879,7 +879,8 @@ static int smart_socket_enqueue(asocket* s, apacket::payload_type data) {
s2 = host_service_to_socket(service, serial, transport_id);
if (s2 == nullptr) {
LOG(VERBOSE) << "SS(" << s->id << "): couldn't create host service '" << service << "'";
- SendFail(s->peer->fd, "unknown host service");
+ std::string msg = std::string("unknown host service '") + std::string(service) + "'";
+ SendFail(s->peer->fd, msg);
goto fail;
}
diff --git a/test_device.py b/test_device.py
index c606adf2..20cd98da 100755
--- a/test_device.py
+++ b/test_device.py
@@ -19,6 +19,7 @@ from __future__ import print_function
import contextlib
import hashlib
+import io
import os
import posixpath
import random
@@ -35,6 +36,8 @@ import threading
import time
import unittest
+import proto.devices_pb2 as proto_devices
+
from datetime import datetime
import adb
@@ -1761,15 +1764,107 @@ class WindowsConsoleTest(DeviceTest):
console_output = read_screen(screen)
self.assertEqual(unicode_string, console_output)
+class DevicesListing(DeviceTest):
+
+ serial = subprocess.check_output(['adb', 'get-serialno']).strip().decode("utf-8")
+ # def get_serial(self):
+ # return subprocess.check_output(self.device.adb_cmd + ['get-serialno']).strip().decode("utf-8")
+
+ def test_devices(self):
+ proc = subprocess.Popen(['adb', 'devices'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+ lines = list(map(lambda b: b.decode("utf-8"), proc.stdout.readlines()))
+ self.assertEqual(len(lines), 3)
+ line = lines[1]
+ self.assertTrue(self.serial in line)
+ self.assertFalse("{" in line)
+ self.assertFalse("}" in line)
+ self.assertTrue("device" in line)
+ self.assertFalse("product" in line)
+ self.assertFalse("transport" in line)
+
+ def test_devices_l(self):
+ proc = subprocess.Popen(['adb', 'devices', '-l'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+ lines = list(map(lambda b: b.decode("utf-8"), proc.stdout.readlines()))
+ self.assertEqual(len(lines), 3)
+ line = lines[1]
+ self.assertTrue(self.serial in line)
+ self.assertFalse("{" in line)
+ self.assertFalse("}" in line)
+ self.assertTrue("device" in line)
+ self.assertTrue("product" in line)
+ self.assertTrue("transport" in line)
+
+ def test_track_devices(self):
+ proc = subprocess.Popen(['adb', 'track-devices'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+ reader = io.TextIOWrapper(proc.stdout, encoding='utf8')
+ output_size = int(reader.read(4), 16)
+ output = reader.read(output_size)
+ self.assertFalse("{" in output)
+ self.assertFalse("}" in output)
+ self.assertTrue(self.serial in output)
+ self.assertTrue("device" in output)
+ self.assertFalse("product" in output)
+ self.assertFalse("transport" in output)
+
+ def test_track_devices_l(self):
+ proc = subprocess.Popen(['adb', 'track-devices', '-l'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+ reader = io.TextIOWrapper(proc.stdout, encoding='utf8')
+ output_size = int(reader.read(4), 16)
+ output = reader.read(output_size)
+ self.assertFalse("{" in output)
+ self.assertFalse("}" in output)
+ self.assertTrue(self.serial in output)
+ self.assertTrue("device" in output)
+ self.assertTrue("product" in output)
+ self.assertTrue("transport" in output)
+
+ def test_track_devices_proto_text(self):
+ proc = subprocess.Popen(['adb', 'track-devices', '--proto-text'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+ reader = io.TextIOWrapper(proc.stdout, encoding='utf8')
+ output_size = int(reader.read(4), 16)
+ output = reader.read(output_size)
+ self.assertTrue("{" in output)
+ self.assertTrue("}" in output)
+ self.assertTrue(self.serial in output)
+ self.assertTrue("device" in output)
+ self.assertTrue("product" in output)
+ self.assertTrue("connection_type" in output)
+
+ def test_track_devices_proto_binary(self):
+ proc = subprocess.Popen(['adb', 'track-devices', '--proto-binary'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+
+ output_size = int(proc.stdout.read(4).decode("utf-8"), 16)
+ proto = proc.stdout.read(output_size)
+
+ devices = proto_devices.Devices()
+ devices.ParseFromString(proto)
+
+ device = devices.device[0]
+ self.assertTrue(device.serial == self.serial)
+ self.assertFalse(device.bus_address == "")
+ self.assertFalse(device.product == "")
+ self.assertFalse(device.model == "")
+ self.assertFalse(device.device == "")
+ self.assertTrue(device.negotiated_speed == int(device.negotiated_speed))
+ self.assertTrue(device.max_speed == int(device.max_speed))
def main():
random.seed(0)
- if len(adb.get_devices()) > 0:
- suite = unittest.TestLoader().loadTestsFromName(__name__)
- unittest.TextTestRunner(verbosity=3).run(suite)
- else:
+ if len(adb.get_devices()) == 0:
print('Test suite must be run with attached devices')
+ return
+
+ # Run only specific test if given on command-line e.g:
+ # ./test_device.py ForwardReverseTest
+ # ./test_device.py ForwardReverseTest.test_forward_no_rebind
+ if len(sys.argv) == 2:
+ test_name = "." + sys.argv[1]
+ else:
+ test_name = ""
+
+ suite = unittest.TestLoader().loadTestsFromName("__main__" + test_name)
+ unittest.TextTestRunner(verbosity=3).run(suite)
if __name__ == '__main__':
- main()
+ main() \ No newline at end of file
diff --git a/transport.cpp b/transport.cpp
index 5f06f291..71756d36 100644
--- a/transport.cpp
+++ b/transport.cpp
@@ -56,7 +56,9 @@
#include "sysdeps/chrono.h"
#if ADB_HOST
+#include <google/protobuf/text_format.h>
#include "client/usb.h"
+#include "devices.pb.h"
#endif
using namespace adb::crypto;
@@ -95,6 +97,7 @@ const char* const kFeatureSendRecv2DryRunSend = "sendrecv_v2_dry_run_send";
const char* const kFeatureDelayedAck = "delayed_ack";
// TODO(joshuaduong): Bump to v2 when openscreen discovery is enabled by default
const char* const kFeatureOpenscreenMdns = "openscreen_mdns";
+const char* const kFeatureDeviceTrackerProtoFormat = "devicetracker_proto_format";
namespace {
@@ -602,7 +605,7 @@ void kick_transport(atransport* t, bool reset) {
struct device_tracker {
asocket socket;
bool update_needed = false;
- bool long_output = false;
+ TrackerOutputType output_type = SHORT_TEXT;
device_tracker* next = nullptr;
};
@@ -662,11 +665,11 @@ static void device_tracker_ready(asocket* socket) {
// for the first time, even if no update occurred.
if (tracker->update_needed) {
tracker->update_needed = false;
- device_tracker_send(tracker, list_transports(tracker->long_output));
+ device_tracker_send(tracker, list_transports(tracker->output_type));
}
}
-asocket* create_device_tracker(bool long_output) {
+asocket* create_device_tracker(TrackerOutputType output_type) {
device_tracker* tracker = new device_tracker();
if (tracker == nullptr) LOG(FATAL) << "cannot allocate device tracker";
@@ -676,7 +679,7 @@ asocket* create_device_tracker(bool long_output) {
tracker->socket.ready = device_tracker_ready;
tracker->socket.close = device_tracker_close;
tracker->update_needed = true;
- tracker->long_output = long_output;
+ tracker->output_type = output_type;
tracker->next = device_tracker_list;
device_tracker_list = tracker;
@@ -709,7 +712,7 @@ void update_transports() {
while (tracker != nullptr) {
device_tracker* next = tracker->next;
// This may destroy the tracker if the connection is closed.
- device_tracker_send(tracker, list_transports(tracker->long_output));
+ device_tracker_send(tracker, list_transports(tracker->output_type));
tracker = next;
}
}
@@ -1202,6 +1205,7 @@ const FeatureSet& supported_features() {
kFeatureSendRecv2Zstd,
kFeatureSendRecv2DryRunSend,
kFeatureOpenscreenMdns,
+ kFeatureDeviceTrackerProtoFormat,
};
// clang-format on
@@ -1316,6 +1320,63 @@ static std::string sanitize(std::string str, bool alphanumeric) {
return str;
}
+static adb::proto::ConnectionState adbStateFromProto(ConnectionState state) {
+ switch (state) {
+ case kCsConnecting:
+ return adb::proto::ConnectionState::CONNECTING;
+ case kCsAuthorizing:
+ return adb::proto::ConnectionState::AUTHORIZING;
+ case kCsUnauthorized:
+ return adb::proto::ConnectionState::UNAUTHORIZED;
+ case kCsNoPerm:
+ return adb::proto::ConnectionState::NOPERMISSION;
+ case kCsDetached:
+ return adb::proto::ConnectionState::DETACHED;
+ case kCsOffline:
+ return adb::proto::ConnectionState::OFFLINE;
+ case kCsBootloader:
+ return adb::proto::ConnectionState::BOOTLOADER;
+ case kCsDevice:
+ return adb::proto::ConnectionState::DEVICE;
+ case kCsHost:
+ return adb::proto::ConnectionState::HOST;
+ case kCsRecovery:
+ return adb::proto::ConnectionState::RECOVERY;
+ case kCsSideload:
+ return adb::proto::ConnectionState::SIDELOAD;
+ case kCsRescue:
+ return adb::proto::ConnectionState::RESCUE;
+ case kCsAny:
+ return adb::proto::ConnectionState::ANY;
+ }
+}
+
+static std::string transportListToProto(const std::list<atransport*>& sorted_transport_list,
+ bool text_version) {
+ adb::proto::Devices devices;
+ for (const auto& t : sorted_transport_list) {
+ auto* device = devices.add_device();
+ device->set_serial(t->serial.c_str());
+ device->set_connection_type(t->type == kTransportUsb ? adb::proto::ConnectionType::USB
+ : adb::proto::ConnectionType::SOCKET);
+ device->set_state(adbStateFromProto(t->GetConnectionState()));
+ device->set_bus_address(sanitize(t->devpath, false));
+ device->set_product(sanitize(t->product, false));
+ device->set_model(sanitize(t->model, true));
+ device->set_device(sanitize(t->device, false));
+ device->set_max_speed(t->connection()->MaxSpeedMbps());
+ device->set_negotiated_speed(t->connection()->NegotiatedSpeedMbps());
+ }
+
+ std::string proto;
+ if (text_version) {
+ google::protobuf::TextFormat::PrintToString(devices, &proto);
+ } else {
+ devices.SerializeToString(&proto);
+ }
+ return proto;
+}
+
static void append_transport_info(std::string* result, const char* key, const std::string& value,
bool alphanumeric) {
if (value.empty()) {
@@ -1354,7 +1415,16 @@ static void append_transport(const atransport* t, std::string* result, bool long
*result += '\n';
}
-std::string list_transports(bool long_listing) {
+static std::string transportListToText(const std::list<atransport*>& sorted_transport_list,
+ bool long_listing) {
+ std::string result;
+ for (const auto& t : sorted_transport_list) {
+ append_transport(t, &result, long_listing);
+ }
+ return result;
+}
+
+std::string list_transports(TrackerOutputType outputType) {
std::lock_guard<std::recursive_mutex> lock(transport_lock);
auto sorted_transport_list = transport_list;
@@ -1365,11 +1435,16 @@ std::string list_transports(bool long_listing) {
return x->serial < y->serial;
});
- std::string result;
- for (const auto& t : sorted_transport_list) {
- append_transport(t, &result, long_listing);
+ switch (outputType) {
+ case SHORT_TEXT:
+ case LONG_TEXT: {
+ return transportListToText(sorted_transport_list, outputType == LONG_TEXT);
+ }
+ case PROTOBUF:
+ case TEXT_PROTOBUF: {
+ return transportListToProto(sorted_transport_list, outputType == TEXT_PROTOBUF);
+ }
}
- return result;
}
void close_usb_devices(std::function<bool(const atransport*)> predicate, bool reset) {
diff --git a/transport.h b/transport.h
index eb634ed7..97391a88 100644
--- a/transport.h
+++ b/transport.h
@@ -136,6 +136,20 @@ struct Connection {
atransport* transport_ = nullptr;
static std::unique_ptr<Connection> FromFd(unique_fd fd);
+
+ enum ConnectionSpeed {
+ UNKNOWN = 0,
+ USB1_0 = 1,
+ USB2_0_FULL = 12,
+ USB2_0_HIGH = 480,
+ USB3_0 = 5000,
+ USB3_1 = 10000,
+ USB3_2 = 20000,
+ USB4_0 = 40000,
+ };
+
+ virtual ConnectionSpeed NegotiatedSpeedMbps() { return UNKNOWN; }
+ virtual ConnectionSpeed MaxSpeedMbps() { return UNKNOWN; }
};
// Abstraction for a blocking packet transport.
@@ -474,7 +488,6 @@ bool iterate_transports(std::function<bool(const atransport*)> fn);
void init_reconnect_handler(void);
void init_mdns_transport_discovery(void);
-std::string list_transports(bool long_listing);
#if ADB_HOST
atransport* find_transport(const char* serial);
@@ -519,7 +532,11 @@ void close_usb_devices(std::function<bool(const atransport*)> predicate, bool re
void send_packet(apacket* p, atransport* t);
-asocket* create_device_tracker(bool long_output);
+#if ADB_HOST
+enum TrackerOutputType { SHORT_TEXT, LONG_TEXT, PROTOBUF, TEXT_PROTOBUF };
+asocket* create_device_tracker(TrackerOutputType type);
+std::string list_transports(TrackerOutputType type);
+#endif
#if !ADB_HOST
unique_fd adb_listen(std::string_view addr, std::string* error);