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

Commit d9d1ca47 authored by Stefan Hilzinger's avatar Stefan Hilzinger Committed by Mike Lockwood
Browse files

Let "adb connect" connect to emulators too



- adb can now connect to an emulator configured with an arbitrary
  pair of <console port, adb port>. These two ports do not have to be
  adjacent.
  This can be done from the commandline at any time using
  adb connect emu:<console_port>,<adb_port>
- Emulators running on ports outside the normal range
  (5554/5555-5584/5585) register themselves on startup if they follow
  the convention "console port+1==abd port".
- Emulators outside the normal port range will not be auto-detected on
  adb startup as these ports are not probed.
- The index into local_transports[] array in transport_local.c does no
  longer indicate the port number of the local transport. Use the altered
  atransport struct to get the port number.
- I have chosen not to document the adb connect emu:console_port,adb_port
  syntax on adb's help screen as this might be confusing to most readers
  and useful to very few.
- I don't expect this to introduce any (backwards) compatibility issues.

Change-Id: Iad3eccb2dcdde174b24ef0644d705ecfbff6e59d
Signed-off-by: default avatarMike Lockwood <lockwood@android.com>
parent 5762ec29
Loading
Loading
Loading
Loading
+99 −33
Original line number Diff line number Diff line
@@ -966,6 +966,99 @@ int adb_main(int is_daemon, int server_port)
    return 0;
}

#if ADB_HOST
void connect_device(char* host, char* buffer, int buffer_size)
{
    int port, fd;
    char* portstr = strchr(host, ':');
    char buf[4096];

    if (!portstr) {
        snprintf(buffer, buffer_size, "unable to parse %s as <host>:<port>", host);
        return;
    }
    if (find_transport(host)) {
        snprintf(buffer, buffer_size, "already connected to %s", host);
        return;
    }

    // zero terminate host by overwriting the ':'
    *portstr++ = 0;
    if (sscanf(portstr, "%d", &port) == 0) {
        snprintf(buffer, buffer_size, "bad port number %s", portstr);
        return;
    }

    fd = socket_network_client(host, port, SOCK_STREAM);
    if (fd < 0) {
        snprintf(buffer, buffer_size, "unable to connect to %s:%d", host, port);
        return;
    }

    D("client: connected on remote on fd %d\n", fd);
    close_on_exec(fd);
    disable_tcp_nagle(fd);
    snprintf(buf, sizeof buf, "%s:%d", host, port);
    register_socket_transport(fd, buf, port, 0);
    snprintf(buffer, buffer_size, "connected to %s:%d", host, port);
}

void connect_emulator(char* port_spec, char* buffer, int buffer_size)
{
    char* port_separator = strchr(port_spec, ',');
    if (!port_separator) {
        snprintf(buffer, buffer_size,
                "unable to parse '%s' as <console port>,<adb port>",
                port_spec);
        return;
    }

    // Zero-terminate console port and make port_separator point to 2nd port.
    *port_separator++ = 0;
    int console_port = strtol(port_spec, NULL, 0);
    int adb_port = strtol(port_separator, NULL, 0);
    if (!(console_port > 0 && adb_port > 0)) {
        *(port_separator - 1) = ',';
        snprintf(buffer, buffer_size,
                "Invalid port numbers: Expected positive numbers, got '%s'",
                port_spec);
        return;
    }

    /* Check if the emulator is already known.
     * Note: There's a small but harmless race condition here: An emulator not
     * present just yet could be registered by another invocation right
     * after doing this check here. However, local_connect protects
     * against double-registration too. From here, a better error message
     * can be produced. In the case of the race condition, the very specific
     * error message won't be shown, but the data doesn't get corrupted. */
    atransport* known_emulator = find_emulator_transport_by_adb_port(adb_port);
    if (known_emulator != NULL) {
        snprintf(buffer, buffer_size,
                "Emulator on port %d already registered.", adb_port);
        return;
    }

    /* Check if more emulators can be registered. Similar unproblematic
     * race condition as above. */
    int candidate_slot = get_available_local_transport_index();
    if (candidate_slot < 0) {
        snprintf(buffer, buffer_size, "Cannot accept more emulators.");
        return;
    }

    /* Preconditions met, try to connect to the emulator. */
    if (!local_connect_arbitrary_ports(console_port, adb_port)) {
        snprintf(buffer, buffer_size,
                "Connected to emulator on ports %d,%d", console_port, adb_port);
    } else {
        snprintf(buffer, buffer_size,
                "Could not connect to emulator on ports %d,%d",
                console_port, adb_port);
    }
}
#endif

