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: Mike Lockwood <lockwood@android.com>
This commit is contained in:
parent
5762ec2905
commit
d9d1ca4780
132
adb/adb.c
132
adb/adb.c
|
@ -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 (!strncmp(host, "emu:", 4)) {
|
||||
connect_emulator(host + 4, buffer, sizeof(buffer));
|
||||
} else {
|
||||
connect_device(host, buffer, sizeof(buffer));
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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,26 +286,30 @@ 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 );
|
||||
}
|
||||
}
|
||||
adb_mutex_unlock( &local_transports_lock );
|
||||
}
|
||||
#endif
|
||||
return fail;
|
||||
|
|
Loading…
Reference in New Issue