Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b4709c2c authored by David Pursell's avatar David Pursell Committed by Gerrit Code Review
Browse files

Merge "adb: relax serial matching rules."

parents 543093cb 3f902aad
Loading
Loading
Loading
Loading
+9 −0
Original line number Original line Diff line number Diff line
@@ -114,4 +114,13 @@ asocket *create_remote_socket(unsigned id, atransport *t);
void connect_to_remote(asocket *s, const char *destination);
void connect_to_remote(asocket *s, const char *destination);
void connect_to_smartsocket(asocket *s);
void connect_to_smartsocket(asocket *s);


// Internal functions that are only made available here for testing purposes.
namespace internal {

#if ADB_HOST
char* skip_host_serial(const char* service);
#endif

}  // namespace internal

#endif  // __ADB_SOCKET_H
#endif  // __ADB_SOCKET_H
+46 −0
Original line number Original line Diff line number Diff line
@@ -270,3 +270,49 @@ TEST_F(LocalSocketTest, close_socket_in_CLOSE_WAIT_state) {
}
}


#endif  // defined(__linux__)
#endif  // defined(__linux__)

#if ADB_HOST

// Checks that skip_host_serial(serial) returns a pointer to the part of |serial| which matches
// |expected|, otherwise logs the failure to gtest.
void VerifySkipHostSerial(const std::string& serial, const char* expected) {
    const char* result = internal::skip_host_serial(serial.c_str());
    if (expected == nullptr) {
        EXPECT_EQ(nullptr, result);
    } else {
        EXPECT_STREQ(expected, result);
    }
}

// Check [tcp:|udp:]<serial>[:<port>]:<command> format.
TEST(socket_test, test_skip_host_serial) {
    for (const std::string& protocol : {"", "tcp:", "udp:"}) {
        VerifySkipHostSerial(protocol, nullptr);
        VerifySkipHostSerial(protocol + "foo", nullptr);

        VerifySkipHostSerial(protocol + "foo:bar", ":bar");
        VerifySkipHostSerial(protocol + "foo:bar:baz", ":bar:baz");

        VerifySkipHostSerial(protocol + "foo:123:bar", ":bar");
        VerifySkipHostSerial(protocol + "foo:123:456", ":456");
        VerifySkipHostSerial(protocol + "foo:123:bar:baz", ":bar:baz");

        // Don't register a port unless it's all numbers and ends with ':'.
        VerifySkipHostSerial(protocol + "foo:123", ":123");
        VerifySkipHostSerial(protocol + "foo:123bar:baz", ":123bar:baz");
    }
}

// Check <prefix>:<serial>:<command> format.
TEST(socket_test, test_skip_host_serial_prefix) {
    for (const std::string& prefix : {"usb:", "product:", "model:", "device:"}) {
        VerifySkipHostSerial(prefix, nullptr);
        VerifySkipHostSerial(prefix + "foo", nullptr);

        VerifySkipHostSerial(prefix + "foo:bar", ":bar");
        VerifySkipHostSerial(prefix + "foo:bar:baz", ":bar:baz");
        VerifySkipHostSerial(prefix + "foo:123:bar", ":123:bar");
    }
}

#endif  // ADB_HOST
+33 −29
Original line number Original line Diff line number Diff line
@@ -26,6 +26,8 @@
#include <unistd.h>
#include <unistd.h>


#include <algorithm>
#include <algorithm>
#include <string>
#include <vector>


#if !ADB_HOST
#if !ADB_HOST
#include "cutils/properties.h"
#include "cutils/properties.h"
@@ -623,43 +625,43 @@ static unsigned unhex(unsigned char *s, int len)


#if ADB_HOST
#if ADB_HOST