int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s)
{
    atransport *transport = NULL;
@@ -1023,43 +1116,16 @@ int handle_host_request(char *service, transport_type ttype, char* serial, int r
        return 0;
    }

    // add a new TCP transport
    // add a new TCP transport, device or emulator
    if (!strncmp(service, "connect:", 8)) {
        char buffer[4096];
        int port, fd;
        char* host = service + 8;
        char* portstr = strchr(host, ':');

        if (!portstr) {
            snprintf(buffer, sizeof(buffer), "unable to parse %s as <host>:<port>", host);
            goto done;
        }
        if (find_transport(host)) {
            snprintf(buffer, sizeof(buffer), "Already connected to %s", host);
            goto done;
        }

        // zero terminate host by overwriting the ':'
        *portstr++ = 0;
        if (sscanf(portstr, "%d", &port) == 0) {
            snprintf(buffer, sizeof(buffer), "bad port number %s", portstr);
            goto done;
        }

        fd = socket_network_client(host, port, SOCK_STREAM);
        if (fd < 0) {
            snprintf(buffer, sizeof(buffer), "unable to connect to %s:%d", host, port);
            goto done;
        if (!strncmp(host, "emu:", 4)) {
            connect_emulator(host + 4, buffer, sizeof(buffer));
        } else {
            connect_device(host, buffer, sizeof(buffer));
        }

        D("client: connected on remote on fd %d\n", fd);
        close_on_exec(fd);
        disable_tcp_nagle(fd);
        snprintf(buf, sizeof buf, "%s:%d", host, port);
        register_socket_transport(fd, buf, port, 0);
        snprintf(buffer, sizeof(buffer), "connected to %s:%d", host, port);

done:
        // Send response for emulator and device
        snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer), buffer);
        writex(reply_fd, buf, strlen(buf));
        return 0;
+8 −0
Original line number Diff line number Diff line
@@ -183,6 +183,7 @@ struct atransport
        /* used to identify transports for clients */
    char *serial;
    char *product;
    int adb_port; // Use for emulators (local transport)

        /* a list of adisconnect callbacks called when the transport is kicked */
    int          kicked;
@@ -262,6 +263,9 @@ void run_transport_disconnects( atransport* t );
void   kick_transport( atransport*  t );

/* initialize a transport object's func pointers and state */
#if ADB_HOST
int get_available_local_transport_index();
#endif
int  init_socket_transport(atransport *t, int s, int port, int local);
void init_usb_transport(atransport *t, usb_handle *usb, int state);

@@ -280,6 +284,9 @@ void register_usb_transport(usb_handle *h, const char *serial, unsigned writeabl
void unregister_usb_transport(usb_handle *usb);

atransport *find_transport(const char *serial);
#if ADB_HOST
atransport* find_emulator_transport_by_adb_port(int adb_port);
#endif

int service_to_fd(const char *name);
#if ADB_HOST
@@ -368,6 +375,7 @@ typedef enum {

void local_init(int port);
int  local_connect(int  port);
int  local_connect_arbitrary_ports(int console_port, int adb_port);

/* usb host/client interface */
void usb_init();
+72 −21
Original line number Diff line number Diff line
@@ -41,9 +41,9 @@ static inline void fix_endians(apacket *p)
#endif

#if ADB_HOST
/* we keep a list of opened transports, transport 0 is bound to 5555,
 * transport 1 to 5557, .. transport n to 5555 + n*2. the list is used
 * to detect when we're trying to connect twice to a given local transport
/* we keep a list of opened transports. The atransport struct knows to which
 * local transport it is connected. The list is used to detect when we're
 * trying to connect twice to a given local transport.
 */
#define  ADB_LOCAL_TRANSPORT_MAX  16

@@ -102,7 +102,11 @@ static int remote_write(apacket *p, atransport *t)
}


int  local_connect(int  port)
int local_connect(int port) {
    return local_connect_arbitrary_ports(port-1, port);
}

int local_connect_arbitrary_ports(int console_port, int adb_port)
{
    char buf[64];
    int  fd = -1;
@@ -110,19 +114,19 @@ int local_connect(int port)
#if ADB_HOST
    const char *host = getenv("ADBHOST");
    if (host) {
        fd = socket_network_client(host, port, SOCK_STREAM);
        fd = socket_network_client(host, adb_port, SOCK_STREAM);
    }
#endif
    if (fd < 0) {
        fd = socket_loopback_client(port, SOCK_STREAM);
        fd = socket_loopback_client(adb_port, SOCK_STREAM);
    }

    if (fd >= 0) {
        D("client: connected on remote on fd %d\n", fd);
        close_on_exec(fd);
        disable_tcp_nagle(fd);
        snprintf(buf, sizeof buf, "%s%d", LOCAL_CLIENT_PREFIX, port - 1);
        register_socket_transport(fd, buf, port, 1);
        snprintf(buf, sizeof buf, "%s%d", LOCAL_CLIENT_PREFIX, console_port);
        register_socket_transport(fd, buf, adb_port, 1);
        return 0;
    }
    return -1;
@@ -227,7 +231,50 @@ static void remote_close(atransport *t)
    adb_close(t->fd);
}

int init_socket_transport(atransport *t, int s, int port, int local)

#if ADB_HOST
/* Only call this function if you already hold local_transports_lock. */
atransport* find_emulator_transport_by_adb_port_locked(int adb_port)
{
    int i;
    for (i = 0; i < ADB_LOCAL_TRANSPORT_MAX; i++) {
        if (local_transports[i] && local_transports[i]->adb_port == adb_port) {
            return local_transports[i];
        }
    }
    return NULL;
}

atransport* find_emulator_transport_by_adb_port(int adb_port)
{
    adb_mutex_lock( &local_transports_lock );
    atransport* result = find_emulator_transport_by_adb_port_locked(adb_port);
    adb_mutex_unlock( &local_transports_lock );
    return result;
}

/* Only call this function if you already hold local_transports_lock. */
int get_available_local_transport_index_locked()
{
    int i;
    for (i = 0; i < ADB_LOCAL_TRANSPORT_MAX; i++) {
        if (local_transports[i] == NULL) {
            return i;
        }
    }
    return -1;
}

int get_available_local_transport_index()
{
    adb_mutex_lock( &local_transports_lock );
    int result = get_available_local_transport_index_locked();
    adb_mutex_unlock( &local_transports_lock );
    return result;
}
#endif

int init_socket_transport(atransport *t, int s, int adb_port, int local)
{
    int  fail = 0;

@@ -239,25 +286,29 @@ int init_socket_transport(atransport *t, int s, int port, int local)
    t->sync_token = 1;
    t->connection_state = CS_OFFLINE;
    t->type = kTransportLocal;
    t->adb_port = 0;

#if ADB_HOST
    if (HOST && local) {
        adb_mutex_lock( &local_transports_lock );
        {
            int  index = (port - DEFAULT_ADB_LOCAL_TRANSPORT_PORT)/2;

            if (!(port & 1) || index < 0 || index >= ADB_LOCAL_TRANSPORT_MAX) {
                D("bad local transport port number: %d\n", port);
                fail = -1;
            }
            else if (local_transports[index] != NULL) {
            t->adb_port = adb_port;
            atransport* existing_transport =
                    find_emulator_transport_by_adb_port_locked(adb_port);
            int index = get_available_local_transport_index_locked();
            if (existing_transport != NULL) {
                D("local transport for port %d already registered (%p)?\n",
                port, local_transports[index]);
                adb_port, existing_transport);
                fail = -1;
            }
            else
            } else if (index < 0) {
                // Too many emulators.
                D("cannot register more emulators. Maximum is %d\n",
                        ADB_LOCAL_TRANSPORT_MAX);
                fail = -1;
            } else {
                local_transports[index] = t;
            }
       }
       adb_mutex_unlock( &local_transports_lock );
    }
#endif