diff options
Diffstat (limited to 'adb')
-rw-r--r-- | adb/Android.mk | 24 | ||||
-rw-r--r-- | adb/SERVICES.TXT | 34 | ||||
-rw-r--r-- | adb/adb.c | 528 | ||||
-rw-r--r-- | adb/adb.h | 32 | ||||
-rw-r--r-- | adb/adb_auth.h | 54 | ||||
-rw-r--r-- | adb/adb_auth_client.c | 245 | ||||
-rw-r--r-- | adb/adb_auth_host.c | 426 | ||||
-rw-r--r-- | adb/adb_client.c | 19 | ||||
-rw-r--r-- | adb/adb_client.h | 4 | ||||
-rw-r--r-- | adb/commandline.c | 161 | ||||
-rw-r--r-- | adb/protocol.txt | 21 | ||||
-rw-r--r-- | adb/services.c | 2 | ||||
-rw-r--r-- | adb/sockets.c | 18 | ||||
-rw-r--r-- | adb/sysdeps.h | 43 | ||||
-rw-r--r-- | adb/sysdeps_win32.c | 80 | ||||
-rw-r--r-- | adb/transport.c | 125 | ||||
-rw-r--r-- | adb/usb_libusb.c | 2 | ||||
-rw-r--r-- | adb/usb_linux.c | 35 | ||||
-rw-r--r-- | adb/usb_linux_client.c | 369 | ||||
-rw-r--r-- | adb/usb_osx.c | 10 | ||||
-rw-r--r-- | adb/usb_vendors.c | 8 | ||||
-rw-r--r-- | adb/usb_windows.c | 2 |
22 files changed, 2072 insertions, 170 deletions
diff --git a/adb/Android.mk b/adb/Android.mk index 1a25106..32dd95a 100644 --- a/adb/Android.mk +++ b/adb/Android.mk @@ -16,7 +16,7 @@ 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 endif ifeq ($(HOST_OS),darwin) @@ -33,16 +33,16 @@ endif ifeq ($(HOST_OS),windows) USB_SRCS := usb_windows.c - EXTRA_SRCS := get_my_path_windows.c + EXTRA_SRCS := get_my_path_windows.c ../libcutils/list.c EXTRA_STATIC_LIBS := AdbWinApi ifneq ($(strip $(USE_CYGWIN)),) # Pure cygwin case - LOCAL_LDLIBS += -lpthread + LOCAL_LDLIBS += -lpthread -lgdi32 LOCAL_C_INCLUDES += /usr/include/w32api/ddk endif ifneq ($(strip $(USE_MINGW)),) # MinGW under Linux case - LOCAL_LDLIBS += -lws2_32 + LOCAL_LDLIBS += -lws2_32 -lgdi32 USE_SYSDEPS_WIN32 := 1 LOCAL_C_INCLUDES += /usr/i586-mingw32msvc/include/ddk endif @@ -57,6 +57,7 @@ LOCAL_SRC_FILES := \ transport_usb.c \ commandline.c \ adb_client.c \ + adb_auth_host.c \ sockets.c \ services.c \ file_sync_client.c \ @@ -65,6 +66,7 @@ LOCAL_SRC_FILES := \ utils.c \ usb_vendors.c +LOCAL_C_INCLUDES += external/openssl/include ifneq ($(USE_SYSDEPS_WIN32),) LOCAL_SRC_FILES += sysdeps_win32.c @@ -76,14 +78,14 @@ LOCAL_CFLAGS += -O2 -g -DADB_HOST=1 -Wall -Wno-unused-parameter LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE LOCAL_MODULE := adb -LOCAL_STATIC_LIBRARIES := libzipfile libunz $(EXTRA_STATIC_LIBS) +LOCAL_STATIC_LIBRARIES := libzipfile libunz libcrypto_static $(EXTRA_STATIC_LIBS) ifeq ($(USE_SYSDEPS_WIN32),) LOCAL_STATIC_LIBRARIES += libcutils endif include $(BUILD_HOST_EXECUTABLE) -$(call dist-for-goals,dist_files,$(LOCAL_BUILT_MODULE)) +$(call dist-for-goals,dist_files sdk,$(LOCAL_BUILT_MODULE)) ifeq ($(HOST_OS),windows) $(LOCAL_INSTALLED_MODULE): \ @@ -104,6 +106,7 @@ LOCAL_SRC_FILES := \ transport.c \ transport_local.c \ transport_usb.c \ + adb_auth_client.c \ sockets.c \ services.c \ file_sync_service.c \ @@ -127,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 +LOCAL_STATIC_LIBRARIES := libcutils libc libmincrypt include $(BUILD_EXECUTABLE) @@ -136,7 +139,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 \ @@ -146,6 +149,7 @@ LOCAL_SRC_FILES := \ transport_usb.c \ commandline.c \ adb_client.c \ + adb_auth_host.c \ sockets.c \ services.c \ file_sync_client.c \ @@ -165,9 +169,13 @@ LOCAL_CFLAGS := \ -D_XOPEN_SOURCE \ -D_GNU_SOURCE +LOCAL_C_INCLUDES += external/openssl/include + LOCAL_MODULE := adb LOCAL_STATIC_LIBRARIES := libzipfile libunz libcutils +LOCAL_SHARED_LIBRARIES := libcrypto + include $(BUILD_EXECUTABLE) endif diff --git a/adb/SERVICES.TXT b/adb/SERVICES.TXT index be4d50b..b53bc44 100644 --- a/adb/SERVICES.TXT +++ b/adb/SERVICES.TXT @@ -17,8 +17,10 @@ host:kill upgrade. host:devices +host:devices-l Ask to return the list of available Android devices and their - state. After the OKAY, this is followed by a 4-byte hex len, + state. devices-l includes the device paths in the state. + After the OKAY, this is followed by a 4-byte hex len, and a string that will be dumped as-is by the client, then the connection is closed @@ -88,6 +90,9 @@ host:<request> Returns the serial number of the corresponding device/emulator. Note that emulator serial numbers are of the form "emulator-5554" +<host-prefix>:get-devpath + Returns the device path of the corresponding device/emulator. + <host-prefix>:get-state Returns the state of a given device as a string. @@ -112,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: @@ -21,17 +21,23 @@ #include <ctype.h> #include <stdarg.h> #include <errno.h> +#include <stddef.h> #include <string.h> #include <time.h> #include <sys/time.h> +#include <stdint.h> #include "sysdeps.h" #include "adb.h" +#include "adb_auth.h" + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) #if !ADB_HOST #include <private/android_filesystem_config.h> -#include <linux/capability.h> +#include <sys/capability.h> #include <linux/prctl.h> +#include <sys/mount.h> #else #include "usb_vendors.h" #endif @@ -41,8 +47,13 @@ ADB_MUTEX_DEFINE( D_lock ); #endif int HOST = 0; +int gListenAll = 0; + +static int auth_enabled = 0; +#if !ADB_HOST static const char *adb_device_banner = "device"; +#endif void fatal(const char *fmt, ...) { @@ -94,6 +105,7 @@ void adb_trace_init(void) { "transport", TRACE_TRANSPORT }, { "jdwp", TRACE_JDWP }, { "services", TRACE_SERVICES }, + { "auth", TRACE_AUTH }, { NULL, 0 } }; @@ -197,19 +209,21 @@ void put_apacket(apacket *p) free(p); } -void handle_online(void) +void handle_online(atransport *t) { D("adb: online\n"); + t->online = 1; } void handle_offline(atransport *t) { D("adb: offline\n"); //Close the associated usb + t->online = 0; run_transport_disconnects(t); } -#if TRACE_PACKETS +#if DEBUG_PACKETS #define DUMPMAX 32 void print_packet(const char *label, apacket *p) { @@ -224,6 +238,7 @@ void print_packet(const char *label, apacket *p) case A_OKAY: tag = "OKAY"; break; case A_CLSE: tag = "CLSE"; break; case A_WRTE: tag = "WRTE"; break; + case A_AUTH: tag = "AUTH"; break; default: tag = "????"; break; } @@ -245,7 +260,7 @@ void print_packet(const char *label, apacket *p) } x++; } - fprintf(stderr, tag); + fputs(tag, stderr); } #endif @@ -269,6 +284,36 @@ static void send_close(unsigned local, unsigned remote, atransport *t) send_packet(p, t); } +static size_t fill_connect_data(char *buf, size_t bufsize) +{ +#if ADB_HOST + return snprintf(buf, bufsize, "host::") + 1; +#else + static const char *cnxn_props[] = { + "ro.product.name", + "ro.product.model", + "ro.product.device", + }; + static const int num_cnxn_props = ARRAY_SIZE(cnxn_props); + int i; + size_t remaining = bufsize; + size_t len; + + len = snprintf(buf, remaining, "%s::", adb_device_banner); + remaining -= len; + buf += len; + for (i = 0; i < num_cnxn_props; i++) { + char value[PROPERTY_VALUE_MAX]; + property_get(cnxn_props[i], value, ""); + len = snprintf(buf, remaining, "%s=%s;", cnxn_props[i], value); + remaining -= len; + buf += len; + } + + return bufsize - remaining + 1; +#endif +} + static void send_connect(atransport *t) { D("Calling send_connect \n"); @@ -276,15 +321,73 @@ static void send_connect(atransport *t) cp->msg.command = A_CNXN; cp->msg.arg0 = A_VERSION; cp->msg.arg1 = MAX_PAYLOAD; - snprintf((char*) cp->data, sizeof cp->data, "%s::", - HOST ? "host" : adb_device_banner); - cp->msg.data_length = strlen((char*) cp->data) + 1; + cp->msg.data_length = fill_connect_data((char *)cp->data, + sizeof(cp->data)); send_packet(cp, t); -#if ADB_HOST - /* XXX why sleep here? */ - // allow the device some time to respond to the connect message - adb_sleep_ms(1000); -#endif +} + +static void send_auth_request(atransport *t) +{ + D("Calling send_auth_request\n"); + apacket *p; + int ret; + + ret = adb_auth_generate_token(t->token, sizeof(t->token)); + if (ret != sizeof(t->token)) { + D("Error generating token ret=%d\n", ret); + return; + } + + p = get_apacket(); + memcpy(p->data, t->token, ret); + p->msg.command = A_AUTH; + p->msg.arg0 = ADB_AUTH_TOKEN; + p->msg.data_length = ret; + send_packet(p, t); +} + +static void send_auth_response(uint8_t *token, size_t token_size, atransport *t) +{ + D("Calling send_auth_response\n"); + apacket *p = get_apacket(); + int ret; + + ret = adb_auth_sign(t->key, token, token_size, p->data); + if (!ret) { + D("Error signing the token\n"); + put_apacket(p); + return; + } + + p->msg.command = A_AUTH; + p->msg.arg0 = ADB_AUTH_SIGNATURE; + p->msg.data_length = ret; + send_packet(p, t); +} + +static void send_auth_publickey(atransport *t) +{ + D("Calling send_auth_publickey\n"); + apacket *p = get_apacket(); + int ret; + + ret = adb_auth_get_userkey(p->data, sizeof(p->data)); + if (!ret) { + D("Failed to get user public key\n"); + put_apacket(p); + return; + } + + p->msg.command = A_AUTH; + p->msg.arg0 = ADB_AUTH_RSAPUBLICKEY; + p->msg.data_length = ret; + send_packet(p, t); +} + +void adb_auth_verified(atransport *t) +{ + handle_online(t); + send_connect(t); } static char *connection_state_name(atransport *t) @@ -305,29 +408,56 @@ static char *connection_state_name(atransport *t) } } +/* qual_overwrite is used to overwrite a qualifier string. dst is a + * pointer to a char pointer. It is assumed that if *dst is non-NULL, it + * was malloc'ed and needs to freed. *dst will be set to a dup of src. + */ +static void qual_overwrite(char **dst, const char *src) +{ + if (!dst) + return; + + free(*dst); + *dst = NULL; + + if (!src || !*src) + return; + + *dst = strdup(src); +} + void parse_banner(char *banner, atransport *t) { - char *type, *product, *end; + static const char *prop_seps = ";"; + static const char key_val_sep = '='; + char *cp; + char *type; D("parse_banner: %s\n", banner); type = banner; - product = strchr(type, ':'); - if(product) { - *product++ = 0; - } else { - product = ""; - } - - /* remove trailing ':' */ - end = strchr(product, ':'); - if(end) *end = 0; - - /* save product name in device structure */ - if (t->product == NULL) { - t->product = strdup(product); - } else if (strcmp(product, t->product) != 0) { - free(t->product); - t->product = strdup(product); + cp = strchr(type, ':'); + if (cp) { + *cp++ = 0; + /* Nothing is done with second field. */ + cp = strchr(cp, ':'); + if (cp) { + char *save; + char *key; + key = adb_strtok_r(cp + 1, prop_seps, &save); + while (key) { + cp = strchr(key, key_val_sep); + if (cp) { + *cp++ = '\0'; + if (!strcmp(key, "ro.product.name")) + qual_overwrite(&t->product, cp); + else if (!strcmp(key, "ro.product.model")) + qual_overwrite(&t->model, cp); + else if (!strcmp(key, "ro.product.device")) + qual_overwrite(&t->device, cp); + } + key = adb_strtok_r(NULL, prop_seps, &save); + } + } } if(!strcmp(type, "bootloader")){ @@ -389,13 +519,42 @@ void handle_packet(apacket *p, atransport *t) t->connection_state = CS_OFFLINE; handle_offline(t); } + parse_banner((char*) p->data, t); - handle_online(); - if(!HOST) send_connect(t); + + if (HOST || !auth_enabled) { + handle_online(t); + if(!HOST) send_connect(t); + } else { + send_auth_request(t); + } + break; + + case A_AUTH: + if (p->msg.arg0 == ADB_AUTH_TOKEN) { + t->key = adb_auth_nextkey(t->key); + if (t->key) { + send_auth_response(p->data, p->msg.data_length, t); + } else { + /* No more private keys to try, send the public key */ + send_auth_publickey(t); + } + } else if (p->msg.arg0 == ADB_AUTH_SIGNATURE) { + if (adb_auth_verify(t->token, p->data, p->msg.data_length)) { + adb_auth_verified(t); + t->failed_auth_attempts = 0; + } else { + if (t->failed_auth_attempts++ > 10) + adb_sleep_ms(1000); + send_auth_request(t); + } + } else if (p->msg.arg0 == ADB_AUTH_RSAPUBLICKEY) { + adb_auth_confirm_key(p->data, p->msg.data_length, t); + } break; case A_OPEN: /* OPEN(local-id, 0, "destination") */ - if(t->connection_state != CS_OFFLINE) { + if (t->online) { char *name = (char*) p->data; name[p->msg.data_length > 0 ? p->msg.data_length - 1 : 0] = 0; s = create_local_service_socket(name); @@ -411,7 +570,7 @@ void handle_packet(apacket *p, atransport *t) break; case A_OKAY: /* READY(local-id, remote-id, "") */ - if(t->connection_state != CS_OFFLINE) { + if (t->online) { if((s = find_local_socket(p->msg.arg1))) { if(s->peer == 0) { s->peer = create_remote_socket(p->msg.arg0, t); @@ -423,7 +582,7 @@ void handle_packet(apacket *p, atransport *t) break; case A_CLSE: /* CLOSE(local-id, remote-id, "") */ - if(t->connection_state != CS_OFFLINE) { + if (t->online) { if((s = find_local_socket(p->msg.arg1))) { s->close(s); } @@ -431,7 +590,7 @@ void handle_packet(apacket *p, atransport *t) break; case A_WRTE: - if(t->connection_state != CS_OFFLINE) { + if (t->online) { if((s = find_local_socket(p->msg.arg1))) { unsigned rid = p->msg.arg0; p->len = p->msg.data_length; @@ -544,7 +703,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 */ @@ -565,24 +730,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; @@ -594,12 +825,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); @@ -610,7 +846,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; } } @@ -647,11 +883,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 @@ -756,6 +992,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; @@ -775,6 +1012,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 ); @@ -851,8 +1108,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 { @@ -947,25 +1206,39 @@ int adb_main(int is_daemon, int server_port) init_transport_registration(); - #if ADB_HOST HOST = 1; usb_vendors_init(); usb_init(); local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT); + adb_auth_init(); 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 + property_get("ro.adb.secure", value, "0"); + auth_enabled = !strcmp(value, "1"); + if (auth_enabled) + adb_auth_init(); + + // Our external storage path may be different than apps, since + // we aren't able to bind mount after dropping root. + const char* adb_external_storage = getenv("ADB_EXTERNAL_STORAGE"); + if (NULL != adb_external_storage) { + setenv("EXTERNAL_STORAGE", adb_external_storage, 1); + } else { + D("Warning: ADB_EXTERNAL_STORAGE is not set. Leaving EXTERNAL_STORAGE" + " unchanged.\n"); + } /* 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; + struct __user_cap_data_struct cap[2]; if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) { exit(1); @@ -998,40 +1271,48 @@ 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; + header.version = _LINUX_CAPABILITY_VERSION_3; header.pid = 0; - cap.effective = cap.permitted = (1 << CAP_SYS_BOOT); - cap.inheritable = 0; - capset(&header, &cap); + 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]; 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); } } - /* for the device, start the usb transport if the - ** android usb device exists and the "service.adb.tcp.port" and - ** "persist.adb.tcp.port" properties are not set. - ** Otherwise start the network transport. - */ + int usb = 0; + if (access(USB_ADB_PATH, F_OK) == 0 || access(USB_FFS_ADB_EP0, F_OK) == 0) { + // listen on USB + usb_init(); + usb = 1; + } + + // If one of these properties is set, also listen on that port + // If one of the properties isn't set and we couldn't listen on usb, + // listen on the default port. property_get("service.adb.tcp.port", value, ""); - if (!value[0]) + if (!value[0]) { property_get("persist.adb.tcp.port", value, ""); + } if (sscanf(value, "%d", &port) == 1 && port > 0) { + printf("using port=%d\n", port); // listen on TCP port specified by service.adb.tcp.port property local_init(port); - } else if (access("/dev/android_adb", F_OK) == 0) { - // listen on USB - usb_init(); - } else { + } else if (!usb) { // listen on default port local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT); } + D("adb_main(): pre init_jdwp()\n"); init_jdwp(); D("adb_main(): post init_jdwp()\n"); @@ -1067,7 +1348,7 @@ void connect_device(char* host, char* buffer, int buffer_size) strncpy(hostbuf, host, sizeof(hostbuf) - 1); if (portstr) { - if ((unsigned int)(portstr - host) >= sizeof(hostbuf)) { + if (portstr - host >= (ptrdiff_t)sizeof(hostbuf)) { snprintf(buffer, buffer_size, "bad host name %s", host); return; } @@ -1201,16 +1482,19 @@ int handle_host_request(char *service, transport_type ttype, char* serial, int r } // return a list of all connected devices - if (!strcmp(service, "devices")) { + if (!strncmp(service, "devices", 7)) { char buffer[4096]; - memset(buf, 0, sizeof(buf)); - memset(buffer, 0, sizeof(buffer)); - D("Getting device list \n"); - list_transports(buffer, sizeof(buffer)); - snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer),buffer); - D("Wrote device list \n"); - writex(reply_fd, buf, strlen(buf)); - return 0; + int use_long = !strcmp(service+7, "-l"); + if (use_long || service[7] == 0) { + memset(buf, 0, sizeof(buf)); + memset(buffer, 0, sizeof(buffer)); + D("Getting device list \n"); + list_transports(buffer, sizeof(buffer), use_long); + snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer),buffer); + D("Wrote device list \n"); + writex(reply_fd, buf, strlen(buf)); + return 0; + } } // add a new TCP transport, device or emulator @@ -1276,6 +1560,16 @@ int handle_host_request(char *service, transport_type ttype, char* serial, int r writex(reply_fd, buf, strlen(buf)); return 0; } + if(!strncmp(service,"get-devpath",strlen("get-devpath"))) { + char *out = "unknown"; + transport = acquire_one_transport(CS_ANY, ttype, serial, NULL); + if (transport && transport->devpath) { + out = transport->devpath; + } + snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(out),out); + writex(reply_fd, buf, strlen(buf)); + return 0; + } // indicates a new emulator instance has started if (!strncmp(service,"emulator:",9)) { int port = atoi(service+9); @@ -1285,24 +1579,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); @@ -1312,9 +1645,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 */ @@ -1323,7 +1656,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"); } @@ -29,13 +29,14 @@ #define A_OKAY 0x59414b4f #define A_CLSE 0x45534c43 #define A_WRTE 0x45545257 +#define A_AUTH 0x48545541 #define A_VERSION 0x01000000 // ADB protocol version #define ADB_VERSION_MAJOR 1 // Used for help/version information #define ADB_VERSION_MINOR 0 // Used for help/version information -#define ADB_SERVER_VERSION 29 // Increment this when we want to force users to start a new adb server +#define ADB_SERVER_VERSION 31 // Increment this when we want to force users to start a new adb server typedef struct amessage amessage; typedef struct apacket apacket; @@ -165,6 +166,8 @@ typedef enum transport_type { kTransportHost, } transport_type; +#define TOKEN_SIZE 20 + struct atransport { atransport *next; @@ -181,6 +184,7 @@ struct atransport int ref_count; unsigned sync_token; int connection_state; + int online; transport_type type; /* usb handle or socket fd as needed */ @@ -190,11 +194,19 @@ struct atransport /* used to identify transports for clients */ char *serial; char *product; + char *model; + char *device; + char *devpath; int adb_port; // Use for emulators (local transport) /* a list of adisconnect callbacks called when the transport is kicked */ int kicked; adisconnect disconnects; + + void *key; + unsigned char token[TOKEN_SIZE]; + fdevent auth_fde; + unsigned failed_auth_attempts; }; @@ -253,7 +265,7 @@ int adb_main(int is_daemon, int server_port); ** get_device_transport does an acquire on your behalf before returning */ void init_transport_registration(void); -int list_transports(char *buf, size_t bufsize); +int list_transports(char *buf, size_t bufsize, int long_listing); void update_transports(void); asocket* create_device_tracker(void); @@ -286,7 +298,7 @@ void register_socket_transport(int s, const char *serial, int port, int local); void unregister_transport(atransport *t); void unregister_all_tcp_transports(); -void register_usb_transport(usb_handle *h, const char *serial, unsigned writeable); +void register_usb_transport(usb_handle *h, const char *serial, const char *devpath, unsigned writeable); /* this should only be used for transports with connection_state == CS_NOPERM */ void unregister_usb_transport(usb_handle *usb); @@ -346,6 +358,7 @@ typedef enum { TRACE_SYSDEPS, TRACE_JDWP, /* 0x100 */ TRACE_SERVICES, + TRACE_AUTH, } AdbTrace; #if ADB_TRACE @@ -405,7 +418,7 @@ void adb_qemu_trace(const char* fmt, ...); #endif -#if !TRACE_PACKETS +#if !DEBUG_PACKETS #define print_packet(tag,p) do {} while (0) #endif @@ -461,6 +474,17 @@ extern int SHELL_EXIT_NOTIFY_FD; #define CHUNK_SIZE (64*1024) +#if !ADB_HOST +#define USB_ADB_PATH "/dev/android_adb" + +#define USB_FFS_ADB_PATH "/dev/usb-ffs/adb/" +#define USB_FFS_ADB_EP(x) USB_FFS_ADB_PATH#x + +#define USB_FFS_ADB_EP0 USB_FFS_ADB_EP(ep0) +#define USB_FFS_ADB_OUT USB_FFS_ADB_EP(ep1) +#define USB_FFS_ADB_IN USB_FFS_ADB_EP(ep2) +#endif + int sendfailmsg(int fd, const char *reason); int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s); diff --git a/adb/adb_auth.h b/adb/adb_auth.h new file mode 100644 index 0000000..1fffa49 --- /dev/null +++ b/adb/adb_auth.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2012 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_AUTH_H +#define __ADB_AUTH_H + +void adb_auth_init(void); +void adb_auth_verified(atransport *t); + +/* AUTH packets first argument */ +/* Request */ +#define ADB_AUTH_TOKEN 1 +/* Response */ +#define ADB_AUTH_SIGNATURE 2 +#define ADB_AUTH_RSAPUBLICKEY 3 + +#if ADB_HOST + +int adb_auth_sign(void *key, void *token, size_t token_size, void *sig); +void *adb_auth_nextkey(void *current); +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 + +static inline int adb_auth_sign(void* key, void *token, size_t token_size, void *sig) { return 0; } +static inline void *adb_auth_nextkey(void *current) { return NULL; } +static inline int adb_auth_get_userkey(unsigned char *data, size_t len) { return 0; } + +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 + +#endif // __ADB_AUTH_H diff --git a/adb/adb_auth_client.c b/adb/adb_auth_client.c new file mode 100644 index 0000000..0b4913e --- /dev/null +++ b/adb/adb_auth_client.c @@ -0,0 +1,245 @@ +/* + * Copyright (C) 2012 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 <stdio.h> +#include <string.h> +#include <resolv.h> +#include <cutils/list.h> +#include <cutils/sockets.h> + +#include "sysdeps.h" +#include "adb.h" +#include "adb_auth.h" +#include "fdevent.h" +#include "mincrypt/rsa.h" + +#define TRACE_TAG TRACE_AUTH + + +struct adb_public_key { + struct listnode node; + RSAPublicKey key; +}; + +static struct listnode key_list; + +static char *key_paths[] = { + "/adb_keys", + "/data/misc/adb/adb_keys", + NULL +}; + +static fdevent listener_fde; +static int framework_fd = -1; + + +static void read_keys(const char *file, struct listnode *list) +{ + struct adb_public_key *key; + FILE *f; + char buf[MAX_PAYLOAD]; + char *sep; + int ret; + + f = fopen(file, "r"); + if (!f) { + D("Can't open '%s'\n", file); + return; + } + + while (fgets(buf, sizeof(buf), f)) { + /* Allocate 4 extra bytes to decode the base64 data in-place */ + key = calloc(1, sizeof(*key) + 4); + if (!key) { + D("Can't malloc key\n"); + break; + } + + sep = strpbrk(buf, " \t"); + if (sep) + *sep = '\0'; + + ret = __b64_pton(buf, (u_char *)&key->key, sizeof(key->key) + 4); + if (ret != sizeof(key->key)) { + D("%s: Invalid base64 data ret=%d\n", file, ret); + free(key); + continue; + } + + if (key->key.len != RSANUMWORDS) { + D("%s: Invalid key len %d\n", file, key->key.len); + free(key); + continue; + } + + list_add_tail(list, &key->node); + } + + fclose(f); +} + +static void free_keys(struct listnode *list) +{ + struct listnode *item; + + while (!list_empty(list)) { + item = list_head(list); + list_remove(item); + free(node_to_item(item, struct adb_public_key, node)); + } +} + +void adb_auth_reload_keys(void) +{ + char *path; + char **paths = key_paths; + struct stat buf; + + free_keys(&key_list); + + while ((path = *paths++)) { + if (!stat(path, &buf)) { + D("Loading keys from '%s'\n", path); + read_keys(path, &key_list); + } + } +} + +int adb_auth_generate_token(void *token, size_t token_size) +{ + FILE *f; + int ret; + + f = fopen("/dev/urandom", "r"); + if (!f) + return 0; + + ret = fread(token, token_size, 1, f); + + fclose(f); + return ret * token_size; +} + +int adb_auth_verify(void *token, void *sig, int siglen) +{ + struct listnode *item; + struct adb_public_key *key; + int ret; + + if (siglen != RSANUMBYTES) + return 0; + + 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; + } + + return 0; +} + +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); + framework_fd = -1; + } + else if (ret == 2 && response[0] == 'O' && response[1] == 'K') { + adb_auth_reload_keys(); + adb_auth_verified(t); + } + } +} + +void adb_auth_confirm_key(unsigned char *key, size_t len, atransport *t) +{ + char msg[MAX_PAYLOAD]; + int ret; + + if (framework_fd < 0) { + D("Client not connected\n"); + return; + } + + if (key[len - 1] != '\0') { + D("Key must be a null-terminated string\n"); + return; + } + + ret = snprintf(msg, sizeof(msg), "PK%s", key); + if (ret >= (signed)sizeof(msg)) { + D("Key too long. ret=%d", ret); + return; + } + D("Sending '%s'\n", msg); + + ret = unix_write(framework_fd, msg, ret); + if (ret < 0) { + D("Failed to write PK, errno=%d\n", errno); + return; + } + + fdevent_install(&t->auth_fde, framework_fd, adb_auth_event, t); + fdevent_add(&t->auth_fde, FDE_READ); +} + +static void adb_auth_listener(int fd, unsigned events, void *data) +{ + struct sockaddr addr; + socklen_t alen; + int s; + + alen = sizeof(addr); + + s = adb_socket_accept(fd, &addr, &alen); + if (s < 0) { + D("Failed to accept: errno=%d\n", errno); + return; + } + + framework_fd = s; +} + +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"); + return; + } + + ret = listen(fd, 4); + if (ret < 0) { + D("Failed to listen on '%d'\n", fd); + return; + } + + fdevent_install(&listener_fde, fd, adb_auth_listener, NULL); + fdevent_add(&listener_fde, FDE_READ); +} diff --git a/adb/adb_auth_host.c b/adb/adb_auth_host.c new file mode 100644 index 0000000..9039d42 --- /dev/null +++ b/adb/adb_auth_host.c @@ -0,0 +1,426 @@ +/* + * Copyright (C) 2012 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 <stdio.h> + +#ifdef _WIN32 +# define WIN32_LEAN_AND_MEAN +# include "windows.h" +# include "shlobj.h" +#else +# include <sys/types.h> +# include <sys/stat.h> +# include <unistd.h> +#endif +#include <string.h> + +#include "sysdeps.h" +#include "adb.h" +#include "adb_auth.h" + +/* HACK: we need the RSAPublicKey struct + * but RSA_verify conflits with openssl */ +#define RSA_verify RSA_verify_mincrypt +#include "mincrypt/rsa.h" +#undef RSA_verify + +#include <cutils/list.h> + +#include <openssl/evp.h> +#include <openssl/objects.h> +#include <openssl/pem.h> +#include <openssl/rsa.h> +#include <openssl/sha.h> + +#define TRACE_TAG TRACE_AUTH + +#define ANDROID_PATH ".android" +#define ADB_KEY_FILE "adbkey" + + +struct adb_private_key { + struct listnode node; + RSA *rsa; +}; + +static struct listnode key_list; + + +/* Convert OpenSSL RSA private key to android pre-computed RSAPublicKey format */ +static int RSA_to_RSAPublicKey(RSA *rsa, RSAPublicKey *pkey) +{ + int ret = 1; + unsigned int i; + + BN_CTX* ctx = BN_CTX_new(); + BIGNUM* r32 = BN_new(); + BIGNUM* rr = BN_new(); + BIGNUM* r = BN_new(); + BIGNUM* rem = BN_new(); + BIGNUM* n = BN_new(); + BIGNUM* n0inv = BN_new(); + + if (RSA_size(rsa) != RSANUMBYTES) { + ret = 0; + goto out; + } + + BN_set_bit(r32, 32); + BN_copy(n, rsa->n); + BN_set_bit(r, RSANUMWORDS * 32); + BN_mod_sqr(rr, r, n, ctx); + BN_div(NULL, rem, n, r32, ctx); + BN_mod_inverse(n0inv, rem, r32, ctx); + + pkey->len = RSANUMWORDS; + pkey->n0inv = 0 - BN_get_word(n0inv); + for (i = 0; i < RSANUMWORDS; i++) { + BN_div(rr, rem, rr, r32, ctx); + pkey->rr[i] = BN_get_word(rem); + BN_div(n, rem, n, r32, ctx); + pkey->n[i] = BN_get_word(rem); + } + pkey->exponent = BN_get_word(rsa->e); + +out: + BN_free(n0inv); + BN_free(n); + BN_free(rem); + BN_free(r); + BN_free(rr); + BN_free(r32); + BN_CTX_free(ctx); + + return ret; +} + +static void get_user_info(char *buf, size_t len) +{ + char hostname[1024], username[1024]; + int ret; + +#ifndef _WIN32 + ret = gethostname(hostname, sizeof(hostname)); + if (ret < 0) +#endif + strcpy(hostname, "unknown"); + +#if !defined _WIN32 && !defined ADB_HOST_ON_TARGET + ret = getlogin_r(username, sizeof(username)); + if (ret < 0) +#endif + strcpy(username, "unknown"); + + ret = snprintf(buf, len, " %s@%s", username, hostname); + if (ret >= (signed)len) + buf[len - 1] = '\0'; +} + +static int write_public_keyfile(RSA *private_key, const char *private_key_path) +{ + RSAPublicKey pkey; + BIO *bio, *b64, *bfile; + char path[PATH_MAX], info[MAX_PAYLOAD]; + int ret; + + ret = snprintf(path, sizeof(path), "%s.pub", private_key_path); + if (ret >= (signed)sizeof(path)) + return 0; + + ret = RSA_to_RSAPublicKey(private_key, &pkey); + if (!ret) { + D("Failed to convert to publickey\n"); + return 0; + } + + bfile = BIO_new_file(path, "w"); + if (!bfile) { + D("Failed to open '%s'\n", path); + return 0; + } + + D("Writing public key to '%s'\n", path); + + b64 = BIO_new(BIO_f_base64()); + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); + + bio = BIO_push(b64, bfile); + BIO_write(bio, &pkey, sizeof(pkey)); + BIO_flush(bio); + BIO_pop(b64); + BIO_free(b64); + + get_user_info(info, sizeof(info)); + BIO_write(bfile, info, strlen(info)); + BIO_flush(bfile); + BIO_free_all(bfile); + + return 1; +} + +static int generate_key(const char *file) +{ + EVP_PKEY* pkey = EVP_PKEY_new(); + BIGNUM* exponent = BN_new(); + RSA* rsa = RSA_new(); + mode_t old_mask; + FILE *f = NULL; + int ret = 0; + + D("generate_key '%s'\n", file); + + if (!pkey || !exponent || !rsa) { + D("Failed to allocate key\n"); + goto out; + } + + BN_set_word(exponent, RSA_F4); + RSA_generate_key_ex(rsa, 2048, exponent, NULL); + EVP_PKEY_set1_RSA(pkey, rsa); + + old_mask = umask(077); + + f = fopen(file, "w"); + if (!f) { + D("Failed to open '%s'\n", file); + umask(old_mask); + goto out; + } + + umask(old_mask); + + if (!PEM_write_PrivateKey(f, pkey, NULL, NULL, 0, NULL, NULL)) { + D("Failed to write key\n"); + goto out; + } + + if (!write_public_keyfile(rsa, file)) { + D("Failed to write public key\n"); + goto out; + } + + ret = 1; + +out: + if (f) + fclose(f); + EVP_PKEY_free(pkey); + RSA_free(rsa); + BN_free(exponent); + return ret; +} + +static int read_key(const char *file, struct listnode *list) +{ + struct adb_private_key *key; + FILE *f; + + D("read_key '%s'\n", file); + + f = fopen(file, "r"); + if (!f) { + D("Failed to open '%s'\n", file); + return 0; + } + + key = malloc(sizeof(*key)); + if (!key) { + D("Failed to alloc key\n"); + fclose(f); + return 0; + } + key->rsa = RSA_new(); + + if (!PEM_read_RSAPrivateKey(f, &key->rsa, NULL, NULL)) { + D("Failed to read key\n"); + fclose(f); + RSA_free(key->rsa); + free(key); + return 0; + } + + fclose(f); + list_add_tail(list, &key->node); + return 1; +} + +static int get_user_keyfilepath(char *filename, size_t len) +{ + const char *format, *home; + char android_dir[PATH_MAX]; + struct stat buf; +#ifdef _WIN32 + char path[PATH_MAX]; + home = getenv("ANDROID_SDK_HOME"); + if (!home) { + SHGetFolderPath(NULL, CSIDL_PROFILE, NULL, 0, path); + home = path; + } + format = "%s\\%s"; +#else + home = getenv("HOME"); + if (!home) + return -1; + format = "%s/%s"; +#endif + + D("home '%s'\n", home); + + if (snprintf(android_dir, sizeof(android_dir), format, home, + ANDROID_PATH) >= (int)sizeof(android_dir)) + return -1; + + if (stat(android_dir, &buf)) { + if (adb_mkdir(android_dir, 0750) < 0) { + D("Cannot mkdir '%s'", android_dir); + return -1; + } + } + + return snprintf(filename, len, format, android_dir, ADB_KEY_FILE); +} + +static int get_user_key(struct listnode *list) +{ + struct stat buf; + char path[PATH_MAX]; + int ret; + + ret = get_user_keyfilepath(path, sizeof(path)); + if (ret < 0 || ret >= (signed)sizeof(path)) { + D("Error getting user key filename"); + return 0; + } + + D("user key '%s'\n", path); + + if (stat(path, &buf) == -1) { + if (!generate_key(path)) { + D("Failed to generate new key\n"); + return 0; + } + } + + return read_key(path, list); +} + +static void get_vendor_keys(struct listnode *list) +{ + const char *adb_keys_path; + char keys_path[MAX_PAYLOAD]; + char *path; + char *save; + struct stat buf; + + adb_keys_path = getenv("ADB_VENDOR_KEYS"); + if (!adb_keys_path) + return; + strncpy(keys_path, adb_keys_path, sizeof(keys_path)); + + path = adb_strtok_r(keys_path, ENV_PATH_SEPARATOR_STR, &save); + while (path) { + D("Reading: '%s'\n", path); + + if (stat(path, &buf)) + D("Can't read '%s'\n", path); + else if (!read_key(path, list)) + D("Failed to read '%s'\n", path); + + path = adb_strtok_r(NULL, ENV_PATH_SEPARATOR_STR, &save); + } +} + +int adb_auth_sign(void *node, void *token, size_t token_size, void *sig) +{ + unsigned int len; + struct adb_private_key *key = node_to_item(node, struct adb_private_key, node); + + if (!RSA_sign(NID_sha1, token, token_size, sig, &len, key->rsa)) { + return 0; + } + + D("adb_auth_sign len=%d\n", len); + return (int)len; +} + +void *adb_auth_nextkey(void *current) +{ + struct listnode *item; + + if (list_empty(&key_list)) + return NULL; + + if (!current) + return list_head(&key_list); + + list_for_each(item, &key_list) { + if (item == current) { + /* current is the last item, we tried all the keys */ + if (item->next == &key_list) + return NULL; + return item->next; + } + } + + return NULL; +} + +int adb_auth_get_userkey(unsigned char *data, size_t len) +{ + char path[PATH_MAX]; + char *file; + int ret; + + ret = get_user_keyfilepath(path, sizeof(path) - 4); + if (ret < 0 || ret >= (signed)(sizeof(path) - 4)) { + D("Error getting user key filename"); + return 0; + } + strcat(path, ".pub"); + + file = load_file(path, (unsigned*)&ret); + if (!file) { + D("Can't load '%s'\n", path); + return 0; + } + + if (len < (size_t)(ret + 1)) { + D("%s: Content too large ret=%d\n", path, ret); + return 0; + } + + memcpy(data, file, ret); + data[ret] = '\0'; + + return ret + 1; +} + +void adb_auth_init(void) +{ + int ret; + + D("adb_auth_init\n"); + + list_init(&key_list); + + ret = get_user_key(&key_list); + if (!ret) { + D("Failed to get user key\n"); + return; + } + + get_vendor_keys(&key_list); +} 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 d2b8166..a927423 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,12 +81,13 @@ 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" " returns an error if more than one emulator is running.\n" - " -s <serial number> - directs command to the USB device or emulator with\n" - " the given serial number. Overrides ANDROID_SERIAL\n" + " -s <specific device> - directs command to the device or emulator with the given\n" + " serial number or qualifier. Overrides ANDROID_SERIAL\n" " environment variable.\n" " -p <product name or path> - simple product name like 'sooner', or\n" " a relative/absolute path to a product\n" @@ -93,7 +95,10 @@ void help() " If -p is not specified, the ANDROID_PRODUCT_OUT\n" " environment variable is used, which must\n" " be an absolute path.\n" - " devices - list all connected devices\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" " Port 5555 is used by default if no port number is specified.\n" " disconnect [<host>[:<port>]] - disconnect from a TCP/IP device.\n" @@ -111,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" @@ -119,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" @@ -159,6 +172,7 @@ void help() " adb kill-server - kill the server if it is running\n" " adb get-state - prints: offline | bootloader | device\n" " adb get-serialno - prints: <serial-number>\n" + " adb get-devpath - prints: <device-path>\n" " adb status-window - continuously print device status for a specified device\n" " adb remount - remounts the /system partition on the device read-write\n" " adb reboot [bootloader|recovery] - reboots the device, optionally into the bootloader or recovery program\n" @@ -369,7 +383,7 @@ static void format_host_command(char* buffer, size_t buflen, const char* comman } } -int adb_download_buffer(const char *service, const void* data, int sz, +int adb_download_buffer(const char *service, const char *fn, const void* data, int sz, unsigned progress) { char buf[4096]; @@ -405,7 +419,7 @@ int adb_download_buffer(const char *service, const void* data, int sz, sz -= xfer; ptr += xfer; if(progress) { - printf("sending: '%s' %4d%% \r", service, (int)(100LL - ((100LL * sz) / (total)))); + printf("sending: '%s' %4d%% \r", fn, (int)(100LL - ((100LL * sz) / (total)))); fflush(stdout); } } @@ -437,11 +451,11 @@ int adb_download(const char *service, const char *fn, unsigned progress) data = load_file(fn, &sz); if(data == 0) { - fprintf(stderr,"* cannot read '%s' *\n", service); + fprintf(stderr,"* cannot read '%s' *\n", fn); return -1; } - int status = adb_download_buffer(service, data, sz, progress); + int status = adb_download_buffer(service, fn, data, sz, progress); free(data); return status; } @@ -936,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(); } @@ -984,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; @@ -1016,7 +1066,16 @@ top: if(!strcmp(argv[0], "devices")) { char *tmp; - snprintf(buf, sizeof buf, "host:%s", argv[0]); + char *listopt; + if (argc < 2) + listopt = ""; + else if (argc == 2 && !strcmp(argv[1], "-l")) + listopt = argv[1]; + else { + fprintf(stderr, "Usage: adb devices [-l]\n"); + return 1; + } + snprintf(buf, sizeof buf, "host:%s%s", argv[0], listopt); tmp = adb_query(buf); if(tmp) { printf("List of devices attached \n"); @@ -1212,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; @@ -1298,7 +1426,8 @@ top: /* passthrough commands */ if(!strcmp(argv[0],"get-state") || - !strcmp(argv[0],"get-serialno")) + !strcmp(argv[0],"get-serialno") || + !strcmp(argv[0],"get-devpath")) { char *tmp; diff --git a/adb/protocol.txt b/adb/protocol.txt index 398d042..c9d3c24 100644 --- a/adb/protocol.txt +++ b/adb/protocol.txt @@ -72,7 +72,25 @@ large maxdata value, the connection with the other side must be closed. The system identity string should be "<systemtype>:<serialno>:<banner>" where systemtype is "bootloader", "device", or "host", serialno is some kind of unique ID (or empty), and banner is a human-readable version -or identifier string (informational only). +or identifier string. The banner is used to transmit useful properties. + + +--- AUTH(type, 0, "data") ---------------------------------------------- + +The AUTH message informs the recipient that authentication is required to +connect to the sender. If type is TOKEN(1), data is a random token that +the recipient can sign with a private key. The recipient replies with an +AUTH packet where type is SIGNATURE(2) and data is the signature. If the +signature verification succeeds, the sender replies with a CONNECT packet. + +If the signature verification fails, the sender replies with a new AUTH +packet and a new random token, so that the recipient can retry signing +with a different private key. + +Once the recipient has tried all its private keys, it can reply with an +AUTH packet where type is RSAPUBLICKEY(3) and data is the public key. If +possible, an on-screen confirmation may be displayed for the user to +confirm they want to install the public key on the device. --- OPEN(local-id, 0, "destination") ----------------------------------- @@ -166,6 +184,7 @@ to send across the wire. #define A_SYNC 0x434e5953 #define A_CNXN 0x4e584e43 +#define A_AUTH 0x48545541 #define A_OPEN 0x4e45504f #define A_OKAY 0x59414b4f #define A_CLSE 0x45534c43 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/sockets.c b/adb/sockets.c index cd31b23..305cb44 100644 --- a/adb/sockets.c +++ b/adb/sockets.c @@ -608,12 +608,30 @@ unsigned unhex(unsigned char *s, int len) return n; } +#define PREFIX(str) { str, sizeof(str) - 1 } +static const struct prefix_struct { + const char *str; + const size_t len; +} prefixes[] = { + PREFIX("usb:"), + PREFIX("product:"), + PREFIX("model:"), + PREFIX("device:"), +}; +static const int num_prefixes = (sizeof(prefixes) / sizeof(prefixes[0])); + /* skip_host_serial return the position in a string skipping over the 'serial' parameter in the ADB protocol, where parameter string may be a host:port string containing the protocol delimiter (colon). */ char *skip_host_serial(char *service) { char *first_colon, *serial_end; + int i; + + for (i = 0; i < num_prefixes; i++) { + if (!strncmp(service, prefixes[i].str, prefixes[i].len)) + return strchr(service + prefixes[i].len, ':'); + } first_colon = strchr(service, ':'); if (!first_colon) { diff --git a/adb/sysdeps.h b/adb/sysdeps.h index b518076..0252ef3 100644 --- a/adb/sysdeps.h +++ b/adb/sysdeps.h @@ -38,6 +38,7 @@ #define OS_PATH_SEPARATOR '\\' #define OS_PATH_SEPARATOR_STR "\\" +#define ENV_PATH_SEPARATOR_STR ";" typedef CRITICAL_SECTION adb_mutex_t; @@ -254,6 +255,8 @@ static __inline__ int adb_is_absolute_host_path( const char* path ) return isalpha(path[0]) && path[1] == ':' && path[2] == '\\'; } +extern char* adb_strtok_r(char *str, const char *delim, char **saveptr); + #else /* !_WIN32 a.k.a. Unix */ #include "fdevent.h" @@ -272,9 +275,26 @@ static __inline__ int adb_is_absolute_host_path( const char* path ) #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 "/" +#define ENV_PATH_SEPARATOR_STR ":" typedef pthread_mutex_t adb_mutex_t; @@ -306,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 { @@ -315,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 ); @@ -353,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 @@ -361,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 @@ -382,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; @@ -397,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); @@ -490,6 +510,13 @@ static __inline__ int adb_is_absolute_host_path( const char* path ) return path[0] == '/'; } +static __inline__ char* adb_strtok_r(char *str, const char *delim, char **saveptr) +{ + return strtok_r(str, delim, saveptr); +} +#undef strtok_r +#define strtok_r ___xxx_strtok_r + #endif /* !_WIN32 */ #endif /* _ADB_SYSDEPS_H */ diff --git a/adb/sysdeps_win32.c b/adb/sysdeps_win32.c index c426718..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; @@ -2140,3 +2140,81 @@ adb_sysdeps_init( void ) InitializeCriticalSection( &_win32_lock ); } +/* Windows doesn't have strtok_r. Use the one from bionic. */ + +/* + * Copyright (c) 1988 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +char * +adb_strtok_r(char *s, const char *delim, char **last) +{ + char *spanp; + int c, sc; + char *tok; + + + if (s == NULL && (s = *last) == NULL) + return (NULL); + + /* + * Skip (span) leading delimiters (s += strspn(s, delim), sort of). + */ +cont: + c = *s++; + for (spanp = (char *)delim; (sc = *spanp++) != 0;) { + if (c == sc) + goto cont; + } + + if (c == 0) { /* no non-delimiter characters */ + *last = NULL; + return (NULL); + } + tok = s - 1; + + /* + * Scan token (scan for delimiters: s += strcspn(s, delim), sort of). + * Note that delim must have one NUL; we stop if we see that, too. + */ + for (;;) { + c = *s++; + spanp = (char *)delim; + do { + if ((sc = *spanp++) == c) { + if (c == 0) + s = NULL; + else + s[-1] = 0; + *last = s; + return (tok); + } + } while (sc != 0); + } + /* NOTREACHED */ +} diff --git a/adb/transport.c b/adb/transport.c index 2f7bd27..9fd6cc2 100644 --- a/adb/transport.c +++ b/adb/transport.c @@ -370,7 +370,7 @@ static int list_transports_msg(char* buffer, size_t bufferlen) char head[5]; int len; - len = list_transports(buffer+4, bufferlen-4); + len = list_transports(buffer+4, bufferlen-4, 0); snprintf(head, sizeof(head), "%04x", len); memcpy(buffer, head, 4); len += 4; @@ -601,6 +601,12 @@ static void transport_registration_func(int _fd, unsigned ev, void *data) free(t->product); if (t->serial) free(t->serial); + if (t->model) + free(t->model); + if (t->device) + free(t->device); + if (t->devpath) + free(t->devpath); memset(t,0xee,sizeof(atransport)); free(t); @@ -737,6 +743,45 @@ void remove_transport_disconnect(atransport* t, adisconnect* dis) dis->next = dis->prev = dis; } +static int qual_char_is_invalid(char ch) +{ + if ('A' <= ch && ch <= 'Z') + return 0; + if ('a' <= ch && ch <= 'z') + return 0; + if ('0' <= ch && ch <= '9') + return 0; + return 1; +} + +static int qual_match(const char *to_test, + const char *prefix, const char *qual, int sanitize_qual) +{ + if (!to_test || !*to_test) + /* Return true if both the qual and to_test are null strings. */ + return !qual || !*qual; + + if (!qual) + return 0; + + if (prefix) { + while (*prefix) { + if (*prefix++ != *to_test++) + return 0; + } + } + + while (*qual) { + char ch = *qual++; + if (sanitize_qual && qual_char_is_invalid(ch)) + ch = '_'; + if (ch != *to_test++) + return 0; + } + + /* Everything matched so far. Return true if *to_test is a NUL. */ + return !*to_test; +} atransport *acquire_one_transport(int state, transport_type ttype, const char* serial, char** error_out) { @@ -758,9 +803,19 @@ retry: /* check for matching serial number */ if (serial) { - if (t->serial && !strcmp(serial, t->serial)) { + if ((t->serial && !strcmp(serial, t->serial)) || + (t->devpath && !strcmp(serial, t->devpath)) || + qual_match(serial, "product:", t->product, 0) || + qual_match(serial, "model:", t->model, 1) || + qual_match(serial, "device:", t->device, 0)) { + if (result) { + if (error_out) + *error_out = "more than one device"; + ambiguous = 1; + result = NULL; + break; + } result = t; - break; } } else { if (ttype == kTransportUsb && t->type == kTransportUsb) { @@ -837,7 +892,58 @@ static const char *statename(atransport *t) } } -int list_transports(char *buf, size_t bufsize) +static void add_qual(char **buf, size_t *buf_size, + const char *prefix, const char *qual, int sanitize_qual) +{ + size_t len; + int prefix_len; + + if (!buf || !*buf || !buf_size || !*buf_size || !qual || !*qual) + return; + + len = snprintf(*buf, *buf_size, "%s%n%s", prefix, &prefix_len, qual); + + if (sanitize_qual) { + char *cp; + for (cp = *buf + prefix_len; cp < *buf + len; cp++) { + if (qual_char_is_invalid(*cp)) + *cp = '_'; + } + } + + *buf_size -= len; + *buf += len; +} + +static size_t format_transport(atransport *t, char *buf, size_t bufsize, + int long_listing) +{ + const char* serial = t->serial; + if (!serial || !serial[0]) + serial = "????????????"; + + if (!long_listing) { + return snprintf(buf, bufsize, "%s\t%s\n", serial, statename(t)); + } else { + size_t len, remaining = bufsize; + + len = snprintf(buf, remaining, "%-22s %s", serial, statename(t)); + remaining -= len; + buf += len; + + add_qual(&buf, &remaining, " ", t->devpath, 0); + add_qual(&buf, &remaining, " product:", t->product, 0); + add_qual(&buf, &remaining, " model:", t->model, 1); + add_qual(&buf, &remaining, " device:", t->device, 0); + + len = snprintf(buf, remaining, "\n"); + remaining -= len; + + return bufsize - remaining; + } +} + +int list_transports(char *buf, size_t bufsize, int long_listing) { char* p = buf; char* end = buf + bufsize; @@ -847,11 +953,7 @@ int list_transports(char *buf, size_t bufsize) /* XXX OVERRUN PROBLEMS XXX */ adb_mutex_lock(&transport_lock); for(t = transport_list.next; t != &transport_list; t = t->next) { - const char* serial = t->serial; - if (!serial || !serial[0]) - serial = "????????????"; - len = snprintf(p, end - p, "%s\t%s\n", serial, statename(t)); - + len = format_transport(t, p, end - p, long_listing); if (p + len >= end) { /* discard last line if buffer is too short */ break; @@ -956,7 +1058,7 @@ void unregister_all_tcp_transports() #endif -void register_usb_transport(usb_handle *usb, const char *serial, unsigned writeable) +void register_usb_transport(usb_handle *usb, const char *serial, const char *devpath, unsigned writeable) { atransport *t = calloc(1, sizeof(atransport)); D("transport: %p init'ing for usb_handle %p (sn='%s')\n", t, usb, @@ -965,6 +1067,9 @@ void register_usb_transport(usb_handle *usb, const char *serial, unsigned writea if(serial) { t->serial = strdup(serial); } + if(devpath) { + t->devpath = strdup(devpath); + } register_transport(t); } diff --git a/adb/usb_libusb.c b/adb/usb_libusb.c index 8c75266..06ff5dc 100644 --- a/adb/usb_libusb.c +++ b/adb/usb_libusb.c @@ -347,7 +347,7 @@ register_device(struct usb_handle *uh, const char *serial) adb_mutex_unlock(&usb_lock); - register_usb_transport(usb, serial, 1); + register_usb_transport(usb, serial, NULL, 1); return (1); } diff --git a/adb/usb_linux.c b/adb/usb_linux.c index 4d55b74..7bf2057 100644 --- a/adb/usb_linux.c +++ b/adb/usb_linux.c @@ -116,7 +116,8 @@ static void kick_disconnected_devices() } -static void register_device(const char *dev_name, unsigned char ep_in, unsigned char ep_out, +static void register_device(const char *dev_name, const char *devpath, + unsigned char ep_in, unsigned char ep_out, int ifc, int serial_index, unsigned zero_mask); static inline int badname(const char *name) @@ -129,7 +130,7 @@ static inline int badname(const char *name) static void find_usb_device(const char *base, void (*register_device_callback) - (const char *, unsigned char, unsigned char, int, int, unsigned)) + (const char *, const char *, unsigned char, unsigned char, int, int, unsigned)) { char busname[32], devname[32]; unsigned char local_ep_in, local_ep_out; @@ -227,6 +228,11 @@ static void find_usb_device(const char *base, is_adb_interface(vid, pid, interface->bInterfaceClass, interface->bInterfaceSubClass, interface->bInterfaceProtocol)) { + struct stat st; + char pathbuf[128]; + char link[256]; + char *devpath = NULL; + DBGX("looking for bulk endpoints\n"); // looks like ADB... ep1 = (struct usb_endpoint_descriptor *)bufptr; @@ -263,7 +269,26 @@ static void find_usb_device(const char *base, local_ep_out = ep1->bEndpointAddress; } - register_device_callback(devname, local_ep_in, local_ep_out, + // Determine the device path + if (!fstat(fd, &st) && S_ISCHR(st.st_mode)) { + char *slash; + ssize_t link_len; + snprintf(pathbuf, sizeof(pathbuf), "/sys/dev/char/%d:%d", + major(st.st_rdev), minor(st.st_rdev)); + link_len = readlink(pathbuf, link, sizeof(link) - 1); + if (link_len > 0) { + link[link_len] = '\0'; + slash = strrchr(link, '/'); + if (slash) { + snprintf(pathbuf, sizeof(pathbuf), + "usb:%s", slash + 1); + devpath = pathbuf; + } + } + } + + register_device_callback(devname, devpath, + local_ep_in, local_ep_out, interface->bInterfaceNumber, device->iSerialNumber, zero_mask); break; } @@ -532,7 +557,7 @@ int usb_close(usb_handle *h) return 0; } -static void register_device(const char *dev_name, +static void register_device(const char *dev_name, const char *devpath, unsigned char ep_in, unsigned char ep_out, int interface, int serial_index, unsigned zero_mask) { @@ -644,7 +669,7 @@ static void register_device(const char *dev_name, usb->next->prev = usb; adb_mutex_unlock(&usb_lock); - register_usb_transport(usb, serial, usb->writeable); + register_usb_transport(usb, serial, devpath, usb->writeable); return; fail: diff --git a/adb/usb_linux_client.c b/adb/usb_linux_client.c index 635fa4b..fb1dad0 100644 --- a/adb/usb_linux_client.c +++ b/adb/usb_linux_client.c @@ -19,6 +19,8 @@ #include <unistd.h> #include <string.h> +#include <linux/usb/ch9.h> +#include <linux/usb/functionfs.h> #include <sys/ioctl.h> #include <sys/types.h> #include <dirent.h> @@ -29,20 +31,122 @@ #define TRACE_TAG TRACE_USB #include "adb.h" +#define MAX_PACKET_SIZE_FS 64 +#define MAX_PACKET_SIZE_HS 512 + +#define cpu_to_le16(x) htole16(x) +#define cpu_to_le32(x) htole32(x) struct usb_handle { - int fd; adb_cond_t notify; adb_mutex_t lock; + + int (*write)(usb_handle *h, const void *data, int len); + int (*read)(usb_handle *h, void *data, int len); + void (*kick)(usb_handle *h); + + // Legacy f_adb + int fd; + + // FunctionFS + int control; + int bulk_out; /* "out" from the host's perspective => source for adbd */ + int bulk_in; /* "in" from the host's perspective => sink for adbd */ +}; + +static const struct { + struct usb_functionfs_descs_head header; + struct { + struct usb_interface_descriptor intf; + struct usb_endpoint_descriptor_no_audio source; + struct usb_endpoint_descriptor_no_audio sink; + } __attribute__((packed)) fs_descs, hs_descs; +} __attribute__((packed)) descriptors = { + .header = { + .magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC), + .length = cpu_to_le32(sizeof(descriptors)), + .fs_count = 3, + .hs_count = 3, + }, + .fs_descs = { + .intf = { + .bLength = sizeof(descriptors.fs_descs.intf), + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bNumEndpoints = 2, + .bInterfaceClass = ADB_CLASS, + .bInterfaceSubClass = ADB_SUBCLASS, + .bInterfaceProtocol = ADB_PROTOCOL, + .iInterface = 1, /* first string from the provided table */ + }, + .source = { + .bLength = sizeof(descriptors.fs_descs.source), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 1 | USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = MAX_PACKET_SIZE_FS, + }, + .sink = { + .bLength = sizeof(descriptors.fs_descs.sink), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 2 | USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = MAX_PACKET_SIZE_FS, + }, + }, + .hs_descs = { + .intf = { + .bLength = sizeof(descriptors.hs_descs.intf), + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bNumEndpoints = 2, + .bInterfaceClass = ADB_CLASS, + .bInterfaceSubClass = ADB_SUBCLASS, + .bInterfaceProtocol = ADB_PROTOCOL, + .iInterface = 1, /* first string from the provided table */ + }, + .source = { + .bLength = sizeof(descriptors.hs_descs.source), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 1 | USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = MAX_PACKET_SIZE_HS, + }, + .sink = { + .bLength = sizeof(descriptors.hs_descs.sink), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 2 | USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = MAX_PACKET_SIZE_HS, + }, + }, +}; + +#define STR_INTERFACE_ "ADB Interface" + +static const struct { + struct usb_functionfs_strings_head header; + struct { + __le16 code; + const char str1[sizeof(STR_INTERFACE_)]; + } __attribute__((packed)) lang0; +} __attribute__((packed)) strings = { + .header = { + .magic = cpu_to_le32(FUNCTIONFS_STRINGS_MAGIC), + .length = cpu_to_le32(sizeof(strings)), + .str_count = cpu_to_le32(1), + .lang_count = cpu_to_le32(1), + }, + .lang0 = { + cpu_to_le16(0x0409), /* en-us */ + STR_INTERFACE_, + }, }; -void usb_cleanup() -{ - // nothing to do here -} -static void *usb_open_thread(void *x) + +static void *usb_adb_open_thread(void *x) { struct usb_handle *usb = (struct usb_handle *)x; int fd; @@ -72,14 +176,14 @@ static void *usb_open_thread(void *x) usb->fd = fd; D("[ usb_thread - registering device ]\n"); - register_usb_transport(usb, 0, 1); + register_usb_transport(usb, 0, 0, 1); } // never gets here return 0; } -int usb_write(usb_handle *h, const void *data, int len) +static int usb_adb_write(usb_handle *h, const void *data, int len) { int n; @@ -94,7 +198,7 @@ int usb_write(usb_handle *h, const void *data, int len) return 0; } -int usb_read(usb_handle *h, void *data, int len) +static int usb_adb_read(usb_handle *h, void *data, int len) { int n; @@ -109,14 +213,31 @@ int usb_read(usb_handle *h, void *data, int len) return 0; } -void usb_init() +static void usb_adb_kick(usb_handle *h) +{ + D("usb_kick\n"); + adb_mutex_lock(&h->lock); + adb_close(h->fd); + h->fd = -1; + + // notify usb_adb_open_thread that we are disconnected + adb_cond_signal(&h->notify); + adb_mutex_unlock(&h->lock); +} + +static void usb_adb_init() { usb_handle *h; adb_thread_t tid; int fd; h = calloc(1, sizeof(usb_handle)); + + h->write = usb_adb_write; + h->read = usb_adb_read; + h->kick = usb_adb_kick; h->fd = -1; + adb_cond_init(&h->notify, 0); adb_mutex_init(&h->lock, 0); @@ -133,25 +254,239 @@ void usb_init() } D("[ usb_init - starting thread ]\n"); - if(adb_thread_create(&tid, usb_open_thread, h)){ + if(adb_thread_create(&tid, usb_adb_open_thread, h)){ fatal_errno("cannot create usb thread"); } } -void usb_kick(usb_handle *h) + +static void init_functionfs(struct usb_handle *h) { - D("usb_kick\n"); + ssize_t ret; + + D("OPENING %s\n", USB_FFS_ADB_EP0); + h->control = adb_open(USB_FFS_ADB_EP0, O_RDWR); + if (h->control < 0) { + D("[ %s: cannot open control endpoint: errno=%d]\n", USB_FFS_ADB_EP0, errno); + goto err; + } + + ret = adb_write(h->control, &descriptors, sizeof(descriptors)); + if (ret < 0) { + D("[ %s: write descriptors failed: errno=%d ]\n", USB_FFS_ADB_EP0, errno); + goto err; + } + + ret = adb_write(h->control, &strings, sizeof(strings)); + if (ret < 0) { + D("[ %s: writing strings failed: errno=%d]\n", USB_FFS_ADB_EP0, errno); + goto err; + } + + h->bulk_out = adb_open(USB_FFS_ADB_OUT, O_RDWR); + if (h->bulk_out < 0) { + D("[ %s: cannot open bulk-out ep: errno=%d ]\n", USB_FFS_ADB_OUT, errno); + goto err; + } + + h->bulk_in = adb_open(USB_FFS_ADB_IN, O_RDWR); + if (h->bulk_in < 0) { + D("[ %s: cannot open bulk-in ep: errno=%d ]\n", USB_FFS_ADB_IN, errno); + goto err; + } + + return; + +err: + if (h->bulk_in > 0) { + adb_close(h->bulk_in); + h->bulk_in = -1; + } + if (h->bulk_out > 0) { + adb_close(h->bulk_out); + h->bulk_out = -1; + } + if (h->control > 0) { + adb_close(h->control); + h->control = -1; + } + return; +} + +static void *usb_ffs_open_thread(void *x) +{ + struct usb_handle *usb = (struct usb_handle *)x; + + while (1) { + // wait until the USB device needs opening + adb_mutex_lock(&usb->lock); + while (usb->control != -1) + adb_cond_wait(&usb->notify, &usb->lock); + adb_mutex_unlock(&usb->lock); + + while (1) { + init_functionfs(usb); + + if (usb->control >= 0) + break; + + adb_sleep_ms(1000); + } + + D("[ usb_thread - registering device ]\n"); + register_usb_transport(usb, 0, 0, 1); + } + + // never gets here + return 0; +} + +static int bulk_write(int bulk_in, const char *buf, size_t length) +{ + size_t count = 0; + int ret; + + do { + ret = adb_write(bulk_in, buf + count, length - count); + if (ret < 0) { + if (errno != EINTR) + return ret; + } else { + count += ret; + } + } while (count < length); + + D("[ bulk_write done fd=%d ]\n", bulk_in); + return count; +} + +static int usb_ffs_write(usb_handle *h, const void *data, int len) +{ + int n; + + D("about to write (fd=%d, len=%d)\n", h->bulk_in, len); + n = bulk_write(h->bulk_in, data, len); + if (n != len) { + D("ERROR: fd = %d, n = %d, errno = %d (%s)\n", + h->bulk_in, n, errno, strerror(errno)); + return -1; + } + D("[ done fd=%d ]\n", h->bulk_in); + return 0; +} + +static int bulk_read(int bulk_out, char *buf, size_t length) +{ + size_t count = 0; + int ret; + + do { + ret = adb_read(bulk_out, buf + count, length - count); + if (ret < 0) { + if (errno != EINTR) { + D("[ bulk_read failed fd=%d length=%d count=%d ]\n", + bulk_out, length, count); + return ret; + } + } else { + count += ret; + } + } while (count < length); + + return count; +} + +static int usb_ffs_read(usb_handle *h, void *data, int len) +{ + int n; + + D("about to read (fd=%d, len=%d)\n", h->bulk_out, len); + n = bulk_read(h->bulk_out, data, len); + if (n != len) { + D("ERROR: fd = %d, n = %d, errno = %d (%s)\n", + h->bulk_out, n, errno, strerror(errno)); + return -1; + } + D("[ done fd=%d ]\n", h->bulk_out); + return 0; +} + +static void usb_ffs_kick(usb_handle *h) +{ + int err; + + err = ioctl(h->bulk_in, FUNCTIONFS_CLEAR_HALT); + if (err < 0) + D("[ kick: source (fd=%d) clear halt failed (%d) ]", h->bulk_in, errno); + + err = ioctl(h->bulk_out, FUNCTIONFS_CLEAR_HALT); + if (err < 0) + D("[ kick: sink (fd=%d) clear halt failed (%d) ]", h->bulk_out, errno); + adb_mutex_lock(&h->lock); - adb_close(h->fd); - h->fd = -1; + adb_close(h->control); + adb_close(h->bulk_out); + adb_close(h->bulk_in); + h->control = h->bulk_out = h->bulk_in = -1; - // notify usb_open_thread that we are disconnected + // notify usb_ffs_open_thread that we are disconnected adb_cond_signal(&h->notify); adb_mutex_unlock(&h->lock); } +static void usb_ffs_init() +{ + usb_handle *h; + adb_thread_t tid; + + D("[ usb_init - using FunctionFS ]\n"); + + h = calloc(1, sizeof(usb_handle)); + + h->write = usb_ffs_write; + h->read = usb_ffs_read; + h->kick = usb_ffs_kick; + + h->control = -1; + h->bulk_out = -1; + h->bulk_out = -1; + + adb_cond_init(&h->notify, 0); + adb_mutex_init(&h->lock, 0); + + D("[ usb_init - starting thread ]\n"); + if (adb_thread_create(&tid, usb_ffs_open_thread, h)){ + fatal_errno("[ cannot create usb thread ]\n"); + } +} + +void usb_init() +{ + if (access(USB_FFS_ADB_EP0, F_OK) == 0) + usb_ffs_init(); + else + usb_adb_init(); +} + +void usb_cleanup() +{ +} + +int usb_write(usb_handle *h, const void *data, int len) +{ + return h->write(h, data, len); +} + +int usb_read(usb_handle *h, void *data, int len) +{ + return h->read(h, data, len); +} int usb_close(usb_handle *h) { - // nothing to do here return 0; } + +void usb_kick(usb_handle *h) +{ + h->kick(h); +} diff --git a/adb/usb_osx.c b/adb/usb_osx.c index 00d02da..45ce444 100644 --- a/adb/usb_osx.c +++ b/adb/usb_osx.c @@ -125,10 +125,13 @@ AndroidInterfaceAdded(void *refCon, io_iterator_t iterator) IOUSBDeviceInterface197 **dev = NULL; HRESULT result; SInt32 score; + UInt32 locationId; UInt16 vendor; UInt16 product; UInt8 serialIndex; char serial[256]; + char devpathBuf[64]; + char *devpath = NULL; while ((usbInterface = IOIteratorNext(iterator))) { //* Create an intermediate interface plugin @@ -192,6 +195,11 @@ AndroidInterfaceAdded(void *refCon, io_iterator_t iterator) kr = (*dev)->GetDeviceVendor(dev, &vendor); kr = (*dev)->GetDeviceProduct(dev, &product); + kr = (*dev)->GetLocationID(dev, &locationId); + if (kr == 0) { + snprintf(devpathBuf, sizeof(devpathBuf), "usb:%lX", locationId); + devpath = devpathBuf; + } kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex); if (serialIndex > 0) { @@ -256,7 +264,7 @@ AndroidInterfaceAdded(void *refCon, io_iterator_t iterator) } DBG("AndroidDeviceAdded calling register_usb_transport\n"); - register_usb_transport(handle, (serial[0] ? serial : NULL), 1); + register_usb_transport(handle, (serial[0] ? serial : NULL), devpath, 1); // Register for an interest notification of this device being removed. // Pass the reference to our private data as the refCon for the diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c index b988115..3a8e8fd 100644 --- a/adb/usb_vendors.c +++ b/adb/usb_vendors.c @@ -127,6 +127,11 @@ #define VENDOR_ID_LAB126 0x1949 // Yulong Coolpad's USB Vendor ID #define VENDOR_ID_YULONG_COOLPAD 0x1EBF +// Kobo's USB Vendor ID +#define VENDOR_ID_KOBO 0x2237 +// Teleepoch's USB Vendor ID +#define VENDOR_ID_TELEEPOCH 0x2340 + /** built-in vendor list */ int builtInVendorIds[] = { @@ -176,6 +181,8 @@ int builtInVendorIds[] = { VENDOR_ID_SONY, VENDOR_ID_LAB126, VENDOR_ID_YULONG_COOLPAD, + VENDOR_ID_KOBO, + VENDOR_ID_TELEEPOCH, }; #define BUILT_IN_VENDOR_COUNT (sizeof(builtInVendorIds)/sizeof(builtInVendorIds[0])) @@ -228,6 +235,7 @@ void usb_vendors_init(void) break; } } + fclose(f); } } } diff --git a/adb/usb_windows.c b/adb/usb_windows.c index 251bf17..4936b77 100644 --- a/adb/usb_windows.c +++ b/adb/usb_windows.c @@ -490,7 +490,7 @@ void find_devices() { true)) { // Lets make sure that we don't duplicate this device if (register_new_device(handle)) { - register_usb_transport(handle, serial_number, 1); + register_usb_transport(handle, serial_number, NULL, 1); } else { D("register_new_device failed for %s\n", interf_name); usb_cleanup_handle(handle); |