#define PREFIX(str) { str, sizeof(str) - 1 }
namespace internal {
static const struct prefix_struct {

    const char *str;
// Returns the position in |service| following the target serial parameter. Serial format can be
    const size_t len;
// any of:
} prefixes[] = {
//   * [tcp:|udp:]<serial>[:<port>]:<command>
    PREFIX("usb:"),
//   * <prefix>:<serial>:<command>
    PREFIX("product:"),
// Where <port> must be a base-10 number and <prefix> may be any of {usb,product,model,device}.
    PREFIX("model:"),
//
    PREFIX("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 int num_prefixes = (sizeof(prefixes) / sizeof(prefixes[0]));
    static const std::vector<std::string>& prefixes =
        *(new std::vector<std::string>{"usb:", "product:", "model:", "device:"});


/* skip_host_serial return the position in a string
    for (const std::string& prefix : prefixes) {
   skipping over the 'serial' parameter in the ADB protocol,
        if (!strncmp(service, prefix.c_str(), prefix.length())) {
   where parameter string may be a host:port string containing
            return strchr(service + prefix.length(), ':');
   the protocol delimiter (colon). */
        }
static char *skip_host_serial(char *service) {
    }
    char *first_colon, *serial_end;
    int i;


    for (i = 0; i < num_prefixes; i++) {
    // For fastboot compatibility, ignore protocol prefixes.
        if (!strncmp(service, prefixes[i].str, prefixes[i].len))
    if (!strncmp(service, "tcp:", 4) || !strncmp(service, "udp:", 4)) {
            return strchr(service + prefixes[i].len, ':');
        service += 4;
    }
    }


    first_colon = strchr(service, ':');
    char* first_colon = strchr(service, ':');
    if (!first_colon) {
    if (!first_colon) {
        /* No colon in service string. */
        // No colon in service string.
        return NULL;
        return nullptr;
    }
    }
    serial_end = first_colon;

    char* serial_end = first_colon;
    if (isdigit(serial_end[1])) {
    if (isdigit(serial_end[1])) {
        serial_end++;
        serial_end++;
        while ((*serial_end) && isdigit(*serial_end)) {
        while (*serial_end && isdigit(*serial_end)) {
            serial_end++;
            serial_end++;
        }
        }
        if ((*serial_end) != ':') {
        if (*serial_end != ':') {
            // Something other than numbers was found, reset the end.
            // Something other than numbers was found, reset the end.
            serial_end = first_colon;
            serial_end = first_colon;
        }
        }
@@ -667,6 +669,8 @@ static char *skip_host_serial(char *service) {
    return serial_end;
    return serial_end;
}
}


}  // namespace internal

#endif // ADB_HOST
#endif // ADB_HOST


static int smart_socket_enqueue(asocket *s, apacket *p)
static int smart_socket_enqueue(asocket *s, apacket *p)
@@ -725,7 +729,7 @@ static int smart_socket_enqueue(asocket *s, apacket *p)
        service += strlen("host-serial:");
        service += strlen("host-serial:");


        // serial number should follow "host:" and could be a host:port string.
        // 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) {
        if (serial_end) {
            *serial_end = 0; // terminate string
            *serial_end = 0; // terminate string
            serial = service;
            serial = service;
+39 −5
Original line number Original line Diff line number Diff line
@@ -30,6 +30,7 @@
#include <list>
#include <list>


#include <android-base/logging.h>
#include <android-base/logging.h>
#include <android-base/parsenetaddress.h>
#include <android-base/stringprintf.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/strings.h>


@@ -679,11 +680,7 @@ atransport* acquire_one_transport(TransportType type, const char* serial,


        // Check for matching serial number.
        // Check for matching serial number.
        if (serial) {
        if (serial) {
            if ((t->serial && !strcmp(serial, t->serial)) ||
            if (t->MatchesTarget(serial)) {
                (t->devpath && !strcmp(serial, t->devpath)) ||
                qual_match(serial, "product:", t->product, false) ||
                qual_match(serial, "model:", t->model, true) ||
                qual_match(serial, "device:", t->device, false)) {
                if (result) {
                if (result) {
                    *error_out = "more than one device";
                    *error_out = "more than one device";
                    if (is_ambiguous) *is_ambiguous = true;
                    if (is_ambiguous) *is_ambiguous = true;
@@ -837,6 +834,43 @@ void atransport::RunDisconnects() {
    disconnects_.clear();
    disconnects_.clear();
}
}


bool atransport::MatchesTarget(const std::string& target) const {
    if (serial) {
        if (target == serial) {
            return true;
        } else if (type == kTransportLocal) {
            // Local transports can match [tcp:|udp:]<hostname>[:port].
            const char* local_target_ptr = target.c_str();

            // For fastboot compatibility, ignore protocol prefixes.
            if (android::base::StartsWith(target, "tcp:") ||
                    android::base::StartsWith(target, "udp:")) {
                local_target_ptr += 4;
            }

            // 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)) {
                // |target| may omit the port to default to ours.
                std::string target_host;
                int target_port = serial_port;
                if (android::base::ParseNetAddress(local_target_ptr, &target_host, &target_port,
                                                   nullptr, &error) &&
                        serial_host == target_host && serial_port == target_port) {
                    return true;
                }
            }
        }
    }

    return (devpath && target == devpath) ||
           qual_match(target.c_str(), "product:", product, false) ||
           qual_match(target.c_str(), "model:", model, true) ||
           qual_match(target.c_str(), "device:", device, false);
}

#if ADB_HOST
#if ADB_HOST


static void append_transport_info(std::string* result, const char* key,
static void append_transport_info(std::string* result, const char* key,
+15 −0
Original line number Original line Diff line number Diff line
@@ -107,6 +107,21 @@ public:
    void RemoveDisconnect(adisconnect* disconnect);
    void RemoveDisconnect(adisconnect* disconnect);
    void RunDisconnects();
    void RunDisconnects();


    // Returns true if |target| matches this transport. A matching |target| can be any of:
    //   * <serial>
    //   * <devpath>
    //   * product:<product>
    //   * model:<model>
    //   * device:<device>
    //
    // If this is a local transport, serial will also match [tcp:|udp:]<hostname>[:port] targets.
    // For example, serial "100.100.100.100:5555" would match any of:
    //   * 100.100.100.100
    //   * tcp:100.100.100.100
    //   * udp:100.100.100.100:5555
    // This is to make it easier to use the same network target for both fastboot and adb.
    bool MatchesTarget(const std::string& target) const;

private:
private:
    // A set of features transmitted in the banner with the initial connection.
    // A set of features transmitted in the banner with the initial connection.
    // This is stored in the banner as 'features=feature0,feature1,etc'.
    // This is stored in the banner as 'features=feature0,feature1,etc'.
Loading