diff options
Diffstat (limited to 'adb')
-rw-r--r-- | adb/Android.mk | 8 | ||||
-rw-r--r-- | adb/SERVICES.TXT | 21 | ||||
-rw-r--r-- | adb/adb.c | 238 | ||||
-rw-r--r-- | adb/adb.h | 16 | ||||
-rw-r--r-- | adb/adb_auth.h | 4 | ||||
-rw-r--r-- | adb/adb_auth_client.c | 58 | ||||
-rw-r--r-- | adb/adb_client.c | 4 | ||||
-rw-r--r-- | adb/commandline.c | 7 | ||||
-rw-r--r-- | adb/file_sync_client.c | 8 | ||||
-rw-r--r-- | adb/file_sync_service.c | 74 | ||||
-rw-r--r-- | adb/framebuffer_service.c | 16 | ||||
-rw-r--r-- | adb/log_service.c | 2 | ||||
-rw-r--r-- | adb/mutex_list.h | 1 | ||||
-rw-r--r-- | adb/remount_service.c | 9 | ||||
-rw-r--r-- | adb/services.c | 244 | ||||
-rw-r--r-- | adb/sockets.c | 69 | ||||
-rw-r--r-- | adb/sysdeps.h | 1 | ||||
-rw-r--r-- | adb/transport.c | 60 | ||||
-rw-r--r-- | adb/transport_local.c | 3 | ||||
-rwxr-xr-x | adb/usb_vendors.c | 25 | ||||
-rw-r--r-- | adb/utils.c | 106 | ||||
-rw-r--r-- | adb/utils.h | 68 |
22 files changed, 520 insertions, 522 deletions
diff --git a/adb/Android.mk b/adb/Android.mk index 6cd82ec..155c6e5 100644 --- a/adb/Android.mk +++ b/adb/Android.mk @@ -17,6 +17,7 @@ ifeq ($(HOST_OS),linux) USB_SRCS := usb_linux.c EXTRA_SRCS := get_my_path_linux.c LOCAL_LDLIBS += -lrt -ldl -lpthread + LOCAL_CFLAGS += -DWORKAROUND_BUG6558362 endif ifeq ($(HOST_OS),darwin) @@ -63,7 +64,6 @@ LOCAL_SRC_FILES := \ file_sync_client.c \ $(EXTRA_SRCS) \ $(USB_SRCS) \ - utils.c \ usb_vendors.c LOCAL_C_INCLUDES += external/openssl/include @@ -115,8 +115,7 @@ LOCAL_SRC_FILES := \ framebuffer_service.c \ remount_service.c \ usb_linux_client.c \ - log_service.c \ - utils.c + log_service.c LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -Wall -Wno-unused-parameter LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE @@ -131,7 +130,7 @@ LOCAL_FORCE_STATIC_EXECUTABLE := true LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN) LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED) -LOCAL_STATIC_LIBRARIES := libcutils libc libmincrypt +LOCAL_STATIC_LIBRARIES := liblog libcutils libc libmincrypt libselinux include $(BUILD_EXECUTABLE) @@ -156,7 +155,6 @@ LOCAL_SRC_FILES := \ file_sync_client.c \ get_my_path_linux.c \ usb_linux.c \ - utils.c \ usb_vendors.c \ fdevent.c diff --git a/adb/SERVICES.TXT b/adb/SERVICES.TXT index b53bc44..5966686 100644 --- a/adb/SERVICES.TXT +++ b/adb/SERVICES.TXT @@ -225,27 +225,6 @@ framebuffer: If the adbd daemon doesn't have sufficient privileges to open the framebuffer device, the connection is simply closed immediately. -dns:<server-name> - This service is an exception because it only runs within the ADB server. - It is used to implement USB networking, i.e. to provide a network connection - to the device through the host machine (note: this is the exact opposite of - network tethering). - - It is used to perform a gethostbyname(<address>) on the host and return - the corresponding IP address as a 4-byte string. - -recover:<size> - This service is used to upload a recovery image to the device. <size> - must be a number corresponding to the size of the file. The service works - by: - - - creating a file named /tmp/update - - reading 'size' bytes from the client and writing them to /tmp/update - - when everything is read successfully, create a file named /tmp/update.start - - This service can only work when the device is in recovery mode. Otherwise, - the /tmp directory doesn't exist and the connection will be closed immediately. - jdwp:<pid> Connects to the JDWP thread running in the VM of process <pid>. @@ -34,6 +34,7 @@ #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) #if !ADB_HOST +#include <cutils/properties.h> #include <private/android_filesystem_config.h> #include <sys/capability.h> #include <linux/prctl.h> @@ -326,7 +327,7 @@ static void send_connect(atransport *t) send_packet(cp, t); } -static void send_auth_request(atransport *t) +void send_auth_request(atransport *t) { D("Calling send_auth_request\n"); apacket *p; @@ -407,6 +408,8 @@ static char *connection_state_name(atransport *t) return "sideload"; case CS_OFFLINE: return "offline"; + case CS_UNAUTHORIZED: + return "unauthorized"; default: return "unknown"; } @@ -536,6 +539,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); @@ -558,7 +562,7 @@ void handle_packet(apacket *p, atransport *t) break; case A_OPEN: /* OPEN(local-id, 0, "destination") */ - if (t->online) { + if (t->online && p->msg.arg0 != 0 && p->msg.arg1 == 0) { char *name = (char*) p->data; name[p->msg.data_length > 0 ? p->msg.data_length - 1 : 0] = 0; s = create_local_service_socket(name); @@ -574,28 +578,50 @@ void handle_packet(apacket *p, atransport *t) break; case A_OKAY: /* READY(local-id, remote-id, "") */ - if (t->online) { - if((s = find_local_socket(p->msg.arg1))) { + if (t->online && p->msg.arg0 != 0 && p->msg.arg1 != 0) { + if((s = find_local_socket(p->msg.arg1, 0))) { if(s->peer == 0) { + /* On first READY message, create the connection. */ s->peer = create_remote_socket(p->msg.arg0, t); s->peer->peer = s; + s->ready(s); + } else if (s->peer->id == p->msg.arg0) { + /* Other READY messages must use the same local-id */ + s->ready(s); + } else { + D("Invalid A_OKAY(%d,%d), expected A_OKAY(%d,%d) on transport %s\n", + p->msg.arg0, p->msg.arg1, s->peer->id, p->msg.arg1, t->serial); } - s->ready(s); } } break; - case A_CLSE: /* CLOSE(local-id, remote-id, "") */ - if (t->online) { - if((s = find_local_socket(p->msg.arg1))) { - s->close(s); + case A_CLSE: /* CLOSE(local-id, remote-id, "") or CLOSE(0, remote-id, "") */ + if (t->online && p->msg.arg1 != 0) { + if((s = find_local_socket(p->msg.arg1, p->msg.arg0))) { + /* According to protocol.txt, p->msg.arg0 might be 0 to indicate + * a failed OPEN only. However, due to a bug in previous ADB + * versions, CLOSE(0, remote-id, "") was also used for normal + * CLOSE() operations. + * + * This is bad because it means a compromised adbd could + * send packets to close connections between the host and + * other devices. To avoid this, only allow this if the local + * socket has a peer on the same transport. + */ + if (p->msg.arg0 == 0 && s->peer && s->peer->transport != t) { + D("Invalid A_CLSE(0, %u) from transport %s, expected transport %s\n", + p->msg.arg1, t->serial, s->peer->transport->serial); + } else { + s->close(s); + } } } break; - case A_WRTE: - if (t->online) { - if((s = find_local_socket(p->msg.arg1))) { + case A_WRTE: /* WRITE(local-id, remote-id, <data>) */ + if (t->online && p->msg.arg0 != 0 && p->msg.arg1 != 0) { + if((s = find_local_socket(p->msg.arg1, p->msg.arg0))) { unsigned rid = p->msg.arg0; p->len = p->msg.data_length; @@ -988,6 +1014,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 @@ -1158,6 +1211,32 @@ void build_local_name(char* target_str, size_t target_size, int server_port) } #if !ADB_HOST + +static void drop_capabilities_bounding_set_if_needed() { +#ifdef ALLOW_ADBD_ROOT + char value[PROPERTY_VALUE_MAX]; + property_get("ro.debuggable", value, ""); + if (strcmp(value, "1") == 0) { + return; + } +#endif + int i; + for (i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >= 0; i++) { + if (i == CAP_SETUID || i == CAP_SETGID) { + // CAP_SETUID CAP_SETGID needed by /system/bin/run-as + continue; + } + int err = prctl(PR_CAPBSET_DROP, i, 0, 0, 0); + + // Some kernels don't have file capabilities compiled in, and + // prctl(PR_CAPBSET_DROP) returns EINVAL. Don't automatically + // die when we see such misconfigured kernels. + if ((err < 0) && (errno != EINVAL)) { + exit(1); + } + } +} + static int should_drop_privileges() { #ifndef ALLOW_ADBD_ROOT return 1; @@ -1212,6 +1291,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); @@ -1241,12 +1324,7 @@ int adb_main(int is_daemon, int server_port) /* don't listen on a port (default 5037) if running in secure mode */ /* don't run as root if we are running in secure mode */ if (should_drop_privileges()) { - struct __user_cap_header_struct header; - struct __user_cap_data_struct cap[2]; - - if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) { - exit(1); - } + drop_capabilities_bounding_set_if_needed(); /* add extra groups: ** AID_ADB to access the USB driver @@ -1275,16 +1353,6 @@ int adb_main(int is_daemon, int server_port) exit(1); } - memset(&header, 0, sizeof(header)); - memset(cap, 0, sizeof(cap)); - - /* set CAP_SYS_BOOT capability, so "adb reboot" will succeed */ - header.version = _LINUX_CAPABILITY_VERSION_3; - header.pid = 0; - cap[CAP_TO_INDEX(CAP_SYS_BOOT)].effective |= CAP_TO_MASK(CAP_SYS_BOOT); - cap[CAP_TO_INDEX(CAP_SYS_BOOT)].permitted |= CAP_TO_MASK(CAP_SYS_BOOT); - capset(&header, cap); - D("Local port disabled\n"); } else { char local_name[30]; @@ -1342,105 +1410,6 @@ 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 hostbuf[100]; - char serial[100]; - - strncpy(hostbuf, host, sizeof(hostbuf) - 1); - if (portstr) { - if (portstr - host >= (ptrdiff_t)sizeof(hostbuf)) { - snprintf(buffer, buffer_size, "bad host name %s", host); - return; - } - // zero terminate the host at the point we found the colon - hostbuf[portstr - host] = 0; - if (sscanf(portstr + 1, "%d", &port) == 0) { - snprintf(buffer, buffer_size, "bad port number %s", portstr); - return; - } - } else { - port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT; - } - - snprintf(serial, sizeof(serial), "%s:%d", hostbuf, port); - if (find_transport(serial)) { - snprintf(buffer, buffer_size, "already connected to %s", serial); - return; - } - - fd = socket_network_client(hostbuf, 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); - register_socket_transport(fd, serial, port, 0); - snprintf(buffer, buffer_size, "connected to %s", serial); -} - -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; @@ -1501,21 +1470,6 @@ int handle_host_request(char *service, transport_type ttype, char* serial, int r } } - // add a new TCP transport, device or emulator - if (!strncmp(service, "connect:", 8)) { - char buffer[4096]; - char* host = service + 8; - if (!strncmp(host, "emu:", 4)) { - connect_emulator(host + 4, buffer, sizeof(buffer)); - } else { - connect_device(host, buffer, sizeof(buffer)); - } - // 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; - } - // remove TCP transport if (!strncmp(service, "disconnect:", 11)) { char buffer[4096]; @@ -122,16 +122,19 @@ struct asocket { */ void (*ready)(asocket *s); + /* shutdown is called by the peer before it goes away. + ** the socket should not do any further calls on its peer. + ** Always followed by a call to close. Optional, i.e. can be NULL. + */ + void (*shutdown)(asocket *s); + /* close is called by the peer when it has gone away. ** we are not allowed to make any further calls on the ** peer once our close method is called. */ void (*close)(asocket *s); - /* socket-type-specific extradata */ - void *extra; - - /* A socket is bound to atransport */ + /* A socket is bound to atransport */ atransport *transport; }; @@ -236,7 +239,7 @@ struct alistener void print_packet(const char *label, apacket *p); -asocket *find_local_socket(unsigned id); +asocket *find_local_socket(unsigned local_id, unsigned remote_id); void install_local_socket(asocket *s); void remove_socket(asocket *s); void close_all_sockets(atransport *t); @@ -292,7 +295,7 @@ void init_usb_transport(atransport *t, usb_handle *usb, int state); void close_usb_devices(); /* cause new transports to be init'd and added to the list */ -void register_socket_transport(int s, const char *serial, int port, int local); +int register_socket_transport(int s, const char *serial, int port, int local); /* these should only be used for the "adb disconnect" command */ void unregister_transport(atransport *t); @@ -468,6 +471,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..b24c674 100644 --- a/adb/adb_auth.h +++ b/adb/adb_auth.h @@ -20,6 +20,8 @@ void adb_auth_init(void); void adb_auth_verified(atransport *t); +void send_auth_request(atransport *t); + /* AUTH packets first argument */ /* Request */ #define ADB_AUTH_TOKEN 1 @@ -36,7 +38,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 +48,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..f8d7306 100644 --- a/adb/adb_auth_client.c +++ b/adb/adb_auth_client.c @@ -25,6 +25,7 @@ #include "adb_auth.h" #include "fdevent.h" #include "mincrypt/rsa.h" +#include "mincrypt/sha.h" #define TRACE_TAG TRACE_AUTH @@ -34,8 +35,6 @@ struct adb_public_key { RSAPublicKey key; }; -static struct listnode key_list; - static char *key_paths[] = { "/adb_keys", "/data/misc/adb/adb_keys", @@ -45,6 +44,10 @@ static char *key_paths[] = { static fdevent listener_fde; static int framework_fd = -1; +static void usb_disconnected(void* unused, atransport* t); +static struct adisconnect usb_disconnect = { usb_disconnected, 0, 0, 0 }; +static atransport* usb_transport; +static bool needs_retry = false; static void read_keys(const char *file, struct listnode *list) { @@ -102,18 +105,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,37 +140,50 @@ 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); + ret = RSA_verify(&key->key, sig, siglen, token, SHA_DIGEST_SIZE); if (ret) - return 1; + break; } - return 0; + free_keys(&key_list); + + return ret; +} + +static void usb_disconnected(void* unused, atransport* t) +{ + D("USB disconnect\n"); + remove_transport_disconnect(usb_transport, &usb_disconnect); + usb_transport = NULL; + needs_retry = false; } static void adb_auth_event(int fd, unsigned events, void *data) { - atransport *t = data; char response[2]; int ret; if (events & FDE_READ) { ret = unix_read(fd, response, sizeof(response)); if (ret < 0) { - D("Disconnect"); - fdevent_remove(&t->auth_fde); + D("Framework disconnect\n"); + if (usb_transport) + fdevent_remove(&usb_transport->auth_fde); framework_fd = -1; } else if (ret == 2 && response[0] == 'O' && response[1] == 'K') { - adb_auth_reload_keys(); - adb_auth_verified(t); + if (usb_transport) + adb_auth_verified(usb_transport); } } } @@ -177,8 +193,14 @@ void adb_auth_confirm_key(unsigned char *key, size_t len, atransport *t) char msg[MAX_PAYLOAD]; int ret; + if (!usb_transport) { + usb_transport = t; + add_transport_disconnect(t, &usb_disconnect); + } + if (framework_fd < 0) { D("Client not connected\n"); + needs_retry = true; return; } @@ -219,15 +241,17 @@ static void adb_auth_listener(int fd, unsigned events, void *data) } framework_fd = s; + + if (needs_retry) { + needs_retry = false; + send_auth_request(usb_transport); + } } 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 8340738..f7823a8 100644 --- a/adb/adb_client.c +++ b/adb/adb_client.c @@ -278,7 +278,9 @@ int adb_connect(const char *service) return 0; fd = _adb_connect(service); - if(fd == -2) { + if(fd == -1) { + fprintf(stderr,"error: %s\n", __adb_error); + } else if(fd == -2) { fprintf(stderr,"** daemon still not running\n"); } D("adb_connect: return fd %d\n", fd); diff --git a/adb/commandline.c b/adb/commandline.c index a927423..c9bb437 100644 --- a/adb/commandline.c +++ b/adb/commandline.c @@ -144,12 +144,15 @@ void help() " adb bugreport - return all information from the device\n" " that should be included in a bug report.\n" "\n" - " adb backup [-f <file>] [-apk|-noapk] [-shared|-noshared] [-all] [-system|-nosystem] [<packages...>]\n" + " adb backup [-f <file>] [-apk|-noapk] [-obb|-noobb] [-shared|-noshared] [-all] [-system|-nosystem] [<packages...>]\n" " - write an archive of the device's data to <file>.\n" " If no -f option is supplied then the data is written\n" " to \"backup.ab\" in the current directory.\n" " (-apk|-noapk enable/disable backup of the .apks themselves\n" " in the archive; the default is noapk.)\n" + " (-obb|-noobb enable/disable backup of any installed apk expansion\n" + " (aka .obb) files associated with each application; the default\n" + " is noobb.)\n" " (-shared|-noshared enable/disable backup of the device's\n" " shared storage / SD card contents; the default is noshared.)\n" " (-all means to back up all installed applications)\n" @@ -764,7 +767,7 @@ static int restore(int argc, char** argv) { fd = adb_connect("restore:"); if (fd < 0) { - fprintf(stderr, "adb: unable to connect for backup\n"); + fprintf(stderr, "adb: unable to connect for restore\n"); adb_close(tarFd); return -1; } diff --git a/adb/file_sync_client.c b/adb/file_sync_client.c index 64e393c..9fec081 100644 --- a/adb/file_sync_client.c +++ b/adb/file_sync_client.c @@ -32,7 +32,7 @@ #include "file_sync_service.h" -static unsigned total_bytes; +static unsigned long long total_bytes; static long long start_time; static long long NOW() @@ -58,8 +58,8 @@ static void END() t = 1000000; fprintf(stderr,"%lld KB/s (%lld bytes in %lld.%03llds)\n", - ((((long long) total_bytes) * 1000000LL) / t) / 1024LL, - (long long) total_bytes, (t / 1000000LL), (t % 1000000LL) / 1000LL); + ((total_bytes * 1000000LL) / t) / 1024LL, + total_bytes, (t / 1000000LL), (t % 1000000LL) / 1000LL); } void sync_quit(int fd) @@ -642,8 +642,8 @@ static int local_build_list(copyinfo **filelist, ci = mkcopyinfo(lpath, rpath, name, 0); if(lstat(ci->src, &st)) { fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno)); + free(ci); closedir(d); - return -1; } if(!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) { diff --git a/adb/file_sync_service.c b/adb/file_sync_service.c index d3e841b..c30f9fb 100644 --- a/adb/file_sync_service.c +++ b/adb/file_sync_service.c @@ -22,19 +22,32 @@ #include <sys/types.h> #include <dirent.h> #include <utime.h> +#include <unistd.h> #include <errno.h> - +#include <private/android_filesystem_config.h> +#include <selinux/android.h> #include "sysdeps.h" #define TRACE_TAG TRACE_SYNC #include "adb.h" #include "file_sync_service.h" +/* TODO: use fs_config to configure permissions on /data */ +static bool is_on_system(const char *name) { + const char *SYSTEM = "/system/"; + return (strncmp(SYSTEM, name, strlen(SYSTEM)) == 0); +} + static int mkdirs(char *name) { int ret; char *x = name + 1; + unsigned int uid, gid; + unsigned int mode = 0775; + uint64_t cap = 0; + uid = getuid(); + gid = getgid(); if(name[0] != '/') return -1; @@ -42,11 +55,21 @@ static int mkdirs(char *name) x = adb_dirstart(x); if(x == 0) return 0; *x = 0; - ret = adb_mkdir(name, 0775); + if (is_on_system(name)) { + fs_config(name, 1, &uid, &gid, &mode, &cap); + } + ret = adb_mkdir(name, mode); if((ret < 0) && (errno != EEXIST)) { D("mkdir(\"%s\") -> %s\n", name, strerror(errno)); *x = '/'; return ret; + } else if(ret == 0) { + ret = chown(name, uid, gid); + if (ret < 0) { + *x = '/'; + return ret; + } + selinux_android_restorecon(name); } *x++ = '/'; } @@ -110,6 +133,7 @@ static int do_list(int s, const char *path) if(writex(s, &msg.dent, sizeof(msg.dent)) || writex(s, de->d_name, len)) { + closedir(d); return -1; } } @@ -148,7 +172,8 @@ static int fail_errno(int s) return fail_message(s, strerror(errno)); } -static int handle_send_file(int s, char *path, mode_t mode, char *buffer) +static int handle_send_file(int s, char *path, unsigned int uid, + unsigned int gid, mode_t mode, char *buffer) { syncmsg msg; unsigned int timestamp = 0; @@ -156,8 +181,13 @@ static int handle_send_file(int s, char *path, mode_t mode, char *buffer) fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL, mode); if(fd < 0 && errno == ENOENT) { - mkdirs(path); - fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL, mode); + if(mkdirs(path) != 0) { + if(fail_errno(s)) + return -1; + fd = -1; + } else { + fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL, mode); + } } if(fd < 0 && errno == EEXIST) { fd = adb_open_mode(path, O_WRONLY, mode); @@ -166,6 +196,16 @@ static int handle_send_file(int s, char *path, mode_t mode, char *buffer) if(fail_errno(s)) return -1; fd = -1; + } else { + if(fchown(fd, uid, gid) != 0) { + fail_errno(s); + errno = 0; + } + /* fchown clears the setuid bit - restore it if present */ + if(fchmod(fd, mode) != 0) { + fail_errno(s); + errno = 0; + } } for(;;) { @@ -205,6 +245,7 @@ static int handle_send_file(int s, char *path, mode_t mode, char *buffer) if(fd >= 0) { struct utimbuf u; adb_close(fd); + selinux_android_restorecon(path); u.actime = timestamp; u.modtime = timestamp; utime(path, &u); @@ -248,7 +289,10 @@ static int handle_send_link(int s, char *path, char *buffer) ret = symlink(buffer, path); if(ret && errno == ENOENT) { - mkdirs(path); + if(mkdirs(path) != 0) { + fail_errno(s); + return -1; + } ret = symlink(buffer, path); } if(ret) { @@ -276,7 +320,7 @@ static int handle_send_link(int s, char *path, char *buffer) static int do_send(int s, char *path, char *buffer) { char *tmp; - mode_t mode; + unsigned int mode; int is_link, ret; tmp = strrchr(path,','); @@ -287,7 +331,7 @@ static int do_send(int s, char *path, char *buffer) #ifndef HAVE_SYMLINKS is_link = 0; #else - is_link = S_ISLNK(mode); + is_link = S_ISLNK((mode_t) mode); #endif mode &= 0777; } @@ -306,11 +350,23 @@ static int do_send(int s, char *path, char *buffer) #else { #endif + unsigned int uid, gid; + uint64_t cap = 0; + uid = getuid(); + gid = getgid(); + /* copy user permission bits to "group" and "other" permissions */ mode |= ((mode >> 3) & 0070); mode |= ((mode >> 3) & 0007); - ret = handle_send_file(s, path, mode, buffer); + tmp = path; + if(*tmp == '/') { + tmp++; + } + if (is_on_system(path)) { + fs_config(tmp, 0, &uid, &gid, &mode, &cap); + } + ret = handle_send_file(s, path, uid, gid, mode, buffer); } return ret; diff --git a/adb/framebuffer_service.c b/adb/framebuffer_service.c index 20c08d2..fa7fd98 100644 --- a/adb/framebuffer_service.c +++ b/adb/framebuffer_service.c @@ -55,13 +55,13 @@ struct fbinfo { void framebuffer_service(int fd, void *cookie) { struct fbinfo fbinfo; - unsigned int i; + unsigned int i, bsize; char buf[640]; int fd_screencap; int w, h, f; int fds[2]; - if (pipe(fds) < 0) goto done; + if (pipe(fds) < 0) goto pipefail; pid_t pid = fork(); if (pid < 0) goto done; @@ -164,17 +164,19 @@ void framebuffer_service(int fd, void *cookie) if(writex(fd, &fbinfo, sizeof(fbinfo))) goto done; /* write data */ - for(i = 0; i < fbinfo.size; i += sizeof(buf)) { - if(readx(fd_screencap, buf, sizeof(buf))) goto done; - if(writex(fd, buf, sizeof(buf))) goto done; + for(i = 0; i < fbinfo.size; i += bsize) { + bsize = sizeof(buf); + if (i + bsize > fbinfo.size) + bsize = fbinfo.size - i; + if(readx(fd_screencap, buf, bsize)) goto done; + if(writex(fd, buf, bsize)) goto done; } - if(readx(fd_screencap, buf, fbinfo.size % sizeof(buf))) goto done; - if(writex(fd, buf, fbinfo.size % sizeof(buf))) goto done; done: TEMP_FAILURE_RETRY(waitpid(pid, NULL, 0)); close(fds[0]); close(fds[1]); +pipefail: close(fd); } diff --git a/adb/log_service.c b/adb/log_service.c index 6e9bdee..af24356 100644 --- a/adb/log_service.c +++ b/adb/log_service.c @@ -22,7 +22,7 @@ #include <fcntl.h> #include <errno.h> #include <sys/socket.h> -#include <cutils/logger.h> +#include <log/logger.h> #include "sysdeps.h" #include "adb.h" diff --git a/adb/mutex_list.h b/adb/mutex_list.h index 652dd73..ff72751 100644 --- a/adb/mutex_list.h +++ b/adb/mutex_list.h @@ -6,7 +6,6 @@ #ifndef ADB_MUTEX #error ADB_MUTEX not defined when including this file #endif -ADB_MUTEX(dns_lock) ADB_MUTEX(socket_list_lock) ADB_MUTEX(transport_lock) #if ADB_HOST diff --git a/adb/remount_service.c b/adb/remount_service.c index 4cb41e7..ad61284 100644 --- a/adb/remount_service.c +++ b/adb/remount_service.c @@ -72,6 +72,8 @@ static char *find_mount(const char *dir) static int remount_system() { char *dev; + int fd; + int OFF = 0; if (system_ro == 0) { return 0; @@ -82,6 +84,13 @@ static int remount_system() if (!dev) return -1; + fd = unix_open(dev, O_RDONLY); + if (fd < 0) + return -1; + + ioctl(fd, BLKROSET, &OFF); + adb_close(fd); + system_ro = mount(dev, "/system", "none", MS_REMOUNT, NULL); free(dev); diff --git a/adb/services.c b/adb/services.c index 54d21a8..951048e 100644 --- a/adb/services.c +++ b/adb/services.c @@ -14,6 +14,7 @@ * limitations under the License. */ +#include <stddef.h> #include <stdlib.h> #include <stdio.h> #include <unistd.h> @@ -34,6 +35,7 @@ # endif #else # include <cutils/android_reboot.h> +# include <cutils/properties.h> #endif typedef struct stinfo stinfo; @@ -53,59 +55,7 @@ void *service_bootstrap_func(void *x) return 0; } -#if ADB_HOST -ADB_MUTEX_DEFINE( dns_lock ); - -static void dns_service(int fd, void *cookie) -{ - char *hostname = cookie; - struct hostent *hp; - unsigned zero = 0; - - adb_mutex_lock(&dns_lock); - hp = gethostbyname(hostname); - free(cookie); - if(hp == 0) { - writex(fd, &zero, 4); - } else { - writex(fd, hp->h_addr, 4); - } - adb_mutex_unlock(&dns_lock); - adb_close(fd); -} -#else -extern int recovery_mode; - -static void recover_service(int s, void *cookie) -{ - unsigned char buf[4096]; - unsigned count = (unsigned) cookie; - int fd; - - fd = adb_creat("/tmp/update", 0644); - if(fd < 0) { - adb_close(s); - return; - } - - while(count > 0) { - unsigned xfer = (count > 4096) ? 4096 : count; - if(readx(s, buf, xfer)) break; - if(writex(fd, buf, xfer)) break; - count -= xfer; - } - - if(count == 0) { - writex(s, "OKAY", 4); - } else { - writex(s, "FAIL", 4); - } - adb_close(fd); - adb_close(s); - - fd = adb_creat("/tmp/update.begin", 0644); - adb_close(fd); -} +#if !ADB_HOST void restart_root_service(int fd, void *cookie) { @@ -165,6 +115,7 @@ void restart_usb_service(int fd, void *cookie) void reboot_service(int fd, void *arg) { char buf[100]; + char property_val[PROPERTY_VALUE_MAX]; int pid, ret; sync(); @@ -182,51 +133,29 @@ void reboot_service(int fd, void *arg) waitpid(pid, &ret, 0); } - ret = android_reboot(ANDROID_RB_RESTART2, 0, (char *) arg); + ret = snprintf(property_val, sizeof(property_val), "reboot,%s", (char *) arg); + if (ret >= (int) sizeof(property_val)) { + snprintf(buf, sizeof(buf), "reboot string too long. length=%d\n", ret); + writex(fd, buf, strlen(buf)); + goto cleanup; + } + + ret = property_set(ANDROID_RB_PROPERTY, property_val); if (ret < 0) { - snprintf(buf, sizeof(buf), "reboot failed: %s\n", strerror(errno)); + snprintf(buf, sizeof(buf), "reboot failed: %d\n", ret); writex(fd, buf, strlen(buf)); + goto cleanup; } + // Don't return early. Give the reboot command time to take effect + // to avoid messing up scripts which do "adb reboot && adb wait-for-device" + while(1) { pause(); } +cleanup: free(arg); adb_close(fd); } #endif -#if 0 -static void echo_service(int fd, void *cookie) -{ - char buf[4096]; - int r; - char *p; - int c; - - for(;;) { - r = adb_read(fd, buf, 4096); - if(r == 0) goto done; - if(r < 0) { - if(errno == EINTR) continue; - else goto done; - } - - c = r; - p = buf; - while(c > 0) { - r = write(fd, p, c); - if(r > 0) { - c -= r; - p += r; - continue; - } - if((r < 0) && (errno == EINTR)) continue; - goto done; - } - } -done: - close(fd); -} -#endif - static int create_service_thread(void (*func)(int, void *), void *cookie) { stinfo *sti; @@ -413,9 +342,7 @@ int service_to_fd(const char *name) disable_tcp_nagle(ret); } else { #if ADB_HOST - adb_mutex_lock(&dns_lock); ret = socket_network_client(name + 1, port, SOCK_STREAM); - adb_mutex_unlock(&dns_lock); #else return -1; #endif @@ -434,18 +361,11 @@ int service_to_fd(const char *name) ret = socket_local_client(name + 16, ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM); #endif -#if ADB_HOST - } else if(!strncmp("dns:", name, 4)){ - char *n = strdup(name + 4); - if(n == 0) return -1; - ret = create_service_thread(dns_service, n); -#else /* !ADB_HOST */ +#if !ADB_HOST } else if(!strncmp("dev:", name, 4)) { ret = unix_open(name + 4, O_RDWR); } else if(!strncmp(name, "framebuffer:", 12)) { ret = create_service_thread(framebuffer_service, 0); - } else if(recovery_mode && !strncmp(name, "recover:", 8)) { - ret = create_service_thread(recover_service, (void*) atoi(name + 8)); } else if (!strncmp(name, "jdwp:", 5)) { ret = create_jdwp_connection_fd(atoi(name+5)); } else if (!strncmp(name, "log:", 4)) { @@ -481,10 +401,6 @@ int service_to_fd(const char *name) } else if(!strncmp(name, "usb:", 4)) { ret = create_service_thread(restart_usb_service, NULL); #endif -#if 0 - } else if(!strncmp(name, "echo:", 5)){ - ret = create_service_thread(echo_service, 0); -#endif } if (ret >= 0) { close_on_exec(ret); @@ -519,6 +435,124 @@ static void wait_for_state(int fd, void* cookie) adb_close(fd); D("wait_for_state is done\n"); } + +static void connect_device(char* host, char* buffer, int buffer_size) +{ + int port, fd; + char* portstr = strchr(host, ':'); + char hostbuf[100]; + char serial[100]; + int ret; + + strncpy(hostbuf, host, sizeof(hostbuf) - 1); + if (portstr) { + if (portstr - host >= (ptrdiff_t)sizeof(hostbuf)) { + snprintf(buffer, buffer_size, "bad host name %s", host); + return; + } + // zero terminate the host at the point we found the colon + hostbuf[portstr - host] = 0; + if (sscanf(portstr + 1, "%d", &port) == 0) { + snprintf(buffer, buffer_size, "bad port number %s", portstr); + return; + } + } else { + port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT; + } + + snprintf(serial, sizeof(serial), "%s:%d", hostbuf, port); + + fd = socket_network_client(hostbuf, 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); + + ret = register_socket_transport(fd, serial, port, 0); + if (ret < 0) { + adb_close(fd); + snprintf(buffer, buffer_size, "already connected to %s", serial); + } else { + snprintf(buffer, buffer_size, "connected to %s", serial); + } +} + +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); + } +} + +static void connect_service(int fd, void* cookie) +{ + char buf[4096]; + char resp[4096]; + char *host = cookie; + + if (!strncmp(host, "emu:", 4)) { + connect_emulator(host + 4, buf, sizeof(buf)); + } else { + connect_device(host, buf, sizeof(buf)); + } + + // Send response for emulator and device + snprintf(resp, sizeof(resp), "%04x%s",(unsigned)strlen(buf), buf); + writex(fd, resp, strlen(resp)); + adb_close(fd); +} #endif #if ADB_HOST @@ -552,6 +586,10 @@ asocket* host_service_to_socket(const char* name, const char *serial) int fd = create_service_thread(wait_for_state, sinfo); return create_local_socket(fd); + } else if (!strncmp(name, "connect:", 8)) { + const char *host = name + 8; + int fd = create_service_thread(connect_service, (void *)host); + return create_local_socket(fd); } return NULL; } diff --git a/adb/sockets.c b/adb/sockets.c index 305cb44..7f54ad9 100644 --- a/adb/sockets.c +++ b/adb/sockets.c @@ -59,17 +59,22 @@ static asocket local_socket_closing_list = { .prev = &local_socket_closing_list, }; -asocket *find_local_socket(unsigned id) +// Parse the global list of sockets to find one with id |local_id|. +// If |peer_id| is not 0, also check that it is connected to a peer +// with id |peer_id|. Returns an asocket handle on success, NULL on failure. +asocket *find_local_socket(unsigned local_id, unsigned peer_id) { asocket *s; asocket *result = NULL; adb_mutex_lock(&socket_list_lock); for (s = local_socket_list.next; s != &local_socket_list; s = s->next) { - if (s->id == id) { + if (s->id != local_id) + continue; + if (peer_id == 0 || (s->peer && s->peer->id == peer_id)) { result = s; - break; } + break; } adb_mutex_unlock(&socket_list_lock); @@ -91,6 +96,11 @@ void install_local_socket(asocket *s) adb_mutex_lock(&socket_list_lock); s->id = local_socket_next_id++; + + // Socket ids should never be 0. + if (local_socket_next_id == 0) + local_socket_next_id = 1; + insert_local_socket(s, &local_socket_list); adb_mutex_unlock(&socket_list_lock); @@ -230,6 +240,12 @@ static void local_socket_close_locked(asocket *s) if(s->peer) { D("LS(%d): closing peer. peer->id=%d peer->fd=%d\n", s->id, s->peer->id, s->peer->fd); + /* Note: it's important to call shutdown before disconnecting from + * the peer, this ensures that remote sockets can still get the id + * of the local socket they're connected to, to send a CLOSE() + * protocol event. */ + if (s->peer->shutdown) + s->peer->shutdown(s->peer); s->peer->peer = 0; // tweak to avoid deadlock if (s->peer->close == local_socket_close) { @@ -397,6 +413,7 @@ asocket *create_local_socket(int fd) s->fd = fd; s->enqueue = local_socket_enqueue; s->ready = local_socket_ready; + s->shutdown = NULL; s->close = local_socket_close; install_local_socket(s); @@ -485,21 +502,29 @@ static void remote_socket_ready(asocket *s) send_packet(p, s->transport); } -static void remote_socket_close(asocket *s) +static void remote_socket_shutdown(asocket *s) { - D("entered remote_socket_close RS(%d) CLOSE fd=%d peer->fd=%d\n", + D("entered remote_socket_shutdown RS(%d) CLOSE fd=%d peer->fd=%d\n", s->id, s->fd, s->peer?s->peer->fd:-1); apacket *p = get_apacket(); p->msg.command = A_CLSE; if(s->peer) { p->msg.arg0 = s->peer->id; + } + p->msg.arg1 = s->id; + send_packet(p, s->transport); +} + +static void remote_socket_close(asocket *s) +{ + if (s->peer) { s->peer->peer = 0; D("RS(%d) peer->close()ing peer->id=%d peer->fd=%d\n", s->id, s->peer->id, s->peer->fd); s->peer->close(s->peer); } - p->msg.arg1 = s->id; - send_packet(p, s->transport); + D("entered remote_socket_close RS(%d) CLOSE fd=%d peer->fd=%d\n", + s->id, s->fd, s->peer?s->peer->fd:-1); D("RS(%d): closed\n", s->id); remove_transport_disconnect( s->transport, &((aremotesocket*)s)->disconnect ); free(s); @@ -519,15 +544,24 @@ static void remote_socket_disconnect(void* _s, atransport* t) free(s); } +/* Create an asocket to exchange packets with a remote service through transport + |t|. Where |id| is the socket id of the corresponding service on the other + side of the transport (it is allocated by the remote side and _cannot_ be 0). + Returns a new non-NULL asocket handle. */ asocket *create_remote_socket(unsigned id, atransport *t) { - asocket *s = calloc(1, sizeof(aremotesocket)); - adisconnect* dis = &((aremotesocket*)s)->disconnect; + asocket* s; + adisconnect* dis; + + if (id == 0) fatal("invalid remote socket id (0)"); + s = calloc(1, sizeof(aremotesocket)); + dis = &((aremotesocket*)s)->disconnect; if (s == NULL) fatal("cannot allocate socket"); s->id = id; s->enqueue = remote_socket_enqueue; s->ready = remote_socket_ready; + s->shutdown = remote_socket_shutdown; s->close = remote_socket_close; s->transport = t; @@ -562,6 +596,7 @@ void connect_to_remote(asocket *s, const char *destination) static void local_socket_ready_notify(asocket *s) { s->ready = local_socket_ready; + s->shutdown = NULL; s->close = local_socket_close; adb_write(s->fd, "OKAY", 4); s->ready(s); @@ -573,6 +608,7 @@ static void local_socket_ready_notify(asocket *s) static void local_socket_close_notify(asocket *s) { s->ready = local_socket_ready; + s->shutdown = NULL; s->close = local_socket_close; sendfailmsg(s->fd, "closed"); s->close(s); @@ -767,6 +803,7 @@ static int smart_socket_enqueue(asocket *s, apacket *p) adb_write(s->peer->fd, "OKAY", 4); s->peer->ready = local_socket_ready; + s->peer->shutdown = NULL; s->peer->close = local_socket_close; s->peer->peer = s2; s2->peer = s->peer; @@ -806,6 +843,7 @@ static int smart_socket_enqueue(asocket *s, apacket *p) ** tear down */ s->peer->ready = local_socket_ready_notify; + s->peer->shutdown = NULL; s->peer->close = local_socket_close_notify; s->peer->peer = 0; /* give him our transport and upref it */ @@ -844,29 +882,24 @@ static void smart_socket_close(asocket *s) free(s); } -asocket *create_smart_socket(void (*action_cb)(asocket *s, const char *act)) +static asocket *create_smart_socket(void) { D("Creating smart socket \n"); asocket *s = calloc(1, sizeof(asocket)); if (s == NULL) fatal("cannot allocate socket"); s->enqueue = smart_socket_enqueue; s->ready = smart_socket_ready; + s->shutdown = NULL; s->close = smart_socket_close; - s->extra = action_cb; - D("SS(%d): created %p\n", s->id, action_cb); + D("SS(%d)\n", s->id); return s; } -void smart_socket_action(asocket *s, const char *act) -{ - -} - void connect_to_smartsocket(asocket *s) { D("Connecting to smart socket \n"); - asocket *ss = create_smart_socket(smart_socket_action); + asocket *ss = create_smart_socket(); s->peer = ss; ss->peer = s; s->ready(s); diff --git a/adb/sysdeps.h b/adb/sysdeps.h index 0252ef3..4033b72 100644 --- a/adb/sysdeps.h +++ b/adb/sysdeps.h @@ -261,7 +261,6 @@ extern char* adb_strtok_r(char *str, const char *delim, char **saveptr); #include "fdevent.h" #include <cutils/sockets.h> -#include <cutils/properties.h> #include <cutils/misc.h> #include <signal.h> #include <sys/wait.h> diff --git a/adb/transport.c b/adb/transport.c index 9fd6cc2..224fe55 100644 --- a/adb/transport.c +++ b/adb/transport.c @@ -32,6 +32,11 @@ static atransport transport_list = { .prev = &transport_list, }; +static atransport pending_list = { + .next = &pending_list, + .prev = &pending_list, +}; + ADB_MUTEX_DEFINE( transport_lock ); #if ADB_TRACE @@ -645,8 +650,11 @@ static void transport_registration_func(int _fd, unsigned ev, void *data) } } - /* put us on the master device list */ adb_mutex_lock(&transport_lock); + /* remove from pending list */ + t->next->prev = t->prev; + t->prev->next = t->next; + /* put us on the master device list */ t->next = &transport_list; t->prev = transport_list.prev; t->next->prev = t; @@ -851,6 +859,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 +902,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"; } } @@ -982,9 +997,10 @@ void close_usb_devices() } #endif // ADB_HOST -void register_socket_transport(int s, const char *serial, int port, int local) +int register_socket_transport(int s, const char *serial, int port, int local) { atransport *t = calloc(1, sizeof(atransport)); + atransport *n; char buff[32]; if (!serial) { @@ -992,15 +1008,37 @@ void register_socket_transport(int s, const char *serial, int port, int local) serial = buff; } D("transport: %s init'ing for socket %d, on port %d\n", serial, s, port); - if ( init_socket_transport(t, s, port, local) < 0 ) { - adb_close(s); + if (init_socket_transport(t, s, port, local) < 0) { free(t); - return; + return -1; } - if(serial) { - t->serial = strdup(serial); + + adb_mutex_lock(&transport_lock); + for (n = pending_list.next; n != &pending_list; n = n->next) { + if (n->serial && !strcmp(serial, n->serial)) { + adb_mutex_unlock(&transport_lock); + free(t); + return -1; + } } + + for (n = transport_list.next; n != &transport_list; n = n->next) { + if (n->serial && !strcmp(serial, n->serial)) { + adb_mutex_unlock(&transport_lock); + free(t); + return -1; + } + } + + t->next = &pending_list; + t->prev = pending_list.prev; + t->next->prev = t; + t->prev->next = t; + t->serial = strdup(serial); + adb_mutex_unlock(&transport_lock); + register_transport(t); + return 0; } #if ADB_HOST @@ -1070,6 +1108,14 @@ void register_usb_transport(usb_handle *usb, const char *serial, const char *dev if(devpath) { t->devpath = strdup(devpath); } + + adb_mutex_lock(&transport_lock); + t->next = &pending_list; + t->prev = pending_list.prev; + t->next->prev = t; + t->prev->next = t; + adb_mutex_unlock(&transport_lock); + register_transport(t); } diff --git a/adb/transport_local.c b/adb/transport_local.c index 96a24ba..1cfa24d 100644 --- a/adb/transport_local.c +++ b/adb/transport_local.c @@ -21,6 +21,9 @@ #include "sysdeps.h" #include <sys/types.h> +#if !ADB_HOST +#include <cutils/properties.h> +#endif #define TRACE_TAG TRACE_TRANSPORT #include "adb.h" diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c index 8edec86..b39bcc0 100755 --- a/adb/usb_vendors.c +++ b/adb/usb_vendors.c @@ -143,7 +143,22 @@ #define VENDOR_ID_BYD 0x1D91 // OUYA's USB Vendor ID #define VENDOR_ID_OUYA 0x2836 - +// Haier's USB Vendor ID +#define VENDOR_ID_HAIER 0x201E +// Hisense's USB Vendor ID +#define VENDOR_ID_HISENSE 0x109b +// MTK's USB Vendor ID +#define VENDOR_ID_MTK 0x0e8d +// B&N Nook's USB Vendor ID +#define VENDOR_ID_NOOK 0x2080 +// Qisda's USB Vendor ID +#define VENDOR_ID_QISDA 0x1D45 +// ECS's USB Vendor ID +#define VENDOR_ID_ECS 0x03fc +// MSI's USB Vendor ID +#define VENDOR_ID_MSI 0x0DB0 +// Wacom's USB Vendor ID +#define VENDOR_ID_WACOM 0x0531 /** built-in vendor list */ int builtInVendorIds[] = { @@ -201,6 +216,14 @@ int builtInVendorIds[] = { VENDOR_ID_XIAOMI, VENDOR_ID_BYD, VENDOR_ID_OUYA, + VENDOR_ID_HAIER, + VENDOR_ID_HISENSE, + VENDOR_ID_MTK, + VENDOR_ID_NOOK, + VENDOR_ID_QISDA, + VENDOR_ID_ECS, + VENDOR_ID_MSI, + VENDOR_ID_WACOM, }; #define BUILT_IN_VENDOR_COUNT (sizeof(builtInVendorIds)/sizeof(builtInVendorIds[0])) diff --git a/adb/utils.c b/adb/utils.c deleted file mode 100644 index 91518ba..0000000 --- a/adb/utils.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "utils.h" -#include <stdarg.h> -#include <stdio.h> -#include <string.h> - -char* -buff_addc (char* buff, char* buffEnd, int c) -{ - int avail = buffEnd - buff; - - if (avail <= 0) /* already in overflow mode */ - return buff; - - if (avail == 1) { /* overflowing, the last byte is reserved for zero */ - buff[0] = 0; - return buff + 1; - } - - buff[0] = (char) c; /* add char and terminating zero */ - buff[1] = 0; - return buff + 1; -} - -char* -buff_adds (char* buff, char* buffEnd, const char* s) -{ - int slen = strlen(s); - - return buff_addb(buff, buffEnd, s, slen); -} - -char* -buff_addb (char* buff, char* buffEnd, const void* data, int len) -{ - int avail = (buffEnd - buff); - - if (avail <= 0 || len <= 0) /* already overflowing */ - return buff; - - if (len > avail) - len = avail; - - memcpy(buff, data, len); - - buff += len; - - /* ensure there is a terminating zero */ - if (buff >= buffEnd) { /* overflow */ - buff[-1] = 0; - } else - buff[0] = 0; - - return buff; -} - -char* -buff_add (char* buff, char* buffEnd, const char* format, ... ) -{ - int avail; - - avail = (buffEnd - buff); - - if (avail > 0) { - va_list args; - int nn; - - va_start(args, format); - nn = vsnprintf( buff, avail, format, args); - va_end(args); - - if (nn < 0) { - /* some C libraries return -1 in case of overflow, - * but they will also do that if the format spec is - * invalid. We assume ADB is not buggy enough to - * trigger that last case. */ - nn = avail; - } - else if (nn > avail) { - nn = avail; - } - - buff += nn; - - /* ensure that there is a terminating zero */ - if (buff >= buffEnd) - buff[-1] = 0; - else - buff[0] = 0; - } - return buff; -} diff --git a/adb/utils.h b/adb/utils.h deleted file mode 100644 index f70ecd2..0000000 --- a/adb/utils.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef _ADB_UTILS_H -#define _ADB_UTILS_H - -/* bounded buffer functions */ - -/* all these functions are used to append data to a bounded buffer. - * - * after each operation, the buffer is guaranteed to be zero-terminated, - * even in the case of an overflow. they all return the new buffer position - * which allows one to use them in succession, only checking for overflows - * at the end. For example: - * - * BUFF_DECL(temp,p,end,1024); - * char* p; - * - * p = buff_addc(temp, end, '"'); - * p = buff_adds(temp, end, string); - * p = buff_addc(temp, end, '"'); - * - * if (p >= end) { - * overflow detected. note that 'temp' is - * zero-terminated for safety. - * } - * return strdup(temp); - */ - -/* tries to add a character to the buffer, in case of overflow - * this will only write a terminating zero and return buffEnd. - */ -char* buff_addc (char* buff, char* buffEnd, int c); - -/* tries to add a string to the buffer */ -char* buff_adds (char* buff, char* buffEnd, const char* s); - -/* tries to add a bytes to the buffer. the input can contain zero bytes, - * but a terminating zero will always be appended at the end anyway - */ -char* buff_addb (char* buff, char* buffEnd, const void* data, int len); - -/* tries to add a formatted string to a bounded buffer */ -char* buff_add (char* buff, char* buffEnd, const char* format, ... ); - -/* convenience macro used to define a bounded buffer, as well as - * a 'cursor' and 'end' variables all in one go. - * - * note: this doesn't place an initial terminating zero in the buffer, - * you need to use one of the buff_ functions for this. or simply - * do _cursor[0] = 0 manually. - */ -#define BUFF_DECL(_buff,_cursor,_end,_size) \ - char _buff[_size], *_cursor=_buff, *_end = _cursor + (_size) - -#endif /* _ADB_UTILS_H */ |