summaryrefslogtreecommitdiffstats
path: root/adb
diff options
context:
space:
mode:
Diffstat (limited to 'adb')
-rw-r--r--adb/Android.mk6
-rw-r--r--adb/SERVICES.TXT27
-rw-r--r--adb/adb.c246
-rw-r--r--adb/adb.h1
-rw-r--r--adb/adb_auth.h2
-rw-r--r--adb/adb_auth_client.c23
-rw-r--r--adb/adb_client.c19
-rw-r--r--adb/adb_client.h4
-rw-r--r--adb/commandline.c131
-rw-r--r--adb/services.c2
-rw-r--r--adb/sysdeps.h32
-rw-r--r--adb/sysdeps_win32.c2
-rw-r--r--adb/transport.c7
13 files changed, 436 insertions, 66 deletions
diff --git a/adb/Android.mk b/adb/Android.mk
index bc8315e..a803978 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -16,7 +16,8 @@ EXTRA_SRCS :=
ifeq ($(HOST_OS),linux)
USB_SRCS := usb_linux.c
EXTRA_SRCS := get_my_path_linux.c
- LOCAL_LDLIBS += -lrt -lncurses -lpthread
+ LOCAL_LDLIBS += -lrt -ldl -lpthread
+ LOCAL_CFLAGS += -DWORKAROUND_BUG6558362
endif
ifeq ($(HOST_OS),darwin)
@@ -77,6 +78,7 @@ endif
LOCAL_CFLAGS += -O2 -g -DADB_HOST=1 -Wall -Wno-unused-parameter
LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE
LOCAL_MODULE := adb
+LOCAL_MODULE_TAGS := debug
LOCAL_STATIC_LIBRARIES := libzipfile libunz libcrypto_static $(EXTRA_STATIC_LIBS)
ifeq ($(USE_SYSDEPS_WIN32),)
@@ -139,7 +141,7 @@ include $(BUILD_EXECUTABLE)
ifneq ($(SDK_ONLY),true)
include $(CLEAR_VARS)
-LOCAL_LDLIBS := -lrt -lncurses -lpthread
+LOCAL_LDLIBS := -lrt -ldl -lpthread
LOCAL_SRC_FILES := \
adb.c \
diff --git a/adb/SERVICES.TXT b/adb/SERVICES.TXT
index d9aa09c..b53bc44 100644
--- a/adb/SERVICES.TXT
+++ b/adb/SERVICES.TXT
@@ -117,7 +117,34 @@ host:<request>
or even any one of the local services described below.
+<host-prefix>:forward:norebind:<local>;<remote>
+ Same as <host-prefix>:forward:<local>;<remote> except that it will
+ fail it there is already a forward connection from <local>.
+ Used to implement 'adb forward --no-rebind <local> <remote>'
+
+<host-prefix>:killforward:<local>
+ Remove any existing forward local connection from <local>.
+ This is used to implement 'adb forward --remove <local>'
+
+<host-prefix>:killforward-all
+ Remove all forward network connections.
+ This is used to implement 'adb forward --remove-all'.
+
+<host-prefix>:list-forward
+ List all existing forward connections from this server.
+ This returns something that looks like the following:
+
+ <hex4>: The length of the payload, as 4 hexadecimal chars.
+ <payload>: A series of lines of the following format:
+
+ <serial> " " <local> " " <remote> "\n"
+
+ Where <serial> is a device serial number.
+ <local> is the host-specific endpoint (e.g. tcp:9000).
+ <remote> is the device-specific endpoint.
+
+ Used to implement 'adb forward --list'.
LOCAL SERVICES:
diff --git a/adb/adb.c b/adb/adb.c
index 07bfbe5..c57a875 100644
--- a/adb/adb.c
+++ b/adb/adb.c
@@ -25,6 +25,7 @@
#include <string.h>
#include <time.h>
#include <sys/time.h>
+#include <stdint.h>
#include "sysdeps.h"
#include "adb.h"
@@ -46,6 +47,7 @@ ADB_MUTEX_DEFINE( D_lock );
#endif
int HOST = 0;
+int gListenAll = 0;
static int auth_enabled = 0;
@@ -401,6 +403,8 @@ static char *connection_state_name(atransport *t)
return "device";
case CS_OFFLINE:
return "offline";
+ case CS_UNAUTHORIZED:
+ return "unauthorized";
default:
return "unknown";
}
@@ -530,6 +534,7 @@ void handle_packet(apacket *p, atransport *t)
case A_AUTH:
if (p->msg.arg0 == ADB_AUTH_TOKEN) {
+ t->connection_state = CS_UNAUTHORIZED;
t->key = adb_auth_nextkey(t->key);
if (t->key) {
send_auth_response(p->data, p->msg.data_length, t);
@@ -701,7 +706,13 @@ int local_name_to_fd(const char *name)
if(!strncmp("tcp:", name, 4)){
int ret;
port = atoi(name + 4);
- ret = socket_loopback_server(port, SOCK_STREAM);
+
+ if (gListenAll > 0) {
+ ret = socket_inaddr_any_server(port, SOCK_STREAM);
+ } else {
+ ret = socket_loopback_server(port, SOCK_STREAM);
+ }
+
return ret;
}
#ifndef HAVE_WIN32_IPC /* no Unix-domain sockets on Win32 */
@@ -722,24 +733,90 @@ int local_name_to_fd(const char *name)
return -1;
}
-static int remove_listener(const char *local_name, const char *connect_to, atransport* transport)
+// Write a single line describing a listener to a user-provided buffer.
+// Appends a trailing zero, even in case of truncation, but the function
+// returns the full line length.
+// If |buffer| is NULL, does not write but returns required size.
+static int format_listener(alistener* l, char* buffer, size_t buffer_len) {
+ // Format is simply:
+ //
+ // <device-serial> " " <local-name> " " <remote-name> "\n"
+ //
+ int local_len = strlen(l->local_name);
+ int connect_len = strlen(l->connect_to);
+ int serial_len = strlen(l->transport->serial);
+
+ if (buffer != NULL) {
+ snprintf(buffer, buffer_len, "%s %s %s\n",
+ l->transport->serial, l->local_name, l->connect_to);
+ }
+ // NOTE: snprintf() on Windows returns -1 in case of truncation, so
+ // return the computed line length instead.
+ return local_len + connect_len + serial_len + 3;
+}
+
+// Write the list of current listeners (network redirections) into a
+// user-provided buffer. Appends a trailing zero, even in case of
+// trunctaion, but return the full size in bytes.
+// If |buffer| is NULL, does not write but returns required size.
+static int format_listeners(char* buf, size_t buflen)
+{
+ alistener* l;
+ int result = 0;
+ for (l = listener_list.next; l != &listener_list; l = l->next) {
+ // Ignore special listeners like those for *smartsocket*
+ if (l->connect_to[0] == '*')
+ continue;
+ int len = format_listener(l, buf, buflen);
+ // Ensure there is space for the trailing zero.
+ result += len;
+ if (buf != NULL) {
+ buf += len;
+ buflen -= len;
+ if (buflen <= 0)
+ break;
+ }
+ }
+ return result;
+}
+
+static int remove_listener(const char *local_name, atransport* transport)
{
alistener *l;
for (l = listener_list.next; l != &listener_list; l = l->next) {
- if (!strcmp(local_name, l->local_name) &&
- !strcmp(connect_to, l->connect_to) &&
- l->transport && l->transport == transport) {
-
- listener_disconnect(l, transport);
+ if (!strcmp(local_name, l->local_name)) {
+ listener_disconnect(l, l->transport);
return 0;
}
}
-
return -1;
}
-static int install_listener(const char *local_name, const char *connect_to, atransport* transport)
+static void remove_all_listeners(void)
+{
+ alistener *l, *l_next;
+ for (l = listener_list.next; l != &listener_list; l = l_next) {
+ l_next = l->next;
+ // Never remove smart sockets.
+ if (l->connect_to[0] == '*')
+ continue;
+ listener_disconnect(l, l->transport);
+ }
+}
+
+// error/status codes for install_listener.
+typedef enum {
+ INSTALL_STATUS_OK = 0,
+ INSTALL_STATUS_INTERNAL_ERROR = -1,
+ INSTALL_STATUS_CANNOT_BIND = -2,
+ INSTALL_STATUS_CANNOT_REBIND = -3,
+} install_status_t;
+
+static install_status_t install_listener(const char *local_name,
+ const char *connect_to,
+ atransport* transport,
+ int no_rebind)
{
alistener *l;
@@ -751,12 +828,17 @@ static int install_listener(const char *local_name, const char *connect_to, atra
/* can't repurpose a smartsocket */
if(l->connect_to[0] == '*') {
- return -1;
+ return INSTALL_STATUS_INTERNAL_ERROR;
+ }
+
+ /* can't repurpose a listener if 'no_rebind' is true */
+ if (no_rebind) {
+ return INSTALL_STATUS_CANNOT_REBIND;
}
cto = strdup(connect_to);
if(cto == 0) {
- return -1;
+ return INSTALL_STATUS_INTERNAL_ERROR;
}
//printf("rebinding '%s' to '%s'\n", local_name, connect_to);
@@ -767,7 +849,7 @@ static int install_listener(const char *local_name, const char *connect_to, atra
l->transport = transport;
add_transport_disconnect(l->transport, &l->disconnect);
}
- return 0;
+ return INSTALL_STATUS_OK;
}
}
@@ -804,11 +886,11 @@ static int install_listener(const char *local_name, const char *connect_to, atra
l->disconnect.func = listener_disconnect;
add_transport_disconnect(transport, &l->disconnect);
}
- return 0;
+ return INSTALL_STATUS_OK;
nomem:
fatal("cannot allocate listener");
- return 0;
+ return INSTALL_STATUS_INTERNAL_ERROR;
}
#ifdef HAVE_WIN32_PROC
@@ -905,6 +987,33 @@ void start_device_log(void)
#endif
#if ADB_HOST
+
+#ifdef WORKAROUND_BUG6558362
+#include <sched.h>
+#define AFFINITY_ENVVAR "ADB_CPU_AFFINITY_BUG6558362"
+void adb_set_affinity(void)
+{
+ cpu_set_t cpu_set;
+ const char* cpunum_str = getenv(AFFINITY_ENVVAR);
+ char* strtol_res;
+ int cpu_num;
+
+ if (!cpunum_str || !*cpunum_str)
+ return;
+ cpu_num = strtol(cpunum_str, &strtol_res, 0);
+ if (*strtol_res != '\0')
+ fatal("bad number (%s) in env var %s. Expecting 0..n.\n", cpunum_str, AFFINITY_ENVVAR);
+
+ sched_getaffinity(0, sizeof(cpu_set), &cpu_set);
+ D("orig cpu_set[0]=0x%08lx\n", cpu_set.__bits[0]);
+ CPU_ZERO(&cpu_set);
+ CPU_SET(cpu_num, &cpu_set);
+ sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
+ sched_getaffinity(0, sizeof(cpu_set), &cpu_set);
+ D("new cpu_set[0]=0x%08lx\n", cpu_set.__bits[0]);
+}
+#endif
+
int launch_server(int server_port)
{
#ifdef HAVE_WIN32_PROC
@@ -913,6 +1022,7 @@ int launch_server(int server_port)
/* message since the pipe handles must be inheritable, we use a */
/* security attribute */
HANDLE pipe_read, pipe_write;
+ HANDLE stdout_handle, stderr_handle;
SECURITY_ATTRIBUTES sa;
STARTUPINFO startup;
PROCESS_INFORMATION pinfo;
@@ -932,6 +1042,26 @@ int launch_server(int server_port)
SetHandleInformation( pipe_read, HANDLE_FLAG_INHERIT, 0 );
+ /* Some programs want to launch an adb command and collect its output by
+ * calling CreateProcess with inheritable stdout/stderr handles, then
+ * using read() to get its output. When this happens, the stdout/stderr
+ * handles passed to the adb client process will also be inheritable.
+ * When starting the adb server here, care must be taken to reset them
+ * to non-inheritable.
+ * Otherwise, something bad happens: even if the adb command completes,
+ * the calling process is stuck while read()-ing from the stdout/stderr
+ * descriptors, because they're connected to corresponding handles in the
+ * adb server process (even if the latter never uses/writes to them).
+ */
+ stdout_handle = GetStdHandle( STD_OUTPUT_HANDLE );
+ stderr_handle = GetStdHandle( STD_ERROR_HANDLE );
+ if (stdout_handle != INVALID_HANDLE_VALUE) {
+ SetHandleInformation( stdout_handle, HANDLE_FLAG_INHERIT, 0 );
+ }
+ if (stderr_handle != INVALID_HANDLE_VALUE) {
+ SetHandleInformation( stderr_handle, HANDLE_FLAG_INHERIT, 0 );
+ }
+
ZeroMemory( &startup, sizeof(startup) );
startup.cb = sizeof(startup);
startup.hStdInput = GetStdHandle( STD_INPUT_HANDLE );
@@ -1008,8 +1138,10 @@ int launch_server(int server_port)
dup2(fd[1], STDERR_FILENO);
adb_close(fd[1]);
+ char str_port[30];
+ snprintf(str_port, sizeof(str_port), "%d", server_port);
// child process
- int result = execl(path, "adb", "fork-server", "server", NULL);
+ int result = execl(path, "adb", "-P", str_port, "fork-server", "server", NULL);
// this should not return
fprintf(stderr, "OOPS! execl returned %d, errno: %d\n", result, errno);
} else {
@@ -1106,6 +1238,10 @@ int adb_main(int is_daemon, int server_port)
#if ADB_HOST
HOST = 1;
+
+#ifdef WORKAROUND_BUG6558362
+ if(is_daemon) adb_set_affinity();
+#endif
usb_vendors_init();
usb_init();
local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
@@ -1113,7 +1249,7 @@ int adb_main(int is_daemon, int server_port)
char local_name[30];
build_local_name(local_name, sizeof(local_name), server_port);
- if(install_listener(local_name, "*smartsocket*", NULL)) {
+ if(install_listener(local_name, "*smartsocket*", NULL, 0)) {
exit(1);
}
#else
@@ -1180,7 +1316,7 @@ int adb_main(int is_daemon, int server_port)
} else {
char local_name[30];
build_local_name(local_name, sizeof(local_name), server_port);
- if(install_listener(local_name, "*smartsocket*", NULL)) {
+ if(install_listener(local_name, "*smartsocket*", NULL, 0)) {
exit(1);
}
}
@@ -1474,24 +1610,63 @@ int handle_host_request(char *service, transport_type ttype, char* serial, int r
}
#endif // ADB_HOST
- if(!strncmp(service,"forward:",8) || !strncmp(service,"killforward:",12)) {
+ if(!strcmp(service,"list-forward")) {
+ // Create the list of forward redirections.
+ char header[9];
+ int buffer_size = format_listeners(NULL, 0);
+ // Add one byte for the trailing zero.
+ char* buffer = malloc(buffer_size+1);
+ (void) format_listeners(buffer, buffer_size+1);
+ snprintf(header, sizeof header, "OKAY%04x", buffer_size);
+ writex(reply_fd, header, 8);
+ writex(reply_fd, buffer, buffer_size);
+ free(buffer);
+ return 0;
+ }
+
+ if (!strcmp(service,"killforward-all")) {
+ remove_all_listeners();
+ adb_write(reply_fd, "OKAYOKAY", 8);
+ return 0;
+ }
+
+ if(!strncmp(service,"forward:",8) ||
+ !strncmp(service,"killforward:",12)) {
char *local, *remote, *err;
int r;
atransport *transport;
int createForward = strncmp(service,"kill",4);
+ int no_rebind = 0;
- local = service + (createForward ? 8 : 12);
- remote = strchr(local,';');
- if(remote == 0) {
- sendfailmsg(reply_fd, "malformed forward spec");
- return 0;
+ local = strchr(service, ':') + 1;
+
+ // Handle forward:norebind:<local>... here
+ if (createForward && !strncmp(local, "norebind:", 9)) {
+ no_rebind = 1;
+ local = strchr(local, ':') + 1;
}
- *remote++ = 0;
- if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')){
- sendfailmsg(reply_fd, "malformed forward spec");
- return 0;
+ remote = strchr(local,';');
+
+ if (createForward) {
+ // Check forward: parameter format: '<local>;<remote>'
+ if(remote == 0) {
+ sendfailmsg(reply_fd, "malformed forward spec");
+ return 0;
+ }
+
+ *remote++ = 0;
+ if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')){
+ sendfailmsg(reply_fd, "malformed forward spec");
+ return 0;
+ }
+ } else {
+ // Check killforward: parameter format: '<local>'
+ if (local[0] == 0) {
+ sendfailmsg(reply_fd, "malformed forward spec");
+ return 0;
+ }
}
transport = acquire_one_transport(CS_ANY, ttype, serial, &err);
@@ -1501,9 +1676,9 @@ int handle_host_request(char *service, transport_type ttype, char* serial, int r
}
if (createForward) {
- r = install_listener(local, remote, transport);
+ r = install_listener(local, remote, transport, no_rebind);
} else {
- r = remove_listener(local, remote, transport);
+ r = remove_listener(local, transport);
}
if(r == 0) {
/* 1st OKAY is connect, 2nd OKAY is status */
@@ -1512,7 +1687,18 @@ int handle_host_request(char *service, transport_type ttype, char* serial, int r
}
if (createForward) {
- sendfailmsg(reply_fd, (r == -1) ? "cannot rebind smartsocket" : "cannot bind socket");
+ const char* message;
+ switch (r) {
+ case INSTALL_STATUS_CANNOT_BIND:
+ message = "cannot bind to socket";
+ break;
+ case INSTALL_STATUS_CANNOT_REBIND:
+ message = "cannot rebind existing socket";
+ break;
+ default:
+ message = "internal error";
+ }
+ sendfailmsg(reply_fd, message);
} else {
sendfailmsg(reply_fd, "cannot remove listener");
}
diff --git a/adb/adb.h b/adb/adb.h
index 9da8af8..a01d460 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -468,6 +468,7 @@ int connection_state(atransport *t);
#define CS_RECOVERY 4
#define CS_NOPERM 5 /* Insufficient permissions to communicate with the device */
#define CS_SIDELOAD 6
+#define CS_UNAUTHORIZED 7
extern int HOST;
extern int SHELL_EXIT_NOTIFY_FD;
diff --git a/adb/adb_auth.h b/adb/adb_auth.h
index 1fffa49..96f637b 100644
--- a/adb/adb_auth.h
+++ b/adb/adb_auth.h
@@ -36,7 +36,6 @@ int adb_auth_get_userkey(unsigned char *data, size_t len);
static inline int adb_auth_generate_token(void *token, size_t token_size) { return 0; }
static inline int adb_auth_verify(void *token, void *sig, int siglen) { return 0; }
static inline void adb_auth_confirm_key(unsigned char *data, size_t len, atransport *t) { }
-static inline void adb_auth_reload_keys(void) { }
#else // !ADB_HOST
@@ -47,7 +46,6 @@ static inline int adb_auth_get_userkey(unsigned char *data, size_t len) { return
int adb_auth_generate_token(void *token, size_t token_size);
int adb_auth_verify(void *token, void *sig, int siglen);
void adb_auth_confirm_key(unsigned char *data, size_t len, atransport *t);
-void adb_auth_reload_keys(void);
#endif // ADB_HOST
diff --git a/adb/adb_auth_client.c b/adb/adb_auth_client.c
index 0b4913e..a4ad18f 100644
--- a/adb/adb_auth_client.c
+++ b/adb/adb_auth_client.c
@@ -34,8 +34,6 @@ struct adb_public_key {
RSAPublicKey key;
};
-static struct listnode key_list;
-
static char *key_paths[] = {
"/adb_keys",
"/data/misc/adb/adb_keys",
@@ -102,18 +100,18 @@ static void free_keys(struct listnode *list)
}
}
-void adb_auth_reload_keys(void)
+static void load_keys(struct listnode *list)
{
char *path;
char **paths = key_paths;
struct stat buf;
- free_keys(&key_list);
+ list_init(list);
while ((path = *paths++)) {
if (!stat(path, &buf)) {
D("Loading keys from '%s'\n", path);
- read_keys(path, &key_list);
+ read_keys(path, list);
}
}
}
@@ -137,19 +135,24 @@ int adb_auth_verify(void *token, void *sig, int siglen)
{
struct listnode *item;
struct adb_public_key *key;
- int ret;
+ struct listnode key_list;
+ int ret = 0;
if (siglen != RSANUMBYTES)
return 0;
+ load_keys(&key_list);
+
list_for_each(item, &key_list) {
key = node_to_item(item, struct adb_public_key, node);
ret = RSA_verify(&key->key, sig, siglen, token);
if (ret)
- return 1;
+ break;
}
- return 0;
+ free_keys(&key_list);
+
+ return ret;
}
static void adb_auth_event(int fd, unsigned events, void *data)
@@ -166,7 +169,6 @@ static void adb_auth_event(int fd, unsigned events, void *data)
framework_fd = -1;
}
else if (ret == 2 && response[0] == 'O' && response[1] == 'K') {
- adb_auth_reload_keys();
adb_auth_verified(t);
}
}
@@ -225,9 +227,6 @@ void adb_auth_init(void)
{
int fd, ret;
- list_init(&key_list);
- adb_auth_reload_keys();
-
fd = android_get_control_socket("adbd");
if (fd < 0) {
D("Failed to get adbd socket\n");
diff --git a/adb/adb_client.c b/adb/adb_client.c
index 9a812f0..8340738 100644
--- a/adb/adb_client.c
+++ b/adb/adb_client.c
@@ -17,6 +17,7 @@ static transport_type __adb_transport = kTransportAny;
static const char* __adb_serial = NULL;
static int __adb_server_port = DEFAULT_ADB_PORT;
+static const char* __adb_server_name = NULL;
void adb_set_transport(transport_type type, const char* serial)
{
@@ -29,6 +30,11 @@ void adb_set_tcp_specifics(int server_port)
__adb_server_port = server_port;
}
+void adb_set_tcp_name(const char* hostname)
+{
+ __adb_server_name = hostname;
+}
+
int adb_get_emulator_console_port(void)
{
const char* serial = __adb_serial;
@@ -181,7 +187,11 @@ int _adb_connect(const char *service)
}
snprintf(tmp, sizeof tmp, "%04x", len);
- fd = socket_loopback_client(__adb_server_port, SOCK_STREAM);
+ if (__adb_server_name)
+ fd = socket_network_client(__adb_server_name, __adb_server_port, SOCK_STREAM);
+ else
+ fd = socket_loopback_client(__adb_server_port, SOCK_STREAM);
+
if(fd < 0) {
strcpy(__adb_error, "cannot connect to daemon");
return -2;
@@ -212,7 +222,10 @@ int adb_connect(const char *service)
int fd = _adb_connect("host:version");
D("adb_connect: service %s\n", service);
- if(fd == -2) {
+ if(fd == -2 && __adb_server_name) {
+ fprintf(stderr,"** Cannot start server on remote host\n");
+ return fd;
+ } else if(fd == -2) {
fprintf(stdout,"* daemon not running. starting it now on port %d *\n",
__adb_server_port);
start_server:
@@ -266,7 +279,7 @@ int adb_connect(const char *service)
fd = _adb_connect(service);
if(fd == -2) {
- fprintf(stderr,"** daemon still not running");
+ fprintf(stderr,"** daemon still not running\n");
}
D("adb_connect: return fd %d\n", fd);
diff --git a/adb/adb_client.h b/adb/adb_client.h
index 40ab189..0ec47ca 100644
--- a/adb/adb_client.h
+++ b/adb/adb_client.h
@@ -29,6 +29,10 @@ void adb_set_transport(transport_type type, const char* serial);
*/
void adb_set_tcp_specifics(int server_port);
+/* Set TCP Hostname of the transport to use
+*/
+void adb_set_tcp_name(const char* hostname);
+
/* Return the console port of the currently connected emulator (if any)
* of -1 if there is no emulator, and -2 if there is more than one.
* assumes adb_set_transport() was alled previously...
diff --git a/adb/commandline.c b/adb/commandline.c
index 24cbb5a..cbe4616 100644
--- a/adb/commandline.c
+++ b/adb/commandline.c
@@ -46,6 +46,7 @@ int install_app(transport_type transport, char* serial, int argc, char** argv);
int uninstall_app(transport_type transport, char* serial, int argc, char** argv);
static const char *gProductOutPath = NULL;
+extern int gListenAll;
static char *product_file(const char *extra)
{
@@ -80,6 +81,7 @@ void help()
fprintf(stderr,
"\n"
+ " -a - directs adb to listen on all interfaces for a connection\n"
" -d - directs command to the only connected USB device\n"
" returns an error if more than one USB device is present.\n"
" -e - directs command to the only running emulator.\n"
@@ -93,6 +95,8 @@ void help()
" If -p is not specified, the ANDROID_PRODUCT_OUT\n"
" environment variable is used, which must\n"
" be an absolute path.\n"
+ " -H - Name of adb server host (default: localhost)\n"
+ " -P - Port of adb server (default: 5037)\n"
" devices [-l] - list all connected devices\n"
" ('-l' will also list device qualifiers)\n"
" connect <host>[:<port>] - connect to a device via TCP/IP\n"
@@ -112,6 +116,9 @@ void help()
" adb shell <command> - run remote shell command\n"
" adb emu <command> - run emulator console command\n"
" adb logcat [ <filter-spec> ] - View device log\n"
+ " adb forward --list - list all forward socket connections.\n"
+ " the format is a list of lines with the following format:\n"
+ " <serial> \" \" <local> \" \" <remote> \"\\n\"\n"
" adb forward <local> <remote> - forward socket connections\n"
" forward specs are one of: \n"
" tcp:<port>\n"
@@ -120,6 +127,11 @@ void help()
" localfilesystem:<unix domain socket name>\n"
" dev:<character device name>\n"
" jdwp:<process pid> (remote only)\n"
+ " adb forward --no-rebind <local> <remote>\n"
+ " - same as 'adb forward <local> <remote>' but fails\n"
+ " if <local> is already forwarded\n"
+ " adb forward --remove <local> - remove a specific forward socket connection\n"
+ " adb forward --remove-all - remove all forward socket connections\n"
" adb jdwp - list PIDs of processes hosting a JDWP transport\n"
" adb install [-l] [-r] [-s] [--algo <algorithm name> --key <hex-encoded key> --iv <hex-encoded iv>] <file>\n"
" - push this package file to the device and install it\n"
@@ -938,9 +950,9 @@ int adb_commandline(int argc, char **argv)
int server_port = DEFAULT_ADB_PORT;
if (server_port_str && strlen(server_port_str) > 0) {
server_port = (int) strtol(server_port_str, NULL, 0);
- if (server_port <= 0) {
+ if (server_port <= 0 || server_port > 65535) {
fprintf(stderr,
- "adb: Env var ANDROID_ADB_SERVER_PORT must be a positive number. Got \"%s\"\n",
+ "adb: Env var ANDROID_ADB_SERVER_PORT must be a positive number less than 65535. Got \"%s\"\n",
server_port_str);
return usage();
}
@@ -986,6 +998,42 @@ int adb_commandline(int argc, char **argv)
ttype = kTransportUsb;
} else if (!strcmp(argv[0],"-e")) {
ttype = kTransportLocal;
+ } else if (!strcmp(argv[0],"-a")) {
+ gListenAll = 1;
+ } else if(!strncmp(argv[0], "-H", 2)) {
+ const char *hostname = NULL;
+ if (argv[0][2] == '\0') {
+ if (argc < 2) return usage();
+ hostname = argv[1];
+ argc--;
+ argv++;
+ } else {
+ hostname = argv[0] + 2;
+ }
+ adb_set_tcp_name(hostname);
+
+ } else if(!strncmp(argv[0], "-P", 2)) {
+ if (argv[0][2] == '\0') {
+ if (argc < 2) return usage();
+ server_port_str = argv[1];
+ argc--;
+ argv++;
+ } else {
+ server_port_str = argv[0] + 2;
+ }
+ if (strlen(server_port_str) > 0) {
+ server_port = (int) strtol(server_port_str, NULL, 0);
+ if (server_port <= 0 || server_port > 65535) {
+ fprintf(stderr,
+ "adb: port number must be a positive number less than 65536. Got \"%s\"\n",
+ server_port_str);
+ return usage();
+ }
+ } else {
+ fprintf(stderr,
+ "adb: port number must be a positive number less than 65536. Got empty string.\n");
+ return usage();
+ }
} else {
/* out of recognized modifiers and flags */
break;
@@ -1223,16 +1271,85 @@ top:
}
if(!strcmp(argv[0], "forward")) {
- if(argc != 3) return usage();
+ char host_prefix[64];
+ char remove = 0;
+ char remove_all = 0;
+ char list = 0;
+ char no_rebind = 0;
+
+ // Parse options here.
+ while (argc > 1 && argv[1][0] == '-') {
+ if (!strcmp(argv[1], "--list"))
+ list = 1;
+ else if (!strcmp(argv[1], "--remove"))
+ remove = 1;
+ else if (!strcmp(argv[1], "--remove-all"))
+ remove_all = 1;
+ else if (!strcmp(argv[1], "--no-rebind"))
+ no_rebind = 1;
+ else {
+ return usage();
+ }
+ argc--;
+ argv++;
+ }
+
+ // Ensure we can only use one option at a time.
+ if (list + remove + remove_all + no_rebind > 1) {
+ return usage();
+ }
+
+ // Determine the <host-prefix> for this command.
if (serial) {
- snprintf(buf, sizeof buf, "host-serial:%s:forward:%s;%s",serial, argv[1], argv[2]);
+ snprintf(host_prefix, sizeof host_prefix, "host-serial:%s",
+ serial);
} else if (ttype == kTransportUsb) {
- snprintf(buf, sizeof buf, "host-usb:forward:%s;%s", argv[1], argv[2]);
+ snprintf(host_prefix, sizeof host_prefix, "host-usb");
} else if (ttype == kTransportLocal) {
- snprintf(buf, sizeof buf, "host-local:forward:%s;%s", argv[1], argv[2]);
+ snprintf(host_prefix, sizeof host_prefix, "host-local");
} else {
- snprintf(buf, sizeof buf, "host:forward:%s;%s", argv[1], argv[2]);
+ snprintf(host_prefix, sizeof host_prefix, "host");
+ }
+
+ // Implement forward --list
+ if (list) {
+ if (argc != 1)
+ return usage();
+ snprintf(buf, sizeof buf, "%s:list-forward", host_prefix);
+ char* forwards = adb_query(buf);
+ if (forwards == NULL) {
+ fprintf(stderr, "error: %s\n", adb_error());
+ return 1;
+ }
+ printf("%s", forwards);
+ free(forwards);
+ return 0;
}
+
+ // Implement forward --remove-all
+ else if (remove_all) {
+ if (argc != 1)
+ return usage();
+ snprintf(buf, sizeof buf, "%s:killforward-all", host_prefix);
+ }
+
+ // Implement forward --remove <local>
+ else if (remove) {
+ if (argc != 2)
+ return usage();
+ snprintf(buf, sizeof buf, "%s:killforward:%s", host_prefix, argv[1]);
+ }
+ // Or implement one of:
+ // forward <local> <remote>
+ // forward --no-rebind <local> <remote>
+ else
+ {
+ if (argc != 3)
+ return usage();
+ const char* command = no_rebind ? "forward:norebind:" : "forward";
+ snprintf(buf, sizeof buf, "%s:%s:%s;%s", host_prefix, command, argv[1], argv[2]);
+ }
+
if(adb_command(buf)) {
fprintf(stderr,"error: %s\n", adb_error());
return 1;
diff --git a/adb/services.c b/adb/services.c
index 495a083..54d21a8 100644
--- a/adb/services.c
+++ b/adb/services.c
@@ -202,7 +202,7 @@ static void echo_service(int fd, void *cookie)
int c;
for(;;) {
- r = read(fd, buf, 4096);
+ r = adb_read(fd, buf, 4096);
if(r == 0) goto done;
if(r < 0) {
if(errno == EINTR) continue;
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 66b60cc..0252ef3 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -275,6 +275,22 @@ extern char* adb_strtok_r(char *str, const char *delim, char **saveptr);
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <string.h>
+#include <unistd.h>
+
+/*
+ * TEMP_FAILURE_RETRY is defined by some, but not all, versions of
+ * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
+ * not already defined, then define it here.
+ */
+#ifndef TEMP_FAILURE_RETRY
+/* Used to retry syscalls that can return EINTR. */
+#define TEMP_FAILURE_RETRY(exp) ({ \
+ typeof (exp) _rc; \
+ do { \
+ _rc = (exp); \
+ } while (_rc == -1 && errno == EINTR); \
+ _rc; })
+#endif
#define OS_PATH_SEPARATOR '/'
#define OS_PATH_SEPARATOR_STR "/"
@@ -310,7 +326,7 @@ static __inline__ int unix_open(const char* path, int options,...)
{
if ((options & O_CREAT) == 0)
{
- return open(path, options);
+ return TEMP_FAILURE_RETRY( open(path, options) );
}
else
{
@@ -319,19 +335,19 @@ static __inline__ int unix_open(const char* path, int options,...)
va_start( args, options );
mode = va_arg( args, int );
va_end( args );
- return open(path, options, mode);
+ return TEMP_FAILURE_RETRY( open( path, options, mode ) );
}
}
static __inline__ int adb_open_mode( const char* pathname, int options, int mode )
{
- return open( pathname, options, mode );
+ return TEMP_FAILURE_RETRY( open( pathname, options, mode ) );
}
static __inline__ int adb_open( const char* pathname, int options )
{
- int fd = open( pathname, options );
+ int fd = TEMP_FAILURE_RETRY( open( pathname, options ) );
if (fd < 0)
return -1;
close_on_exec( fd );
@@ -357,7 +373,7 @@ static __inline__ int adb_close(int fd)
static __inline__ int adb_read(int fd, void* buf, size_t len)
{
- return read(fd, buf, len);
+ return TEMP_FAILURE_RETRY( read( fd, buf, len ) );
}
#undef read
@@ -365,7 +381,7 @@ static __inline__ int adb_read(int fd, void* buf, size_t len)
static __inline__ int adb_write(int fd, const void* buf, size_t len)
{
- return write(fd, buf, len);
+ return TEMP_FAILURE_RETRY( write( fd, buf, len ) );
}
#undef write
#define write ___xxx_write
@@ -386,7 +402,7 @@ static __inline__ int adb_unlink(const char* path)
static __inline__ int adb_creat(const char* path, int mode)
{
- int fd = creat(path, mode);
+ int fd = TEMP_FAILURE_RETRY( creat( path, mode ) );
if ( fd < 0 )
return -1;
@@ -401,7 +417,7 @@ static __inline__ int adb_socket_accept(int serverfd, struct sockaddr* addr,
{
int fd;
- fd = accept(serverfd, addr, addrlen);
+ fd = TEMP_FAILURE_RETRY( accept( serverfd, addr, addrlen ) );
if (fd >= 0)
close_on_exec(fd);
diff --git a/adb/sysdeps_win32.c b/adb/sysdeps_win32.c
index d41c42c..2105b16 100644
--- a/adb/sysdeps_win32.c
+++ b/adb/sysdeps_win32.c
@@ -781,7 +781,7 @@ int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrle
void disable_tcp_nagle(int fd)
{
FH fh = _fh_from_int(fd);
- int on;
+ int on = 1;
if ( !fh || fh->clazz != &_fh_socket_class )
return;
diff --git a/adb/transport.c b/adb/transport.c
index 9fd6cc2..b4abb66 100644
--- a/adb/transport.c
+++ b/adb/transport.c
@@ -851,6 +851,12 @@ retry:
adb_mutex_unlock(&transport_lock);
if (result) {
+ if (result->connection_state == CS_UNAUTHORIZED) {
+ if (error_out)
+ *error_out = "device unauthorized. Please check the confirmation dialog on your device.";
+ result = NULL;
+ }
+
/* offline devices are ignored -- they are either being born or dying */
if (result && result->connection_state == CS_OFFLINE) {
if (error_out)
@@ -888,6 +894,7 @@ static const char *statename(atransport *t)
case CS_RECOVERY: return "recovery";
case CS_SIDELOAD: return "sideload";
case CS_NOPERM: return "no permissions";
+ case CS_UNAUTHORIZED: return "unauthorized";
default: return "unknown";
}
}