adb: relax serial matching rules.
Currently targeting a device by serial requires matching the serial
number exactly. This CL relaxes the matching rules for local transports
to ignore protocol prefixes and make the port optional:
[tcp:|udp:]<hostname>[:port]
The purpose of this is to allow a user to set ANDROID_SERIAL to
something like "tcp:100.100.100.100" and have it work for both fastboot
and adb (assuming the device comes up at 100.100.100.100 in both
modes).
This CL also adds some unit tests for the modified functions to make
sure they work as expected.
Bug: 27340240
Change-Id: I006e0c70c84331ab44d05d0a0f462d06592eb879
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index d8e4e93..c083ee1 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -26,6 +26,8 @@
#include <unistd.h>
#include <algorithm>
+#include <string>
+#include <vector>
#if !ADB_HOST
#include "cutils/properties.h"
@@ -623,43 +625,43 @@
#if ADB_HOST
-#define PREFIX(str) { str, sizeof(str) - 1 }
-static const struct prefix_struct {
- const char *str;
- const size_t len;
-} prefixes[] = {
- PREFIX("usb:"),
- PREFIX("product:"),
- PREFIX("model:"),
- PREFIX("device:"),
-};
-static const int num_prefixes = (sizeof(prefixes) / sizeof(prefixes[0]));
+namespace internal {
-/* skip_host_serial return the position in a string
- skipping over the 'serial' parameter in the ADB protocol,
- where parameter string may be a host:port string containing
- the protocol delimiter (colon). */
-static char *skip_host_serial(char *service) {
- char *first_colon, *serial_end;
- int i;
+// Returns the position in |service| following the target serial parameter. Serial format can be
+// any of:
+// * [tcp:|udp:]<serial>[:<port>]:<command>
+// * <prefix>:<serial>:<command>
+// Where <port> must be a base-10 number and <prefix> may be any of {usb,product,model,device}.
+//
+// The returned pointer will point to the ':' just before <command>, or nullptr if not found.
+char* skip_host_serial(const char* service) {
+ static const std::vector<std::string>& prefixes =
+ *(new std::vector<std::string>{"usb:", "product:", "model:", "device:"});
- for (i = 0; i < num_prefixes; i++) {
- if (!strncmp(service, prefixes[i].str, prefixes[i].len))
- return strchr(service + prefixes[i].len, ':');
+ for (const std::string& prefix : prefixes) {
+ if (!strncmp(service, prefix.c_str(), prefix.length())) {
+ return strchr(service + prefix.length(), ':');
+ }
}
- first_colon = strchr(service, ':');
+ // For fastboot compatibility, ignore protocol prefixes.
+ if (!strncmp(service, "tcp:", 4) || !strncmp(service, "udp:", 4)) {
+ service += 4;
+ }
+
+ char* first_colon = strchr(service, ':');
if (!first_colon) {
- /* No colon in service string. */
- return NULL;
+ // No colon in service string.
+ return nullptr;
}
- serial_end = first_colon;
+
+ char* serial_end = first_colon;
if (isdigit(serial_end[1])) {
serial_end++;
- while ((*serial_end) && isdigit(*serial_end)) {
+ while (*serial_end && isdigit(*serial_end)) {
serial_end++;
}
- if ((*serial_end) != ':') {
+ if (*serial_end != ':') {
// Something other than numbers was found, reset the end.
serial_end = first_colon;
}
@@ -667,6 +669,8 @@
return serial_end;
}
+} // namespace internal
+
#endif // ADB_HOST
static int smart_socket_enqueue(asocket *s, apacket *p)
@@ -725,7 +729,7 @@
service += strlen("host-serial:");
// serial number should follow "host:" and could be a host:port string.
- serial_end = skip_host_serial(service);
+ serial_end = internal::skip_host_serial(service);
if (serial_end) {
*serial_end = 0; // terminate string
serial = service;