diff options
Diffstat (limited to 'adb')
-rw-r--r-- | adb/.clang-format | 11 | ||||
-rw-r--r-- | adb/Android.mk | 301 | ||||
-rw-r--r-- | adb/CPPLINT.cfg | 2 | ||||
-rw-r--r-- | adb/adb.cpp (renamed from adb/adb.c) | 997 | ||||
-rw-r--r-- | adb/adb.h | 90 | ||||
-rw-r--r-- | adb/adb_auth.cpp | 95 | ||||
-rw-r--r-- | adb/adb_auth.h | 20 | ||||
-rw-r--r-- | adb/adb_auth_client.cpp (renamed from adb/adb_auth_client.c) | 57 | ||||
-rw-r--r-- | adb/adb_auth_host.cpp (renamed from adb/adb_auth_host.c) | 116 | ||||
-rw-r--r-- | adb/adb_client.cpp (renamed from adb/adb_client.c) | 63 | ||||
-rw-r--r-- | adb/adb_client.h | 2 | ||||
-rw-r--r-- | adb/adb_io.cpp | 95 | ||||
-rw-r--r-- | adb/adb_io.h | 45 | ||||
-rw-r--r-- | adb/adb_io_test.cpp | 154 | ||||
-rw-r--r-- | adb/adb_listeners.cpp | 304 | ||||
-rw-r--r-- | adb/adb_listeners.h | 47 | ||||
-rw-r--r-- | adb/adb_main.cpp | 411 | ||||
-rw-r--r-- | adb/adb_trace.h | 30 | ||||
-rw-r--r-- | adb/adb_utils.cpp | 52 | ||||
-rw-r--r-- | adb/adb_utils.h (renamed from adb/get_my_path_freebsd.c) | 25 | ||||
-rw-r--r-- | adb/adb_utils_test.cpp | 52 | ||||
-rw-r--r-- | adb/commandline.cpp (renamed from adb/commandline.c) | 1005 | ||||
-rw-r--r-- | adb/console.cpp (renamed from adb/console.c) | 2 | ||||
-rw-r--r-- | adb/fdevent.cpp (renamed from adb/fdevent.c) | 41 | ||||
-rw-r--r-- | adb/fdevent.h | 10 | ||||
-rw-r--r-- | adb/file_sync_client.cpp (renamed from adb/file_sync_client.c) | 187 | ||||
-rw-r--r-- | adb/file_sync_service.cpp (renamed from adb/file_sync_service.c) | 136 | ||||
-rw-r--r-- | adb/file_sync_service.h | 22 | ||||
-rw-r--r-- | adb/framebuffer_service.cpp (renamed from adb/framebuffer_service.c) | 47 | ||||
-rw-r--r-- | adb/get_my_path_darwin.cpp (renamed from adb/get_my_path_darwin.c) | 2 | ||||
-rw-r--r-- | adb/get_my_path_linux.cpp (renamed from adb/get_my_path_linux.c) | 6 | ||||
-rw-r--r-- | adb/get_my_path_windows.cpp (renamed from adb/get_my_path_windows.c) | 4 | ||||
-rw-r--r-- | adb/jdwp_service.cpp (renamed from adb/jdwp_service.c) | 47 | ||||
-rw-r--r-- | adb/qemu_tracing.cpp | 69 | ||||
-rw-r--r-- | adb/qemu_tracing.h | 28 | ||||
-rw-r--r-- | adb/remount_service.c | 170 | ||||
-rw-r--r-- | adb/remount_service.cpp | 147 | ||||
-rw-r--r-- | adb/remount_service.h (renamed from adb/usb_vendors.h) | 12 | ||||
-rw-r--r-- | adb/services.cpp (renamed from adb/services.c) | 224 | ||||
-rw-r--r-- | adb/set_verity_enable_state_service.cpp (renamed from adb/disable_verity_service.c) | 160 | ||||
-rw-r--r-- | adb/sockets.cpp (renamed from adb/sockets.c) | 168 | ||||
-rw-r--r-- | adb/sysdeps.h | 101 | ||||
-rw-r--r-- | adb/sysdeps_win32.cpp (renamed from adb/sysdeps_win32.c) | 1109 | ||||
-rw-r--r-- | adb/test_track_devices.cpp (renamed from adb/test_track_devices.c) | 0 | ||||
-rw-r--r-- | adb/test_track_jdwp.cpp (renamed from adb/test_track_jdwp.c) | 0 | ||||
-rwxr-xr-x | adb/tests/test_adb.py | 412 | ||||
-rw-r--r-- | adb/transport.cpp (renamed from adb/transport.c) | 218 | ||||
-rw-r--r-- | adb/transport.h | 58 | ||||
-rw-r--r-- | adb/transport_local.cpp (renamed from adb/transport_local.c) | 49 | ||||
-rw-r--r-- | adb/transport_test.cpp | 53 | ||||
-rw-r--r-- | adb/transport_usb.cpp (renamed from adb/transport_usb.c) | 53 | ||||
-rw-r--r-- | adb/usb_libusb.c | 657 | ||||
-rw-r--r-- | adb/usb_linux.cpp (renamed from adb/usb_linux.c) | 97 | ||||
-rw-r--r-- | adb/usb_linux_client.cpp (renamed from adb/usb_linux_client.c) | 234 | ||||
-rw-r--r-- | adb/usb_osx.cpp (renamed from adb/usb_osx.c) | 116 | ||||
-rwxr-xr-x | adb/usb_vendors.c | 370 | ||||
-rw-r--r-- | adb/usb_windows.cpp (renamed from adb/usb_windows.c) | 18 |
57 files changed, 4943 insertions, 4058 deletions
diff --git a/adb/.clang-format b/adb/.clang-format new file mode 100644 index 0000000..0395c8e --- /dev/null +++ b/adb/.clang-format @@ -0,0 +1,11 @@ +BasedOnStyle: Google +AllowShortBlocksOnASingleLine: false +AllowShortFunctionsOnASingleLine: false + +CommentPragmas: NOLINT:.* +DerivePointerAlignment: false +IndentWidth: 4 +PointerAlignment: Left +TabWidth: 4 +UseTab: Never +PenaltyExcessCharacter: 32 diff --git a/adb/Android.mk b/adb/Android.mk index b70c153..6951904 100644 --- a/adb/Android.mk +++ b/adb/Android.mk @@ -5,83 +5,180 @@ LOCAL_PATH:= $(call my-dir) -# adb host tool +ifeq ($(HOST_OS),windows) + adb_host_clang := false # libc++ for mingw not ready yet. +else + adb_host_clang := true +endif + +# libadb # ========================================================= + +# Much of adb is duplicated in bootable/recovery/minadb and fastboot. Changes +# made to adb rarely get ported to the other two, so the trees have diverged a +# bit. We'd like to stop this because it is a maintenance nightmare, but the +# divergence makes this difficult to do all at once. For now, we will start +# small by moving common files into a static library. Hopefully some day we can +# get enough of adb in here that we no longer need minadb. https://b/17626262 +LIBADB_SRC_FILES := \ + adb.cpp \ + adb_auth.cpp \ + adb_io.cpp \ + adb_listeners.cpp \ + adb_utils.cpp \ + sockets.cpp \ + transport.cpp \ + transport_local.cpp \ + transport_usb.cpp \ + +LIBADB_TEST_SRCS := \ + adb_io_test.cpp \ + adb_utils_test.cpp \ + transport_test.cpp \ + +LIBADB_CFLAGS := \ + -Wall -Werror \ + -Wno-unused-parameter \ + -Wno-missing-field-initializers \ + -fvisibility=hidden \ + +LIBADB_darwin_SRC_FILES := \ + fdevent.cpp \ + get_my_path_darwin.cpp \ + usb_osx.cpp \ + +LIBADB_linux_SRC_FILES := \ + fdevent.cpp \ + get_my_path_linux.cpp \ + usb_linux.cpp \ + +LIBADB_windows_SRC_FILES := \ + get_my_path_windows.cpp \ + sysdeps_win32.cpp \ + usb_windows.cpp \ + +include $(CLEAR_VARS) +LOCAL_CLANG := true +LOCAL_MODULE := libadbd +LOCAL_CFLAGS := $(LIBADB_CFLAGS) -DADB_HOST=0 +LOCAL_SRC_FILES := \ + $(LIBADB_SRC_FILES) \ + adb_auth_client.cpp \ + fdevent.cpp \ + jdwp_service.cpp \ + qemu_tracing.cpp \ + usb_linux_client.cpp \ + +LOCAL_SHARED_LIBRARIES := libbase + +include $(BUILD_STATIC_LIBRARY) + include $(CLEAR_VARS) +LOCAL_CLANG := $(adb_host_clang) +LOCAL_MODULE := libadb +LOCAL_CFLAGS := $(LIBADB_CFLAGS) -DADB_HOST=1 +LOCAL_SRC_FILES := \ + $(LIBADB_SRC_FILES) \ + $(LIBADB_$(HOST_OS)_SRC_FILES) \ + adb_auth_host.cpp \ + +LOCAL_SHARED_LIBRARIES := libbase -# Default to a virtual (sockets) usb interface -USB_SRCS := -EXTRA_SRCS := +# Even though we're building a static library (and thus there's no link step for +# this to take effect), this adds the SSL includes to our path. +LOCAL_STATIC_LIBRARIES := libcrypto_static + +ifeq ($(HOST_OS),windows) + LOCAL_C_INCLUDES += development/host/windows/usb/api/ +endif + +include $(BUILD_HOST_STATIC_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_CLANG := true +LOCAL_MODULE := adbd_test +LOCAL_CFLAGS := -DADB_HOST=0 $(LIBADB_CFLAGS) +LOCAL_SRC_FILES := $(LIBADB_TEST_SRCS) +LOCAL_STATIC_LIBRARIES := libadbd +LOCAL_SHARED_LIBRARIES := liblog libbase libcutils +include $(BUILD_NATIVE_TEST) + +include $(CLEAR_VARS) +LOCAL_CLANG := $(adb_host_clang) +LOCAL_MODULE := adb_test +LOCAL_CFLAGS := -DADB_HOST=1 $(LIBADB_CFLAGS) +LOCAL_SRC_FILES := $(LIBADB_TEST_SRCS) services.cpp +LOCAL_SHARED_LIBRARIES := liblog libbase +LOCAL_STATIC_LIBRARIES := \ + libadb \ + libcrypto_static \ + libcutils \ 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) - USB_SRCS := usb_osx.c - EXTRA_SRCS := get_my_path_darwin.c - LOCAL_LDLIBS += -lpthread -framework CoreFoundation -framework IOKit -framework Carbon + LOCAL_LDLIBS += -framework CoreFoundation -framework IOKit +endif + +include $(BUILD_HOST_NATIVE_TEST) + +# adb host tool +# ========================================================= +include $(CLEAR_VARS) + +ifeq ($(HOST_OS),linux) + LOCAL_LDLIBS += -lrt -ldl -lpthread + LOCAL_CFLAGS += -DWORKAROUND_BUG6558362 endif -ifeq ($(HOST_OS),freebsd) - USB_SRCS := usb_libusb.c - EXTRA_SRCS := get_my_path_freebsd.c - LOCAL_LDLIBS += -lpthread -lusb +ifeq ($(HOST_OS),darwin) + LOCAL_LDLIBS += -lpthread -framework CoreFoundation -framework IOKit -framework Carbon + LOCAL_CFLAGS += -Wno-sizeof-pointer-memaccess -Wno-unused-parameter endif ifeq ($(HOST_OS),windows) - USB_SRCS := usb_windows.c - EXTRA_SRCS := get_my_path_windows.c + LOCAL_LDLIBS += -lws2_32 -lgdi32 EXTRA_STATIC_LIBS := AdbWinApi - ifneq ($(strip $(USE_CYGWIN)),) - # Pure cygwin case - LOCAL_LDLIBS += -lpthread -lgdi32 - endif - ifneq ($(strip $(USE_MINGW)),) - # MinGW under Linux case - LOCAL_LDLIBS += -lws2_32 -lgdi32 - USE_SYSDEPS_WIN32 := 1 - endif - LOCAL_C_INCLUDES += development/host/windows/usb/api/ endif +LOCAL_CLANG := $(adb_host_clang) + LOCAL_SRC_FILES := \ - adb.c \ - console.c \ - transport.c \ - transport_local.c \ - transport_usb.c \ - commandline.c \ - adb_client.c \ - adb_auth_host.c \ - sockets.c \ - services.c \ - file_sync_client.c \ - $(EXTRA_SRCS) \ - $(USB_SRCS) \ - usb_vendors.c - -LOCAL_C_INCLUDES += external/openssl/include - -ifneq ($(USE_SYSDEPS_WIN32),) - LOCAL_SRC_FILES += sysdeps_win32.c -else - LOCAL_SRC_FILES += fdevent.c -endif + adb_main.cpp \ + console.cpp \ + commandline.cpp \ + adb_client.cpp \ + services.cpp \ + file_sync_client.cpp \ + +LOCAL_CFLAGS += \ + -Wall -Werror \ + -Wno-unused-parameter \ + -D_GNU_SOURCE \ + -DADB_HOST=1 \ -LOCAL_CFLAGS += -O2 -g -DADB_HOST=1 -Wall -Wno-unused-parameter -Werror -LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE LOCAL_MODULE := adb LOCAL_MODULE_TAGS := debug -LOCAL_STATIC_LIBRARIES := libzipfile libunz libcrypto_static $(EXTRA_STATIC_LIBS) -ifeq ($(USE_SYSDEPS_WIN32),) - LOCAL_STATIC_LIBRARIES += libcutils +LOCAL_STATIC_LIBRARIES := \ + libadb \ + libbase \ + libcrypto_static \ + libcutils \ + $(EXTRA_STATIC_LIBS) \ + +# libc++ not available on windows yet +ifneq ($(HOST_OS),windows) + LOCAL_CXX_STL := libc++_static endif +# Don't add anything here, we don't want additional shared dependencies +# on the host adb tool, and shared libraries that link against libc++ +# will violate ODR +LOCAL_SHARED_LIBRARIES := + include $(BUILD_HOST_EXECUTABLE) $(call dist-for-goals,dist_files sdk,$(LOCAL_BUILT_MODULE)) @@ -98,30 +195,28 @@ endif include $(CLEAR_VARS) +LOCAL_CLANG := true + LOCAL_SRC_FILES := \ - adb.c \ - fdevent.c \ - transport.c \ - transport_local.c \ - transport_usb.c \ - adb_auth_client.c \ - sockets.c \ - services.c \ - file_sync_service.c \ - jdwp_service.c \ - framebuffer_service.c \ - remount_service.c \ - disable_verity_service.c \ - usb_linux_client.c - -LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -Wall -Wno-unused-parameter -Werror -LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE + adb_main.cpp \ + services.cpp \ + file_sync_service.cpp \ + framebuffer_service.cpp \ + remount_service.cpp \ + set_verity_enable_state_service.cpp \ + +LOCAL_CFLAGS := \ + -DADB_HOST=0 \ + -D_GNU_SOURCE \ + -Wall -Werror \ + -Wno-unused-parameter \ + -Wno-deprecated-declarations \ ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT))) LOCAL_CFLAGS += -DALLOW_ADBD_ROOT=1 endif -ifneq (,$(filter userdebug,$(TARGET_BUILD_VARIANT))) +ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT))) LOCAL_CFLAGS += -DALLOW_ADBD_DISABLE_VERITY=1 endif @@ -130,57 +225,17 @@ LOCAL_MODULE := adbd LOCAL_FORCE_STATIC_EXECUTABLE := true LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN) LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED) -LOCAL_C_INCLUDES += system/extras/ext4_utils system/core/fs_mgr/include - -LOCAL_STATIC_LIBRARIES := liblog \ - libfs_mgr \ - libcutils \ - libc \ - libmincrypt \ - libselinux \ - libext4_utils_static +LOCAL_C_INCLUDES += system/extras/ext4_utils + +LOCAL_STATIC_LIBRARIES := \ + libadbd \ + libbase \ + libfs_mgr \ + liblog \ + libcutils \ + libc \ + libmincrypt \ + libselinux \ + libext4_utils_static \ include $(BUILD_EXECUTABLE) - - -# adb host tool for device-as-host -# ========================================================= -ifneq ($(SDK_ONLY),true) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - adb.c \ - console.c \ - transport.c \ - transport_local.c \ - transport_usb.c \ - commandline.c \ - adb_client.c \ - adb_auth_host.c \ - sockets.c \ - services.c \ - file_sync_client.c \ - get_my_path_linux.c \ - usb_linux.c \ - usb_vendors.c \ - fdevent.c - -LOCAL_CFLAGS := \ - -O2 \ - -g \ - -DADB_HOST=1 \ - -DADB_HOST_ON_TARGET=1 \ - -Wall -Wno-unused-parameter -Werror \ - -D_XOPEN_SOURCE \ - -D_GNU_SOURCE - -LOCAL_C_INCLUDES += external/openssl/include - -LOCAL_MODULE := adb - -LOCAL_STATIC_LIBRARIES := libzipfile libunz libcutils liblog - -LOCAL_SHARED_LIBRARIES := libcrypto - -include $(BUILD_EXECUTABLE) -endif diff --git a/adb/CPPLINT.cfg b/adb/CPPLINT.cfg new file mode 100644 index 0000000..9b906e8 --- /dev/null +++ b/adb/CPPLINT.cfg @@ -0,0 +1,2 @@ +set noparent +filter=-build/header_guard,-build/include,-readability/function @@ -14,35 +14,37 @@ * limitations under the License. */ -#define TRACE_TAG TRACE_ADB +#define TRACE_TAG TRACE_ADB + +#include "sysdeps.h" +#include "adb.h" -#include <stdio.h> -#include <stdlib.h> #include <ctype.h> -#include <stdarg.h> #include <errno.h> +#include <stdarg.h> #include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> #include <string.h> -#include <time.h> #include <sys/time.h> -#include <stdint.h> +#include <time.h> + +#include <string> + +#include <base/stringprintf.h> -#include "sysdeps.h" -#include "adb.h" #include "adb_auth.h" +#include "adb_io.h" +#include "adb_listeners.h" +#include "transport.h" #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 <sys/mount.h> -#include <sys/prctl.h> -#include <getopt.h> -#include <selinux/selinux.h> -#else -#include "usb_vendors.h" #endif #if ADB_TRACE @@ -50,13 +52,9 @@ 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"; -static const char *root_seclabel = NULL; +const char *adb_device_banner = "device"; #endif void fatal(const char *fmt, ...) @@ -81,17 +79,68 @@ void fatal_errno(const char *fmt, ...) exit(-1); } -int adb_trace_mask; +#if !ADB_HOST +void start_device_log(void) { + struct tm now; + time_t t; + tzset(); + time(&t); + localtime_r(&t, &now); -/* read a comma/space/colum/semi-column separated list of tags - * from the ADB_TRACE environment variable and build the trace - * mask from it. note that '1' and 'all' are special cases to - * enable all tracing - */ -void adb_trace_init(void) -{ - const char* p = getenv("ADB_TRACE"); - const char* q; + char timestamp[PATH_MAX]; + strftime(timestamp, sizeof(timestamp), "%Y-%m-%d-%H-%M-%S", &now); + + char path[PATH_MAX]; + snprintf(path, sizeof(path), "/data/adb/adb-%s-%d", timestamp, getpid()); + + int fd = unix_open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0640); + if (fd == -1) { + return; + } + + // redirect stdout and stderr to the log file + dup2(fd, STDOUT_FILENO); + dup2(fd, STDERR_FILENO); + fprintf(stderr, "--- adb starting (pid %d) ---\n", getpid()); + adb_close(fd); +} +#endif + +int adb_trace_mask; + +std::string get_trace_setting_from_env() { + const char* setting = getenv("ADB_TRACE"); + if (setting == nullptr) { + setting = ""; + } + + return std::string(setting); +} + +#if !ADB_HOST +std::string get_trace_setting_from_prop() { + char buf[PROPERTY_VALUE_MAX]; + property_get("persist.adb.trace_mask", buf, ""); + return std::string(buf); +} +#endif + +std::string get_trace_setting() { +#if ADB_HOST + return get_trace_setting_from_env(); +#else + return get_trace_setting_from_prop(); +#endif +} + +// Split the comma/space/colum/semi-column separated list of tags from the trace +// setting and build the trace mask from it. note that '1' and 'all' are special +// cases to enable all tracing. +// +// adb's trace setting comes from the ADB_TRACE environment variable, whereas +// adbd's comes from the system property persist.adb.trace_mask. +void adb_trace_init() { + const std::string trace_setting = get_trace_setting(); static const struct { const char* tag; @@ -113,25 +162,25 @@ void adb_trace_init(void) { NULL, 0 } }; - if (p == NULL) - return; + if (trace_setting.empty()) { + return; + } - /* use a comma/column/semi-colum/space separated list */ + // Use a comma/colon/semi-colon/space separated list + const char* p = trace_setting.c_str(); while (*p) { int len, tagn; - q = strpbrk(p, " ,:;"); + const char* q = strpbrk(p, " ,:;"); if (q == NULL) { q = p + strlen(p); } len = q - p; - for (tagn = 0; tags[tagn].tag != NULL; tagn++) - { + for (tagn = 0; tags[tagn].tag != NULL; tagn++) { int taglen = strlen(tags[tagn].tag); - if (len == taglen && !memcmp(tags[tagn].tag, p, len) ) - { + if (len == taglen && !memcmp(tags[tagn].tag, p, len)) { int flag = tags[tagn].flag; if (flag == 0) { adb_trace_mask = ~0; @@ -145,65 +194,19 @@ void adb_trace_init(void) if (*p) p++; } -} #if !ADB_HOST -/* - * Implements ADB tracing inside the emulator. - */ - -#include <stdarg.h> - -/* - * Redefine open and write for qemu_pipe.h that contains inlined references - * to those routines. We will redifine them back after qemu_pipe.h inclusion. - */ - -#undef open -#undef write -#define open adb_open -#define write adb_write -#include <hardware/qemu_pipe.h> -#undef open -#undef write -#define open ___xxx_open -#define write ___xxx_write - -/* A handle to adb-debug qemud service in the emulator. */ -int adb_debug_qemu = -1; - -/* Initializes connection with the adb-debug qemud service in the emulator. */ -static int adb_qemu_trace_init(void) -{ - char con_name[32]; - - if (adb_debug_qemu >= 0) { - return 0; - } - - /* adb debugging QEMUD service connection request. */ - snprintf(con_name, sizeof(con_name), "qemud:adb-debug"); - adb_debug_qemu = qemu_pipe_open(con_name); - return (adb_debug_qemu >= 0) ? 0 : -1; + start_device_log(); +#endif } -void adb_qemu_trace(const char* fmt, ...) +apacket* get_apacket(void) { - va_list args; - va_start(args, fmt); - char msg[1024]; - - if (adb_debug_qemu >= 0) { - vsnprintf(msg, sizeof(msg), fmt, args); - adb_write(adb_debug_qemu, msg, strlen(msg)); + apacket* p = reinterpret_cast<apacket*>(malloc(sizeof(apacket))); + if (p == nullptr) { + fatal("failed to allocate an apacket"); } -} -#endif /* !ADB_HOST */ -apacket *get_apacket(void) -{ - apacket *p = malloc(sizeof(apacket)); - if(p == 0) fatal("failed to allocate an apacket"); memset(p, 0, sizeof(apacket) - MAX_PAYLOAD); return p; } @@ -324,21 +327,23 @@ static void send_msg_with_header(int fd, const char* msg, size_t msglen) { if (msglen > 0xffff) msglen = 0xffff; snprintf(header, sizeof(header), "%04x", (unsigned)msglen); - writex(fd, header, 4); - writex(fd, msg, msglen); + WriteFdExactly(fd, header, 4); + WriteFdExactly(fd, msg, msglen); } #endif +#if ADB_HOST static void send_msg_with_okay(int fd, const char* msg, size_t msglen) { char header[9]; if (msglen > 0xffff) msglen = 0xffff; snprintf(header, sizeof(header), "OKAY%04x", (unsigned)msglen); - writex(fd, header, 8); - writex(fd, msg, msglen); + WriteFdExactly(fd, header, 8); + WriteFdExactly(fd, msg, msglen); } +#endif // ADB_HOST -static void send_connect(atransport *t) +void send_connect(atransport *t) { D("Calling send_connect \n"); apacket *cp = get_apacket(); @@ -350,71 +355,8 @@ static void send_connect(atransport *t) send_packet(cp, t); } -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) +#if ADB_HOST +static const char* connection_state_name(atransport *t) { if (t == NULL) { return "unknown"; @@ -437,6 +379,7 @@ static char *connection_state_name(atransport *t) return "unknown"; } } +#endif // ADB_HOST /* 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 @@ -664,409 +607,11 @@ void handle_packet(apacket *p, atransport *t) put_apacket(p); } -alistener listener_list = { - .next = &listener_list, - .prev = &listener_list, -}; - -static void ss_listener_event_func(int _fd, unsigned ev, void *_l) -{ - asocket *s; - - if(ev & FDE_READ) { - struct sockaddr addr; - socklen_t alen; - int fd; - - alen = sizeof(addr); - fd = adb_socket_accept(_fd, &addr, &alen); - if(fd < 0) return; - - adb_socket_setbufsize(fd, CHUNK_SIZE); - - s = create_local_socket(fd); - if(s) { - connect_to_smartsocket(s); - return; - } - - adb_close(fd); - } -} - -static void listener_event_func(int _fd, unsigned ev, void *_l) -{ - alistener *l = _l; - asocket *s; - - if(ev & FDE_READ) { - struct sockaddr addr; - socklen_t alen; - int fd; - - alen = sizeof(addr); - fd = adb_socket_accept(_fd, &addr, &alen); - if(fd < 0) return; - - s = create_local_socket(fd); - if(s) { - s->transport = l->transport; - connect_to_remote(s, l->connect_to); - return; - } - - adb_close(fd); - } -} - -static void free_listener(alistener* l) -{ - if (l->next) { - l->next->prev = l->prev; - l->prev->next = l->next; - l->next = l->prev = l; - } - - // closes the corresponding fd - fdevent_remove(&l->fde); - - if (l->local_name) - free((char*)l->local_name); - - if (l->connect_to) - free((char*)l->connect_to); - - if (l->transport) { - remove_transport_disconnect(l->transport, &l->disconnect); - } - free(l); -} - -static void listener_disconnect(void* _l, atransport* t) -{ - alistener* l = _l; - - free_listener(l); -} - -int local_name_to_fd(const char *name) -{ - int port; - - if(!strncmp("tcp:", name, 4)){ - int ret; - port = atoi(name + 4); - - 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 */ - // It's non-sensical to support the "reserved" space on the adb host side - if(!strncmp(name, "local:", 6)) { - return socket_local_server(name + 6, - ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM); - } else if(!strncmp(name, "localabstract:", 14)) { - return socket_local_server(name + 14, - ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM); - } else if(!strncmp(name, "localfilesystem:", 16)) { - return socket_local_server(name + 16, - ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM); - } - -#endif - printf("unknown local portname '%s'\n", name); - return -1; -} - -// 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)) { - listener_disconnect(l, l->transport); - return 0; - } - } - return -1; -} - -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; - - //printf("install_listener('%s','%s')\n", local_name, connect_to); - - for(l = listener_list.next; l != &listener_list; l = l->next){ - if(strcmp(local_name, l->local_name) == 0) { - char *cto; - - /* can't repurpose a smartsocket */ - if(l->connect_to[0] == '*') { - 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 INSTALL_STATUS_INTERNAL_ERROR; - } - - //printf("rebinding '%s' to '%s'\n", local_name, connect_to); - free((void*) l->connect_to); - l->connect_to = cto; - if (l->transport != transport) { - remove_transport_disconnect(l->transport, &l->disconnect); - l->transport = transport; - add_transport_disconnect(l->transport, &l->disconnect); - } - return INSTALL_STATUS_OK; - } - } - - if((l = calloc(1, sizeof(alistener))) == 0) goto nomem; - if((l->local_name = strdup(local_name)) == 0) goto nomem; - if((l->connect_to = strdup(connect_to)) == 0) goto nomem; - - - l->fd = local_name_to_fd(local_name); - if(l->fd < 0) { - free((void*) l->local_name); - free((void*) l->connect_to); - free(l); - printf("cannot bind '%s'\n", local_name); - return -2; - } - - close_on_exec(l->fd); - if(!strcmp(l->connect_to, "*smartsocket*")) { - fdevent_install(&l->fde, l->fd, ss_listener_event_func, l); - } else { - fdevent_install(&l->fde, l->fd, listener_event_func, l); - } - fdevent_set(&l->fde, FDE_READ); - - l->next = &listener_list; - l->prev = listener_list.prev; - l->next->prev = l; - l->prev->next = l; - l->transport = transport; - - if (transport) { - l->disconnect.opaque = l; - l->disconnect.func = listener_disconnect; - add_transport_disconnect(transport, &l->disconnect); - } - return INSTALL_STATUS_OK; - -nomem: - fatal("cannot allocate listener"); - return INSTALL_STATUS_INTERNAL_ERROR; -} - -#ifdef HAVE_WIN32_PROC -static BOOL WINAPI ctrlc_handler(DWORD type) -{ - exit(STATUS_CONTROL_C_EXIT); - return TRUE; -} -#endif - -static void adb_cleanup(void) -{ - usb_cleanup(); -} - -void start_logging(void) -{ -#ifdef HAVE_WIN32_PROC - char temp[ MAX_PATH ]; - FILE* fnul; - FILE* flog; - - GetTempPath( sizeof(temp) - 8, temp ); - strcat( temp, "adb.log" ); - - /* Win32 specific redirections */ - fnul = fopen( "NUL", "rt" ); - if (fnul != NULL) - stdin[0] = fnul[0]; - - flog = fopen( temp, "at" ); - if (flog == NULL) - flog = fnul; - - setvbuf( flog, NULL, _IONBF, 0 ); - - stdout[0] = flog[0]; - stderr[0] = flog[0]; - fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid()); -#else - int fd; - - fd = unix_open("/dev/null", O_RDONLY); - dup2(fd, 0); - adb_close(fd); - - fd = unix_open("/tmp/adb.log", O_WRONLY | O_CREAT | O_APPEND, 0640); - if(fd < 0) { - fd = unix_open("/dev/null", O_WRONLY); - } - dup2(fd, 1); - dup2(fd, 2); - adb_close(fd); - fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid()); -#endif -} - -#if !ADB_HOST -void start_device_log(void) -{ - int fd; - char path[PATH_MAX]; - struct tm now; - time_t t; - char value[PROPERTY_VALUE_MAX]; - - // read the trace mask from persistent property persist.adb.trace_mask - // give up if the property is not set or cannot be parsed - property_get("persist.adb.trace_mask", value, ""); - if (sscanf(value, "%x", &adb_trace_mask) != 1) - return; - - adb_mkdir("/data/adb", 0775); - tzset(); - time(&t); - localtime_r(&t, &now); - strftime(path, sizeof(path), - "/data/adb/adb-%Y-%m-%d-%H-%M-%S.txt", - &now); - fd = unix_open(path, O_WRONLY | O_CREAT | O_TRUNC, 0640); - if (fd < 0) - return; - - // redirect stdout and stderr to the log file - dup2(fd, 1); - dup2(fd, 2); - fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid()); - adb_close(fd); - - fd = unix_open("/dev/null", O_RDONLY); - dup2(fd, 0); - adb_close(fd); -} -#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 +#if defined(_WIN32) /* we need to start the server in the background */ /* we create a PIPE that will be used to wait for the server's "OK" */ /* message since the pipe handles must be inheritable, we use a */ @@ -1123,10 +668,11 @@ int launch_server(int server_port) /* get path of current program */ GetModuleFileName( NULL, program_path, sizeof(program_path) ); - + char args[64]; + snprintf(args, sizeof(args), "adb -P %d fork-server server", server_port); ret = CreateProcess( program_path, /* program path */ - "adb fork-server server", + args, /* the fork-server argument will set the debug = 2 in the child */ NULL, /* process handle is not inheritable */ @@ -1165,7 +711,7 @@ int launch_server(int server_port) return -1; } } -#elif defined(HAVE_FORKEXEC) +#else /* !defined(_WIN32) */ char path[PATH_MAX]; int fd[2]; @@ -1216,227 +762,10 @@ int launch_server(int server_port) setsid(); } -#else -#error "cannot implement background server start on this platform" -#endif - return 0; -} -#endif - -/* Constructs a local name of form tcp:port. - * target_str points to the target string, it's content will be overwritten. - * target_size is the capacity of the target string. - * server_port is the port number to use for the local name. - */ -void build_local_name(char* target_str, size_t target_size, int server_port) -{ - snprintf(target_str, target_size, "tcp:%d", 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; -#else /* ALLOW_ADBD_ROOT */ - int secure = 0; - char value[PROPERTY_VALUE_MAX]; - - /* run adbd in secure mode if ro.secure is set and - ** we are not in the emulator - */ - property_get("ro.kernel.qemu", value, ""); - if (strcmp(value, "1") != 0) { - property_get("ro.secure", value, "1"); - if (strcmp(value, "1") == 0) { - // don't run as root if ro.secure is set... - secure = 1; - - // ... except we allow running as root in userdebug builds if the - // service.adb.root property has been set by the "adb root" command - property_get("ro.debuggable", value, ""); - if (strcmp(value, "1") == 0) { - property_get("service.adb.root", value, ""); - if (strcmp(value, "1") == 0) { - secure = 0; - } - } - } - } - return secure; -#endif /* ALLOW_ADBD_ROOT */ -} -#endif /* !ADB_HOST */ - -int adb_main(int is_daemon, int server_port) -{ -#if !ADB_HOST - int port; - char value[PROPERTY_VALUE_MAX]; - - umask(000); -#endif - - atexit(adb_cleanup); -#ifdef HAVE_WIN32_PROC - SetConsoleCtrlHandler( ctrlc_handler, TRUE ); -#elif defined(HAVE_FORKEXEC) - // No SIGCHLD. Let the service subproc handle its children. - signal(SIGPIPE, SIG_IGN); -#endif - - init_transport_registration(); - -#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); - adb_auth_init(); - - char local_name[30]; - build_local_name(local_name, sizeof(local_name), server_port); - 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"); - } - - /* add extra groups: - ** AID_ADB to access the USB driver - ** AID_LOG to read system logs (adb logcat) - ** AID_INPUT to diagnose input issues (getevent) - ** AID_INET to diagnose network issues (netcfg, ping) - ** AID_GRAPHICS to access the frame buffer - ** AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump) - ** AID_SDCARD_R to allow reading from the SD card - ** AID_SDCARD_RW to allow writing to the SD card - ** AID_NET_BW_STATS to read out qtaguid statistics - */ - gid_t groups[] = { AID_ADB, AID_LOG, AID_INPUT, AID_INET, AID_GRAPHICS, - AID_NET_BT, AID_NET_BT_ADMIN, AID_SDCARD_R, AID_SDCARD_RW, - AID_NET_BW_STATS }; - if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) { - exit(1); - } - - /* 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()) { - drop_capabilities_bounding_set_if_needed(); - - /* then switch user and group to "shell" */ - if (setgid(AID_SHELL) != 0) { - exit(1); - } - if (setuid(AID_SHELL) != 0) { - exit(1); - } - - D("Local port disabled\n"); - } else { - char local_name[30]; - if ((root_seclabel != NULL) && (is_selinux_enabled() > 0)) { - // b/12587913: fix setcon to allow const pointers - if (setcon((char *)root_seclabel) < 0) { - exit(1); - } - } - build_local_name(local_name, sizeof(local_name), server_port); - if(install_listener(local_name, "*smartsocket*", NULL, 0)) { - exit(1); - } - } - - 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]) { - 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 (!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"); -#endif - - if (is_daemon) - { - // inform our parent that we are up and running. -#ifdef HAVE_WIN32_PROC - DWORD count; - WriteFile( GetStdHandle( STD_OUTPUT_HANDLE ), "OK\n", 3, &count, NULL ); -#elif defined(HAVE_FORKEXEC) - fprintf(stderr, "OK\n"); -#endif - start_logging(); - } - D("Event loop starting\n"); - - fdevent_loop(); - - usb_cleanup(); - +#endif /* !defined(_WIN32) */ return 0; } +#endif /* ADB_HOST */ // Try to handle a network forwarding request. // This returns 1 on success, 0 on failure, and -1 to indicate this is not @@ -1447,8 +776,8 @@ int handle_forward_request(const char* service, transport_type ttype, char* seri // Create the list of forward redirections. int buffer_size = format_listeners(NULL, 0); // Add one byte for the trailing zero. - char* buffer = malloc(buffer_size + 1); - if (buffer == NULL) { + char* buffer = reinterpret_cast<char*>(malloc(buffer_size + 1)); + if (buffer == nullptr) { sendfailmsg(reply_fd, "not enough memory"); return 1; } @@ -1474,8 +803,7 @@ int handle_forward_request(const char* service, transport_type ttype, char* seri if (!strncmp(service, "forward:",8) || !strncmp(service, "killforward:",12)) { - char *local, *remote, *err; - int r; + char *local, *remote; atransport *transport; int createForward = strncmp(service, "kill", 4); @@ -1511,42 +839,41 @@ int handle_forward_request(const char* service, transport_type ttype, char* seri } } - transport = acquire_one_transport(CS_ANY, ttype, serial, &err); + std::string error_msg; + transport = acquire_one_transport(CS_ANY, ttype, serial, &error_msg); if (!transport) { - sendfailmsg(reply_fd, err); + sendfailmsg(reply_fd, error_msg.c_str()); return 1; } + install_status_t r; if (createForward) { r = install_listener(local, remote, transport, no_rebind); } else { r = remove_listener(local, transport); } - if(r == 0) { + if (r == INSTALL_STATUS_OK) { #if ADB_HOST /* On the host: 1st OKAY is connect, 2nd OKAY is status */ - writex(reply_fd, "OKAY", 4); + WriteFdExactly(reply_fd, "OKAY", 4); #endif - writex(reply_fd, "OKAY", 4); + WriteFdExactly(reply_fd, "OKAY", 4); return 1; } - if (createForward) { - 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"); + std::string message; + switch (r) { + case INSTALL_STATUS_OK: message = " "; break; + case INSTALL_STATUS_INTERNAL_ERROR: message = "internal error"; break; + case INSTALL_STATUS_CANNOT_BIND: + message = android::base::StringPrintf("cannot bind to socket: %s", strerror(errno)); + break; + case INSTALL_STATUS_CANNOT_REBIND: + message = android::base::StringPrintf("cannot rebind existing socket: %s", strerror(errno)); + break; + case INSTALL_STATUS_LISTENER_NOT_FOUND: message = "listener not found"; break; } + sendfailmsg(reply_fd, message.c_str()); return 1; } return 0; @@ -1554,8 +881,6 @@ int handle_forward_request(const char* service, transport_type ttype, char* seri int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s) { - atransport *transport = NULL; - if(!strcmp(service, "kill")) { fprintf(stderr,"adb server killed by remote request\n"); fflush(stdout); @@ -1565,12 +890,12 @@ int handle_host_request(char *service, transport_type ttype, char* serial, int r } #if ADB_HOST + atransport *transport = NULL; // "transport:" is used for switching transport with a specified serial number // "transport-usb:" is used for switching transport to the only USB transport // "transport-local:" is used for switching transport to the only local transport // "transport-any:" is used for switching transport to the only transport if (!strncmp(service, "transport", strlen("transport"))) { - char* error_string = "unknown failure"; transport_type type = kTransportAny; if (!strncmp(service, "transport-usb", strlen("transport-usb"))) { @@ -1584,13 +909,14 @@ int handle_host_request(char *service, transport_type ttype, char* serial, int r serial = service; } - transport = acquire_one_transport(CS_ANY, type, serial, &error_string); + std::string error_msg = "unknown failure"; + transport = acquire_one_transport(CS_ANY, type, serial, &error_msg); if (transport) { s->transport = transport; adb_write(reply_fd, "OKAY", 4); } else { - sendfailmsg(reply_fd, error_string); + sendfailmsg(reply_fd, error_msg.c_str()); } return 1; } @@ -1646,18 +972,18 @@ int handle_host_request(char *service, transport_type ttype, char* serial, int r } if(!strncmp(service,"get-serialno",strlen("get-serialno"))) { - char *out = "unknown"; - transport = acquire_one_transport(CS_ANY, ttype, serial, NULL); - if (transport && transport->serial) { + const char *out = "unknown"; + transport = acquire_one_transport(CS_ANY, ttype, serial, NULL); + if (transport && transport->serial) { out = transport->serial; } send_msg_with_okay(reply_fd, out, strlen(out)); 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) { + const char *out = "unknown"; + transport = acquire_one_transport(CS_ANY, ttype, serial, NULL); + if (transport && transport->devpath) { out = transport->devpath; } send_msg_with_okay(reply_fd, out, strlen(out)); @@ -1673,7 +999,7 @@ int handle_host_request(char *service, transport_type ttype, char* serial, int r if(!strncmp(service,"get-state",strlen("get-state"))) { transport = acquire_one_transport(CS_ANY, ttype, serial, NULL); - char *state = connection_state_name(transport); + const char *state = connection_state_name(transport); send_msg_with_okay(reply_fd, state, strlen(state)); return 0; } @@ -1684,42 +1010,3 @@ int handle_host_request(char *service, transport_type ttype, char* serial, int r return ret - 1; return -1; } - -int main(int argc, char **argv) -{ -#if ADB_HOST - adb_sysdeps_init(); - adb_trace_init(); - D("Handling commandline()\n"); - return adb_commandline(argc - 1, argv + 1); -#else - /* If adbd runs inside the emulator this will enable adb tracing via - * adb-debug qemud service in the emulator. */ - adb_qemu_trace_init(); - while(1) { - int c; - int option_index = 0; - static struct option opts[] = { - {"root_seclabel", required_argument, 0, 's' }, - {"device_banner", required_argument, 0, 'b' } - }; - c = getopt_long(argc, argv, "", opts, &option_index); - if (c == -1) - break; - switch (c) { - case 's': - root_seclabel = optarg; - break; - case 'b': - adb_device_banner = optarg; - break; - default: - break; - } - } - - start_device_log(); - D("Handling main()\n"); - return adb_main(0, DEFAULT_ADB_PORT); -#endif -} @@ -18,9 +18,10 @@ #define __ADB_H #include <limits.h> +#include <sys/types.h> #include "adb_trace.h" -#include "transport.h" /* readx(), writex() */ +#include "fdevent.h" #define MAX_PAYLOAD 4096 @@ -32,21 +33,18 @@ #define A_WRTE 0x45545257 #define A_AUTH 0x48545541 -#define A_VERSION 0x01000000 // ADB protocol version +// ADB protocol version. +#define A_VERSION 0x01000000 -#define ADB_VERSION_MAJOR 1 // Used for help/version information -#define ADB_VERSION_MINOR 0 // Used for help/version information +// Used for help/version information. +#define ADB_VERSION_MAJOR 1 +#define ADB_VERSION_MINOR 0 -#define ADB_SERVER_VERSION 32 // Increment this when we want to force users to start a new adb server +// Increment this when we want to force users to start a new adb server. +#define ADB_SERVER_VERSION 32 -typedef struct amessage amessage; -typedef struct apacket apacket; -typedef struct asocket asocket; -typedef struct alistener alistener; -typedef struct aservice aservice; -typedef struct atransport atransport; -typedef struct adisconnect adisconnect; -typedef struct usb_handle usb_handle; +struct atransport; +struct usb_handle; struct amessage { unsigned command; /* command identifier constant */ @@ -163,12 +161,12 @@ struct adisconnect ** object, it's a special value used to indicate that a client wants to ** connect to a service implemented within the ADB server itself. */ -typedef enum transport_type { +enum transport_type { kTransportUsb, kTransportLocal, kTransportAny, kTransportHost, -} transport_type; +}; #define TOKEN_SIZE 20 @@ -231,8 +229,8 @@ struct alistener fdevent fde; int fd; - const char *local_name; - const char *connect_to; + char *local_name; + char *connect_to; atransport *transport; adisconnect disconnect; }; @@ -258,33 +256,11 @@ void fatal(const char *fmt, ...); void fatal_errno(const char *fmt, ...); void handle_packet(apacket *p, atransport *t); -void send_packet(apacket *p, atransport *t); void get_my_path(char *s, size_t maxLen); int launch_server(int server_port); int adb_main(int is_daemon, int server_port); - -/* transports are ref-counted -** 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 long_listing); -void update_transports(void); - -asocket* create_device_tracker(void); - -/* Obtain a transport from the available transports. -** If state is != CS_ANY, only transports in that state are considered. -** If serial is non-NULL then only the device with that serial will be chosen. -** If no suitable transport is found, error is set. -*/ -atransport *acquire_one_transport(int state, transport_type ttype, const char* serial, char **error_out); -void add_transport_disconnect( atransport* t, adisconnect* dis ); -void remove_transport_disconnect( atransport* t, adisconnect* dis ); -void run_transport_disconnects( atransport* t ); -void kick_transport( atransport* t ); - /* initialize a transport object's func pointers and state */ #if ADB_HOST int get_available_local_transport_index(); @@ -292,22 +268,6 @@ int get_available_local_transport_index(); int init_socket_transport(atransport *t, int s, int port, int local); void init_usb_transport(atransport *t, usb_handle *usb, int state); -/* for MacOS X cleanup */ -void close_usb_devices(); - -/* cause new transports to be init'd and added to the list */ -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); -void unregister_all_tcp_transports(); - -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); - -atransport *find_transport(const char *serial); #if ADB_HOST atransport* find_emulator_transport_by_adb_port(int adb_port); #endif @@ -328,16 +288,15 @@ int handle_forward_request(const char* service, transport_type ttype, char* seri #if !ADB_HOST void framebuffer_service(int fd, void *cookie); -void remount_service(int fd, void *cookie); -void disable_verity_service(int fd, void* cookie); +void set_verity_enabled_state_service(int fd, void* cookie); #endif /* packet allocator */ apacket *get_apacket(void); void put_apacket(apacket *p); -int check_header(apacket *p); -int check_data(apacket *p); +// Define it if you want to dump packets. +#define DEBUG_PACKETS 0 #if !DEBUG_PACKETS #define print_packet(tag,p) do {} while (0) @@ -376,8 +335,7 @@ void usb_kick(usb_handle *h); int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol); #endif -unsigned host_to_le32(unsigned n); -int adb_commandline(int argc, char **argv); +int adb_commandline(int argc, const char **argv); int connection_state(atransport *t); @@ -391,13 +349,14 @@ int connection_state(atransport *t); #define CS_SIDELOAD 6 #define CS_UNAUTHORIZED 7 +extern const char *adb_device_banner; extern int HOST; extern int SHELL_EXIT_NOTIFY_FD; -typedef enum { +enum subproc_mode { SUBPROC_PTY = 0, SUBPROC_RAW = 1, -} subproc_mode; +} ; #define CHUNK_SIZE (64*1024) @@ -415,4 +374,9 @@ typedef enum { int sendfailmsg(int fd, const char *reason); int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s); +void handle_online(atransport *t); +void handle_offline(atransport *t); + +void send_connect(atransport *t); + #endif diff --git a/adb/adb_auth.cpp b/adb/adb_auth.cpp new file mode 100644 index 0000000..dc01825 --- /dev/null +++ b/adb/adb_auth.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2015 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. + */ + +#define TRACE_TAG TRACE_ADB + +#include "sysdeps.h" +#include "adb_auth.h" + +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <unistd.h> + +#include "adb.h" +#include "transport.h" + +int auth_enabled = 0; + +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); +} + +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); +} + +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); +} diff --git a/adb/adb_auth.h b/adb/adb_auth.h index 54dd537..1e1978d 100644 --- a/adb/adb_auth.h +++ b/adb/adb_auth.h @@ -17,11 +17,16 @@ #ifndef __ADB_AUTH_H #define __ADB_AUTH_H -void adb_auth_init(void); +#include "adb.h" + +extern int auth_enabled; + int adb_auth_keygen(const char* filename); void adb_auth_verified(atransport *t); void send_auth_request(atransport *t); +void send_auth_response(uint8_t *token, size_t token_size, atransport *t); +void send_auth_publickey(atransport *t); /* AUTH packets first argument */ /* Request */ @@ -32,7 +37,9 @@ void send_auth_request(atransport *t); #if ADB_HOST -int adb_auth_sign(void *key, void *token, size_t token_size, void *sig); +void adb_auth_init(void); +int adb_auth_sign(void *key, const unsigned char* token, size_t token_size, + unsigned char* sig); void *adb_auth_nextkey(void *current); int adb_auth_get_userkey(unsigned char *data, size_t len); @@ -42,12 +49,17 @@ static inline void adb_auth_confirm_key(unsigned char *data, size_t len, atransp #else // !ADB_HOST -static inline int adb_auth_sign(void* key, void *token, size_t token_size, void *sig) { return 0; } +static inline int adb_auth_sign(void* key, const unsigned char* token, + size_t token_size, unsigned char* 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; } +void adbd_auth_init(void); +void adbd_cloexec_auth_socket(); int adb_auth_generate_token(void *token, size_t token_size); -int adb_auth_verify(void *token, void *sig, int siglen); +int adb_auth_verify(uint8_t* token, uint8_t* sig, int siglen); void adb_auth_confirm_key(unsigned char *data, size_t len, atransport *t); #endif // ADB_HOST diff --git a/adb/adb_auth_client.c b/adb/adb_auth_client.cpp index 55e9dca..8e7d38b 100644 --- a/adb/adb_auth_client.c +++ b/adb/adb_auth_client.cpp @@ -14,28 +14,30 @@ * limitations under the License. */ -#include <stdio.h> -#include <string.h> -#include <resolv.h> -#include <cutils/list.h> -#include <cutils/sockets.h> +#define TRACE_TAG TRACE_AUTH #include "sysdeps.h" -#include "adb.h" #include "adb_auth.h" -#include "fdevent.h" + +#include <resolv.h> +#include <stdio.h> +#include <string.h> + +#include "cutils/list.h" +#include "cutils/sockets.h" #include "mincrypt/rsa.h" #include "mincrypt/sha.h" -#define TRACE_TAG TRACE_AUTH - +#include "adb.h" +#include "fdevent.h" +#include "transport.h" struct adb_public_key { struct listnode node; RSAPublicKey key; }; -static char *key_paths[] = { +static const char *key_paths[] = { "/adb_keys", "/data/misc/adb/adb_keys", NULL @@ -51,7 +53,6 @@ static bool needs_retry = false; static void read_keys(const char *file, struct listnode *list) { - struct adb_public_key *key; FILE *f; char buf[MAX_PAYLOAD]; char *sep; @@ -65,8 +66,9 @@ static void read_keys(const char *file, struct listnode *list) 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) { + auto key = reinterpret_cast<adb_public_key*>( + calloc(1, sizeof(adb_public_key) + 4)); + if (key == nullptr) { D("Can't malloc key\n"); break; } @@ -107,8 +109,8 @@ static void free_keys(struct listnode *list) static void load_keys(struct listnode *list) { - char *path; - char **paths = key_paths; + const char* path; + const char** paths = key_paths; struct stat buf; list_init(list); @@ -136,10 +138,9 @@ int adb_auth_generate_token(void *token, size_t token_size) return ret * token_size; } -int adb_auth_verify(void *token, void *sig, int siglen) +int adb_auth_verify(uint8_t* token, uint8_t* sig, int siglen) { struct listnode *item; - struct adb_public_key *key; struct listnode key_list; int ret = 0; @@ -149,7 +150,7 @@ int adb_auth_verify(void *token, void *sig, int siglen) load_keys(&key_list); list_for_each(item, &key_list) { - key = node_to_item(item, struct adb_public_key, node); + adb_public_key* key = node_to_item(item, struct adb_public_key, node); ret = RSA_verify(&key->key, sig, siglen, token, SHA_DIGEST_SIZE); if (ret) break; @@ -248,19 +249,23 @@ static void adb_auth_listener(int fd, unsigned events, void *data) } } -void adb_auth_init(void) -{ - int fd, ret; - - fd = android_get_control_socket("adbd"); - if (fd < 0) { +void adbd_cloexec_auth_socket() { + int fd = android_get_control_socket("adbd"); + if (fd == -1) { D("Failed to get adbd socket\n"); return; } fcntl(fd, F_SETFD, FD_CLOEXEC); +} - ret = listen(fd, 4); - if (ret < 0) { +void adbd_auth_init(void) { + int fd = android_get_control_socket("adbd"); + if (fd == -1) { + D("Failed to get adbd socket\n"); + return; + } + + if (listen(fd, 4) == -1) { D("Failed to listen on '%d'\n", fd); return; } diff --git a/adb/adb_auth_host.c b/adb/adb_auth_host.cpp index dd83900..7c2bcfb 100644 --- a/adb/adb_auth_host.c +++ b/adb/adb_auth_host.cpp @@ -14,8 +14,14 @@ * limitations under the License. */ +#define TRACE_TAG TRACE_AUTH + +#include "sysdeps.h" +#include "adb_auth.h" + #include <stdio.h> #include <stdlib.h> +#include <string.h> #ifdef _WIN32 # ifndef WIN32_LEAN_AND_MEAN @@ -28,11 +34,8 @@ # 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 */ @@ -48,12 +51,13 @@ #include <openssl/rsa.h> #include <openssl/sha.h> -#define TRACE_TAG TRACE_AUTH +#if defined(OPENSSL_IS_BORINGSSL) +#include <openssl/base64.h> +#endif #define ANDROID_PATH ".android" #define ADB_KEY_FILE "adbkey" - struct adb_private_key { struct listnode node; RSA *rsa; @@ -151,43 +155,67 @@ static void get_user_info(char *buf, size_t len) static int write_public_keyfile(RSA *private_key, const char *private_key_path) { RSAPublicKey pkey; - BIO *bio, *b64, *bfile; + FILE *outfile = NULL; char path[PATH_MAX], info[MAX_PAYLOAD]; - int ret; + uint8_t* encoded = nullptr; + size_t encoded_length; + int ret = 0; - ret = snprintf(path, sizeof(path), "%s.pub", private_key_path); - if (ret >= (signed)sizeof(path)) + if (snprintf(path, sizeof(path), "%s.pub", private_key_path) >= + (int)sizeof(path)) { + D("Path too long while writing public key\n"); return 0; + } - ret = RSA_to_RSAPublicKey(private_key, &pkey); - if (!ret) { + if (!RSA_to_RSAPublicKey(private_key, &pkey)) { D("Failed to convert to publickey\n"); return 0; } - bfile = BIO_new_file(path, "w"); - if (!bfile) { + outfile = fopen(path, "w"); + if (!outfile) { 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); +#if defined(OPENSSL_IS_BORINGSSL) + if (!EVP_EncodedLength(&encoded_length, sizeof(pkey))) { + D("Public key too large to base64 encode"); + goto out; + } +#else + /* While we switch from OpenSSL to BoringSSL we have to implement + * |EVP_EncodedLength| here. */ + encoded_length = 1 + ((sizeof(pkey) + 2) / 3 * 4); +#endif - bio = BIO_push(b64, bfile); - BIO_write(bio, &pkey, sizeof(pkey)); - (void) BIO_flush(bio); - BIO_pop(b64); - BIO_free(b64); + encoded = reinterpret_cast<uint8_t*>(malloc(encoded_length)); + if (encoded == nullptr) { + D("Allocation failure"); + goto out; + } + encoded_length = EVP_EncodeBlock(encoded, (uint8_t*) &pkey, sizeof(pkey)); get_user_info(info, sizeof(info)); - BIO_write(bfile, info, strlen(info)); - (void) BIO_flush(bfile); - BIO_free_all(bfile); - return 1; + if (fwrite(encoded, encoded_length, 1, outfile) != 1 || + fwrite(info, strlen(info), 1, outfile) != 1) { + D("Write error while writing public key"); + goto out; + } + + ret = 1; + + out: + if (outfile != NULL) { + fclose(outfile); + } + if (encoded != NULL) { + free(encoded); + } + return ret; } static int generate_key(const char *file) @@ -244,18 +272,16 @@ out: 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"); + FILE* f = fopen(file, "r"); if (!f) { D("Failed to open '%s'\n", file); return 0; } - key = malloc(sizeof(*key)); + adb_private_key* key = reinterpret_cast<adb_private_key*>( + malloc(sizeof(adb_private_key))); if (!key) { D("Failed to alloc key\n"); fclose(f); @@ -362,11 +388,17 @@ static void get_vendor_keys(struct listnode *list) } } -int adb_auth_sign(void *node, void *token, size_t token_size, void *sig) +int adb_auth_sign(void *node, const unsigned char* token, size_t token_size, + unsigned char* sig) { unsigned int len; struct adb_private_key *key = node_to_item(node, struct adb_private_key, node); + if (token_size != TOKEN_SIZE) { + D("Unexpected token size %zd\n", token_size); + return 0; + } + if (!RSA_sign(NID_sha1, token, token_size, sig, &len, key->rsa)) { return 0; } @@ -400,31 +432,33 @@ void *adb_auth_nextkey(void *current) 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); + int 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) { + // TODO(danalbert): ReadFileToString + unsigned size; + char* file_data = reinterpret_cast<char*>(load_file(path, &size)); + if (file_data == nullptr) { 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); + if (len < (size_t)(size + 1)) { + D("%s: Content too large ret=%d\n", path, size); + free(file_data); return 0; } - memcpy(data, file, ret); - data[ret] = '\0'; + memcpy(data, file_data, size); + free(file_data); + file_data = nullptr; + data[size] = '\0'; - return ret + 1; + return size + 1; } int adb_auth_keygen(const char* filename) { diff --git a/adb/adb_client.c b/adb/adb_client.cpp index eb1720d..4751bff 100644 --- a/adb/adb_client.c +++ b/adb/adb_client.cpp @@ -1,17 +1,34 @@ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> +/* + * Copyright (C) 2015 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. + */ + +#define TRACE_TAG TRACE_ADB + +#include "sysdeps.h" +#include "adb_client.h" + #include <errno.h> #include <limits.h> #include <stdarg.h> -#include <zipfile/zipfile.h> -#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> #include <sys/stat.h> +#include <sys/types.h> -#include "sysdeps.h" - -#define TRACE_TAG TRACE_ADB -#include "adb_client.h" +#include "adb_io.h" static transport_type __adb_transport = kTransportAny; static const char* __adb_serial = NULL; @@ -98,7 +115,7 @@ static int switch_socket_transport(int fd) if (__adb_serial) snprintf(service, sizeof service, "host:transport:%s", __adb_serial); else { - char* transport_type = "???"; + const char* transport_type = "???"; switch (__adb_transport) { case kTransportUsb: @@ -121,7 +138,7 @@ static int switch_socket_transport(int fd) len = strlen(service); snprintf(tmp, sizeof tmp, "%04x", len); - if(writex(fd, tmp, 4) || writex(fd, service, len)) { + if(!WriteFdExactly(fd, tmp, 4) || !WriteFdExactly(fd, service, len)) { strcpy(__adb_error, "write failure during connection"); adb_close(fd); return -1; @@ -142,7 +159,7 @@ int adb_status(int fd) unsigned char buf[5]; unsigned len; - if(readx(fd, buf, 4)) { + if(!ReadFdExactly(fd, buf, 4)) { strcpy(__adb_error, "protocol fault (no status)"); return -1; } @@ -158,14 +175,14 @@ int adb_status(int fd) return -1; } - if(readx(fd, buf, 4)) { + if(!ReadFdExactly(fd, buf, 4)) { strcpy(__adb_error, "protocol fault (status len)"); return -1; } buf[4] = 0; len = strtoul((char*)buf, 0, 16); if(len > 255) len = 255; - if(readx(fd, __adb_error, len)) { + if(!ReadFdExactly(fd, __adb_error, len)) { strcpy(__adb_error, "protocol fault (status read)"); return -1; } @@ -201,7 +218,7 @@ int _adb_connect(const char *service) return -1; } - if(writex(fd, tmp, 4) || writex(fd, service, len)) { + if(!WriteFdExactly(fd, tmp, 4) || !WriteFdExactly(fd, service, len)) { strcpy(__adb_error, "write failure during connection"); adb_close(fd); return -1; @@ -246,12 +263,12 @@ int adb_connect(const char *service) // if we have a file descriptor, then parse version result if(fd >= 0) { - if(readx(fd, buf, 4)) goto error; + if(!ReadFdExactly(fd, buf, 4)) goto error; buf[4] = 0; n = strtoul(buf, 0, 16); if(n > sizeof(buf)) goto error; - if(readx(fd, buf, n)) goto error; + if(!ReadFdExactly(fd, buf, n)) goto error; adb_close(fd); if (sscanf(buf, "%04x", &version) != 1) goto error; @@ -279,7 +296,7 @@ int adb_connect(const char *service) fd = _adb_connect(service); if(fd == -1) { - D("_adb_connect error: %s\n", __adb_error); + D("_adb_connect error: %s", __adb_error); } else if(fd == -2) { fprintf(stderr,"** daemon still not running\n"); } @@ -311,8 +328,8 @@ int adb_command(const char *service) char *adb_query(const char *service) { char buf[5]; - unsigned n; - char *tmp; + unsigned long n; + char* tmp; D("adb_query: %s\n", service); int fd = adb_connect(service); @@ -321,7 +338,7 @@ char *adb_query(const char *service) return 0; } - if(readx(fd, buf, 4)) goto oops; + if(!ReadFdExactly(fd, buf, 4)) goto oops; buf[4] = 0; n = strtoul(buf, 0, 16); @@ -330,10 +347,10 @@ char *adb_query(const char *service) goto oops; } - tmp = malloc(n + 1); + tmp = reinterpret_cast<char*>(malloc(n + 1)); if(tmp == 0) goto oops; - if(readx(fd, tmp, n) == 0) { + if(!ReadFdExactly(fd, tmp, n) == 0) { tmp[n] = 0; adb_close(fd); return tmp; diff --git a/adb/adb_client.h b/adb/adb_client.h index 0ec47ca..934362a 100644 --- a/adb/adb_client.h +++ b/adb/adb_client.h @@ -43,7 +43,7 @@ int adb_get_emulator_console_port(void); * is zero, or more than one emulator connected (or if you use -s <serial> * with a <serial> that does not designate an emulator) */ -int adb_send_emulator_command(int argc, char** argv); +int adb_send_emulator_command(int argc, const char** argv); /* return verbose error string from last operation */ const char *adb_error(void); diff --git a/adb/adb_io.cpp b/adb/adb_io.cpp new file mode 100644 index 0000000..d89f304 --- /dev/null +++ b/adb/adb_io.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2015 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. + */ + +#define TRACE_TAG TRACE_RWX + +#include "sysdeps.h" +#include "adb_io.h" + +#include <unistd.h> + +#include "adb_trace.h" +#include "transport.h" + +bool ReadFdExactly(int fd, void* buf, size_t len) { + char* p = reinterpret_cast<char*>(buf); + +#if ADB_TRACE + size_t len0 = len; +#endif + + D("readx: fd=%d wanted=%zu\n", fd, len); + while (len > 0) { + int r = adb_read(fd, p, len); + if (r > 0) { + len -= r; + p += r; + } else if (r == -1) { + D("readx: fd=%d error %d: %s\n", fd, errno, strerror(errno)); + return false; + } else { + D("readx: fd=%d disconnected\n", fd); + errno = 0; + return false; + } + } + +#if ADB_TRACE + D("readx: fd=%d wanted=%zu got=%zu\n", fd, len0, len0 - len); + if (ADB_TRACING) { + dump_hex(reinterpret_cast<const unsigned char*>(buf), len0); + } +#endif + + return true; +} + +bool WriteFdExactly(int fd, const void* buf, size_t len) { + const char* p = reinterpret_cast<const char*>(buf); + int r; + +#if ADB_TRACE + D("writex: fd=%d len=%d: ", fd, (int)len); + if (ADB_TRACING) { + dump_hex(reinterpret_cast<const unsigned char*>(buf), len); + } +#endif + + while (len > 0) { + r = adb_write(fd, p, len); + if (r == -1) { + D("writex: fd=%d error %d: %s\n", fd, errno, strerror(errno)); + if (errno == EAGAIN) { + adb_sleep_ms(1); // just yield some cpu time + continue; + } else if (errno == EPIPE) { + D("writex: fd=%d disconnected\n", fd); + errno = 0; + return false; + } else { + return false; + } + } else { + len -= r; + p += r; + } + } + return true; +} + +bool WriteStringFully(int fd, const char* str) { + return WriteFdExactly(fd, str, strlen(str)); +} diff --git a/adb/adb_io.h b/adb/adb_io.h new file mode 100644 index 0000000..8d237ce --- /dev/null +++ b/adb/adb_io.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2015 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_IO_H +#define ADB_IO_H + +#include <stdbool.h> +#include <sys/types.h> + +/* + * Reads exactly len bytes from fd into buf. + * + * Returns false if there is an error or if EOF was reached before len bytes + * were read. If EOF was found, errno will be set to 0. + * + * If this function fails, the contents of buf are undefined. + */ +bool ReadFdExactly(int fd, void *buf, size_t len); + +/* + * Writes exactly len bytes from buf to fd. + * + * Returns false if there is an error or if the fd was closed before the write + * completed. If the other end of the fd (such as in a socket, pipe, or fifo), + * is closed, errno will be set to 0. + */ +bool WriteFdExactly(int fd, const void *buf, size_t len); + +/* Same as WriteFdExactly, but with an implicit len = strlen(buf). */ +bool WriteStringFully(int fd, const char* str); + +#endif /* ADB_IO_H */ diff --git a/adb/adb_io_test.cpp b/adb/adb_io_test.cpp new file mode 100644 index 0000000..da340b2 --- /dev/null +++ b/adb/adb_io_test.cpp @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2015 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 "adb_io.h" + +#include <gtest/gtest.h> + +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include <string> + +#include "base/file.h" + +class TemporaryFile { + public: + TemporaryFile() { + init("/data/local/tmp"); + if (fd == -1) { + init("/tmp"); + } + } + + ~TemporaryFile() { + close(fd); + unlink(filename); + } + + int fd; + char filename[1024]; + + private: + void init(const char* tmp_dir) { + snprintf(filename, sizeof(filename), "%s/TemporaryFile-XXXXXX", tmp_dir); + fd = mkstemp(filename); + } +}; + +TEST(io, ReadFdExactly_whole) { + const char expected[] = "Foobar"; + TemporaryFile tf; + ASSERT_NE(-1, tf.fd); + + ASSERT_TRUE(android::base::WriteStringToFd(expected, tf.fd)) << strerror(errno); + ASSERT_EQ(0, lseek(tf.fd, SEEK_SET, 0)); + + // Test reading the whole file. + char buf[sizeof(expected)] = {}; + ASSERT_TRUE(ReadFdExactly(tf.fd, buf, sizeof(buf) - 1)) << strerror(errno); + EXPECT_STREQ(expected, buf); +} + +TEST(io, ReadFdExactly_eof) { + const char expected[] = "Foobar"; + TemporaryFile tf; + ASSERT_NE(-1, tf.fd); + + ASSERT_TRUE(android::base::WriteStringToFd(expected, tf.fd)) << strerror(errno); + ASSERT_EQ(0, lseek(tf.fd, SEEK_SET, 0)); + + // Test that not having enough data will fail. + char buf[sizeof(expected) + 1] = {}; + ASSERT_FALSE(ReadFdExactly(tf.fd, buf, sizeof(buf))); + EXPECT_EQ(0, errno) << strerror(errno); +} + +TEST(io, ReadFdExactly_partial) { + const char input[] = "Foobar"; + TemporaryFile tf; + ASSERT_NE(-1, tf.fd); + + ASSERT_TRUE(android::base::WriteStringToFd(input, tf.fd)) << strerror(errno); + ASSERT_EQ(0, lseek(tf.fd, SEEK_SET, 0)); + + // Test reading a partial file. + char buf[sizeof(input) - 1] = {}; + ASSERT_TRUE(ReadFdExactly(tf.fd, buf, sizeof(buf) - 1)); + + std::string expected(input); + expected.pop_back(); + EXPECT_STREQ(expected.c_str(), buf); +} + +TEST(io, WriteFdExactly_whole) { + const char expected[] = "Foobar"; + TemporaryFile tf; + ASSERT_NE(-1, tf.fd); + + // Test writing the whole string to the file. + ASSERT_TRUE(WriteFdExactly(tf.fd, expected, sizeof(expected))) + << strerror(errno); + ASSERT_EQ(0, lseek(tf.fd, SEEK_SET, 0)); + + std::string s; + ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s)); + EXPECT_STREQ(expected, s.c_str()); +} + +TEST(io, WriteFdExactly_partial) { + const char buf[] = "Foobar"; + TemporaryFile tf; + ASSERT_NE(-1, tf.fd); + + // Test writing a partial string to the file. + ASSERT_TRUE(WriteFdExactly(tf.fd, buf, sizeof(buf) - 2)) << strerror(errno); + ASSERT_EQ(0, lseek(tf.fd, SEEK_SET, 0)); + + std::string expected(buf); + expected.pop_back(); + + std::string s; + ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s)); + EXPECT_EQ(expected, s); +} + +TEST(io, WriteFdExactly_ENOSPC) { + int fd = open("/dev/full", O_WRONLY); + ASSERT_NE(-1, fd); + + char buf[] = "foo"; + ASSERT_FALSE(WriteFdExactly(fd, buf, sizeof(buf))); + ASSERT_EQ(ENOSPC, errno); +} + +TEST(io, WriteStringFully) { + const char str[] = "Foobar"; + TemporaryFile tf; + ASSERT_NE(-1, tf.fd); + + // Test writing a partial string to the file. + ASSERT_TRUE(WriteStringFully(tf.fd, str)) << strerror(errno); + ASSERT_EQ(0, lseek(tf.fd, SEEK_SET, 0)); + + std::string s; + ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s)); + EXPECT_STREQ(str, s.c_str()); +} diff --git a/adb/adb_listeners.cpp b/adb/adb_listeners.cpp new file mode 100644 index 0000000..a1a5ddb --- /dev/null +++ b/adb/adb_listeners.cpp @@ -0,0 +1,304 @@ +/* + * Copyright (C) 2015 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 "adb_listeners.h" + +#include <stdio.h> +#include <stdlib.h> + +#include "sysdeps.h" +#include "transport.h" + +int gListenAll = 0; /* Not static because it is used in commandline.c. */ + +alistener listener_list = { + .next = &listener_list, + .prev = &listener_list, +}; + +void ss_listener_event_func(int _fd, unsigned ev, void *_l) +{ + asocket *s; + + if(ev & FDE_READ) { + struct sockaddr addr; + socklen_t alen; + int fd; + + alen = sizeof(addr); + fd = adb_socket_accept(_fd, &addr, &alen); + if(fd < 0) return; + + adb_socket_setbufsize(fd, CHUNK_SIZE); + + s = create_local_socket(fd); + if(s) { + connect_to_smartsocket(s); + return; + } + + adb_close(fd); + } +} + +void listener_event_func(int _fd, unsigned ev, void* _l) +{ + alistener* listener = reinterpret_cast<alistener*>(_l); + asocket *s; + + if (ev & FDE_READ) { + struct sockaddr addr; + socklen_t alen; + int fd; + + alen = sizeof(addr); + fd = adb_socket_accept(_fd, &addr, &alen); + if (fd < 0) { + return; + } + + s = create_local_socket(fd); + if (s) { + s->transport = listener->transport; + connect_to_remote(s, listener->connect_to); + return; + } + + adb_close(fd); + } +} + +static void free_listener(alistener* l) +{ + if (l->next) { + l->next->prev = l->prev; + l->prev->next = l->next; + l->next = l->prev = l; + } + + // closes the corresponding fd + fdevent_remove(&l->fde); + + if (l->local_name) + free((char*)l->local_name); + + if (l->connect_to) + free((char*)l->connect_to); + + if (l->transport) { + remove_transport_disconnect(l->transport, &l->disconnect); + } + free(l); +} + +void listener_disconnect(void* listener, atransport* t) +{ + free_listener(reinterpret_cast<alistener*>(listener)); +} + +int local_name_to_fd(const char *name) +{ + int port; + + if(!strncmp("tcp:", name, 4)){ + int ret; + port = atoi(name + 4); + + 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 */ + // It's non-sensical to support the "reserved" space on the adb host side + if(!strncmp(name, "local:", 6)) { + return socket_local_server(name + 6, + ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM); + } else if(!strncmp(name, "localabstract:", 14)) { + return socket_local_server(name + 14, + ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM); + } else if(!strncmp(name, "localfilesystem:", 16)) { + return socket_local_server(name + 16, + ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM); + } + +#endif + printf("unknown local portname '%s'\n", name); + return -1; +} + +// 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. +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; +} + +install_status_t 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)) { + listener_disconnect(l, l->transport); + return INSTALL_STATUS_OK; + } + } + return INSTALL_STATUS_LISTENER_NOT_FOUND; +} + +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); + } +} + +install_status_t install_listener(const char *local_name, + const char *connect_to, + atransport* transport, + int no_rebind) +{ + for (alistener* l = listener_list.next; l != &listener_list; l = l->next) { + if (strcmp(local_name, l->local_name) == 0) { + char* cto; + + /* can't repurpose a smartsocket */ + if(l->connect_to[0] == '*') { + 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 INSTALL_STATUS_INTERNAL_ERROR; + } + + free((void*) l->connect_to); + l->connect_to = cto; + if (l->transport != transport) { + remove_transport_disconnect(l->transport, &l->disconnect); + l->transport = transport; + add_transport_disconnect(l->transport, &l->disconnect); + } + return INSTALL_STATUS_OK; + } + } + + alistener* listener = reinterpret_cast<alistener*>( + calloc(1, sizeof(alistener))); + if (listener == nullptr) { + goto nomem; + } + + listener->local_name = strdup(local_name); + if (listener->local_name == nullptr) { + goto nomem; + } + + listener->connect_to = strdup(connect_to); + if (listener->connect_to == nullptr) { + goto nomem; + } + + listener->fd = local_name_to_fd(local_name); + if (listener->fd < 0) { + printf("cannot bind '%s': %s\n", local_name, strerror(errno)); + free(listener->local_name); + free(listener->connect_to); + free(listener); + return INSTALL_STATUS_CANNOT_BIND; + } + + close_on_exec(listener->fd); + if (!strcmp(listener->connect_to, "*smartsocket*")) { + fdevent_install(&listener->fde, listener->fd, ss_listener_event_func, + listener); + } else { + fdevent_install(&listener->fde, listener->fd, listener_event_func, + listener); + } + fdevent_set(&listener->fde, FDE_READ); + + listener->next = &listener_list; + listener->prev = listener_list.prev; + listener->next->prev = listener; + listener->prev->next = listener; + listener->transport = transport; + + if (transport) { + listener->disconnect.opaque = listener; + listener->disconnect.func = listener_disconnect; + add_transport_disconnect(transport, &listener->disconnect); + } + return INSTALL_STATUS_OK; + +nomem: + fatal("cannot allocate listener"); + return INSTALL_STATUS_INTERNAL_ERROR; +} diff --git a/adb/adb_listeners.h b/adb/adb_listeners.h new file mode 100644 index 0000000..f55fdee --- /dev/null +++ b/adb/adb_listeners.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2015 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_LISTENERS_H +#define __ADB_LISTENERS_H + +#include "adb.h" + +// error/status codes for install_listener. +enum install_status_t { + INSTALL_STATUS_OK = 0, + INSTALL_STATUS_INTERNAL_ERROR = -1, + INSTALL_STATUS_CANNOT_BIND = -2, + INSTALL_STATUS_CANNOT_REBIND = -3, + INSTALL_STATUS_LISTENER_NOT_FOUND = -4, +}; + +extern alistener listener_list; + +void listener_disconnect(void* _l, atransport* t); +void listener_event_func(int _fd, unsigned ev, void *_l); +void ss_listener_event_func(int _fd, unsigned ev, void *_l); + +install_status_t install_listener(const char *local_name, + const char *connect_to, + atransport* transport, + int no_rebind); + +int format_listeners(char* buf, size_t buflen); + +install_status_t remove_listener(const char* local_name, atransport* transport); +void remove_all_listeners(void); + +#endif /* __ADB_LISTENERS_H */ diff --git a/adb/adb_main.cpp b/adb/adb_main.cpp new file mode 100644 index 0000000..5acaf80 --- /dev/null +++ b/adb/adb_main.cpp @@ -0,0 +1,411 @@ +/* + * Copyright (C) 2015 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. + */ + +#define TRACE_TAG TRACE_ADB + +#include "sysdeps.h" + +#include <errno.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> + +#include "adb.h" +#include "adb_auth.h" +#include "adb_listeners.h" +#include "transport.h" + +#if !ADB_HOST +#include <getopt.h> +#include <sys/prctl.h> + +#include "cutils/properties.h" +#include "private/android_filesystem_config.h" +#include "selinux/selinux.h" + +#include "qemu_tracing.h" +#endif + +static void adb_cleanup(void) +{ + usb_cleanup(); +} + +#if defined(_WIN32) +static BOOL WINAPI ctrlc_handler(DWORD type) +{ + exit(STATUS_CONTROL_C_EXIT); + return TRUE; +} +#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 +#else /* ADB_HOST */ +static const char *root_seclabel = NULL; + +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 bool should_drop_privileges() { +#if defined(ALLOW_ADBD_ROOT) + char value[PROPERTY_VALUE_MAX]; + + // The emulator is never secure, so don't drop privileges there. + // TODO: this seems like a bug --- shouldn't the emulator behave like a device? + property_get("ro.kernel.qemu", value, ""); + if (strcmp(value, "1") == 0) { + return false; + } + + // The properties that affect `adb root` and `adb unroot` are ro.secure and + // ro.debuggable. In this context the names don't make the expected behavior + // particularly obvious. + // + // ro.debuggable: + // Allowed to become root, but not necessarily the default. Set to 1 on + // eng and userdebug builds. + // + // ro.secure: + // Drop privileges by default. Set to 1 on userdebug and user builds. + property_get("ro.secure", value, "1"); + bool ro_secure = (strcmp(value, "1") == 0); + + property_get("ro.debuggable", value, ""); + bool ro_debuggable = (strcmp(value, "1") == 0); + + // Drop privileges if ro.secure is set... + bool drop = ro_secure; + + property_get("service.adb.root", value, ""); + bool adb_root = (strcmp(value, "1") == 0); + bool adb_unroot = (strcmp(value, "0") == 0); + + // ...except "adb root" lets you keep privileges in a debuggable build. + if (ro_debuggable && adb_root) { + drop = false; + } + + // ...and "adb unroot" lets you explicitly drop privileges. + if (adb_unroot) { + drop = true; + } + + return drop; +#else + return true; // "adb root" not allowed, always drop privileges. +#endif /* ALLOW_ADBD_ROOT */ +} +#endif /* ADB_HOST */ + +/* Constructs a local name of form tcp:port. + * target_str points to the target string, it's content will be overwritten. + * target_size is the capacity of the target string. + * server_port is the port number to use for the local name. + */ +void build_local_name(char* target_str, size_t target_size, int server_port) +{ + snprintf(target_str, target_size, "tcp:%d", server_port); +} + +void start_logging(void) +{ +#if defined(_WIN32) + char temp[ MAX_PATH ]; + FILE* fnul; + FILE* flog; + + GetTempPath( sizeof(temp) - 8, temp ); + strcat( temp, "adb.log" ); + + /* Win32 specific redirections */ + fnul = fopen( "NUL", "rt" ); + if (fnul != NULL) + stdin[0] = fnul[0]; + + flog = fopen( temp, "at" ); + if (flog == NULL) + flog = fnul; + + setvbuf( flog, NULL, _IONBF, 0 ); + + stdout[0] = flog[0]; + stderr[0] = flog[0]; + fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid()); +#else + int fd; + + fd = unix_open("/dev/null", O_RDONLY); + dup2(fd, 0); + adb_close(fd); + + fd = unix_open("/tmp/adb.log", O_WRONLY | O_CREAT | O_APPEND, 0640); + if(fd < 0) { + fd = unix_open("/dev/null", O_WRONLY); + } + dup2(fd, 1); + dup2(fd, 2); + adb_close(fd); + fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid()); +#endif +} + +int adb_main(int is_daemon, int server_port) +{ +#if !ADB_HOST + int port; + char value[PROPERTY_VALUE_MAX]; + + umask(000); +#endif + + atexit(adb_cleanup); +#if defined(_WIN32) + SetConsoleCtrlHandler( ctrlc_handler, TRUE ); +#else + // No SIGCHLD. Let the service subproc handle its children. + signal(SIGPIPE, SIG_IGN); +#endif + + init_transport_registration(); + +#if ADB_HOST + HOST = 1; + +#ifdef WORKAROUND_BUG6558362 + if(is_daemon) adb_set_affinity(); +#endif + 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, 0)) { + exit(1); + } +#else + // We need to call this even if auth isn't enabled because the file + // descriptor will always be open. + adbd_cloexec_auth_socket(); + + property_get("ro.adb.secure", value, "0"); + auth_enabled = !strcmp(value, "1"); + if (auth_enabled) + adbd_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"); + } + + /* add extra groups: + ** AID_ADB to access the USB driver + ** AID_LOG to read system logs (adb logcat) + ** AID_INPUT to diagnose input issues (getevent) + ** AID_INET to diagnose network issues (ping) + ** AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump) + ** AID_SDCARD_R to allow reading from the SD card + ** AID_SDCARD_RW to allow writing to the SD card + ** AID_NET_BW_STATS to read out qtaguid statistics + */ + gid_t groups[] = { AID_ADB, AID_LOG, AID_INPUT, AID_INET, AID_NET_BT, + AID_NET_BT_ADMIN, AID_SDCARD_R, AID_SDCARD_RW, + AID_NET_BW_STATS }; + if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) { + exit(1); + } + + /* 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()) { + drop_capabilities_bounding_set_if_needed(); + + /* then switch user and group to "shell" */ + if (setgid(AID_SHELL) != 0) { + exit(1); + } + if (setuid(AID_SHELL) != 0) { + exit(1); + } + + D("Local port disabled\n"); + } else { + char local_name[30]; + if ((root_seclabel != NULL) && (is_selinux_enabled() > 0)) { + // b/12587913: fix setcon to allow const pointers + if (setcon((char *)root_seclabel) < 0) { + exit(1); + } + } + build_local_name(local_name, sizeof(local_name), server_port); + if(install_listener(local_name, "*smartsocket*", NULL, 0)) { + exit(1); + } + } + + 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]) { + 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 (!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"); +#endif + + if (is_daemon) + { + // inform our parent that we are up and running. +#if defined(_WIN32) + DWORD count; + WriteFile( GetStdHandle( STD_OUTPUT_HANDLE ), "OK\n", 3, &count, NULL ); +#else + fprintf(stderr, "OK\n"); +#endif + start_logging(); + } + D("Event loop starting\n"); + + fdevent_loop(); + + usb_cleanup(); + + return 0; +} + +#if !ADB_HOST +void close_stdin() { + int fd = unix_open("/dev/null", O_RDONLY); + if (fd == -1) { + perror("failed to open /dev/null, stdin will remain open"); + return; + } + dup2(fd, 0); + adb_close(fd); +} +#endif + +int main(int argc, char **argv) { +#if ADB_HOST + adb_sysdeps_init(); +#else + close_stdin(); +#endif + adb_trace_init(); + +#if ADB_HOST + D("Handling commandline()\n"); + return adb_commandline(argc - 1, const_cast<const char**>(argv + 1)); +#else + /* If adbd runs inside the emulator this will enable adb tracing via + * adb-debug qemud service in the emulator. */ + adb_qemu_trace_init(); + while (true) { + int c; + int option_index = 0; + static struct option opts[] = { + {"root_seclabel", required_argument, 0, 's' }, + {"device_banner", required_argument, 0, 'b' } + }; + c = getopt_long(argc, argv, "", opts, &option_index); + if (c == -1) + break; + switch (c) { + case 's': + root_seclabel = optarg; + break; + case 'b': + adb_device_banner = optarg; + break; + default: + break; + } + } + + D("Handling main()\n"); + return adb_main(0, DEFAULT_ADB_PORT); +#endif +} diff --git a/adb/adb_trace.h b/adb/adb_trace.h index 8a5d9f8..32b6ae4 100644 --- a/adb/adb_trace.h +++ b/adb/adb_trace.h @@ -19,6 +19,8 @@ #if !ADB_HOST #include <android/log.h> +#else +#include <stdio.h> #endif /* define ADB_TRACE to 1 to enable tracing support, or 0 to disable it */ @@ -28,7 +30,7 @@ * forget to update the corresponding 'tags' table in * the adb_trace_init() function implemented in adb.c */ -typedef enum { +enum AdbTrace { TRACE_ADB = 0, /* 0x001 */ TRACE_SOCKETS, TRACE_PACKETS, @@ -41,7 +43,7 @@ typedef enum { TRACE_SERVICES, TRACE_AUTH, TRACE_FDEVENT, -} AdbTrace; +} ; #if ADB_TRACE @@ -73,8 +75,9 @@ void adb_trace_init(void); if (ADB_TRACING) { \ int save_errno = errno; \ adb_mutex_lock(&D_lock); \ - fprintf(stderr, "%s::%s():", \ - __FILE__, __FUNCTION__); \ + fprintf(stderr, "%16s: %5d:%5lu | ", \ + __FUNCTION__, \ + getpid(), adb_thread_id()); \ errno = save_errno; \ fprintf(stderr, __VA_ARGS__ ); \ fflush(stderr); \ @@ -96,15 +99,16 @@ void adb_trace_init(void); } while (0) # define DD(...) \ do { \ - int save_errno = errno; \ - adb_mutex_lock(&D_lock); \ - fprintf(stderr, "%s::%s():", \ - __FILE__, __FUNCTION__); \ - errno = save_errno; \ - fprintf(stderr, __VA_ARGS__ ); \ - fflush(stderr); \ - adb_mutex_unlock(&D_lock); \ - errno = save_errno; \ + int save_errno = errno; \ + adb_mutex_lock(&D_lock); \ + fprintf(stderr, "%16s: %5d:%5lu | ", \ + __FUNCTION__, \ + getpid(), adb_thread_id()); \ + errno = save_errno; \ + fprintf(stderr, __VA_ARGS__ ); \ + fflush(stderr); \ + adb_mutex_unlock(&D_lock); \ + errno = save_errno; \ } while (0) #else # define D(...) \ diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp new file mode 100644 index 0000000..f10c143 --- /dev/null +++ b/adb/adb_utils.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2015 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 "adb_utils.h" + +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include "sysdeps.h" + +bool getcwd(std::string* s) { + char* cwd = getcwd(nullptr, 0); + if (cwd != nullptr) *s = cwd; + free(cwd); + return (cwd != nullptr); +} + +bool directory_exists(const std::string& path) { + struct stat sb; + return lstat(path.c_str(), &sb) != -1 && S_ISDIR(sb.st_mode); +} + +std::string escape_arg(const std::string& s) { + std::string result = s; + + // Insert a \ before any ' in the string. + for (auto it = result.begin(); it != result.end(); ++it) { + if (*it == '\'') { + it = result.insert(it, '\\') + 1; + } + } + + // Prefix and suffix the whole string with '. + result.insert(result.begin(), '\''); + result.push_back('\''); + return result; +} diff --git a/adb/get_my_path_freebsd.c b/adb/adb_utils.h index b06ec66..4b64afa 100644 --- a/adb/get_my_path_freebsd.c +++ b/adb/adb_utils.h @@ -1,8 +1,5 @@ /* - * Copyright (C) 2009 bsdroid project - * Alexey Tarasov <tarasov@dodologics.com> - * - * Copyright (C) 2007 The Android Open Source Project + * Copyright (C) 2015 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. @@ -17,20 +14,14 @@ * limitations under the License. */ -#include <sys/types.h> -#include <unistd.h> -#include <limits.h> -#include <stdio.h> - -void -get_my_path(char *exe, size_t maxLen) -{ - char proc[64]; +#ifndef _ADB_UTILS_H_ +#define _ADB_UTILS_H_ - snprintf(proc, sizeof(proc), "/proc/%d/file", getpid()); +#include <string> - int err = readlink(proc, exe, maxLen - 1); +bool getcwd(std::string* cwd); +bool directory_exists(const std::string& path); - exe[err > 0 ? err : 0] = '\0'; -} +std::string escape_arg(const std::string& s); +#endif diff --git a/adb/adb_utils_test.cpp b/adb/adb_utils_test.cpp new file mode 100644 index 0000000..a395079 --- /dev/null +++ b/adb/adb_utils_test.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2015 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 "adb_utils.h" + +#include <gtest/gtest.h> + +TEST(adb_utils, directory_exists) { + ASSERT_TRUE(directory_exists("/proc")); + ASSERT_FALSE(directory_exists("/proc/self")); // Symbolic link. + ASSERT_FALSE(directory_exists("/proc/does-not-exist")); +} + +TEST(adb_utils, escape_arg) { + ASSERT_EQ(R"('')", escape_arg("")); + + ASSERT_EQ(R"('abc')", escape_arg("abc")); + + ASSERT_EQ(R"(' abc')", escape_arg(" abc")); + ASSERT_EQ(R"('\'abc')", escape_arg("'abc")); + ASSERT_EQ(R"('"abc')", escape_arg("\"abc")); + ASSERT_EQ(R"('\abc')", escape_arg("\\abc")); + ASSERT_EQ(R"('(abc')", escape_arg("(abc")); + ASSERT_EQ(R"(')abc')", escape_arg(")abc")); + + ASSERT_EQ(R"('abc abc')", escape_arg("abc abc")); + ASSERT_EQ(R"('abc\'abc')", escape_arg("abc'abc")); + ASSERT_EQ(R"('abc"abc')", escape_arg("abc\"abc")); + ASSERT_EQ(R"('abc\abc')", escape_arg("abc\\abc")); + ASSERT_EQ(R"('abc(abc')", escape_arg("abc(abc")); + ASSERT_EQ(R"('abc)abc')", escape_arg("abc)abc")); + + ASSERT_EQ(R"('abc ')", escape_arg("abc ")); + ASSERT_EQ(R"('abc\'')", escape_arg("abc'")); + ASSERT_EQ(R"('abc"')", escape_arg("abc\"")); + ASSERT_EQ(R"('abc\')", escape_arg("abc\\")); + ASSERT_EQ(R"('abc(')", escape_arg("abc(")); + ASSERT_EQ(R"('abc)')", escape_arg("abc)")); +} diff --git a/adb/commandline.c b/adb/commandline.cpp index 7704878..e59a96a 100644 --- a/adb/commandline.c +++ b/adb/commandline.cpp @@ -14,72 +14,68 @@ * limitations under the License. */ -#include <stdio.h> -#include <stdint.h> -#include <stdlib.h> -#include <string.h> +#define TRACE_TAG TRACE_ADB + +#include "sysdeps.h" + +#include <assert.h> +#include <ctype.h> #include <errno.h> -#include <unistd.h> +#include <inttypes.h> #include <limits.h> #include <stdarg.h> -#include <sys/types.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> #include <sys/stat.h> -#include <ctype.h> -#include <assert.h> +#include <sys/types.h> -#include "sysdeps.h" +#include <string> -#ifdef HAVE_TERMIO_H +#include <base/stringprintf.h> + +#if !defined(_WIN32) #include <termios.h> +#include <unistd.h> #endif -#define TRACE_TAG TRACE_ADB #include "adb.h" -#include "adb_client.h" #include "adb_auth.h" +#include "adb_client.h" +#include "adb_io.h" +#include "adb_utils.h" #include "file_sync_service.h" -static int do_cmd(transport_type ttype, char* serial, char *cmd, ...); +static int do_cmd(transport_type ttype, const char* serial, const char *cmd, ...); -void get_my_path(char *s, size_t maxLen); -int find_sync_dirs(const char *srcarg, - char **android_srcdir_out, char **data_srcdir_out, char **vendor_srcdir_out); -int install_app(transport_type transport, char* serial, int argc, char** argv); -int install_multiple_app(transport_type transport, char* serial, int argc, char** argv); -int uninstall_app(transport_type transport, char* serial, int argc, char** argv); +static int install_app(transport_type transport, const char* serial, int argc, + const char** argv); +static int install_multiple_app(transport_type transport, const char* serial, int argc, + const char** argv); +static int uninstall_app(transport_type transport, const char* serial, int argc, + const char** argv); -static const char *gProductOutPath = NULL; +static std::string gProductOutPath; extern int gListenAll; -static char *product_file(const char *extra) -{ - int n; - char *x; - - if (gProductOutPath == NULL) { +static std::string product_file(const char *extra) { + if (gProductOutPath.empty()) { fprintf(stderr, "adb: Product directory not specified; " "use -p or define ANDROID_PRODUCT_OUT\n"); exit(1); } - n = strlen(gProductOutPath) + strlen(extra) + 2; - x = malloc(n); - if (x == 0) { - fprintf(stderr, "adb: Out of memory (product_file())\n"); - exit(1); - } - - snprintf(x, (size_t)n, "%s" OS_PATH_SEPARATOR_STR "%s", gProductOutPath, extra); - return x; + return android::base::StringPrintf("%s%s%s", + gProductOutPath.c_str(), OS_PATH_SEPARATOR_STR, extra); } -void version(FILE * out) { +static void version(FILE* out) { fprintf(out, "Android Debug Bridge version %d.%d.%d\n", - ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION); + ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION); } -void help() -{ +static void help() { version(stderr); fprintf(stderr, @@ -191,6 +187,7 @@ void help() " adb restore <file> - restore device contents from the <file> backup archive\n" "\n" " adb disable-verity - disable dm-verity checking on USERDEBUG builds\n" + " adb enable-verity - re-enable dm-verity checking on USERDEBUG builds\n" " adb keygen <file> - generate adb public/private key. The private key is stored in <file>,\n" " and the public key is stored in <file>.pub. Any existing files\n" " are overwritten.\n" @@ -205,10 +202,15 @@ void help() " 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 and /vendor (if present) partitions on the device read-write\n" - " adb reboot [bootloader|recovery] - reboots the device, optionally into the bootloader or recovery program\n" + " adb remount - remounts the /system, /vendor (if present) and /oem (if present) partitions on the device read-write\n" + " adb reboot [bootloader|recovery]\n" + " - reboots the device, optionally into the bootloader or recovery program.\n" + " adb reboot sideload - reboots the device into the sideload mode in recovery program (adb root required).\n" + " adb reboot sideload-auto-reboot\n" + " - reboots into the sideload mode, then reboots automatically after the sideload regardless of the result.\n" " adb reboot-bootloader - reboots the device into the bootloader\n" " adb root - restarts the adbd daemon with root permissions\n" + " adb unroot - restarts the adbd daemon without root permissions\n" " adb usb - restarts the adbd daemon listening on USB\n" " adb tcpip <port> - restarts the adbd daemon listening on TCP on the specified port\n" "networking:\n" @@ -220,9 +222,9 @@ void help() "adb sync notes: adb sync [ <directory> ]\n" " <localdir> can be interpreted in several ways:\n" "\n" - " - If <directory> is not specified, /system, /vendor (if present), and /data partitions will be updated.\n" + " - If <directory> is not specified, /system, /vendor (if present), /oem (if present) and /data partitions will be updated.\n" "\n" - " - If it is \"system\", \"vendor\" or \"data\", only the corresponding partition\n" + " - If it is \"system\", \"vendor\", \"oem\" or \"data\", only the corresponding partition\n" " is updated.\n" "\n" "environmental variables:\n" @@ -233,36 +235,37 @@ void help() ); } -int usage() -{ +static int usage() { help(); return 1; } -#ifdef HAVE_TERMIO_H -static struct termios tio_save; +#if defined(_WIN32) -static void stdin_raw_init(int fd) -{ - struct termios tio; +// Implemented in sysdeps_win32.cpp. +void stdin_raw_init(int fd); +void stdin_raw_restore(int fd); + +#else +static termios g_saved_terminal_state; + +static void stdin_raw_init(int fd) { + if (tcgetattr(fd, &g_saved_terminal_state)) return; - if(tcgetattr(fd, &tio)) return; - if(tcgetattr(fd, &tio_save)) return; + termios tio; + if (tcgetattr(fd, &tio)) return; - tio.c_lflag = 0; /* disable CANON, ECHO*, etc */ + cfmakeraw(&tio); - /* no timeout but request at least one character per read */ + // No timeout but request at least one character per read. tio.c_cc[VTIME] = 0; tio.c_cc[VMIN] = 1; - tcsetattr(fd, TCSANOW, &tio); - tcflush(fd, TCIFLUSH); + tcsetattr(fd, TCSAFLUSH, &tio); } -static void stdin_raw_restore(int fd) -{ - tcsetattr(fd, TCSANOW, &tio_save); - tcflush(fd, TCIFLUSH); +static void stdin_raw_restore(int fd) { + tcsetattr(fd, TCSAFLUSH, &g_saved_terminal_state); } #endif @@ -309,16 +312,17 @@ static void read_status_line(int fd, char* buf, size_t count) static void copy_to_file(int inFd, int outFd) { const size_t BUFSIZE = 32 * 1024; char* buf = (char*) malloc(BUFSIZE); + if (buf == nullptr) fatal("couldn't allocate buffer for copy_to_file"); int len; long total = 0; D("copy_to_file(%d -> %d)\n", inFd, outFd); -#ifdef HAVE_TERMIO_H + if (inFd == STDIN_FILENO) { stdin_raw_init(STDIN_FILENO); } -#endif - for (;;) { + + while (true) { if (inFd == STDIN_FILENO) { len = unix_read(inFd, buf, BUFSIZE); } else { @@ -344,11 +348,11 @@ static void copy_to_file(int inFd, int outFd) { } total += len; } -#ifdef HAVE_TERMIO_H + if (inFd == STDIN_FILENO) { stdin_raw_restore(STDIN_FILENO); } -#endif + D("copy_to_file() finished after %lu bytes\n", total); free(buf); } @@ -389,9 +393,7 @@ static void *stdin_read_thread(void *x) case '.': if(state == 2) { fprintf(stderr,"\n* disconnect *\n"); -#ifdef HAVE_TERMIO_H stdin_raw_restore(fdi); -#endif exit(0); } default: @@ -406,11 +408,9 @@ static void *stdin_read_thread(void *x) return 0; } -int interactive_shell(void) -{ +static int interactive_shell() { adb_thread_t thr; int fdi, fd; - int *fds; fd = adb_connect("shell:"); if(fd < 0) { @@ -419,18 +419,19 @@ int interactive_shell(void) } fdi = 0; //dup(0); - fds = malloc(sizeof(int) * 2); + int* fds = reinterpret_cast<int*>(malloc(sizeof(int) * 2)); + if (fds == nullptr) { + fprintf(stderr, "couldn't allocate fds array: %s\n", strerror(errno)); + return 1; + } + fds[0] = fd; fds[1] = fdi; -#ifdef HAVE_TERMIO_H stdin_raw_init(fdi); -#endif adb_thread_create(&thr, stdin_read_thread, fds); read_and_dump(fd); -#ifdef HAVE_TERMIO_H stdin_raw_restore(fdi); -#endif return 0; } @@ -450,13 +451,12 @@ static void format_host_command(char* buffer, size_t buflen, const char* comman } } -int adb_download_buffer(const char *service, const char *fn, const void* data, int sz, - unsigned progress) +static int adb_download_buffer(const char *service, const char *fn, const void* data, int sz, + unsigned progress) { char buf[4096]; unsigned total; int fd; - const unsigned char *ptr; sprintf(buf,"%s:%d", service, sz); fd = adb_connect(buf); @@ -466,10 +466,10 @@ int adb_download_buffer(const char *service, const char *fn, const void* data, i } int opt = CHUNK_SIZE; - opt = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *) &opt, sizeof(opt)); + opt = adb_setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *) &opt, sizeof(opt)); total = sz; - ptr = data; + const uint8_t* ptr = reinterpret_cast<const uint8_t*>(data); if(progress) { char *x = strrchr(service, ':'); @@ -478,7 +478,7 @@ int adb_download_buffer(const char *service, const char *fn, const void* data, i while(sz > 0) { unsigned xfer = (sz > CHUNK_SIZE) ? CHUNK_SIZE : sz; - if(writex(fd, ptr, xfer)) { + if(!WriteFdExactly(fd, ptr, xfer)) { adb_status(fd); fprintf(stderr,"* failed to write data '%s' *\n", adb_error()); return -1; @@ -494,7 +494,7 @@ int adb_download_buffer(const char *service, const char *fn, const void* data, i printf("\n"); } - if(readx(fd, buf, 4)){ + if(!ReadFdExactly(fd, buf, 4)){ fprintf(stderr,"* error reading response *\n"); adb_close(fd); return -1; @@ -510,23 +510,6 @@ int adb_download_buffer(const char *service, const char *fn, const void* data, i return 0; } - -int adb_download(const char *service, const char *fn, unsigned progress) -{ - void *data; - unsigned sz; - - data = load_file(fn, &sz); - if(data == 0) { - fprintf(stderr,"* cannot read '%s' *\n", fn); - return -1; - } - - int status = adb_download_buffer(service, fn, data, sz, progress); - free(data); - return status; -} - #define SIDELOAD_HOST_BLOCK_SIZE (CHUNK_SIZE) /* @@ -548,15 +531,16 @@ int adb_download(const char *service, const char *fn, unsigned progress) * - When the other side sends "DONEDONE" instead of a block number, * we hang up. */ -int adb_sideload_host(const char* fn) { - uint8_t* data; +static int adb_sideload_host(const char* fn) { unsigned sz; size_t xfer = 0; int status; + int last_percent = -1; + int opt = SIDELOAD_HOST_BLOCK_SIZE; printf("loading: '%s'", fn); fflush(stdout); - data = load_file(fn, &sz); + uint8_t* data = reinterpret_cast<uint8_t*>(load_file(fn, &sz)); if (data == 0) { printf("\n"); fprintf(stderr, "* cannot read '%s' *\n", fn); @@ -574,12 +558,10 @@ int adb_sideload_host(const char* fn) { goto done; } - int opt = SIDELOAD_HOST_BLOCK_SIZE; - opt = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *) &opt, sizeof(opt)); + opt = adb_setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *) &opt, sizeof(opt)); - int last_percent = -1; - for (;;) { - if (readx(fd, buf, 8)) { + while (true) { + if (!ReadFdExactly(fd, buf, 8)) { fprintf(stderr, "* failed to read command: %s\n", adb_error()); status = -1; goto done; @@ -606,7 +588,7 @@ int adb_sideload_host(const char* fn) { to_write = sz - offset; } - if(writex(fd, start, to_write)) { + if(!WriteFdExactly(fd, start, to_write)) { adb_status(fd); fprintf(stderr,"* failed to write data '%s' *\n", adb_error()); status = -1; @@ -680,50 +662,6 @@ static void status_window(transport_type ttype, const char* serial) } } -static int should_escape(const char c) -{ - return (c == ' ' || c == '\'' || c == '"' || c == '\\' || c == '(' || c == ')'); -} - -/* Duplicate and escape given argument. */ -static char *escape_arg(const char *s) -{ - const char *ts; - size_t alloc_len; - char *ret; - char *dest; - - alloc_len = 0; - for (ts = s; *ts != '\0'; ts++) { - alloc_len++; - if (should_escape(*ts)) { - alloc_len++; - } - } - - if (alloc_len == 0) { - // Preserve empty arguments - ret = (char *) malloc(3); - ret[0] = '\"'; - ret[1] = '\"'; - ret[2] = '\0'; - return ret; - } - - ret = (char *) malloc(alloc_len + 1); - dest = ret; - - for (ts = s; *ts != '\0'; ts++) { - if (should_escape(*ts)) { - *dest++ = '\\'; - } - *dest++ = *ts; - } - *dest++ = '\0'; - - return ret; -} - /** * Run ppp in "notty" mode against a resource listed as the first parameter * eg: @@ -731,13 +669,11 @@ static char *escape_arg(const char *s) * ppp dev:/dev/omap_csmi_tty0 <ppp options> * */ -int ppp(int argc, char **argv) -{ -#ifdef HAVE_WIN32_PROC +static int ppp(int argc, const char** argv) { +#if defined(_WIN32) fprintf(stderr, "error: adb %s not implemented on Win32\n", argv[0]); return -1; #else - char *adb_service_name; pid_t pid; int fd; @@ -748,8 +684,7 @@ int ppp(int argc, char **argv) return 1; } - adb_service_name = argv[1]; - + const char* adb_service_name = argv[1]; fd = adb_connect(adb_service_name); if(fd < 0) { @@ -796,16 +731,15 @@ int ppp(int argc, char **argv) adb_close(fd); return 0; } -#endif /* !HAVE_WIN32_PROC */ +#endif /* !defined(_WIN32) */ } -static int send_shellcommand(transport_type transport, char* serial, char* buf) -{ - int fd, ret; - - for(;;) { - fd = adb_connect(buf); - if(fd >= 0) +static int send_shell_command(transport_type transport, const char* serial, + const std::string& command) { + int fd; + while (true) { + fd = adb_connect(command.c_str()); + if (fd >= 0) break; fprintf(stderr,"- waiting for device -\n"); adb_sleep_ms(1000); @@ -813,41 +747,30 @@ static int send_shellcommand(transport_type transport, char* serial, char* buf) } read_and_dump(fd); - ret = adb_close(fd); - if (ret) + int rc = adb_close(fd); + if (rc) { perror("close"); - - return ret; + } + return rc; } -static int logcat(transport_type transport, char* serial, int argc, char **argv) -{ - char buf[4096]; - - char *log_tags; - char *quoted; +static int logcat(transport_type transport, const char* serial, int argc, const char** argv) { + char* log_tags = getenv("ANDROID_LOG_TAGS"); + std::string quoted = escape_arg(log_tags == nullptr ? "" : log_tags); - log_tags = getenv("ANDROID_LOG_TAGS"); - quoted = escape_arg(log_tags == NULL ? "" : log_tags); - snprintf(buf, sizeof(buf), - "shell:export ANDROID_LOG_TAGS=\"%s\"; exec logcat", quoted); - free(quoted); + std::string cmd = "shell:export ANDROID_LOG_TAGS=\"" + quoted + "\"; exec logcat"; if (!strcmp(argv[0], "longcat")) { - strncat(buf, " -v long", sizeof(buf) - 1); + cmd += " -v long"; } - argc -= 1; - argv += 1; - while(argc-- > 0) { - quoted = escape_arg(*argv++); - strncat(buf, " ", sizeof(buf) - 1); - strncat(buf, quoted, sizeof(buf) - 1); - free(quoted); + --argc; + ++argv; + while (argc-- > 0) { + cmd += " " + escape_arg(*argv++); } - send_shellcommand(transport, serial, buf); - return 0; + return send_shell_command(transport, serial, cmd); } static int mkdirs(const char *path) @@ -869,22 +792,18 @@ static int mkdirs(const char *path) return 0; } -static int backup(int argc, char** argv) { - char buf[4096]; - char default_name[32]; - const char* filename = strcpy(default_name, "./backup.ab"); - int fd, outFd; - int i, j; +static int backup(int argc, const char** argv) { + const char* filename = "./backup.ab"; /* find, extract, and use any -f argument */ - for (i = 1; i < argc; i++) { + for (int i = 1; i < argc; i++) { if (!strcmp("-f", argv[i])) { if (i == argc-1) { fprintf(stderr, "adb: -f passed with no filename\n"); return usage(); } filename = argv[i+1]; - for (j = i+2; j <= argc; ) { + for (int j = i+2; j <= argc; ) { argv[i++] = argv[j++]; } argc -= 2; @@ -897,20 +816,21 @@ static int backup(int argc, char** argv) { adb_unlink(filename); mkdirs(filename); - outFd = adb_creat(filename, 0640); + int outFd = adb_creat(filename, 0640); if (outFd < 0) { fprintf(stderr, "adb: unable to open file %s\n", filename); return -1; } - snprintf(buf, sizeof(buf), "backup"); - for (argc--, argv++; argc; argc--, argv++) { - strncat(buf, ":", sizeof(buf) - strlen(buf) - 1); - strncat(buf, argv[0], sizeof(buf) - strlen(buf) - 1); + std::string cmd = "backup:"; + --argc; + ++argv; + while (argc-- > 0) { + cmd += " " + escape_arg(*argv++); } - D("backup. filename=%s buf=%s\n", filename, buf); - fd = adb_connect(buf); + D("backup. filename=%s cmd=%s\n", filename, cmd.c_str()); + int fd = adb_connect(cmd.c_str()); if (fd < 0) { fprintf(stderr, "adb: unable to connect for backup\n"); adb_close(outFd); @@ -925,7 +845,7 @@ static int backup(int argc, char** argv) { return 0; } -static int restore(int argc, char** argv) { +static int restore(int argc, const char** argv) { const char* filename; int fd, tarFd; @@ -953,81 +873,9 @@ static int restore(int argc, char** argv) { return 0; } -#define SENTINEL_FILE "config" OS_PATH_SEPARATOR_STR "envsetup.make" -static int top_works(const char *top) -{ - if (top != NULL && adb_is_absolute_host_path(top)) { - char path_buf[PATH_MAX]; - snprintf(path_buf, sizeof(path_buf), - "%s" OS_PATH_SEPARATOR_STR SENTINEL_FILE, top); - return access(path_buf, F_OK) == 0; - } - return 0; -} - -static char *find_top_from(const char *indir, char path_buf[PATH_MAX]) -{ - strcpy(path_buf, indir); - while (1) { - if (top_works(path_buf)) { - return path_buf; - } - char *s = adb_dirstop(path_buf); - if (s != NULL) { - *s = '\0'; - } else { - path_buf[0] = '\0'; - return NULL; - } - } -} - -static char *find_top(char path_buf[PATH_MAX]) -{ - char *top = getenv("ANDROID_BUILD_TOP"); - if (top != NULL && top[0] != '\0') { - if (!top_works(top)) { - fprintf(stderr, "adb: bad ANDROID_BUILD_TOP value \"%s\"\n", top); - return NULL; - } - } else { - top = getenv("TOP"); - if (top != NULL && top[0] != '\0') { - if (!top_works(top)) { - fprintf(stderr, "adb: bad TOP value \"%s\"\n", top); - return NULL; - } - } else { - top = NULL; - } - } - - if (top != NULL) { - /* The environment pointed to a top directory that works. - */ - strcpy(path_buf, top); - return path_buf; - } - - /* The environment didn't help. Walk up the tree from the CWD - * to see if we can find the top. - */ - char dir[PATH_MAX]; - top = find_top_from(getcwd(dir, sizeof(dir)), path_buf); - if (top == NULL) { - /* If the CWD isn't under a good-looking top, see if the - * executable is. - */ - get_my_path(dir, PATH_MAX); - top = find_top_from(dir, path_buf); - } - return top; -} - /* <hint> may be: * - A simple product name * e.g., "sooner" -TODO: debug? sooner-debug, sooner:debug? * - A relative path from the CWD to the ANDROID_PRODUCT_OUT dir * e.g., "out/target/product/sooner" * - An absolute path to the PRODUCT_OUT dir @@ -1036,66 +884,57 @@ TODO: debug? sooner-debug, sooner:debug? * Given <hint>, try to construct an absolute path to the * ANDROID_PRODUCT_OUT dir. */ -static const char *find_product_out_path(const char *hint) -{ - static char path_buf[PATH_MAX]; - +static std::string find_product_out_path(const char* hint) { if (hint == NULL || hint[0] == '\0') { - return NULL; + return ""; } - /* If it's already absolute, don't bother doing any work. - */ + // If it's already absolute, don't bother doing any work. if (adb_is_absolute_host_path(hint)) { - strcpy(path_buf, hint); - return path_buf; - } - - /* If there are any slashes in it, assume it's a relative path; - * make it absolute. - */ - if (adb_dirstart(hint) != NULL) { - if (getcwd(path_buf, sizeof(path_buf)) == NULL) { - fprintf(stderr, "adb: Couldn't get CWD: %s\n", strerror(errno)); - return NULL; - } - if (strlen(path_buf) + 1 + strlen(hint) >= sizeof(path_buf)) { - fprintf(stderr, "adb: Couldn't assemble path\n"); - return NULL; - } - strcat(path_buf, OS_PATH_SEPARATOR_STR); - strcat(path_buf, hint); - return path_buf; - } - - /* It's a string without any slashes. Try to do something with it. - * - * Try to find the root of the build tree, and build a PRODUCT_OUT - * path from there. - */ - char top_buf[PATH_MAX]; - const char *top = find_top(top_buf); - if (top == NULL) { - fprintf(stderr, "adb: Couldn't find top of build tree\n"); - return NULL; - } -//TODO: if we have a way to indicate debug, look in out/debug/target/... - snprintf(path_buf, sizeof(path_buf), - "%s" OS_PATH_SEPARATOR_STR - "out" OS_PATH_SEPARATOR_STR - "target" OS_PATH_SEPARATOR_STR - "product" OS_PATH_SEPARATOR_STR - "%s", top_buf, hint); - if (access(path_buf, F_OK) < 0) { - fprintf(stderr, "adb: Couldn't find a product dir " - "based on \"-p %s\"; \"%s\" doesn't exist\n", hint, path_buf); - return NULL; - } - return path_buf; + return hint; + } + + // If there are any slashes in it, assume it's a relative path; + // make it absolute. + if (adb_dirstart(hint) != nullptr) { + std::string cwd; + if (!getcwd(&cwd)) { + fprintf(stderr, "adb: getcwd failed: %s\n", strerror(errno)); + return ""; + } + return android::base::StringPrintf("%s%s%s", cwd.c_str(), OS_PATH_SEPARATOR_STR, hint); + } + + // It's a string without any slashes. Try to do something with it. + // + // Try to find the root of the build tree, and build a PRODUCT_OUT + // path from there. + char* top = getenv("ANDROID_BUILD_TOP"); + if (top == nullptr) { + fprintf(stderr, "adb: ANDROID_BUILD_TOP not set!\n"); + return ""; + } + + std::string path = top; + path += OS_PATH_SEPARATOR_STR; + path += "out"; + path += OS_PATH_SEPARATOR_STR; + path += "target"; + path += OS_PATH_SEPARATOR_STR; + path += "product"; + path += OS_PATH_SEPARATOR_STR; + path += hint; + if (!directory_exists(path)) { + fprintf(stderr, "adb: Couldn't find a product dir based on -p %s; " + "\"%s\" doesn't exist\n", hint, path.c_str()); + return ""; + } + return path; } -static void parse_push_pull_args(char **arg, int narg, char const **path1, char const **path2, - int *show_progress, int *copy_attrs) { +static void parse_push_pull_args(const char **arg, int narg, char const **path1, + char const **path2, int *show_progress, + int *copy_attrs) { *show_progress = 0; *copy_attrs = 0; @@ -1122,7 +961,18 @@ static void parse_push_pull_args(char **arg, int narg, char const **path1, char } } -int adb_commandline(int argc, char **argv) +static int adb_connect_command(const char* command) { + int fd = adb_connect(command); + if (fd != -1) { + read_and_dump(fd); + adb_close(fd); + return 0; + } + fprintf(stderr, "Error: %s\n", adb_error()); + return 1; +} + +int adb_commandline(int argc, const char **argv) { char buf[4096]; int no_daemon = 0; @@ -1131,18 +981,17 @@ int adb_commandline(int argc, char **argv) int persist = 0; int r; transport_type ttype = kTransportAny; - char* serial = NULL; - char* server_port_str = NULL; - - /* If defined, this should be an absolute path to - * the directory containing all of the various system images - * for a particular product. If not defined, and the adb - * command requires this information, then the user must - * specify the path using "-p". - */ - gProductOutPath = getenv("ANDROID_PRODUCT_OUT"); - if (gProductOutPath == NULL || gProductOutPath[0] == '\0') { - gProductOutPath = NULL; + const char* serial = NULL; + const char* server_port_str = NULL; + + // If defined, this should be an absolute path to + // the directory containing all of the various system images + // for a particular product. If not defined, and the adb + // command requires this information, then the user must + // specify the path using "-p". + char* ANDROID_PRODUCT_OUT = getenv("ANDROID_PRODUCT_OUT"); + if (ANDROID_PRODUCT_OUT != nullptr) { + gProductOutPath = ANDROID_PRODUCT_OUT; } // TODO: also try TARGET_PRODUCT/TARGET_DEVICE as a hint @@ -1162,17 +1011,17 @@ int adb_commandline(int argc, char **argv) } /* modifiers and flags */ - while(argc > 0) { - if(!strcmp(argv[0],"server")) { + while (argc > 0) { + if (!strcmp(argv[0],"server")) { is_server = 1; - } else if(!strcmp(argv[0],"nodaemon")) { + } else if (!strcmp(argv[0],"nodaemon")) { no_daemon = 1; } else if (!strcmp(argv[0], "fork-server")) { /* this is a special flag used only when the ADB client launches the ADB Server */ is_daemon = 1; - } else if(!strcmp(argv[0],"persist")) { + } else if (!strcmp(argv[0],"persist")) { persist = 1; - } else if(!strncmp(argv[0], "-p", 2)) { + } else if (!strncmp(argv[0], "-p", 2)) { const char *product = NULL; if (argv[0][2] == '\0') { if (argc < 2) return usage(); @@ -1183,16 +1032,15 @@ int adb_commandline(int argc, char **argv) product = argv[0] + 2; } gProductOutPath = find_product_out_path(product); - if (gProductOutPath == NULL) { - fprintf(stderr, "adb: could not resolve \"-p %s\"\n", - product); + if (gProductOutPath.empty()) { + fprintf(stderr, "adb: could not resolve \"-p %s\"\n", product); return usage(); } } else if (argv[0][0]=='-' && argv[0][1]=='s') { if (isdigit(argv[0][2])) { serial = argv[0] + 2; } else { - if(argc < 2 || argv[0][2] != '\0') return usage(); + if (argc < 2 || argv[0][2] != '\0') return usage(); serial = argv[1]; argc--; argv++; @@ -1203,7 +1051,7 @@ int adb_commandline(int argc, char **argv) ttype = kTransportLocal; } else if (!strcmp(argv[0],"-a")) { gListenAll = 1; - } else if(!strncmp(argv[0], "-H", 2)) { + } else if (!strncmp(argv[0], "-H", 2)) { const char *hostname = NULL; if (argv[0][2] == '\0') { if (argc < 2) return usage(); @@ -1215,7 +1063,7 @@ int adb_commandline(int argc, char **argv) } adb_set_tcp_name(hostname); - } else if(!strncmp(argv[0], "-P", 2)) { + } else if (!strncmp(argv[0], "-P", 2)) { if (argv[0][2] == '\0') { if (argc < 2) return usage(); server_port_str = argv[1]; @@ -1254,22 +1102,53 @@ int adb_commandline(int argc, char **argv) } else { r = launch_server(server_port); } - if(r) { + if (r) { fprintf(stderr,"* could not start server *\n"); } return r; } -top: - if(argc == 0) { + if (argc == 0) { return usage(); } - /* adb_connect() commands */ + /* handle wait-for-* prefix */ + if (!strncmp(argv[0], "wait-for-", strlen("wait-for-"))) { + const char* service = argv[0]; + if (!strncmp(service, "wait-for-device", strlen("wait-for-device"))) { + if (ttype == kTransportUsb) { + service = "wait-for-usb"; + } else if (ttype == kTransportLocal) { + service = "wait-for-local"; + } else { + service = "wait-for-any"; + } + } - if(!strcmp(argv[0], "devices")) { + format_host_command(buf, sizeof buf, service, ttype, serial); + + if (adb_command(buf)) { + D("failure: %s *\n",adb_error()); + fprintf(stderr,"error: %s\n", adb_error()); + return 1; + } + + /* Allow a command to be run after wait-for-device, + * e.g. 'adb wait-for-device shell'. + */ + if (argc == 1) { + return 0; + } + + /* Fall through */ + argc--; + argv++; + } + + /* adb_connect() commands */ + if (!strcmp(argv[0], "devices")) { char *tmp; - char *listopt; + const char *listopt; if (argc < 2) listopt = ""; else if (argc == 2 && !strcmp(argv[1], "-l")) @@ -1280,7 +1159,7 @@ top: } snprintf(buf, sizeof buf, "host:%s%s", argv[0], listopt); tmp = adb_query(buf); - if(tmp) { + if (tmp) { printf("List of devices attached \n"); printf("%s\n", tmp); return 0; @@ -1288,8 +1167,7 @@ top: return 1; } } - - if(!strcmp(argv[0], "connect")) { + else if (!strcmp(argv[0], "connect")) { char *tmp; if (argc != 2) { fprintf(stderr, "Usage: adb connect <host>[:<port>]\n"); @@ -1297,15 +1175,14 @@ top: } snprintf(buf, sizeof buf, "host:connect:%s", argv[1]); tmp = adb_query(buf); - if(tmp) { + if (tmp) { printf("%s\n", tmp); return 0; } else { return 1; } } - - if(!strcmp(argv[0], "disconnect")) { + else if (!strcmp(argv[0], "disconnect")) { char *tmp; if (argc > 2) { fprintf(stderr, "Usage: adb disconnect [<host>[:<port>]]\n"); @@ -1317,22 +1194,17 @@ top: snprintf(buf, sizeof buf, "host:disconnect:"); } tmp = adb_query(buf); - if(tmp) { + if (tmp) { printf("%s\n", tmp); return 0; } else { return 1; } } - - if (!strcmp(argv[0], "emu")) { + else if (!strcmp(argv[0], "emu")) { return adb_send_emulator_command(argc, argv); } - - if(!strcmp(argv[0], "shell") || !strcmp(argv[0], "hell")) { - int r; - int fd; - + else if (!strcmp(argv[0], "shell") || !strcmp(argv[0], "hell")) { char h = (argv[0][0] == 'h'); if (h) { @@ -1340,7 +1212,7 @@ top: fflush(stdout); } - if(argc < 2) { + if (argc < 2) { D("starting interactive shell\n"); r = interactive_shell(); if (h) { @@ -1350,20 +1222,19 @@ top: return r; } - snprintf(buf, sizeof(buf), "shell:%s", argv[1]); + std::string cmd = "shell:"; + cmd += argv[1]; argc -= 2; argv += 2; while (argc-- > 0) { - char *quoted = escape_arg(*argv++); - strncat(buf, " ", sizeof(buf) - 1); - strncat(buf, quoted, sizeof(buf) - 1); - free(quoted); + cmd += " " + escape_arg(*argv++); } - for(;;) { - D("interactive shell loop. buff=%s\n", buf); - fd = adb_connect(buf); - if(fd >= 0) { + while (true) { + D("interactive shell loop. cmd=%s\n", cmd.c_str()); + int fd = adb_connect(cmd.c_str()); + int r; + if (fd >= 0) { D("about to read_and_dump(fd=%d)\n", fd); read_and_dump(fd); D("read_and_dump() done.\n"); @@ -1374,7 +1245,7 @@ top: r = -1; } - if(persist) { + if (persist) { fprintf(stderr,"\n- waiting for device -\n"); adb_sleep_ms(1000); do_cmd(ttype, serial, "wait-for-device", 0); @@ -1388,22 +1259,18 @@ top: } } } - - if (!strcmp(argv[0], "exec-in") || !strcmp(argv[0], "exec-out")) { + else if (!strcmp(argv[0], "exec-in") || !strcmp(argv[0], "exec-out")) { int exec_in = !strcmp(argv[0], "exec-in"); - int fd; - snprintf(buf, sizeof buf, "exec:%s", argv[1]); + std::string cmd = "exec:"; + cmd += argv[1]; argc -= 2; argv += 2; while (argc-- > 0) { - char *quoted = escape_arg(*argv++); - strncat(buf, " ", sizeof(buf) - 1); - strncat(buf, quoted, sizeof(buf) - 1); - free(quoted); + cmd += " " + escape_arg(*argv++); } - fd = adb_connect(buf); + int fd = adb_connect(cmd.c_str()); if (fd < 0) { fprintf(stderr, "error: %s\n", adb_error()); return -1; @@ -1418,89 +1285,49 @@ top: adb_close(fd); return 0; } - - if(!strcmp(argv[0], "kill-server")) { + else if (!strcmp(argv[0], "kill-server")) { int fd; fd = _adb_connect("host:kill"); - if(fd == -1) { + if (fd == -1) { fprintf(stderr,"* server not running *\n"); return 1; } return 0; } - - if(!strcmp(argv[0], "sideload")) { - if(argc != 2) return usage(); + else if (!strcmp(argv[0], "sideload")) { + if (argc != 2) return usage(); if (adb_sideload_host(argv[1])) { return 1; } else { return 0; } } - - if(!strcmp(argv[0], "remount") || !strcmp(argv[0], "reboot") - || !strcmp(argv[0], "reboot-bootloader") - || !strcmp(argv[0], "tcpip") || !strcmp(argv[0], "usb") - || !strcmp(argv[0], "root") || !strcmp(argv[0], "disable-verity")) { + else if (!strcmp(argv[0], "remount") || + !strcmp(argv[0], "reboot") || + !strcmp(argv[0], "reboot-bootloader") || + !strcmp(argv[0], "tcpip") || + !strcmp(argv[0], "usb") || + !strcmp(argv[0], "root") || + !strcmp(argv[0], "unroot") || + !strcmp(argv[0], "disable-verity") || + !strcmp(argv[0], "enable-verity")) { char command[100]; - if (!strcmp(argv[0], "reboot-bootloader")) + if (!strcmp(argv[0], "reboot-bootloader")) { snprintf(command, sizeof(command), "reboot:bootloader"); - else if (argc > 1) + } else if (argc > 1) { snprintf(command, sizeof(command), "%s:%s", argv[0], argv[1]); - else + } else { snprintf(command, sizeof(command), "%s:", argv[0]); - int fd = adb_connect(command); - if(fd >= 0) { - read_and_dump(fd); - adb_close(fd); - return 0; } - fprintf(stderr,"error: %s\n", adb_error()); - return 1; + return adb_connect_command(command); } - - if(!strcmp(argv[0], "bugreport")) { + else if (!strcmp(argv[0], "bugreport")) { if (argc != 1) return usage(); do_cmd(ttype, serial, "shell", "bugreport", 0); return 0; } - /* adb_command() wrapper commands */ - - if(!strncmp(argv[0], "wait-for-", strlen("wait-for-"))) { - char* service = argv[0]; - if (!strncmp(service, "wait-for-device", strlen("wait-for-device"))) { - if (ttype == kTransportUsb) { - service = "wait-for-usb"; - } else if (ttype == kTransportLocal) { - service = "wait-for-local"; - } else { - service = "wait-for-any"; - } - } - - format_host_command(buf, sizeof buf, service, ttype, serial); - - if (adb_command(buf)) { - D("failure: %s *\n",adb_error()); - fprintf(stderr,"error: %s\n", adb_error()); - return 1; - } - - /* Allow a command to be run after wait-for-device, - * e.g. 'adb wait-for-device shell'. - */ - if(argc > 1) { - argc--; - argv++; - goto top; - } - return 0; - } - - if(!strcmp(argv[0], "forward") || - !strcmp(argv[0], "reverse")) - { + else if (!strcmp(argv[0], "forward") || !strcmp(argv[0], "reverse")) { char host_prefix[64]; char reverse = (char) !strcmp(argv[0], "reverse"); char remove = 0; @@ -1581,25 +1408,22 @@ top: { if (argc != 3) return usage(); - const char* command = no_rebind ? "forward:norebind:" : "forward"; + 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)) { + if (adb_command(buf)) { fprintf(stderr,"error: %s\n", adb_error()); return 1; } return 0; } - /* do_sync_*() commands */ - - if(!strcmp(argv[0], "ls")) { - if(argc != 2) return usage(); + else if (!strcmp(argv[0], "ls")) { + if (argc != 2) return usage(); return do_sync_ls(argv[1]); } - - if(!strcmp(argv[0], "push")) { + else if (!strcmp(argv[0], "push")) { int show_progress = 0; int copy_attrs = 0; // unused const char* lpath = NULL, *rpath = NULL; @@ -1612,8 +1436,7 @@ top: return usage(); } - - if(!strcmp(argv[0], "pull")) { + else if (!strcmp(argv[0], "pull")) { int show_progress = 0; int copy_attrs = 0; const char* rpath = NULL, *lpath = "."; @@ -1626,62 +1449,65 @@ top: return usage(); } - - if (!strcmp(argv[0], "install")) { + else if (!strcmp(argv[0], "install")) { if (argc < 2) return usage(); return install_app(ttype, serial, argc, argv); } - - if (!strcmp(argv[0], "install-multiple")) { + else if (!strcmp(argv[0], "install-multiple")) { if (argc < 2) return usage(); return install_multiple_app(ttype, serial, argc, argv); } - - if (!strcmp(argv[0], "uninstall")) { + else if (!strcmp(argv[0], "uninstall")) { if (argc < 2) return usage(); return uninstall_app(ttype, serial, argc, argv); } - - if(!strcmp(argv[0], "sync")) { - char *srcarg, *android_srcpath, *data_srcpath, *vendor_srcpath; - int listonly = 0; - - int ret; - if(argc < 2) { - /* No local path was specified. */ - srcarg = NULL; + else if (!strcmp(argv[0], "sync")) { + std::string src; + bool list_only = false; + if (argc < 2) { + // No local path was specified. + src = ""; } else if (argc >= 2 && strcmp(argv[1], "-l") == 0) { - listonly = 1; + list_only = true; if (argc == 3) { - srcarg = argv[2]; + src = argv[2]; } else { - srcarg = NULL; + src = ""; } - } else if(argc == 2) { - /* A local path or "android"/"data" arg was specified. */ - srcarg = argv[1]; + } else if (argc == 2) { + // A local path or "android"/"data" arg was specified. + src = argv[1]; } else { return usage(); } - ret = find_sync_dirs(srcarg, &android_srcpath, &data_srcpath, &vendor_srcpath); - if(ret != 0) return usage(); - if(android_srcpath != NULL) - ret = do_sync_sync(android_srcpath, "/system", listonly); - if(ret == 0 && vendor_srcpath != NULL) - ret = do_sync_sync(vendor_srcpath, "/vendor", listonly); - if(ret == 0 && data_srcpath != NULL) - ret = do_sync_sync(data_srcpath, "/data", listonly); + if (src != "" && + src != "system" && src != "data" && src != "vendor" && src != "oem") { + return usage(); + } - free(android_srcpath); - free(vendor_srcpath); - free(data_srcpath); - return ret; - } + std::string system_src_path = product_file("system"); + std::string data_src_path = product_file("data"); + std::string vendor_src_path = product_file("vendor"); + std::string oem_src_path = product_file("oem"); + int rc = 0; + if (rc == 0 && (src.empty() || src == "system")) { + rc = do_sync_sync(system_src_path, "/system", list_only); + } + if (rc == 0 && (src.empty() || src == "vendor") && directory_exists(vendor_src_path)) { + rc = do_sync_sync(vendor_src_path, "/vendor", list_only); + } + if (rc == 0 && (src.empty() || src == "oem") && directory_exists(oem_src_path)) { + rc = do_sync_sync(oem_src_path, "/oem", list_only); + } + if (rc == 0 && (src.empty() || src == "data")) { + rc = do_sync_sync(data_src_path, "/data", list_only); + } + return rc; + } /* passthrough commands */ - - if(!strcmp(argv[0],"get-state") || + else if (!strcmp(argv[0],"get-state") || !strcmp(argv[0],"get-serialno") || !strcmp(argv[0],"get-devpath")) { @@ -1689,65 +1515,46 @@ top: format_host_command(buf, sizeof buf, argv[0], ttype, serial); tmp = adb_query(buf); - if(tmp) { + if (tmp) { printf("%s\n", tmp); return 0; } else { return 1; } } - /* other commands */ - - if(!strcmp(argv[0],"status-window")) { + else if (!strcmp(argv[0],"status-window")) { status_window(ttype, serial); return 0; } - - if(!strcmp(argv[0],"logcat") || !strcmp(argv[0],"lolcat") || !strcmp(argv[0],"longcat")) { + else if (!strcmp(argv[0],"logcat") || !strcmp(argv[0],"lolcat") || !strcmp(argv[0],"longcat")) { return logcat(ttype, serial, argc, argv); } - - if(!strcmp(argv[0],"ppp")) { + else if (!strcmp(argv[0],"ppp")) { return ppp(argc, argv); } - - if (!strcmp(argv[0], "start-server")) { + else if (!strcmp(argv[0], "start-server")) { return adb_connect("host:start-server"); } - - if (!strcmp(argv[0], "backup")) { + else if (!strcmp(argv[0], "backup")) { return backup(argc, argv); } - - if (!strcmp(argv[0], "restore")) { + else if (!strcmp(argv[0], "restore")) { return restore(argc, argv); } - - if (!strcmp(argv[0], "keygen")) { + else if (!strcmp(argv[0], "keygen")) { if (argc < 2) return usage(); return adb_auth_keygen(argv[1]); } - - if (!strcmp(argv[0], "jdwp")) { - int fd = adb_connect("jdwp"); - if (fd >= 0) { - read_and_dump(fd); - adb_close(fd); - return 0; - } else { - fprintf(stderr, "error: %s\n", adb_error()); - return -1; - } + else if (!strcmp(argv[0], "jdwp")) { + return adb_connect_command("jdwp"); } - /* "adb /?" is a common idiom under Windows */ - if(!strcmp(argv[0], "help") || !strcmp(argv[0], "/?")) { + else if (!strcmp(argv[0], "help") || !strcmp(argv[0], "/?")) { help(); return 0; } - - if(!strcmp(argv[0], "version")) { + else if (!strcmp(argv[0], "version")) { version(stdout); return 0; } @@ -1757,9 +1564,9 @@ top: } #define MAX_ARGV_LENGTH 16 -static int do_cmd(transport_type ttype, char* serial, char *cmd, ...) +static int do_cmd(transport_type ttype, const char* serial, const char *cmd, ...) { - char *argv[MAX_ARGV_LENGTH]; + const char *argv[MAX_ARGV_LENGTH]; int argc; va_list ap; @@ -1792,72 +1599,20 @@ static int do_cmd(transport_type ttype, char* serial, char *cmd, ...) return adb_commandline(argc, argv); } -int find_sync_dirs(const char *srcarg, - char **android_srcdir_out, char **data_srcdir_out, char **vendor_srcdir_out) -{ - char *android_srcdir = NULL, *data_srcdir = NULL, *vendor_srcdir = NULL; - struct stat st; - - if(srcarg == NULL) { - android_srcdir = product_file("system"); - data_srcdir = product_file("data"); - vendor_srcdir = product_file("vendor"); - /* Check if vendor partition exists */ - if (lstat(vendor_srcdir, &st) || !S_ISDIR(st.st_mode)) - vendor_srcdir = NULL; - } else { - /* srcarg may be "data", "system" or NULL. - * if srcarg is NULL, then both data and system are synced - */ - if(strcmp(srcarg, "system") == 0) { - android_srcdir = product_file("system"); - } else if(strcmp(srcarg, "data") == 0) { - data_srcdir = product_file("data"); - } else if(strcmp(srcarg, "vendor") == 0) { - vendor_srcdir = product_file("vendor"); - } else { - /* It's not "system", "vendor", or "data". - */ - return 1; - } - } - - if(android_srcdir_out != NULL) - *android_srcdir_out = android_srcdir; - else - free(android_srcdir); - - if(vendor_srcdir_out != NULL) - *vendor_srcdir_out = vendor_srcdir; - else - free(vendor_srcdir); - - if(data_srcdir_out != NULL) - *data_srcdir_out = data_srcdir; - else - free(data_srcdir); - return 0; -} - -static int pm_command(transport_type transport, char* serial, - int argc, char** argv) +static int pm_command(transport_type transport, const char* serial, + int argc, const char** argv) { - char buf[4096]; - - snprintf(buf, sizeof(buf), "shell:pm"); + std::string cmd = "shell:pm"; - while(argc-- > 0) { - char *quoted = escape_arg(*argv++); - strncat(buf, " ", sizeof(buf) - 1); - strncat(buf, quoted, sizeof(buf) - 1); - free(quoted); + while (argc-- > 0) { + cmd += " " + escape_arg(*argv++); } - send_shellcommand(transport, serial, buf); - return 0; + return send_shell_command(transport, serial, cmd); } -int uninstall_app(transport_type transport, char* serial, int argc, char** argv) +static int uninstall_app(transport_type transport, const char* serial, int argc, + const char** argv) { /* if the user choose the -k option, we refuse to do it until devices are out with the option to uninstall the remaining data somehow (adb/ui) */ @@ -1875,18 +1630,10 @@ int uninstall_app(transport_type transport, char* serial, int argc, char** argv) return pm_command(transport, serial, argc, argv); } -static int delete_file(transport_type transport, char* serial, char* filename) +static int delete_file(transport_type transport, const char* serial, char* filename) { - char buf[4096]; - char* quoted; - - snprintf(buf, sizeof(buf), "shell:rm -f "); - quoted = escape_arg(filename); - strncat(buf, quoted, sizeof(buf)-1); - free(quoted); - - send_shellcommand(transport, serial, buf); - return 0; + std::string cmd = "shell:rm -f " + escape_arg(filename); + return send_shell_command(transport, serial, cmd); } static const char* get_basename(const char* filename) @@ -1900,7 +1647,8 @@ static const char* get_basename(const char* filename) } } -int install_app(transport_type transport, char* serial, int argc, char** argv) +static int install_app(transport_type transport, const char* serial, int argc, + const char** argv) { static const char *const DATA_DEST = "/data/local/tmp/%s"; static const char *const SD_DEST = "/sdcard/tmp/%s"; @@ -1918,7 +1666,7 @@ int install_app(transport_type transport, char* serial, int argc, char** argv) // All other arguments passed through verbatim. int last_apk = -1; for (i = argc - 1; i >= 0; i--) { - char* file = argv[i]; + const char* file = argv[i]; char* dot = strrchr(file, '.'); if (dot && !strcasecmp(dot, ".apk")) { if (stat(file, &sb) == -1 || !S_ISREG(sb.st_mode)) { @@ -1936,7 +1684,7 @@ int install_app(transport_type transport, char* serial, int argc, char** argv) return -1; } - char* apk_file = argv[last_apk]; + const char* apk_file = argv[last_apk]; char apk_dest[PATH_MAX]; snprintf(apk_dest, sizeof apk_dest, where, get_basename(apk_file)); int err = do_sync_push(apk_file, apk_dest, 0 /* no show progress */); @@ -1946,25 +1694,25 @@ int install_app(transport_type transport, char* serial, int argc, char** argv) argv[last_apk] = apk_dest; /* destination name, not source location */ } - pm_command(transport, serial, argc, argv); + err = pm_command(transport, serial, argc, argv); cleanup_apk: delete_file(transport, serial, apk_dest); return err; } -int install_multiple_app(transport_type transport, char* serial, int argc, char** argv) +static int install_multiple_app(transport_type transport, const char* serial, int argc, + const char** argv) { - char buf[1024]; int i; struct stat sb; - unsigned long long total_size = 0; + uint64_t total_size = 0; // Find all APK arguments starting at end. // All other arguments passed through verbatim. int first_apk = -1; for (i = argc - 1; i >= 0; i--) { - char* file = argv[i]; + const char* file = argv[i]; char* dot = strrchr(file, '.'); if (dot && !strcasecmp(dot, ".apk")) { if (stat(file, &sb) == -1 || !S_ISREG(sb.st_mode)) { @@ -1984,20 +1732,22 @@ int install_multiple_app(transport_type transport, char* serial, int argc, char* return 1; } - snprintf(buf, sizeof(buf), "exec:pm install-create -S %lld", total_size); +#if defined(_WIN32) // Remove when we're using clang for Win32. + std::string cmd = android::base::StringPrintf("exec:pm install-create -S %u", (unsigned) total_size); +#else + std::string cmd = android::base::StringPrintf("exec:pm install-create -S %" PRIu64, total_size); +#endif for (i = 1; i < first_apk; i++) { - char *quoted = escape_arg(argv[i]); - strncat(buf, " ", sizeof(buf) - 1); - strncat(buf, quoted, sizeof(buf) - 1); - free(quoted); + cmd += " " + escape_arg(argv[i]); } // Create install session - int fd = adb_connect(buf); + int fd = adb_connect(cmd.c_str()); if (fd < 0) { fprintf(stderr, "Connect error for create: %s\n", adb_error()); return -1; } + char buf[BUFSIZ]; read_status_line(fd, buf, sizeof(buf)); adb_close(fd); @@ -2019,15 +1769,22 @@ int install_multiple_app(transport_type transport, char* serial, int argc, char* // Valid session, now stream the APKs int success = 1; for (i = first_apk; i < argc; i++) { - char* file = argv[i]; + const char* file = argv[i]; if (stat(file, &sb) == -1) { fprintf(stderr, "Failed to stat %s\n", file); success = 0; goto finalize_session; } - snprintf(buf, sizeof(buf), "exec:pm install-write -S %lld %d %d_%s -", - (long long int) sb.st_size, session_id, i, get_basename(file)); +#if defined(_WIN32) // Remove when we're using clang for Win32. + std::string cmd = android::base::StringPrintf( + "exec:pm install-write -S %u %d %d_%s -", + (unsigned) sb.st_size, session_id, i, get_basename(file)); +#else + std::string cmd = android::base::StringPrintf( + "exec:pm install-write -S %" PRIu64 " %d %d_%s -", + static_cast<uint64_t>(sb.st_size), session_id, i, get_basename(file)); +#endif int localFd = adb_open(file, O_RDONLY); if (localFd < 0) { @@ -2036,7 +1793,7 @@ int install_multiple_app(transport_type transport, char* serial, int argc, char* goto finalize_session; } - int remoteFd = adb_connect(buf); + int remoteFd = adb_connect(cmd.c_str()); if (remoteFd < 0) { fprintf(stderr, "Connect error for write: %s\n", adb_error()); adb_close(localFd); diff --git a/adb/console.c b/adb/console.cpp index b813d33..452ee41 100644 --- a/adb/console.c +++ b/adb/console.cpp @@ -24,7 +24,7 @@ static int connect_to_console(void) } -int adb_send_emulator_command(int argc, char** argv) +int adb_send_emulator_command(int argc, const char** argv) { int fd, nn; diff --git a/adb/fdevent.c b/adb/fdevent.cpp index 43e600c..0c43c5e 100644 --- a/adb/fdevent.c +++ b/adb/fdevent.cpp @@ -15,25 +15,23 @@ ** limitations under the License. */ -#include <sys/ioctl.h> +#define TRACE_TAG TRACE_FDEVENT -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> +#include "sysdeps.h" +#include "fdevent.h" +#include <errno.h> #include <fcntl.h> - #include <stdarg.h> #include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/ioctl.h> +#include <unistd.h> +#include "adb_io.h" #include "adb_trace.h" -#include "fdevent.h" -#include "transport.h" -#include "sysdeps.h" - -#define TRACE_TAG TRACE_FDEVENT /* !!! Do not enable DEBUG for the adb that will run as the server: ** both stdout and stderr are used to communicate between the client @@ -88,6 +86,12 @@ static void fdevent_subproc_event_func(int fd, unsigned events, void *userdata); static fdevent list_pending = { .next = &list_pending, .prev = &list_pending, + .fd = -1, + .force_eof = 0, + .state = 0, + .events = 0, + .func = nullptr, + .arg = nullptr, }; static fdevent **fd_table = 0; @@ -312,7 +316,7 @@ static int fdevent_fd_check(fd_set *fds) } #if !DEBUG -static inline void dump_all_fds(const char *extra_msg) {} +static inline void dump_all_fds(const char* /* extra_msg */) {} #else static void dump_all_fds(const char *extra_msg) { @@ -434,7 +438,8 @@ static void fdevent_register(fdevent *fde) while(fd_table_max <= fde->fd) { fd_table_max *= 2; } - fd_table = realloc(fd_table, sizeof(fdevent*) * fd_table_max); + fd_table = reinterpret_cast<fdevent**>( + realloc(fd_table, sizeof(fdevent*) * fd_table_max)); if(fd_table == 0) { FATAL("could not expand fd_table to %d entries\n", fd_table_max); } @@ -505,7 +510,8 @@ static void fdevent_call_fdfunc(fdevent* fde) fde->func(fde->fd, events, fde->arg); } -static void fdevent_subproc_event_func(int fd, unsigned ev, void *userdata) +static void fdevent_subproc_event_func(int fd, unsigned ev, + void* /* userdata */) { D("subproc handling on fd=%d ev=%04x\n", fd, ev); @@ -520,7 +526,7 @@ static void fdevent_subproc_event_func(int fd, unsigned ev, void *userdata) if(ev & FDE_READ){ int subproc_fd; - if(readx(fd, &subproc_fd, sizeof(subproc_fd))) { + if(!ReadFdExactly(fd, &subproc_fd, sizeof(subproc_fd))) { FATAL("Failed to read the subproc's fd from fd=%d\n", fd); } if((subproc_fd < 0) || (subproc_fd >= fd_table_max)) { @@ -579,6 +585,7 @@ void fdevent_destroy(fdevent *fde) FATAL("fde %p not created by fdevent_create()\n", fde); } fdevent_remove(fde); + free(fde); } void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg) @@ -661,6 +668,8 @@ void fdevent_subproc_setup() if(adb_socketpair(s)) { FATAL("cannot create shell-exit socket-pair\n"); } + D("socketpair: (%d,%d)", s[0], s[1]); + SHELL_EXIT_NOTIFY_FD = s[0]; fdevent *fde; fde = fdevent_create(s[1], fdevent_subproc_event_func, NULL); diff --git a/adb/fdevent.h b/adb/fdevent.h index a0ebe2a..8d84b29 100644 --- a/adb/fdevent.h +++ b/adb/fdevent.h @@ -28,7 +28,7 @@ /* features that may be set (via the events set/add/del interface) */ #define FDE_DONT_CLOSE 0x0080 -typedef struct fdevent fdevent; +struct fdevent; typedef void (*fd_func)(int fd, unsigned events, void *userdata); @@ -64,20 +64,18 @@ void fdevent_set_timeout(fdevent *fde, int64_t timeout_ms); */ void fdevent_loop(); -struct fdevent -{ +struct fdevent { fdevent *next; fdevent *prev; int fd; int force_eof; - unsigned short state; - unsigned short events; + uint16_t state; + uint16_t events; fd_func func; void *arg; }; - #endif diff --git a/adb/file_sync_client.c b/adb/file_sync_client.cpp index ad59e81..49d8783 100644 --- a/adb/file_sync_client.c +++ b/adb/file_sync_client.cpp @@ -14,25 +14,25 @@ * limitations under the License. */ +#include <dirent.h> +#include <errno.h> +#include <limits.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <errno.h> #include <sys/stat.h> #include <sys/time.h> -#include <time.h> -#include <dirent.h> -#include <limits.h> #include <sys/types.h> -#include <zipfile/zipfile.h> +#include <time.h> #include <utime.h> #include "sysdeps.h" + #include "adb.h" #include "adb_client.h" +#include "adb_io.h" #include "file_sync_service.h" - static unsigned long long total_bytes; static long long start_time; @@ -86,7 +86,7 @@ void sync_quit(int fd) msg.req.id = ID_QUIT; msg.req.namelen = 0; - writex(fd, &msg.req, sizeof(msg.req)); + WriteFdExactly(fd, &msg.req, sizeof(msg.req)); } typedef void (*sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char *name, void *cookie); @@ -103,20 +103,20 @@ int sync_ls(int fd, const char *path, sync_ls_cb func, void *cookie) msg.req.id = ID_LIST; msg.req.namelen = htoll(len); - if(writex(fd, &msg.req, sizeof(msg.req)) || - writex(fd, path, len)) { + if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) || + !WriteFdExactly(fd, path, len)) { goto fail; } for(;;) { - if(readx(fd, &msg.dent, sizeof(msg.dent))) break; + if(!ReadFdExactly(fd, &msg.dent, sizeof(msg.dent))) break; if(msg.dent.id == ID_DONE) return 0; if(msg.dent.id != ID_DENT) break; len = ltohl(msg.dent.namelen); if(len > 256) break; - if(readx(fd, buf, len)) break; + if(!ReadFdExactly(fd, buf, len)) break; buf[len] = 0; func(ltohl(msg.dent.mode), @@ -130,8 +130,6 @@ fail: return -1; } -typedef struct syncsendbuf syncsendbuf; - struct syncsendbuf { unsigned id; unsigned size; @@ -149,12 +147,12 @@ int sync_readtime(int fd, const char *path, unsigned int *timestamp, msg.req.id = ID_STAT; msg.req.namelen = htoll(len); - if(writex(fd, &msg.req, sizeof(msg.req)) || - writex(fd, path, len)) { + if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) || + !WriteFdExactly(fd, path, len)) { return -1; } - if(readx(fd, &msg.stat, sizeof(msg.stat))) { + if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat))) { return -1; } @@ -175,8 +173,8 @@ static int sync_start_readtime(int fd, const char *path) msg.req.id = ID_STAT; msg.req.namelen = htoll(len); - if(writex(fd, &msg.req, sizeof(msg.req)) || - writex(fd, path, len)) { + if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) || + !WriteFdExactly(fd, path, len)) { return -1; } @@ -188,7 +186,7 @@ static int sync_finish_readtime(int fd, unsigned int *timestamp, { syncmsg msg; - if(readx(fd, &msg.stat, sizeof(msg.stat))) + if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat))) return -1; if(msg.stat.id != ID_STAT) @@ -209,12 +207,12 @@ int sync_readmode(int fd, const char *path, unsigned *mode) msg.req.id = ID_STAT; msg.req.namelen = htoll(len); - if(writex(fd, &msg.req, sizeof(msg.req)) || - writex(fd, path, len)) { + if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) || + !WriteFdExactly(fd, path, len)) { return -1; } - if(readx(fd, &msg.stat, sizeof(msg.stat))) { + if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat))) { return -1; } @@ -240,7 +238,7 @@ static int write_data_file(int fd, const char *path, syncsendbuf *sbuf, int show if (show_progress) { // Determine local file size. struct stat st; - if (fstat(lfd, &st)) { + if (stat(path, &st)) { fprintf(stderr,"cannot stat '%s': %s\n", path, strerror(errno)); return -1; } @@ -264,7 +262,7 @@ static int write_data_file(int fd, const char *path, syncsendbuf *sbuf, int show } sbuf->size = htoll(ret); - if(writex(fd, sbuf, sizeof(unsigned) * 2 + ret)){ + if(!WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + ret)){ err = -1; break; } @@ -294,7 +292,7 @@ static int write_data_buffer(int fd, char* file_buffer, int size, syncsendbuf *s memcpy(sbuf->data, &file_buffer[total], count); sbuf->size = htoll(count); - if(writex(fd, sbuf, sizeof(unsigned) * 2 + count)){ + if(!WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + count)){ err = -1; break; } @@ -309,7 +307,9 @@ static int write_data_buffer(int fd, char* file_buffer, int size, syncsendbuf *s return err; } -#ifdef HAVE_SYMLINKS +#if defined(_WIN32) +extern int write_data_link(int fd, const char *path, syncsendbuf *sbuf) __attribute__((error("no symlinks on Windows"))); +#else static int write_data_link(int fd, const char *path, syncsendbuf *sbuf) { int len, ret; @@ -324,7 +324,7 @@ static int write_data_link(int fd, const char *path, syncsendbuf *sbuf) sbuf->size = htoll(len + 1); sbuf->id = ID_DATA; - ret = writex(fd, sbuf, sizeof(unsigned) * 2 + len + 1); + ret = !WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + len + 1); if(ret) return -1; @@ -353,8 +353,8 @@ static int sync_send(int fd, const char *lpath, const char *rpath, msg.req.id = ID_SEND; msg.req.namelen = htoll(len + r); - if(writex(fd, &msg.req, sizeof(msg.req)) || - writex(fd, rpath, len) || writex(fd, tmp, r)) { + if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) || + !WriteFdExactly(fd, rpath, len) || !WriteFdExactly(fd, tmp, r)) { free(file_buffer); goto fail; } @@ -364,26 +364,24 @@ static int sync_send(int fd, const char *lpath, const char *rpath, free(file_buffer); } else if (S_ISREG(mode)) write_data_file(fd, lpath, sbuf, show_progress); -#ifdef HAVE_SYMLINKS else if (S_ISLNK(mode)) write_data_link(fd, lpath, sbuf); -#endif else goto fail; msg.data.id = ID_DONE; msg.data.size = htoll(mtime); - if(writex(fd, &msg.data, sizeof(msg.data))) + if(!WriteFdExactly(fd, &msg.data, sizeof(msg.data))) goto fail; - if(readx(fd, &msg.status, sizeof(msg.status))) + if(!ReadFdExactly(fd, &msg.status, sizeof(msg.status))) return -1; if(msg.status.id != ID_OKAY) { if(msg.status.id == ID_FAIL) { len = ltohl(msg.status.msglen); if(len > 256) len = 256; - if(readx(fd, sbuf->data, len)) { + if(!ReadFdExactly(fd, sbuf->data, len)) { return -1; } sbuf->data[len] = 0; @@ -439,12 +437,12 @@ int sync_recv(int fd, const char *rpath, const char *lpath, int show_progress) stat_msg.req.id = ID_STAT; stat_msg.req.namelen = htoll(len); - if (writex(fd, &stat_msg.req, sizeof(stat_msg.req)) || - writex(fd, rpath, len)) { + if (!WriteFdExactly(fd, &stat_msg.req, sizeof(stat_msg.req)) || + !WriteFdExactly(fd, rpath, len)) { return -1; } - if (readx(fd, &stat_msg.stat, sizeof(stat_msg.stat))) { + if (!ReadFdExactly(fd, &stat_msg.stat, sizeof(stat_msg.stat))) { return -1; } @@ -455,12 +453,12 @@ int sync_recv(int fd, const char *rpath, const char *lpath, int show_progress) msg.req.id = ID_RECV; msg.req.namelen = htoll(len); - if(writex(fd, &msg.req, sizeof(msg.req)) || - writex(fd, rpath, len)) { + if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) || + !WriteFdExactly(fd, rpath, len)) { return -1; } - if(readx(fd, &msg.data, sizeof(msg.data))) { + if(!ReadFdExactly(fd, &msg.data, sizeof(msg.data))) { return -1; } id = msg.data.id; @@ -479,7 +477,7 @@ int sync_recv(int fd, const char *rpath, const char *lpath, int show_progress) } for(;;) { - if(readx(fd, &msg.data, sizeof(msg.data))) { + if(!ReadFdExactly(fd, &msg.data, sizeof(msg.data))) { return -1; } id = msg.data.id; @@ -494,12 +492,12 @@ int sync_recv(int fd, const char *rpath, const char *lpath, int show_progress) return -1; } - if(readx(fd, buffer, len)) { + if(!ReadFdExactly(fd, buffer, len)) { adb_close(lfd); return -1; } - if(writex(lfd, buffer, len)) { + if(!WriteFdExactly(lfd, buffer, len)) { fprintf(stderr,"cannot write '%s': %s\n", rpath, strerror(errno)); adb_close(lfd); return -1; @@ -522,24 +520,19 @@ remote_error: if(id == ID_FAIL) { len = ltohl(msg.data.size); if(len > 256) len = 256; - if(readx(fd, buffer, len)) { + if(!ReadFdExactly(fd, buffer, len)) { return -1; } buffer[len] = 0; } else { memcpy(buffer, &id, 4); buffer[4] = 0; -// strcpy(buffer,"unknown reason"); } fprintf(stderr,"failed to copy '%s' to '%s': %s\n", rpath, lpath, buffer); return 0; } - - /* --- */ - - static void do_sync_ls_cb(unsigned mode, unsigned size, unsigned time, const char *name, void *cookie) { @@ -562,8 +555,6 @@ int do_sync_ls(const char *path) } } -typedef struct copyinfo copyinfo; - struct copyinfo { copyinfo *next; @@ -573,7 +564,6 @@ struct copyinfo unsigned int mode; unsigned int size; int flag; - //char data[0]; }; copyinfo *mkcopyinfo(const char *spath, const char *dpath, @@ -585,7 +575,8 @@ copyinfo *mkcopyinfo(const char *spath, const char *dpath, int ssize = slen + nlen + 2; int dsize = dlen + nlen + 2; - copyinfo *ci = malloc(sizeof(copyinfo) + ssize + dsize); + copyinfo *ci = reinterpret_cast<copyinfo*>( + malloc(sizeof(copyinfo) + ssize + dsize)); if(ci == 0) { fprintf(stderr,"out of memory\n"); abort(); @@ -601,7 +592,6 @@ copyinfo *mkcopyinfo(const char *spath, const char *dpath, snprintf((char*) ci->src, ssize, isdir ? "%s%s/" : "%s%s", spath, name); snprintf((char*) ci->dst, dsize, isdir ? "%s%s/" : "%s%s", dpath, name); -// fprintf(stderr,"mkcopyinfo('%s','%s')\n", ci->src, ci->dst); return ci; } @@ -615,8 +605,6 @@ static int local_build_list(copyinfo **filelist, copyinfo *dirlist = 0; copyinfo *ci, *next; -// fprintf(stderr,"local_build_list('%s','%s')\n", lpath, rpath); - d = opendir(lpath); if(d == 0) { fprintf(stderr,"cannot open '%s': %s\n", lpath, strerror(errno)); @@ -692,14 +680,14 @@ static int copy_local_dir_remote(int fd, const char *lpath, const char *rpath, i if((lpath[0] == 0) || (rpath[0] == 0)) return -1; if(lpath[strlen(lpath) - 1] != '/') { int tmplen = strlen(lpath)+2; - char *tmp = malloc(tmplen); + char *tmp = reinterpret_cast<char*>(malloc(tmplen)); if(tmp == 0) return -1; snprintf(tmp, tmplen, "%s/",lpath); lpath = tmp; } if(rpath[strlen(rpath) - 1] != '/') { int tmplen = strlen(rpath)+2; - char *tmp = malloc(tmplen); + char *tmp = reinterpret_cast<char*>(malloc(tmplen)); if(tmp == 0) return -1; snprintf(tmp, tmplen, "%s/",rpath); rpath = tmp; @@ -792,7 +780,8 @@ int do_sync_push(const char *lpath, const char *rpath, int show_progress) name++; } int tmplen = strlen(name) + strlen(rpath) + 2; - char *tmp = malloc(strlen(name) + strlen(rpath) + 2); + char *tmp = reinterpret_cast<char*>( + malloc(strlen(name) + strlen(rpath) + 2)); if(tmp == 0) return 1; snprintf(tmp, tmplen, "%s/%s", rpath, name); rpath = tmp; @@ -811,12 +800,12 @@ int do_sync_push(const char *lpath, const char *rpath, int show_progress) } -typedef struct { +struct sync_ls_build_list_cb_args { copyinfo **filelist; copyinfo **dirlist; const char *rpath; const char *lpath; -} sync_ls_build_list_cb_args; +}; void sync_ls_build_list_cb(unsigned mode, unsigned size, unsigned time, @@ -880,7 +869,7 @@ static int remote_build_list(int syncfd, copyinfo **filelist, return 0; } -static int set_time_and_mode(const char *lpath, unsigned int time, unsigned int mode) +static int set_time_and_mode(const char *lpath, time_t time, unsigned int mode) { struct utimbuf times = { time, time }; int r1 = utime(lpath, ×); @@ -893,6 +882,21 @@ static int set_time_and_mode(const char *lpath, unsigned int time, unsigned int return r1 ? : r2; } +/* Return a copy of the path string with / appended if needed */ +static char *add_slash_to_path(const char *path) +{ + if (path[strlen(path) - 1] != '/') { + size_t len = strlen(path) + 2; + char *path_with_slash = reinterpret_cast<char*>(malloc(len)); + if (path_with_slash == NULL) + return NULL; + snprintf(path_with_slash, len, "%s/", path); + return path_with_slash; + } else { + return strdup(path); + } +} + static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath, int copy_attrs) { @@ -900,28 +904,32 @@ static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath, copyinfo *ci, *next; int pulled = 0; int skipped = 0; + char *rpath_clean = NULL; + char *lpath_clean = NULL; + int ret = 0; + + if (rpath[0] == '\0' || lpath[0] == '\0') { + ret = -1; + goto finish; + } /* Make sure that both directory paths end in a slash. */ - if (rpath[0] == 0 || lpath[0] == 0) return -1; - if (rpath[strlen(rpath) - 1] != '/') { - int tmplen = strlen(rpath) + 2; - char *tmp = malloc(tmplen); - if (tmp == 0) return -1; - snprintf(tmp, tmplen, "%s/", rpath); - rpath = tmp; + rpath_clean = add_slash_to_path(rpath); + if (!rpath_clean) { + ret = -1; + goto finish; } - if (lpath[strlen(lpath) - 1] != '/') { - int tmplen = strlen(lpath) + 2; - char *tmp = malloc(tmplen); - if (tmp == 0) return -1; - snprintf(tmp, tmplen, "%s/", lpath); - lpath = tmp; + lpath_clean = add_slash_to_path(lpath); + if (!lpath_clean) { + ret = -1; + goto finish; } - fprintf(stderr, "pull: building file list...\n"); /* Recursively build the list of files to copy. */ - if (remote_build_list(fd, &filelist, rpath, lpath)) { - return -1; + fprintf(stderr, "pull: building file list...\n"); + if (remote_build_list(fd, &filelist, rpath_clean, lpath_clean)) { + ret = -1; + goto finish; } for (ci = filelist; ci != 0; ci = next) { @@ -929,11 +937,13 @@ static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath, if (ci->flag == 0) { fprintf(stderr, "pull: %s -> %s\n", ci->src, ci->dst); if (sync_recv(fd, ci->src, ci->dst, 0 /* no show progress */)) { - return 1; + ret = -1; + goto finish; } if (copy_attrs && set_time_and_mode(ci->dst, ci->time, ci->mode)) { - return 1; + ret = -1; + goto finish; } pulled++; } else { @@ -946,7 +956,10 @@ static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath, pulled, (pulled == 1) ? "" : "s", skipped, (skipped == 1) ? "" : "s"); - return 0; +finish: + free(lpath_clean); + free(rpath_clean); + return ret; } int do_sync_pull(const char *rpath, const char *lpath, int show_progress, int copy_attrs) @@ -983,7 +996,7 @@ int do_sync_pull(const char *rpath, const char *lpath, int show_progress, int co name++; } int tmplen = strlen(name) + strlen(lpath) + 2; - char *tmp = malloc(tmplen); + char *tmp = reinterpret_cast<char*>(malloc(tmplen)); if(tmp == 0) return 1; snprintf(tmp, tmplen, "%s/%s", lpath, name); lpath = tmp; @@ -1014,18 +1027,18 @@ int do_sync_pull(const char *rpath, const char *lpath, int show_progress, int co } } -int do_sync_sync(const char *lpath, const char *rpath, int listonly) +int do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only) { - fprintf(stderr,"syncing %s...\n",rpath); + fprintf(stderr, "syncing %s...\n", rpath.c_str()); int fd = adb_connect("sync:"); - if(fd < 0) { - fprintf(stderr,"error: %s\n", adb_error()); + if (fd < 0) { + fprintf(stderr, "error: %s\n", adb_error()); return 1; } BEGIN(); - if(copy_local_dir_remote(fd, lpath, rpath, 1, listonly)){ + if (copy_local_dir_remote(fd, lpath.c_str(), rpath.c_str(), 1, list_only)) { return 1; } else { END(); diff --git a/adb/file_sync_service.c b/adb/file_sync_service.cpp index 7933858..e8e9a0f 100644 --- a/adb/file_sync_service.c +++ b/adb/file_sync_service.cpp @@ -14,34 +14,31 @@ * limitations under the License. */ -#include <stdlib.h> +#define TRACE_TAG TRACE_SYNC + +#include "sysdeps.h" +#include "file_sync_service.h" + +#include <dirent.h> +#include <errno.h> +#include <selinux/android.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> - #include <sys/stat.h> #include <sys/types.h> -#include <dirent.h> -#include <utime.h> #include <unistd.h> +#include <utime.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 bool is_on_vendor(const char *name) { - const char *VENDOR = "/vendor/"; - return (strncmp(VENDOR, name, strlen(VENDOR)) == 0); +#include "adb_io.h" +#include "private/android_filesystem_config.h" + +static bool should_use_fs_config(const char* path) { + // TODO: use fs_config to configure permissions on /data. + return strncmp("/system/", path, strlen("/system/")) == 0 || + strncmp("/vendor/", path, strlen("/vendor/")) == 0 || + strncmp("/oem/", path, strlen("/oem/")) == 0; } static int mkdirs(char *name) @@ -59,7 +56,7 @@ static int mkdirs(char *name) x = adb_dirstart(x); if(x == 0) return 0; *x = 0; - if (is_on_system(name) || is_on_vendor(name)) { + if (should_use_fs_config(name)) { fs_config(name, 1, &uid, &gid, &mode, &cap); } ret = adb_mkdir(name, mode); @@ -97,7 +94,7 @@ static int do_stat(int s, const char *path) msg.stat.time = htoll(st.st_mtime); } - return writex(s, &msg.stat, sizeof(msg.stat)); + return WriteFdExactly(s, &msg.stat, sizeof(msg.stat)) ? 0 : -1; } static int do_list(int s, const char *path) @@ -135,8 +132,8 @@ static int do_list(int s, const char *path) msg.dent.time = htoll(st.st_mtime); msg.dent.namelen = htoll(len); - if(writex(s, &msg.dent, sizeof(msg.dent)) || - writex(s, de->d_name, len)) { + if(!WriteFdExactly(s, &msg.dent, sizeof(msg.dent)) || + !WriteFdExactly(s, de->d_name, len)) { closedir(d); return -1; } @@ -151,7 +148,7 @@ done: msg.dent.size = 0; msg.dent.time = 0; msg.dent.namelen = 0; - return writex(s, &msg.dent, sizeof(msg.dent)); + return WriteFdExactly(s, &msg.dent, sizeof(msg.dent)) ? 0 : -1; } static int fail_message(int s, const char *reason) @@ -163,8 +160,8 @@ static int fail_message(int s, const char *reason) msg.data.id = ID_FAIL; msg.data.size = htoll(len); - if(writex(s, &msg.data, sizeof(msg.data)) || - writex(s, reason, len)) { + if(!WriteFdExactly(s, &msg.data, sizeof(msg.data)) || + !WriteFdExactly(s, reason, len)) { return -1; } else { return 0; @@ -217,7 +214,7 @@ static int handle_send_file(int s, char *path, uid_t uid, for(;;) { unsigned int len; - if(readx(s, &msg.data, sizeof(msg.data))) + if(!ReadFdExactly(s, &msg.data, sizeof(msg.data))) goto fail; if(msg.data.id != ID_DATA) { @@ -233,12 +230,12 @@ static int handle_send_file(int s, char *path, uid_t uid, fail_message(s, "oversize data message"); goto fail; } - if(readx(s, buffer, len)) + if(!ReadFdExactly(s, buffer, len)) goto fail; if(fd < 0) continue; - if(writex(fd, buffer, len)) { + if(!WriteFdExactly(fd, buffer, len)) { int saved_errno = errno; adb_close(fd); if (do_unlink) adb_unlink(path); @@ -258,7 +255,7 @@ static int handle_send_file(int s, char *path, uid_t uid, msg.status.id = ID_OKAY; msg.status.msglen = 0; - if(writex(s, &msg.status, sizeof(msg.status))) + if(!WriteFdExactly(s, &msg.status, sizeof(msg.status))) return -1; } return 0; @@ -270,14 +267,16 @@ fail: return -1; } -#ifdef HAVE_SYMLINKS +#if defined(_WIN32) +extern int handle_send_link(int s, char *path, char *buffer) __attribute__((error("no symlinks on Windows"))); +#else static int handle_send_link(int s, char *path, char *buffer) { syncmsg msg; unsigned int len; int ret; - if(readx(s, &msg.data, sizeof(msg.data))) + if(!ReadFdExactly(s, &msg.data, sizeof(msg.data))) return -1; if(msg.data.id != ID_DATA) { @@ -290,7 +289,7 @@ static int handle_send_link(int s, char *path, char *buffer) fail_message(s, "oversize data message"); return -1; } - if(readx(s, buffer, len)) + if(!ReadFdExactly(s, buffer, len)) return -1; ret = symlink(buffer, path); @@ -306,13 +305,13 @@ static int handle_send_link(int s, char *path, char *buffer) return -1; } - if(readx(s, &msg.data, sizeof(msg.data))) + if(!ReadFdExactly(s, &msg.data, sizeof(msg.data))) return -1; if(msg.data.id == ID_DONE) { msg.status.id = ID_OKAY; msg.status.msglen = 0; - if(writex(s, &msg.status, sizeof(msg.status))) + if(!WriteFdExactly(s, &msg.status, sizeof(msg.status))) return -1; } else { fail_message(s, "invalid data message: expected ID_DONE"); @@ -321,25 +320,20 @@ static int handle_send_link(int s, char *path, char *buffer) return 0; } -#endif /* HAVE_SYMLINKS */ +#endif static int do_send(int s, char *path, char *buffer) { - char *tmp; unsigned int mode; - int is_link, ret; + bool is_link = false; bool do_unlink; - tmp = strrchr(path,','); + char* tmp = strrchr(path,','); if(tmp) { *tmp = 0; errno = 0; mode = strtoul(tmp + 1, NULL, 0); -#ifndef HAVE_SYMLINKS - is_link = 0; -#else is_link = S_ISLNK((mode_t) mode); -#endif mode &= 0777; } if(!tmp || errno) { @@ -355,32 +349,26 @@ static int do_send(int s, char *path, char *buffer) } } -#ifdef HAVE_SYMLINKS - if(is_link) - ret = handle_send_link(s, path, buffer); - else { -#else - { -#endif - uid_t uid = -1; - gid_t gid = -1; - uint64_t cap = 0; + if (is_link) { + return handle_send_link(s, path, buffer); + } - /* copy user permission bits to "group" and "other" permissions */ - mode |= ((mode >> 3) & 0070); - mode |= ((mode >> 3) & 0007); + uid_t uid = -1; + gid_t gid = -1; + uint64_t cap = 0; - tmp = path; - if(*tmp == '/') { - tmp++; - } - if (is_on_system(path) || is_on_vendor(path)) { - fs_config(tmp, 0, &uid, &gid, &mode, &cap); - } - ret = handle_send_file(s, path, uid, gid, mode, buffer, do_unlink); - } + /* copy user permission bits to "group" and "other" permissions */ + mode |= ((mode >> 3) & 0070); + mode |= ((mode >> 3) & 0007); - return ret; + tmp = path; + if(*tmp == '/') { + tmp++; + } + if (should_use_fs_config(path)) { + fs_config(tmp, 0, &uid, &gid, &mode, &cap); + } + return handle_send_file(s, path, uid, gid, mode, buffer, do_unlink); } static int do_recv(int s, const char *path, char *buffer) @@ -405,8 +393,8 @@ static int do_recv(int s, const char *path, char *buffer) return r; } msg.data.size = htoll(r); - if(writex(s, &msg.data, sizeof(msg.data)) || - writex(s, buffer, r)) { + if(!WriteFdExactly(s, &msg.data, sizeof(msg.data)) || + !WriteFdExactly(s, buffer, r)) { adb_close(fd); return -1; } @@ -416,7 +404,7 @@ static int do_recv(int s, const char *path, char *buffer) msg.data.id = ID_DONE; msg.data.size = 0; - if(writex(s, &msg.data, sizeof(msg.data))) { + if(!WriteFdExactly(s, &msg.data, sizeof(msg.data))) { return -1; } @@ -429,13 +417,13 @@ void file_sync_service(int fd, void *cookie) char name[1025]; unsigned namelen; - char *buffer = malloc(SYNC_DATA_MAX); + char *buffer = reinterpret_cast<char*>(malloc(SYNC_DATA_MAX)); if(buffer == 0) goto fail; for(;;) { D("sync: waiting for command\n"); - if(readx(fd, &msg.req, sizeof(msg.req))) { + if(!ReadFdExactly(fd, &msg.req, sizeof(msg.req))) { fail_message(fd, "command read failure"); break; } @@ -444,7 +432,7 @@ void file_sync_service(int fd, void *cookie) fail_message(fd, "invalid namelen"); break; } - if(readx(fd, name, namelen)) { + if(!ReadFdExactly(fd, name, namelen)) { fail_message(fd, "filename read failure"); break; } diff --git a/adb/file_sync_service.h b/adb/file_sync_service.h index 5dd2e80..344eb98 100644 --- a/adb/file_sync_service.h +++ b/adb/file_sync_service.h @@ -17,22 +17,12 @@ #ifndef _FILE_SYNC_SERVICE_H_ #define _FILE_SYNC_SERVICE_H_ -#ifdef HAVE_BIG_ENDIAN -static inline unsigned __swap_uint32(unsigned x) -{ - return (((x) & 0xFF000000) >> 24) - | (((x) & 0x00FF0000) >> 8) - | (((x) & 0x0000FF00) << 8) - | (((x) & 0x000000FF) << 24); -} -#define htoll(x) __swap_uint32(x) -#define ltohl(x) __swap_uint32(x) -#define MKID(a,b,c,d) ((d) | ((c) << 8) | ((b) << 16) | ((a) << 24)) -#else +#include <string> + #define htoll(x) (x) #define ltohl(x) (x) + #define MKID(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24)) -#endif #define ID_STAT MKID('S','T','A','T') #define ID_LIST MKID('L','I','S','T') @@ -46,7 +36,7 @@ static inline unsigned __swap_uint32(unsigned x) #define ID_FAIL MKID('F','A','I','L') #define ID_QUIT MKID('Q','U','I','T') -typedef union { +union syncmsg { unsigned id; struct { unsigned id; @@ -73,13 +63,13 @@ typedef union { unsigned id; unsigned msglen; } status; -} syncmsg; +} ; void file_sync_service(int fd, void *cookie); int do_sync_ls(const char *path); int do_sync_push(const char *lpath, const char *rpath, int show_progress); -int do_sync_sync(const char *lpath, const char *rpath, int listonly); +int do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only); int do_sync_pull(const char *rpath, const char *lpath, int show_progress, int pullTime); #define SYNC_DATA_MAX (64*1024) diff --git a/adb/framebuffer_service.c b/adb/framebuffer_service.cpp index 8cbe840..7baad8b 100644 --- a/adb/framebuffer_service.c +++ b/adb/framebuffer_service.cpp @@ -14,21 +14,23 @@ * limitations under the License. */ -#include <stdlib.h> +#include <errno.h> +#include <fcntl.h> +#include <linux/fb.h> #include <stdio.h> -#include <unistd.h> +#include <stdlib.h> #include <string.h> -#include <fcntl.h> -#include <errno.h> +#include <sys/ioctl.h> +#include <sys/mman.h> #include <sys/types.h> #include <sys/wait.h> +#include <unistd.h> -#include "fdevent.h" -#include "adb.h" +#include "sysdeps.h" -#include <linux/fb.h> -#include <sys/ioctl.h> -#include <sys/mman.h> +#include "adb.h" +#include "adb_io.h" +#include "fdevent.h" /* TODO: ** - sync with vsync to avoid tearing @@ -60,28 +62,30 @@ void framebuffer_service(int fd, void *cookie) int fd_screencap; int w, h, f; int fds[2]; + pid_t pid; if (pipe2(fds, O_CLOEXEC) < 0) goto pipefail; - pid_t pid = fork(); + pid = fork(); if (pid < 0) goto done; if (pid == 0) { dup2(fds[1], STDOUT_FILENO); - close(fds[0]); - close(fds[1]); + adb_close(fds[0]); + adb_close(fds[1]); const char* command = "screencap"; const char *args[2] = {command, NULL}; execvp(command, (char**)args); exit(1); } + adb_close(fds[1]); fd_screencap = fds[0]; /* read w, h & format */ - if(readx(fd_screencap, &w, 4)) goto done; - if(readx(fd_screencap, &h, 4)) goto done; - if(readx(fd_screencap, &f, 4)) goto done; + if(!ReadFdExactly(fd_screencap, &w, 4)) goto done; + if(!ReadFdExactly(fd_screencap, &h, 4)) goto done; + if(!ReadFdExactly(fd_screencap, &f, 4)) goto done; fbinfo.version = DDMS_RAWIMAGE_VERSION; /* see hardware/hardware.h */ @@ -161,22 +165,21 @@ void framebuffer_service(int fd, void *cookie) } /* write header */ - if(writex(fd, &fbinfo, sizeof(fbinfo))) goto done; + if(!WriteFdExactly(fd, &fbinfo, sizeof(fbinfo))) goto done; /* write data */ 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(!ReadFdExactly(fd_screencap, buf, bsize)) goto done; + if(!WriteFdExactly(fd, buf, bsize)) goto done; } done: - TEMP_FAILURE_RETRY(waitpid(pid, NULL, 0)); + adb_close(fds[0]); - close(fds[0]); - close(fds[1]); + TEMP_FAILURE_RETRY(waitpid(pid, NULL, 0)); pipefail: - close(fd); + adb_close(fd); } diff --git a/adb/get_my_path_darwin.c b/adb/get_my_path_darwin.cpp index ff1396c..b0c962e 100644 --- a/adb/get_my_path_darwin.c +++ b/adb/get_my_path_darwin.cpp @@ -17,6 +17,8 @@ #import <Carbon/Carbon.h> #include <unistd.h> +#include "adb.h" + void get_my_path(char *s, size_t maxLen) { CFBundleRef mainBundle = CFBundleGetMainBundle(); diff --git a/adb/get_my_path_linux.c b/adb/get_my_path_linux.cpp index 179c3dd..11c0b21 100644 --- a/adb/get_my_path_linux.c +++ b/adb/get_my_path_linux.cpp @@ -14,10 +14,12 @@ * limitations under the License. */ -#include <sys/types.h> -#include <unistd.h> #include <limits.h> #include <stdio.h> +#include <sys/types.h> +#include <unistd.h> + +#include "adb.h" void get_my_path(char *exe, size_t maxLen) { diff --git a/adb/get_my_path_windows.c b/adb/get_my_path_windows.cpp index ddf2816..9d23e1c 100644 --- a/adb/get_my_path_windows.c +++ b/adb/get_my_path_windows.cpp @@ -14,10 +14,12 @@ * limitations under the License. */ -#include <limits.h> #include <assert.h> +#include <limits.h> #include <windows.h> +#include "adb.h" + void get_my_path(char *exe, size_t maxLen) { char *r; diff --git a/adb/jdwp_service.c b/adb/jdwp_service.cpp index cd62b55..c0f7ec2 100644 --- a/adb/jdwp_service.c +++ b/adb/jdwp_service.cpp @@ -1,12 +1,32 @@ +/* + * Copyright (C) 2015 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. + */ + /* implement the "debug-ports" and "track-debug-ports" device services */ + +#define TRACE_TAG TRACE_JDWP + #include "sysdeps.h" -#define TRACE_TAG TRACE_JDWP -#include "adb.h" + #include <errno.h> #include <stdio.h> #include <string.h> #include <unistd.h> +#include "adb.h" + /* here's how these things work. when adbd starts, it creates a unix server socket @@ -101,7 +121,6 @@ #include <sys/socket.h> #include <sys/un.h> -typedef struct JdwpProcess JdwpProcess; struct JdwpProcess { JdwpProcess* next; JdwpProcess* prev; @@ -194,7 +213,8 @@ static void jdwp_process_event(int, unsigned, void*); /* forward */ static JdwpProcess* jdwp_process_alloc( int socket ) { - JdwpProcess* proc = calloc(1,sizeof(*proc)); + JdwpProcess* proc = reinterpret_cast<JdwpProcess*>( + calloc(1, sizeof(*proc))); if (proc == NULL) { D("not enough memory to create new JDWP process\n"); @@ -234,7 +254,7 @@ jdwp_process_alloc( int socket ) static void jdwp_process_event( int socket, unsigned events, void* _proc ) { - JdwpProcess* proc = _proc; + JdwpProcess* proc = reinterpret_cast<JdwpProcess*>(_proc); if (events & FDE_READ) { if (proc->pid < 0) { @@ -415,6 +435,7 @@ FoundIt: __FUNCTION__, strerror(errno)); return -1; } + D("socketpair: (%d,%d)", fds[0], fds[1]); proc->out_fds[ proc->out_count ] = fds[1]; if (++proc->out_count == 1) @@ -433,11 +454,10 @@ FoundIt: #define JDWP_CONTROL_NAME "\0jdwp-control" #define JDWP_CONTROL_NAME_LEN (sizeof(JDWP_CONTROL_NAME)-1) -typedef struct { +struct JdwpControl { int listen_socket; fdevent* fde; - -} JdwpControl; +}; static void @@ -548,10 +568,10 @@ static JdwpControl _jdwp_control; ** this simply returns the list of known JDWP process pids **/ -typedef struct { +struct JdwpSocket { asocket socket; int pass; -} JdwpSocket; +}; static void jdwp_socket_close( asocket* s ) @@ -600,7 +620,7 @@ jdwp_socket_ready( asocket* s ) asocket* create_jdwp_service_socket( void ) { - JdwpSocket* s = calloc(sizeof(*s),1); + JdwpSocket* s = reinterpret_cast<JdwpSocket*>(calloc(sizeof(*s), 1)); if (s == NULL) return NULL; @@ -620,8 +640,6 @@ create_jdwp_service_socket( void ) ** to the client... **/ -typedef struct JdwpTracker JdwpTracker; - struct JdwpTracker { asocket socket; JdwpTracker* next; @@ -695,7 +713,7 @@ jdwp_tracker_enqueue( asocket* s, apacket* p ) asocket* create_jdwp_tracker_service_socket( void ) { - JdwpTracker* t = calloc(sizeof(*t),1); + JdwpTracker* t = reinterpret_cast<JdwpTracker*>(calloc(sizeof(*t), 1)); if (t == NULL) return NULL; @@ -732,4 +750,3 @@ init_jdwp(void) } #endif /* !ADB_HOST */ - diff --git a/adb/qemu_tracing.cpp b/adb/qemu_tracing.cpp new file mode 100644 index 0000000..f31eae8 --- /dev/null +++ b/adb/qemu_tracing.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2015 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. + */ + +/* + * Implements ADB tracing inside the emulator. + */ + +#include <stdarg.h> + +#include "sysdeps.h" +#include "qemu_tracing.h" + +/* + * Redefine open and write for qemu_pipe.h that contains inlined references + * to those routines. We will redifine them back after qemu_pipe.h inclusion. + */ + +#undef open +#undef write +#define open adb_open +#define write adb_write +#include <hardware/qemu_pipe.h> +#undef open +#undef write +#define open ___xxx_open +#define write ___xxx_write + +/* A handle to adb-debug qemud service in the emulator. */ +int adb_debug_qemu = -1; + +/* Initializes connection with the adb-debug qemud service in the emulator. */ +int adb_qemu_trace_init(void) +{ + char con_name[32]; + + if (adb_debug_qemu >= 0) { + return 0; + } + + /* adb debugging QEMUD service connection request. */ + snprintf(con_name, sizeof(con_name), "qemud:adb-debug"); + adb_debug_qemu = qemu_pipe_open(con_name); + return (adb_debug_qemu >= 0) ? 0 : -1; +} + +void adb_qemu_trace(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + char msg[1024]; + + if (adb_debug_qemu >= 0) { + vsnprintf(msg, sizeof(msg), fmt, args); + adb_write(adb_debug_qemu, msg, strlen(msg)); + } +} diff --git a/adb/qemu_tracing.h b/adb/qemu_tracing.h new file mode 100644 index 0000000..ff42d4f --- /dev/null +++ b/adb/qemu_tracing.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2015 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. + */ + +/* + * Implements ADB tracing inside the emulator. + */ + +#ifndef __QEMU_TRACING_H +#define __QEMU_TRACING_H + +/* Initializes connection with the adb-debug qemud service in the emulator. */ +int adb_qemu_trace_init(void); +void adb_qemu_trace(const char* fmt, ...); + +#endif /* __QEMU_TRACING_H */ diff --git a/adb/remount_service.c b/adb/remount_service.c deleted file mode 100644 index 36367a7..0000000 --- a/adb/remount_service.c +++ /dev/null @@ -1,170 +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 "sysdeps.h" - -#include <errno.h> -#include <fcntl.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/mount.h> -#include <unistd.h> - -#include "cutils/properties.h" - -#define TRACE_TAG TRACE_ADB -#include "adb.h" - - -static int system_ro = 1; -static int vendor_ro = 1; - -/* Returns the device used to mount a directory in /proc/mounts */ -static char *find_mount(const char *dir) -{ - int fd; - int res; - char *token = NULL; - const char delims[] = "\n"; - char buf[4096]; - - fd = unix_open("/proc/mounts", O_RDONLY | O_CLOEXEC); - if (fd < 0) - return NULL; - - buf[sizeof(buf) - 1] = '\0'; - adb_read(fd, buf, sizeof(buf) - 1); - adb_close(fd); - - token = strtok(buf, delims); - - while (token) { - char mount_dev[256]; - char mount_dir[256]; - int mount_freq; - int mount_passno; - - res = sscanf(token, "%255s %255s %*s %*s %d %d\n", - mount_dev, mount_dir, &mount_freq, &mount_passno); - mount_dev[255] = 0; - mount_dir[255] = 0; - if (res == 4 && (strcmp(dir, mount_dir) == 0)) - return strdup(mount_dev); - - token = strtok(NULL, delims); - } - return NULL; -} - -static int hasVendorPartition() -{ - struct stat info; - if (!lstat("/vendor", &info)) - if ((info.st_mode & S_IFMT) == S_IFDIR) - return true; - return false; -} - -/* Init mounts /system as read only, remount to enable writes. */ -static int remount(const char* dir, int* dir_ro) -{ - char *dev; - int fd; - int OFF = 0; - - if (dir_ro == 0) { - return 0; - } - - dev = find_mount(dir); - - if (!dev) - return -1; - - fd = unix_open(dev, O_RDONLY | O_CLOEXEC); - if (fd < 0) - return -1; - - ioctl(fd, BLKROSET, &OFF); - adb_close(fd); - - *dir_ro = mount(dev, dir, "none", MS_REMOUNT, NULL); - - free(dev); - - return *dir_ro; -} - -static void write_string(int fd, const char* str) -{ - writex(fd, str, strlen(str)); -} - -void remount_service(int fd, void *cookie) -{ - char buffer[200]; - char prop_buf[PROPERTY_VALUE_MAX]; - - bool system_verified = false, vendor_verified = false; - property_get("partition.system.verified", prop_buf, "0"); - if (!strcmp(prop_buf, "1")) { - system_verified = true; - } - - property_get("partition.vendor.verified", prop_buf, "0"); - if (!strcmp(prop_buf, "1")) { - vendor_verified = true; - } - - if (system_verified || vendor_verified) { - // Allow remount but warn of likely bad effects - bool both = system_verified && vendor_verified; - snprintf(buffer, sizeof(buffer), - "dm_verity is enabled on the %s%s%s partition%s.\n", - system_verified ? "system" : "", - both ? " and " : "", - vendor_verified ? "vendor" : "", - both ? "s" : ""); - write_string(fd, buffer); - snprintf(buffer, sizeof(buffer), - "Use \"adb disable-verity\" to disable verity.\n" - "If you do not, remount may succeed, however, you will still " - "not be able to write to these volumes.\n"); - write_string(fd, buffer); - } - - if (remount("/system", &system_ro)) { - snprintf(buffer, sizeof(buffer), "remount of system failed: %s\n",strerror(errno)); - write_string(fd, buffer); - } - - if (hasVendorPartition()) { - if (remount("/vendor", &vendor_ro)) { - snprintf(buffer, sizeof(buffer), "remount of vendor failed: %s\n",strerror(errno)); - write_string(fd, buffer); - } - } - - if (!system_ro && (!vendor_ro || !hasVendorPartition())) - write_string(fd, "remount succeeded\n"); - else { - write_string(fd, "remount failed\n"); - } - - adb_close(fd); -} - diff --git a/adb/remount_service.cpp b/adb/remount_service.cpp new file mode 100644 index 0000000..1eaee73 --- /dev/null +++ b/adb/remount_service.cpp @@ -0,0 +1,147 @@ +/* + * 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. + */ + +#define TRACE_TAG TRACE_ADB + +#include "sysdeps.h" + +#include <errno.h> +#include <fcntl.h> +#include <mntent.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mount.h> +#include <unistd.h> + +#include <string> + +#include "adb.h" +#include "adb_io.h" +#include "adb_utils.h" +#include "cutils/properties.h" + +static int system_ro = 1; +static int vendor_ro = 1; +static int oem_ro = 1; + +/* Returns the device used to mount a directory in /proc/mounts */ +static std::string find_mount(const char *dir) { + FILE* fp; + struct mntent* mentry; + char* device = NULL; + + if ((fp = setmntent("/proc/mounts", "r")) == NULL) { + return NULL; + } + while ((mentry = getmntent(fp)) != NULL) { + if (strcmp(dir, mentry->mnt_dir) == 0) { + device = mentry->mnt_fsname; + break; + } + } + endmntent(fp); + return device; +} + +int make_block_device_writable(const std::string& dev) { + int fd = unix_open(dev.c_str(), O_RDONLY | O_CLOEXEC); + if (fd == -1) { + return -1; + } + + int result = -1; + int OFF = 0; + if (!ioctl(fd, BLKROSET, &OFF)) { + result = 0; + } + adb_close(fd); + + return result; +} + +// Init mounts /system as read only, remount to enable writes. +static int remount(const char* dir, int* dir_ro) { + std::string dev(find_mount(dir)); + if (dev.empty() || make_block_device_writable(dev)) { + return -1; + } + + int rc = mount(dev.c_str(), dir, "none", MS_REMOUNT, NULL); + *dir_ro = rc; + return rc; +} + +static bool remount_partition(int fd, const char* partition, int* ro) { + if (!directory_exists(partition)) { + return true; + } + if (remount(partition, ro)) { + char buf[200]; + snprintf(buf, sizeof(buf), "remount of %s failed: %s\n", partition, strerror(errno)); + WriteStringFully(fd, buf); + return false; + } + return true; +} + +void remount_service(int fd, void* cookie) { + char prop_buf[PROPERTY_VALUE_MAX]; + + if (getuid() != 0) { + WriteStringFully(fd, "Not running as root. Try \"adb root\" first.\n"); + adb_close(fd); + return; + } + + bool system_verified = false, vendor_verified = false; + property_get("partition.system.verified", prop_buf, ""); + if (strlen(prop_buf) > 0) { + system_verified = true; + } + + property_get("partition.vendor.verified", prop_buf, ""); + if (strlen(prop_buf) > 0) { + vendor_verified = true; + } + + if (system_verified || vendor_verified) { + // Allow remount but warn of likely bad effects + bool both = system_verified && vendor_verified; + char buffer[200]; + snprintf(buffer, sizeof(buffer), + "dm_verity is enabled on the %s%s%s partition%s.\n", + system_verified ? "system" : "", + both ? " and " : "", + vendor_verified ? "vendor" : "", + both ? "s" : ""); + WriteStringFully(fd, buffer); + snprintf(buffer, sizeof(buffer), + "Use \"adb disable-verity\" to disable verity.\n" + "If you do not, remount may succeed, however, you will still " + "not be able to write to these volumes.\n"); + WriteStringFully(fd, buffer); + } + + bool success = true; + success &= remount_partition(fd, "/system", &system_ro); + success &= remount_partition(fd, "/vendor", &vendor_ro); + success &= remount_partition(fd, "/oem", &oem_ro); + + WriteStringFully(fd, success ? "remount succeeded\n" : "remount failed\n"); + + adb_close(fd); +} diff --git a/adb/usb_vendors.h b/adb/remount_service.h index cee23a1..e1763cf 100644 --- a/adb/usb_vendors.h +++ b/adb/remount_service.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * Copyright (C) 2015 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. @@ -14,12 +14,12 @@ * limitations under the License. */ -#ifndef __USB_VENDORS_H -#define __USB_VENDORS_H +#ifndef _REMOUNT_SERVICE_H_ +#define _REMOUNT_SERVICE_H_ -extern int vendorIds[]; -extern unsigned vendorIdCount; +#include <string> -void usb_vendors_init(void); +int make_block_device_writable(const std::string&); +void remount_service(int, void*); #endif diff --git a/adb/services.c b/adb/services.cpp index 21b08dc..e6c84a4 100644 --- a/adb/services.c +++ b/adb/services.cpp @@ -14,31 +14,36 @@ * limitations under the License. */ +#define TRACE_TAG TRACE_SERVICES + +#include "sysdeps.h" + +#include <errno.h> #include <stddef.h> -#include <stdlib.h> #include <stdio.h> -#include <unistd.h> +#include <stdlib.h> #include <string.h> -#include <errno.h> -#include "sysdeps.h" +#ifndef _WIN32 +#include <netdb.h> +#include <netinet/in.h> +#include <sys/ioctl.h> +#include <unistd.h> +#endif -#define TRACE_TAG TRACE_SERVICES -#include "adb.h" -#include "file_sync_service.h" +#include <base/stringprintf.h> -#if ADB_HOST -# ifndef HAVE_WINSOCK -# include <netinet/in.h> -# include <netdb.h> -# include <sys/ioctl.h> -# endif -#else -# include <cutils/android_reboot.h> -# include <cutils/properties.h> +#if !ADB_HOST +#include "base/file.h" +#include "cutils/android_reboot.h" +#include "cutils/properties.h" #endif -typedef struct stinfo stinfo; +#include "adb.h" +#include "adb_io.h" +#include "file_sync_service.h" +#include "remount_service.h" +#include "transport.h" struct stinfo { void (*func)(int fd, void *cookie); @@ -49,7 +54,7 @@ struct stinfo { void *service_bootstrap_func(void *x) { - stinfo *sti = x; + stinfo* sti = reinterpret_cast<stinfo*>(x); sti->func(sti->fd, sti->cookie); free(sti); return 0; @@ -64,20 +69,36 @@ void restart_root_service(int fd, void *cookie) if (getuid() == 0) { snprintf(buf, sizeof(buf), "adbd is already running as root\n"); - writex(fd, buf, strlen(buf)); + WriteFdExactly(fd, buf, strlen(buf)); adb_close(fd); } else { property_get("ro.debuggable", value, ""); if (strcmp(value, "1") != 0) { snprintf(buf, sizeof(buf), "adbd cannot run as root in production builds\n"); - writex(fd, buf, strlen(buf)); + WriteFdExactly(fd, buf, strlen(buf)); adb_close(fd); return; } property_set("service.adb.root", "1"); snprintf(buf, sizeof(buf), "restarting adbd as root\n"); - writex(fd, buf, strlen(buf)); + WriteFdExactly(fd, buf, strlen(buf)); + adb_close(fd); + } +} + +void restart_unroot_service(int fd, void *cookie) +{ + char buf[100]; + + if (getuid() != 0) { + snprintf(buf, sizeof(buf), "adbd not running as root\n"); + WriteFdExactly(fd, buf, strlen(buf)); + adb_close(fd); + } else { + property_set("service.adb.root", "0"); + snprintf(buf, sizeof(buf), "restarting adbd as non root\n"); + WriteFdExactly(fd, buf, strlen(buf)); adb_close(fd); } } @@ -90,7 +111,7 @@ void restart_tcp_service(int fd, void *cookie) if (port <= 0) { snprintf(buf, sizeof(buf), "invalid port\n"); - writex(fd, buf, strlen(buf)); + WriteFdExactly(fd, buf, strlen(buf)); adb_close(fd); return; } @@ -98,7 +119,7 @@ void restart_tcp_service(int fd, void *cookie) snprintf(value, sizeof(value), "%d", port); property_set("service.adb.tcp.port", value); snprintf(buf, sizeof(buf), "restarting in TCP mode port: %d\n", port); - writex(fd, buf, strlen(buf)); + WriteFdExactly(fd, buf, strlen(buf)); adb_close(fd); } @@ -108,42 +129,83 @@ void restart_usb_service(int fd, void *cookie) property_set("service.adb.tcp.port", "0"); snprintf(buf, sizeof(buf), "restarting in USB mode\n"); - writex(fd, buf, strlen(buf)); + WriteFdExactly(fd, buf, strlen(buf)); adb_close(fd); } -void reboot_service(int fd, void *arg) -{ +static bool reboot_service_impl(int fd, const char* arg) { + const char* reboot_arg = arg; + bool auto_reboot = false; + + if (strcmp(reboot_arg, "sideload-auto-reboot") == 0) { + auto_reboot = true; + reboot_arg = "sideload"; + } + char buf[100]; - char property_val[PROPERTY_VALUE_MAX]; - int ret; + // It reboots into sideload mode by setting "--sideload" or "--sideload_auto_reboot" + // in the command file. + if (strcmp(reboot_arg, "sideload") == 0) { + if (getuid() != 0) { + snprintf(buf, sizeof(buf), "'adb root' is required for 'adb reboot sideload'.\n"); + WriteStringFully(fd, buf); + return false; + } + + const char* const recovery_dir = "/cache/recovery"; + const char* const command_file = "/cache/recovery/command"; + // Ensure /cache/recovery exists. + if (adb_mkdir(recovery_dir, 0770) == -1 && errno != EEXIST) { + D("Failed to create directory '%s': %s\n", recovery_dir, strerror(errno)); + return false; + } + + bool write_status = android::base::WriteStringToFile( + auto_reboot ? "--sideload_auto_reboot" : "--sideload", command_file); + if (!write_status) { + return false; + } + + reboot_arg = "recovery"; + } sync(); - ret = snprintf(property_val, sizeof(property_val), "reboot,%s", (char *) arg); - if (ret >= (int) sizeof(property_val)) { + char property_val[PROPERTY_VALUE_MAX]; + int ret = snprintf(property_val, sizeof(property_val), "reboot,%s", reboot_arg); + if (ret >= static_cast<int>(sizeof(property_val))) { snprintf(buf, sizeof(buf), "reboot string too long. length=%d\n", ret); - writex(fd, buf, strlen(buf)); - goto cleanup; + WriteStringFully(fd, buf); + return false; } ret = property_set(ANDROID_RB_PROPERTY, property_val); if (ret < 0) { snprintf(buf, sizeof(buf), "reboot failed: %d\n", ret); - writex(fd, buf, strlen(buf)); - goto cleanup; + WriteStringFully(fd, buf); + return false; + } + + return true; +} + +void reboot_service(int fd, void* arg) +{ + if (reboot_service_impl(fd, static_cast<const char*>(arg))) { + // 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 (true) { + pause(); + } } - // 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); } void reverse_service(int fd, void* arg) { - const char* command = arg; + const char* command = reinterpret_cast<const char*>(arg); if (handle_forward_request(command, kTransportAny, NULL, fd) < 0) { sendfailmsg(fd, "not a reverse forwarding command"); @@ -156,22 +218,23 @@ void reverse_service(int fd, void* arg) static int create_service_thread(void (*func)(int, void *), void *cookie) { - stinfo *sti; - adb_thread_t t; int s[2]; - - if(adb_socketpair(s)) { + if (adb_socketpair(s)) { printf("cannot create service socket pair\n"); return -1; } + D("socketpair: (%d,%d)", s[0], s[1]); - sti = malloc(sizeof(stinfo)); - if(sti == 0) fatal("cannot allocate stinfo"); + stinfo* sti = reinterpret_cast<stinfo*>(malloc(sizeof(stinfo))); + if (sti == nullptr) { + fatal("cannot allocate stinfo"); + } sti->func = func; sti->cookie = cookie; sti->fd = s[1]; - if(adb_thread_create( &t, service_bootstrap_func, sti)){ + adb_thread_t t; + if (adb_thread_create(&t, service_bootstrap_func, sti)) { free(sti); adb_close(s[0]); adb_close(s[1]); @@ -202,10 +265,10 @@ static void init_subproc_child() static int create_subproc_pty(const char *cmd, const char *arg0, const char *arg1, pid_t *pid) { D("create_subproc_pty(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1); -#ifdef HAVE_WIN32_PROC +#if defined(_WIN32) fprintf(stderr, "error: create_subproc_pty not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1); return -1; -#else /* !HAVE_WIN32_PROC */ +#else int ptm; ptm = unix_open("/dev/ptmx", O_RDWR | O_CLOEXEC); // | O_NOCTTY); @@ -251,23 +314,24 @@ static int create_subproc_pty(const char *cmd, const char *arg0, const char *arg } else { return ptm; } -#endif /* !HAVE_WIN32_PROC */ +#endif /* !defined(_WIN32) */ } static int create_subproc_raw(const char *cmd, const char *arg0, const char *arg1, pid_t *pid) { D("create_subproc_raw(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1); -#ifdef HAVE_WIN32_PROC +#if defined(_WIN32) fprintf(stderr, "error: create_subproc_raw not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1); return -1; -#else /* !HAVE_WIN32_PROC */ +#else // 0 is parent socket, 1 is child socket int sv[2]; - if (unix_socketpair(AF_UNIX, SOCK_STREAM, 0, sv) < 0) { + if (adb_socketpair(sv) < 0) { printf("[ cannot create socket pair - %s ]\n", strerror(errno)); return -1; } + D("socketpair: (%d,%d)", sv[0], sv[1]); *pid = fork(); if (*pid < 0) { @@ -295,7 +359,7 @@ static int create_subproc_raw(const char *cmd, const char *arg0, const char *arg adb_close(sv[1]); return sv[0]; } -#endif /* !HAVE_WIN32_PROC */ +#endif /* !defined(_WIN32) */ } #endif /* !ABD_HOST */ @@ -311,7 +375,7 @@ static void subproc_waiter_service(int fd, void *cookie) pid_t pid = (pid_t) (uintptr_t) cookie; D("entered. fd=%d of pid=%d\n", fd, pid); - for (;;) { + while (true) { int status; pid_t p = waitpid(pid, &status, 0); if (p == pid) { @@ -331,7 +395,7 @@ static void subproc_waiter_service(int fd, void *cookie) D("shell exited fd=%d of pid=%d err=%d\n", fd, pid, errno); if (SHELL_EXIT_NOTIFY_FD >=0) { int res; - res = writex(SHELL_EXIT_NOTIFY_FD, &fd, sizeof(fd)); + res = WriteFdExactly(SHELL_EXIT_NOTIFY_FD, &fd, sizeof(fd)) ? 0 : -1; D("notified shell exit via fd=%d for pid=%d res=%d errno=%d\n", SHELL_EXIT_NOTIFY_FD, pid, res, errno); } @@ -339,7 +403,6 @@ static void subproc_waiter_service(int fd, void *cookie) static int create_subproc_thread(const char *name, const subproc_mode mode) { - stinfo *sti; adb_thread_t t; int ret_fd; pid_t pid = -1; @@ -364,7 +427,7 @@ static int create_subproc_thread(const char *name, const subproc_mode mode) } D("create_subproc ret_fd=%d pid=%d\n", ret_fd, pid); - sti = malloc(sizeof(stinfo)); + stinfo* sti = reinterpret_cast<stinfo*>(malloc(sizeof(stinfo))); if(sti == 0) fatal("cannot allocate stinfo"); sti->func = subproc_waiter_service; sti->cookie = (void*) (uintptr_t) pid; @@ -435,25 +498,16 @@ int service_to_fd(const char *name) ret = create_service_thread(reboot_service, arg); } else if(!strncmp(name, "root:", 5)) { ret = create_service_thread(restart_root_service, NULL); + } else if(!strncmp(name, "unroot:", 7)) { + ret = create_service_thread(restart_unroot_service, NULL); } else if(!strncmp(name, "backup:", 7)) { - char* arg = strdup(name + 7); - if (arg == NULL) return -1; - char* c = arg; - for (; *c != '\0'; c++) { - if (*c == ':') - *c = ' '; - } - char* cmd; - if (asprintf(&cmd, "/system/bin/bu backup %s", arg) != -1) { - ret = create_subproc_thread(cmd, SUBPROC_RAW); - free(cmd); - } - free(arg); + ret = create_subproc_thread(android::base::StringPrintf("/system/bin/bu backup %s", + (name + 7)).c_str(), SUBPROC_RAW); } else if(!strncmp(name, "restore:", 8)) { ret = create_subproc_thread("/system/bin/bu restore", SUBPROC_RAW); } else if(!strncmp(name, "tcpip:", 6)) { int port; - if (sscanf(name + 6, "%d", &port) == 0) { + if (sscanf(name + 6, "%d", &port) != 1) { port = 0; } ret = create_service_thread(restart_tcp_service, (void *) (uintptr_t) port); @@ -470,7 +524,9 @@ int service_to_fd(const char *name) } } } else if(!strncmp(name, "disable-verity:", 15)) { - ret = create_service_thread(disable_verity_service, NULL); + ret = create_service_thread(set_verity_enabled_state_service, (void*)0); + } else if(!strncmp(name, "enable-verity:", 15)) { + ret = create_service_thread(set_verity_enabled_state_service, (void*)1); #endif } if (ret >= 0) { @@ -488,16 +544,16 @@ struct state_info { static void wait_for_state(int fd, void* cookie) { - struct state_info* sinfo = cookie; - char* err = "unknown error"; + state_info* sinfo = reinterpret_cast<state_info*>(cookie); D("wait_for_state %d\n", sinfo->state); - atransport *t = acquire_one_transport(sinfo->state, sinfo->transport, sinfo->serial, &err); - if(t != 0) { - writex(fd, "OKAY", 4); + std::string error_msg = "unknown error"; + atransport* t = acquire_one_transport(sinfo->state, sinfo->transport, sinfo->serial, &error_msg); + if (t != 0) { + WriteFdExactly(fd, "OKAY", 4); } else { - sendfailmsg(fd, err); + sendfailmsg(fd, error_msg.c_str()); } if (sinfo->serial) @@ -523,7 +579,7 @@ static void connect_device(char* host, char* buffer, int buffer_size) } // zero terminate the host at the point we found the colon hostbuf[portstr - host] = 0; - if (sscanf(portstr + 1, "%d", &port) == 0) { + if (sscanf(portstr + 1, "%d", &port) != 1) { snprintf(buffer, buffer_size, "bad port number %s", portstr); return; } @@ -611,7 +667,7 @@ static void connect_service(int fd, void* cookie) { char buf[4096]; char resp[4096]; - char *host = cookie; + char *host = reinterpret_cast<char*>(cookie); if (!strncmp(host, "emu:", 4)) { connect_emulator(host + 4, buf, sizeof(buf)); @@ -621,7 +677,7 @@ static void connect_service(int fd, void* cookie) // Send response for emulator and device snprintf(resp, sizeof(resp), "%04x%s",(unsigned)strlen(buf), buf); - writex(fd, resp, strlen(resp)); + WriteFdExactly(fd, resp, strlen(resp)); adb_close(fd); } #endif @@ -632,7 +688,11 @@ asocket* host_service_to_socket(const char* name, const char *serial) if (!strcmp(name,"track-devices")) { return create_device_tracker(); } else if (!strncmp(name, "wait-for-", strlen("wait-for-"))) { - struct state_info* sinfo = malloc(sizeof(struct state_info)); + auto sinfo = reinterpret_cast<state_info*>(malloc(sizeof(state_info))); + if (sinfo == nullptr) { + fprintf(stderr, "couldn't allocate state_info: %s", strerror(errno)); + return NULL; + } if (serial) sinfo->serial = strdup(serial); diff --git a/adb/disable_verity_service.c b/adb/set_verity_enable_state_service.cpp index ed3da52..b75ed4c 100644 --- a/adb/disable_verity_service.c +++ b/adb/set_verity_enable_state_service.cpp @@ -14,24 +14,33 @@ * limitations under the License. */ -#include "sysdeps.h" +#define TRACE_TAG TRACE_ADB -#define TRACE_TAG TRACE_ADB -#include "adb.h" +#include "sysdeps.h" -#include <stdio.h> -#include <stdarg.h> -#include <sys/stat.h> #include <fcntl.h> #include <inttypes.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdio.h> +#include <sys/stat.h> #include "cutils/properties.h" + +#include "adb.h" #include "ext4_sb.h" -#include <fs_mgr.h> +#include "fs_mgr.h" +#include "remount_service.h" #define FSTAB_PREFIX "/fstab." struct fstab *fstab; +#ifdef ALLOW_ADBD_DISABLE_VERITY +static const bool kAllowDisableVerity = true; +#else +static const bool kAllowDisableVerity = false; +#endif + __attribute__((__format__(printf, 2, 3))) __nonnull((2)) static void write_console(int fd, const char* format, ...) { @@ -78,15 +87,23 @@ static int get_target_device_size(int fd, const char *blk_device, return 0; } -static int disable_verity(int fd, const char *block_device, - const char* mount_point) +/* Turn verity on/off */ +static int set_verity_enabled_state(int fd, const char *block_device, + const char* mount_point, bool enable) { uint32_t magic_number; - const uint32_t voff = VERITY_METADATA_MAGIC_DISABLE; - uint64_t device_length; - int device; + const uint32_t new_magic = enable ? VERITY_METADATA_MAGIC_NUMBER + : VERITY_METADATA_MAGIC_DISABLE; + uint64_t device_length = 0; + int device = -1; int retval = -1; + if (make_block_device_writable(block_device)) { + write_console(fd, "Could not make block device %s writable (%s).\n", + block_device, strerror(errno)); + goto errout; + } + device = adb_open(block_device, O_RDWR | O_CLOEXEC); if (device == -1) { write_console(fd, "Could not open block device %s (%s).\n", @@ -114,14 +131,20 @@ static int disable_verity(int fd, const char *block_device, goto errout; } - if (magic_number == VERITY_METADATA_MAGIC_DISABLE) { + if (!enable && magic_number == VERITY_METADATA_MAGIC_DISABLE) { write_console(fd, "Verity already disabled on %s\n", mount_point); goto errout; } - if (magic_number != VERITY_METADATA_MAGIC_NUMBER) { + if (enable && magic_number == VERITY_METADATA_MAGIC_NUMBER) { + write_console(fd, "Verity already enabled on %s\n", mount_point); + goto errout; + } + + if (magic_number != VERITY_METADATA_MAGIC_NUMBER + && magic_number != VERITY_METADATA_MAGIC_DISABLE) { write_console(fd, - "Couldn't find verity metadata at offset %"PRIu64"!\n", + "Couldn't find verity metadata at offset %" PRIu64 "!\n", device_length); goto errout; } @@ -132,13 +155,17 @@ static int disable_verity(int fd, const char *block_device, goto errout; } - if (adb_write(device, &voff, sizeof(voff)) != sizeof(voff)) { - write_console(fd, "Could not set verity disabled flag on device %s\n", - block_device); + if (adb_write(device, &new_magic, sizeof(new_magic)) != sizeof(new_magic)) { + write_console( + fd, "Could not set verity %s flag on device %s with error %s\n", + enable ? "enabled" : "disabled", + block_device, strerror(errno)); goto errout; } - write_console(fd, "Verity disabled on %s\n", mount_point); + write_console(fd, "Verity %s on %s\n", + enable ? "enabled" : "disabled", + mount_point); retval = 0; errout: if (device != -1) @@ -146,54 +173,59 @@ errout: return retval; } -void disable_verity_service(int fd, void* cookie) +void set_verity_enabled_state_service(int fd, void* cookie) { -#ifdef ALLOW_ADBD_DISABLE_VERITY - char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)]; - char propbuf[PROPERTY_VALUE_MAX]; - int i; - bool any_disabled = false; - - property_get("ro.secure", propbuf, "0"); - if (strcmp(propbuf, "1")) { - write_console(fd, "verity not enabled - ENG build\n"); - goto errout; + bool enable = (cookie != NULL); + if (kAllowDisableVerity) { + char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)]; + char propbuf[PROPERTY_VALUE_MAX]; + int i; + bool any_changed = false; + + property_get("ro.secure", propbuf, "0"); + if (strcmp(propbuf, "1")) { + write_console(fd, "verity not enabled - ENG build\n"); + goto errout; + } + + property_get("ro.debuggable", propbuf, "0"); + if (strcmp(propbuf, "1")) { + write_console( + fd, "verity cannot be disabled/enabled - USER build\n"); + goto errout; + } + + property_get("ro.hardware", propbuf, ""); + snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", + propbuf); + + fstab = fs_mgr_read_fstab(fstab_filename); + if (!fstab) { + write_console(fd, "Failed to open %s\nMaybe run adb root?\n", + fstab_filename); + goto errout; + } + + /* Loop through entries looking for ones that vold manages */ + for (i = 0; i < fstab->num_entries; i++) { + if(fs_mgr_is_verified(&fstab->recs[i])) { + if (!set_verity_enabled_state(fd, fstab->recs[i].blk_device, + fstab->recs[i].mount_point, + enable)) { + any_changed = true; + } + } + } + + if (any_changed) { + write_console( + fd, "Now reboot your device for settings to take effect\n"); + } + } else { + write_console(fd, "%s-verity only works for userdebug builds\n", + enable ? "enable" : "disable"); } - property_get("ro.debuggable", propbuf, "0"); - if (strcmp(propbuf, "1")) { - write_console(fd, "verity cannot be disabled - USER build\n"); - goto errout; - } - - property_get("ro.hardware", propbuf, ""); - snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf); - - fstab = fs_mgr_read_fstab(fstab_filename); - if (!fstab) { - write_console(fd, "Failed to open %s\nMaybe run adb root?\n", - fstab_filename); - goto errout; - } - - /* Loop through entries looking for ones that vold manages */ - for (i = 0; i < fstab->num_entries; i++) { - if(fs_mgr_is_verified(&fstab->recs[i])) { - if (!disable_verity(fd, fstab->recs[i].blk_device, - fstab->recs[i].mount_point)) { - any_disabled = true; - } - } - } - - if (any_disabled) { - write_console(fd, - "Now reboot your device for settings to take effect\n"); - } -#else - write_console(fd, "disable-verity only works for userdebug builds\n"); -#endif - errout: adb_close(fd); } diff --git a/adb/sockets.c b/adb/sockets.cpp index faa9564..f468029 100644 --- a/adb/sockets.c +++ b/adb/sockets.cpp @@ -14,21 +14,24 @@ * limitations under the License. */ +#define TRACE_TAG TRACE_SOCKETS + +#include "sysdeps.h" + +#include <ctype.h> +#include <errno.h> #include <stdio.h> #include <stdlib.h> -#include <unistd.h> -#include <errno.h> #include <string.h> -#include <ctype.h> - -#include "sysdeps.h" +#include <unistd.h> #if !ADB_HOST -#include <cutils/properties.h> +#include "cutils/properties.h" #endif -#define TRACE_TAG TRACE_SOCKETS #include "adb.h" +#include "adb_io.h" +#include "transport.h" ADB_MUTEX_DEFINE( socket_list_lock ); @@ -39,13 +42,17 @@ int sendfailmsg(int fd, const char *reason) char buf[9]; int len; len = strlen(reason); - if(len > 0xffff) len = 0xffff; + if (len > 0xffff) { + len = 0xffff; + } + snprintf(buf, sizeof buf, "FAIL%04x", len); - if(writex(fd, buf, 8)) return -1; - return writex(fd, reason, len); -} + if (!WriteFdExactly(fd, buf, 8)) { + return -1; + } -//extern int online; + return WriteFdExactly(fd, reason, len) ? 0 : -1; +} static unsigned local_socket_next_id = 1; @@ -196,10 +203,9 @@ enqueue: static void local_socket_ready(asocket *s) { - /* far side is ready for data, pay attention to - readable events */ + /* far side is ready for data, pay attention to + readable events */ fdevent_add(&s->fde, FDE_READ); -// D("LS(%d): ready()\n", s->id); } static void local_socket_close(asocket *s) @@ -240,7 +246,7 @@ static void local_socket_destroy(asocket *s) static void local_socket_close_locked(asocket *s) { - D("entered. LS(%d) fd=%d\n", s->id, s->fd); + D("entered local_socket_close_locked. LS(%d) fd=%d\n", s->id, s->fd); if(s->peer) { D("LS(%d): closing peer. peer->id=%d peer->fd=%d\n", s->id, s->peer->id, s->peer->fd); @@ -280,98 +286,101 @@ static void local_socket_close_locked(asocket *s) insert_local_socket(s, &local_socket_closing_list); } -static void local_socket_event_func(int fd, unsigned ev, void *_s) +static void local_socket_event_func(int fd, unsigned ev, void* _s) { - asocket *s = _s; - + asocket* s = reinterpret_cast<asocket*>(_s); D("LS(%d): event_func(fd=%d(==%d), ev=%04x)\n", s->id, s->fd, fd, ev); /* put the FDE_WRITE processing before the FDE_READ ** in order to simplify the code. */ - if(ev & FDE_WRITE){ - apacket *p; - - while((p = s->pkt_first) != 0) { - while(p->len > 0) { + if (ev & FDE_WRITE) { + apacket* p; + while ((p = s->pkt_first) != nullptr) { + while (p->len > 0) { int r = adb_write(fd, p->ptr, p->len); - if(r > 0) { - p->ptr += r; - p->len -= r; - continue; - } - if(r < 0) { + if (r == -1) { /* returning here is ok because FDE_READ will ** be processed in the next iteration loop */ - if(errno == EAGAIN) return; - if(errno == EINTR) continue; + if (errno == EAGAIN) { + return; + } + } else if (r > 0) { + p->ptr += r; + p->len -= r; + continue; } + D(" closing after write because r=%d and errno is %d\n", r, errno); s->close(s); return; } - if(p->len == 0) { + if (p->len == 0) { s->pkt_first = p->next; - if(s->pkt_first == 0) s->pkt_last = 0; + if (s->pkt_first == 0) { + s->pkt_last = 0; + } put_apacket(p); } } - /* if we sent the last packet of a closing socket, - ** we can now destroy it. - */ + /* if we sent the last packet of a closing socket, + ** we can now destroy it. + */ if (s->closing) { D(" closing because 'closing' is set after write\n"); s->close(s); return; } - /* no more packets queued, so we can ignore - ** writable events again and tell our peer - ** to resume writing - */ + /* no more packets queued, so we can ignore + ** writable events again and tell our peer + ** to resume writing + */ fdevent_del(&s->fde, FDE_WRITE); s->peer->ready(s->peer); } - if(ev & FDE_READ){ + if (ev & FDE_READ) { apacket *p = get_apacket(); unsigned char *x = p->data; size_t avail = MAX_PAYLOAD; int r; int is_eof = 0; - while(avail > 0) { + while (avail > 0) { r = adb_read(fd, x, avail); - D("LS(%d): post adb_read(fd=%d,...) r=%d (errno=%d) avail=%zu\n", s->id, s->fd, r, r<0?errno:0, avail); - if(r > 0) { + D("LS(%d): post adb_read(fd=%d,...) r=%d (errno=%d) avail=%zu\n", + s->id, s->fd, r, r < 0 ? errno : 0, avail); + if (r == -1) { + if (errno == EAGAIN) { + break; + } + } else if (r > 0) { avail -= r; x += r; continue; } - if(r < 0) { - if(errno == EAGAIN) break; - if(errno == EINTR) continue; - } - /* r = 0 or unhandled error */ + /* r = 0 or unhandled error */ is_eof = 1; break; } D("LS(%d): fd=%d post avail loop. r=%d is_eof=%d forced_eof=%d\n", s->id, s->fd, r, is_eof, s->fde.force_eof); - if((avail == MAX_PAYLOAD) || (s->peer == 0)) { + if ((avail == MAX_PAYLOAD) || (s->peer == 0)) { put_apacket(p); } else { p->len = MAX_PAYLOAD - avail; r = s->peer->enqueue(s->peer, p); - D("LS(%d): fd=%d post peer->enqueue(). r=%d\n", s->id, s->fd, r); + D("LS(%d): fd=%d post peer->enqueue(). r=%d\n", s->id, s->fd, + r); - if(r < 0) { + if (r < 0) { /* error return means they closed us as a side-effect ** and we must return immediately. ** @@ -383,7 +392,7 @@ static void local_socket_event_func(int fd, unsigned ev, void *_s) return; } - if(r > 0) { + if (r > 0) { /* if the remote cannot accept further events, ** we disable notification of READs. They'll ** be enabled again when we get a call to ready() @@ -392,18 +401,18 @@ static void local_socket_event_func(int fd, unsigned ev, void *_s) } } /* Don't allow a forced eof if data is still there */ - if((s->fde.force_eof && !r) || is_eof) { - D(" closing because is_eof=%d r=%d s->fde.force_eof=%d\n", is_eof, r, s->fde.force_eof); + if ((s->fde.force_eof && !r) || is_eof) { + D(" closing because is_eof=%d r=%d s->fde.force_eof=%d\n", + is_eof, r, s->fde.force_eof); s->close(s); } } - if(ev & FDE_ERROR){ + if (ev & FDE_ERROR){ /* this should be caught be the next read or write ** catching it here means we may skip the last few ** bytes of readable data. */ -// s->close(s); D("LS(%d): FDE_ERROR (fd=%d)\n", s->id, s->fd); return; @@ -412,7 +421,7 @@ static void local_socket_event_func(int fd, unsigned ev, void *_s) asocket *create_local_socket(int fd) { - asocket *s = calloc(1, sizeof(asocket)); + asocket *s = reinterpret_cast<asocket*>(calloc(1, sizeof(asocket))); if (s == NULL) fatal("cannot allocate socket"); s->fd = fd; s->enqueue = local_socket_enqueue; @@ -422,20 +431,12 @@ asocket *create_local_socket(int fd) install_local_socket(s); fdevent_install(&s->fde, fd, local_socket_event_func, s); -/* fdevent_add(&s->fde, FDE_ERROR); */ - //fprintf(stderr, "Created local socket in create_local_socket \n"); D("LS(%d): created (fd=%d)\n", s->id, s->fd); return s; } asocket *create_local_service_socket(const char *name) { - asocket *s; - int fd; -#if !ADB_HOST - char debug[PROPERTY_VALUE_MAX]; -#endif - #if !ADB_HOST if (!strcmp(name,"jdwp")) { return create_jdwp_service_socket(); @@ -444,18 +445,19 @@ asocket *create_local_service_socket(const char *name) return create_jdwp_tracker_service_socket(); } #endif - fd = service_to_fd(name); + int fd = service_to_fd(name); if(fd < 0) return 0; - s = create_local_socket(fd); + asocket* s = create_local_socket(fd); D("LS(%d): bound to '%s' via %d\n", s->id, name, fd); #if !ADB_HOST + char debug[PROPERTY_VALUE_MAX]; if (!strncmp(name, "root:", 5)) property_get("ro.debuggable", debug, ""); - if ((!strncmp(name, "root:", 5) && getuid() != 0 - && strcmp(debug, "1") == 0) + if ((!strncmp(name, "root:", 5) && getuid() != 0 && strcmp(debug, "1") == 0) + || (!strncmp(name, "unroot:", 7) && getuid() == 0) || !strncmp(name, "usb:", 4) || !strncmp(name, "tcpip:", 6)) { D("LS(%d): enabling exit_on_close\n", s->id); @@ -485,10 +487,10 @@ static asocket *create_host_service_socket(const char *name, const char* serial) /* a Remote socket is used to send/receive data to/from a given transport object ** it needs to be closed when the transport is forcibly destroyed by the user */ -typedef struct aremotesocket { +struct aremotesocket { asocket socket; adisconnect disconnect; -} aremotesocket; +}; static int remote_socket_enqueue(asocket *s, apacket *p) { @@ -543,8 +545,8 @@ static void remote_socket_close(asocket *s) static void remote_socket_disconnect(void* _s, atransport* t) { - asocket* s = _s; - asocket* peer = s->peer; + asocket* s = reinterpret_cast<asocket*>(_s); + asocket* peer = s->peer; D("remote_socket_disconnect RS(%d)\n", s->id); if (peer) { @@ -561,12 +563,9 @@ static void remote_socket_disconnect(void* _s, atransport* t) Returns a new non-NULL asocket handle. */ asocket *create_remote_socket(unsigned id, atransport *t) { - asocket* s; - adisconnect* dis; - if (id == 0) fatal("invalid remote socket id (0)"); - s = calloc(1, sizeof(aremotesocket)); - dis = &((aremotesocket*)s)->disconnect; + asocket* s = reinterpret_cast<asocket*>(calloc(1, sizeof(aremotesocket))); + adisconnect* dis = &reinterpret_cast<aremotesocket*>(s)->disconnect; if (s == NULL) fatal("cannot allocate socket"); s->id = id; @@ -828,12 +827,11 @@ static int smart_socket_enqueue(asocket *s, apacket *p) } #else /* !ADB_HOST */ if (s->transport == NULL) { - char* error_string = "unknown failure"; - s->transport = acquire_one_transport (CS_ANY, - kTransportAny, NULL, &error_string); + std::string error_msg = "unknown failure"; + s->transport = acquire_one_transport(CS_ANY, kTransportAny, NULL, &error_msg); if (s->transport == NULL) { - sendfailmsg(s->peer->fd, error_string); + sendfailmsg(s->peer->fd, error_msg.c_str()); goto fail; } } @@ -896,7 +894,7 @@ static void smart_socket_close(asocket *s) static asocket *create_smart_socket(void) { D("Creating smart socket \n"); - asocket *s = calloc(1, sizeof(asocket)); + asocket *s = reinterpret_cast<asocket*>(calloc(1, sizeof(asocket))); if (s == NULL) fatal("cannot allocate socket"); s->enqueue = smart_socket_enqueue; s->ready = smart_socket_ready; diff --git a/adb/sysdeps.h b/adb/sysdeps.h index cc1f839..d9a1518 100644 --- a/adb/sysdeps.h +++ b/adb/sysdeps.h @@ -24,18 +24,35 @@ # undef _WIN32 #endif +/* + * 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 + #ifdef _WIN32 -#include <winsock2.h> -#include <windows.h> -#include <ws2tcpip.h> -#include <process.h> +#include <ctype.h> +#include <direct.h> +#include <errno.h> #include <fcntl.h> #include <io.h> +#include <process.h> #include <sys/stat.h> -#include <errno.h> -#include <ctype.h> -#include <direct.h> +#include <winsock2.h> +#include <windows.h> +#include <ws2tcpip.h> + +#include "fdevent.h" #define OS_PATH_SEPARATOR '\\' #define OS_PATH_SEPARATOR_STR "\\" @@ -77,13 +94,16 @@ static __inline__ int adb_thread_create( adb_thread_t *thread, adb_thread_func return 0; } +static __inline__ unsigned long adb_thread_id() +{ + return GetCurrentThreadId(); +} + static __inline__ void close_on_exec(int fd) { /* nothing really */ } -extern void disable_tcp_nagle(int fd); - #define lstat stat /* no symlinks on Win32 */ #define S_ISLNK(m) 0 /* no symlinks on Win32 */ @@ -126,10 +146,8 @@ static __inline__ int unix_close(int fd) #undef close #define close ____xxx_close -static __inline__ int unix_read(int fd, void* buf, size_t len) -{ - return read(fd, buf, len); -} +extern int unix_read(int fd, void* buf, size_t len); + #undef read #define read ___xxx_read @@ -182,8 +200,6 @@ extern int socket_inaddr_any_server(int port, int type); #define FDE_ERROR 0x0004 #define FDE_DONT_CLOSE 0x0080 -typedef struct fdevent fdevent; - typedef void (*fd_func)(int fd, unsigned events, void *userdata); fdevent *fdevent_create(int fd, fd_func func, void *arg); @@ -195,20 +211,6 @@ void fdevent_add(fdevent *fde, unsigned events); void fdevent_del(fdevent *fde, unsigned events); void fdevent_loop(); -struct fdevent { - fdevent *next; - fdevent *prev; - - int fd; - int force_eof; - - unsigned short state; - unsigned short events; - - fd_func func; - void *arg; -}; - static __inline__ void adb_sleep_ms( int mseconds ) { Sleep( mseconds ); @@ -219,10 +221,21 @@ extern int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t #undef accept #define accept ___xxx_accept +extern int adb_setsockopt(int fd, int level, int optname, const void* optval, socklen_t optlen); + +#undef setsockopt +#define setsockopt ___xxx_setsockopt + static __inline__ int adb_socket_setbufsize( int fd, int bufsize ) { int opt = bufsize; - return setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char*)&opt, sizeof(opt)); + return adb_setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const void*)&opt, sizeof(opt)); +} + +static __inline__ void disable_tcp_nagle( int fd ) +{ + int on = 1; + adb_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const void*)&on, sizeof(on)); } extern int adb_socketpair( int sv[2] ); @@ -279,21 +292,6 @@ extern char* adb_strtok_r(char *str, const char *delim, char **saveptr); #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 ":" @@ -459,6 +457,13 @@ static __inline__ void disable_tcp_nagle(int fd) setsockopt( fd, IPPROTO_TCP, TCP_NODELAY, (void*)&on, sizeof(on) ); } +static __inline__ int adb_setsockopt( int fd, int level, int optname, const void* optval, socklen_t optlen ) +{ + return setsockopt( fd, level, optname, optval, optlen ); +} + +#undef setsockopt +#define setsockopt ___xxx_setsockopt static __inline__ int unix_socketpair( int d, int type, int protocol, int sv[2] ) { @@ -516,6 +521,12 @@ static __inline__ char* adb_strtok_r(char *str, const char *delim, char **savep { return strtok_r(str, delim, saveptr); } + +static __inline__ unsigned long adb_thread_id() +{ + return (unsigned long)pthread_self(); +} + #undef strtok_r #define strtok_r ___xxx_strtok_r diff --git a/adb/sysdeps_win32.c b/adb/sysdeps_win32.cpp index e69ec2b..de47638 100644 --- a/adb/sysdeps_win32.c +++ b/adb/sysdeps_win32.cpp @@ -1,14 +1,82 @@ +/* + * Copyright (C) 2015 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. + */ + +#define TRACE_TAG TRACE_SYSDEPS + #include "sysdeps.h" -#include <winsock2.h> + +#include <winsock2.h> /* winsock.h *must* be included before windows.h. */ #include <windows.h> + +#include <errno.h> +#include <stdbool.h> #include <stdio.h> #include <stdlib.h> -#include <errno.h> -#define TRACE_TAG TRACE_SYSDEPS + #include "adb.h" extern void fatal(const char *fmt, ...); +/* forward declarations */ + +typedef const struct FHClassRec_* FHClass; +typedef struct FHRec_* FH; +typedef struct EventHookRec_* EventHook; + +typedef struct FHClassRec_ { + void (*_fh_init)(FH); + int (*_fh_close)(FH); + int (*_fh_lseek)(FH, int, int); + int (*_fh_read)(FH, void*, int); + int (*_fh_write)(FH, const void*, int); + void (*_fh_hook)(FH, int, EventHook); +} FHClassRec; + +static void _fh_file_init(FH); +static int _fh_file_close(FH); +static int _fh_file_lseek(FH, int, int); +static int _fh_file_read(FH, void*, int); +static int _fh_file_write(FH, const void*, int); +static void _fh_file_hook(FH, int, EventHook); + +static const FHClassRec _fh_file_class = { + _fh_file_init, + _fh_file_close, + _fh_file_lseek, + _fh_file_read, + _fh_file_write, + _fh_file_hook +}; + +static void _fh_socket_init(FH); +static int _fh_socket_close(FH); +static int _fh_socket_lseek(FH, int, int); +static int _fh_socket_read(FH, void*, int); +static int _fh_socket_write(FH, const void*, int); +static void _fh_socket_hook(FH, int, EventHook); + +static const FHClassRec _fh_socket_class = { + _fh_socket_init, + _fh_socket_close, + _fh_socket_lseek, + _fh_socket_read, + _fh_socket_write, + _fh_socket_hook +}; + #define assert(cond) do { if (!(cond)) fatal( "assertion failed '%s' on %s:%ld\n", #cond, __FILE__, __LINE__ ); } while (0) /**************************************************************************/ @@ -71,23 +139,6 @@ void *load_file(const char *fn, unsigned *_sz) /**************************************************************************/ /**************************************************************************/ -typedef const struct FHClassRec_* FHClass; - -typedef struct FHRec_* FH; - -typedef struct EventHookRec_* EventHook; - -typedef struct FHClassRec_ -{ - void (*_fh_init) ( FH f ); - int (*_fh_close)( FH f ); - int (*_fh_lseek)( FH f, int pos, int origin ); - int (*_fh_read) ( FH f, void* buf, int len ); - int (*_fh_write)( FH f, const void* buf, int len ); - void (*_fh_hook) ( FH f, int events, EventHook hook ); - -} FHClassRec; - /* used to emulate unix-domain socket pairs */ typedef struct SocketPairRec_* SocketPair; @@ -199,10 +250,6 @@ _fh_close( FH f ) return 0; } -/* forward definitions */ -static const FHClassRec _fh_file_class; -static const FHClassRec _fh_socket_class; - /**************************************************************************/ /**************************************************************************/ /***** *****/ @@ -211,23 +258,17 @@ static const FHClassRec _fh_socket_class; /**************************************************************************/ /**************************************************************************/ -static void -_fh_file_init( FH f ) -{ +static void _fh_file_init( FH f ) { f->fh_handle = INVALID_HANDLE_VALUE; } -static int -_fh_file_close( FH f ) -{ +static int _fh_file_close( FH f ) { CloseHandle( f->fh_handle ); f->fh_handle = INVALID_HANDLE_VALUE; return 0; } -static int -_fh_file_read( FH f, void* buf, int len ) -{ +static int _fh_file_read( FH f, void* buf, int len ) { DWORD read_bytes; if ( !ReadFile( f->fh_handle, buf, (DWORD)len, &read_bytes, NULL ) ) { @@ -240,9 +281,7 @@ _fh_file_read( FH f, void* buf, int len ) return (int)read_bytes; } -static int -_fh_file_write( FH f, const void* buf, int len ) -{ +static int _fh_file_write( FH f, const void* buf, int len ) { DWORD wrote_bytes; if ( !WriteFile( f->fh_handle, buf, (DWORD)len, &wrote_bytes, NULL ) ) { @@ -255,9 +294,7 @@ _fh_file_write( FH f, const void* buf, int len ) return (int)wrote_bytes; } -static int -_fh_file_lseek( FH f, int pos, int origin ) -{ +static int _fh_file_lseek( FH f, int pos, int origin ) { DWORD method; DWORD result; @@ -281,17 +318,6 @@ _fh_file_lseek( FH f, int pos, int origin ) return (int)result; } -static void _fh_file_hook( FH f, int event, EventHook eventhook ); /* forward */ - -static const FHClassRec _fh_file_class = -{ - _fh_file_init, - _fh_file_close, - _fh_file_lseek, - _fh_file_read, - _fh_file_write, - _fh_file_hook -}; /**************************************************************************/ /**************************************************************************/ @@ -440,7 +466,8 @@ int adb_shutdown(int fd) { FH f = _fh_from_int(fd); - if (!f) { + if (!f || f->clazz != &_fh_socket_class) { + D("adb_shutdown: invalid fd %d\n", fd); return -1; } @@ -471,9 +498,9 @@ int adb_close(int fd) /**************************************************************************/ /**************************************************************************/ -static void -_socket_set_errno( void ) -{ +#undef setsockopt + +static void _socket_set_errno( void ) { switch (WSAGetLastError()) { case 0: errno = 0; break; case WSAEWOULDBLOCK: errno = EAGAIN; break; @@ -484,17 +511,13 @@ _socket_set_errno( void ) } } -static void -_fh_socket_init( FH f ) -{ +static void _fh_socket_init( FH f ) { f->fh_socket = INVALID_SOCKET; f->event = WSACreateEvent(); f->mask = 0; } -static int -_fh_socket_close( FH f ) -{ +static int _fh_socket_close( FH f ) { /* gently tell any peer that we're closing the socket */ shutdown( f->fh_socket, SD_BOTH ); closesocket( f->fh_socket ); @@ -504,17 +527,13 @@ _fh_socket_close( FH f ) return 0; } -static int -_fh_socket_lseek( FH f, int pos, int origin ) -{ +static int _fh_socket_lseek( FH f, int pos, int origin ) { errno = EPIPE; return -1; } -static int -_fh_socket_read( FH f, void* buf, int len ) -{ - int result = recv( f->fh_socket, buf, len, 0 ); +static int _fh_socket_read(FH f, void* buf, int len) { + int result = recv(f->fh_socket, reinterpret_cast<char*>(buf), len, 0); if (result == SOCKET_ERROR) { _socket_set_errno(); result = -1; @@ -522,10 +541,8 @@ _fh_socket_read( FH f, void* buf, int len ) return result; } -static int -_fh_socket_write( FH f, const void* buf, int len ) -{ - int result = send( f->fh_socket, buf, len, 0 ); +static int _fh_socket_write(FH f, const void* buf, int len) { + int result = send(f->fh_socket, reinterpret_cast<const char*>(buf), len, 0); if (result == SOCKET_ERROR) { _socket_set_errno(); result = -1; @@ -533,18 +550,6 @@ _fh_socket_write( FH f, const void* buf, int len ) return result; } -static void _fh_socket_hook( FH f, int event, EventHook hook ); /* forward */ - -static const FHClassRec _fh_socket_class = -{ - _fh_socket_init, - _fh_socket_close, - _fh_socket_lseek, - _fh_socket_read, - _fh_socket_write, - _fh_socket_hook -}; - /**************************************************************************/ /**************************************************************************/ /***** *****/ @@ -786,15 +791,16 @@ int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrle } -void disable_tcp_nagle(int fd) +int adb_setsockopt( int fd, int level, int optname, const void* optval, socklen_t optlen ) { FH fh = _fh_from_int(fd); - int on = 1; - if ( !fh || fh->clazz != &_fh_socket_class ) - return; + if ( !fh || fh->clazz != &_fh_socket_class ) { + D("adb_setsockopt: invalid fd %d\n", fd); + return -1; + } - setsockopt( fh->fh_socket, IPPROTO_TCP, TCP_NODELAY, (const char*)&on, sizeof(on) ); + return setsockopt( fh->fh_socket, level, optname, reinterpret_cast<const char*>(optval), optlen ); } /**************************************************************************/ @@ -1194,18 +1200,16 @@ static const FHClassRec _fh_socketpair_class = }; -int adb_socketpair( int sv[2] ) -{ - FH fa, fb; - SocketPair pair; +int adb_socketpair(int sv[2]) { + SocketPair pair; - fa = _fh_alloc( &_fh_socketpair_class ); - fb = _fh_alloc( &_fh_socketpair_class ); + FH fa = _fh_alloc(&_fh_socketpair_class); + FH fb = _fh_alloc(&_fh_socketpair_class); if (!fa || !fb) goto Fail; - pair = malloc( sizeof(*pair) ); + pair = reinterpret_cast<SocketPair>(malloc(sizeof(*pair))); if (pair == NULL) { D("adb_socketpair: not enough memory to allocate pipes\n" ); goto Fail; @@ -1303,13 +1307,12 @@ typedef struct EventHookRec_ static EventHook _free_hooks; static EventHook -event_hook_alloc( FH fh ) -{ - EventHook hook = _free_hooks; - if (hook != NULL) +event_hook_alloc(FH fh) { + EventHook hook = _free_hooks; + if (hook != NULL) { _free_hooks = hook->next; - else { - hook = malloc( sizeof(*hook) ); + } else { + hook = reinterpret_cast<EventHook>(malloc(sizeof(*hook))); if (hook == NULL) fatal( "could not allocate event hook\n" ); } @@ -1771,7 +1774,7 @@ static void fdevent_register(fdevent *fde) while(fd_table_max <= fd) { fd_table_max *= 2; } - fd_table = realloc(fd_table, sizeof(fdevent*) * fd_table_max); + fd_table = reinterpret_cast<fdevent**>(realloc(fd_table, sizeof(fdevent*) * fd_table_max)); if(fd_table == 0) { FATAL("could not expand fd_table to %d entries\n", fd_table_max); } @@ -2226,3 +2229,905 @@ cont: } /* NOTREACHED */ } + +/**************************************************************************/ +/**************************************************************************/ +/***** *****/ +/***** Console Window Terminal Emulation *****/ +/***** *****/ +/**************************************************************************/ +/**************************************************************************/ + +// This reads input from a Win32 console window and translates it into Unix +// terminal-style sequences. This emulates mostly Gnome Terminal (in Normal +// mode, not Application mode), which itself emulates xterm. Gnome Terminal +// is emulated instead of xterm because it is probably more popular than xterm: +// Ubuntu's default Ctrl-Alt-T shortcut opens Gnome Terminal, Gnome Terminal +// supports modern fonts, etc. It seems best to emulate the terminal that most +// Android developers use because they'll fix apps (the shell, etc.) to keep +// working with that terminal's emulation. +// +// The point of this emulation is not to be perfect or to solve all issues with +// console windows on Windows, but to be better than the original code which +// just called read() (which called ReadFile(), which called ReadConsoleA()) +// which did not support Ctrl-C, tab completion, shell input line editing +// keys, server echo, and more. +// +// This implementation reconfigures the console with SetConsoleMode(), then +// calls ReadConsoleInput() to get raw input which it remaps to Unix +// terminal-style sequences which is returned via unix_read() which is used +// by the 'adb shell' command. +// +// Code organization: +// +// * stdin_raw_init() and stdin_raw_restore() reconfigure the console. +// * unix_read() detects console windows (as opposed to pipes, files, etc.). +// * _console_read() is the main code of the emulation. + + +// Read an input record from the console; one that should be processed. +static bool _get_interesting_input_record_uncached(const HANDLE console, + INPUT_RECORD* const input_record) { + for (;;) { + DWORD read_count = 0; + memset(input_record, 0, sizeof(*input_record)); + if (!ReadConsoleInputA(console, input_record, 1, &read_count)) { + D("_get_interesting_input_record_uncached: ReadConsoleInputA() " + "failure, error %ld\n", GetLastError()); + errno = EIO; + return false; + } + + if (read_count == 0) { // should be impossible + fatal("ReadConsoleInputA returned 0"); + } + + if (read_count != 1) { // should be impossible + fatal("ReadConsoleInputA did not return one input record"); + } + + if ((input_record->EventType == KEY_EVENT) && + (input_record->Event.KeyEvent.bKeyDown)) { + if (input_record->Event.KeyEvent.wRepeatCount == 0) { + fatal("ReadConsoleInputA returned a key event with zero repeat" + " count"); + } + + // Got an interesting INPUT_RECORD, so return + return true; + } + } +} + +// Cached input record (in case _console_read() is passed a buffer that doesn't +// have enough space to fit wRepeatCount number of key sequences). A non-zero +// wRepeatCount indicates that a record is cached. +static INPUT_RECORD _win32_input_record; + +// Get the next KEY_EVENT_RECORD that should be processed. +static KEY_EVENT_RECORD* _get_key_event_record(const HANDLE console) { + // If nothing cached, read directly from the console until we get an + // interesting record. + if (_win32_input_record.Event.KeyEvent.wRepeatCount == 0) { + if (!_get_interesting_input_record_uncached(console, + &_win32_input_record)) { + // There was an error, so make sure wRepeatCount is zero because + // that signifies no cached input record. + _win32_input_record.Event.KeyEvent.wRepeatCount = 0; + return NULL; + } + } + + return &_win32_input_record.Event.KeyEvent; +} + +static __inline__ bool _is_shift_pressed(const DWORD control_key_state) { + return (control_key_state & SHIFT_PRESSED) != 0; +} + +static __inline__ bool _is_ctrl_pressed(const DWORD control_key_state) { + return (control_key_state & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) != 0; +} + +static __inline__ bool _is_alt_pressed(const DWORD control_key_state) { + return (control_key_state & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) != 0; +} + +static __inline__ bool _is_numlock_on(const DWORD control_key_state) { + return (control_key_state & NUMLOCK_ON) != 0; +} + +static __inline__ bool _is_capslock_on(const DWORD control_key_state) { + return (control_key_state & CAPSLOCK_ON) != 0; +} + +static __inline__ bool _is_enhanced_key(const DWORD control_key_state) { + return (control_key_state & ENHANCED_KEY) != 0; +} + +// Constants from MSDN for ToAscii(). +static const BYTE TOASCII_KEY_OFF = 0x00; +static const BYTE TOASCII_KEY_DOWN = 0x80; +static const BYTE TOASCII_KEY_TOGGLED_ON = 0x01; // for CapsLock + +// Given a key event, ignore a modifier key and return the character that was +// entered without the modifier. Writes to *ch and returns the number of bytes +// written. +static size_t _get_char_ignoring_modifier(char* const ch, + const KEY_EVENT_RECORD* const key_event, const DWORD control_key_state, + const WORD modifier) { + // If there is no character from Windows, try ignoring the specified + // modifier and look for a character. Note that if AltGr is being used, + // there will be a character from Windows. + if (key_event->uChar.AsciiChar == '\0') { + // Note that we read the control key state from the passed in argument + // instead of from key_event since the argument has been normalized. + if (((modifier == VK_SHIFT) && + _is_shift_pressed(control_key_state)) || + ((modifier == VK_CONTROL) && + _is_ctrl_pressed(control_key_state)) || + ((modifier == VK_MENU) && _is_alt_pressed(control_key_state))) { + + BYTE key_state[256] = {0}; + key_state[VK_SHIFT] = _is_shift_pressed(control_key_state) ? + TOASCII_KEY_DOWN : TOASCII_KEY_OFF; + key_state[VK_CONTROL] = _is_ctrl_pressed(control_key_state) ? + TOASCII_KEY_DOWN : TOASCII_KEY_OFF; + key_state[VK_MENU] = _is_alt_pressed(control_key_state) ? + TOASCII_KEY_DOWN : TOASCII_KEY_OFF; + key_state[VK_CAPITAL] = _is_capslock_on(control_key_state) ? + TOASCII_KEY_TOGGLED_ON : TOASCII_KEY_OFF; + + // cause this modifier to be ignored + key_state[modifier] = TOASCII_KEY_OFF; + + WORD translated = 0; + if (ToAscii(key_event->wVirtualKeyCode, + key_event->wVirtualScanCode, key_state, &translated, 0) == 1) { + // Ignoring the modifier, we found a character. + *ch = (CHAR)translated; + return 1; + } + } + } + + // Just use whatever Windows told us originally. + *ch = key_event->uChar.AsciiChar; + + // If the character from Windows is NULL, return a size of zero. + return (*ch == '\0') ? 0 : 1; +} + +// If a Ctrl key is pressed, lookup the character, ignoring the Ctrl key, +// but taking into account the shift key. This is because for a sequence like +// Ctrl-Alt-0, we want to find the character '0' and for Ctrl-Alt-Shift-0, +// we want to find the character ')'. +// +// Note that Windows doesn't seem to pass bKeyDown for Ctrl-Shift-NoAlt-0 +// because it is the default key-sequence to switch the input language. +// This is configurable in the Region and Language control panel. +static __inline__ size_t _get_non_control_char(char* const ch, + const KEY_EVENT_RECORD* const key_event, const DWORD control_key_state) { + return _get_char_ignoring_modifier(ch, key_event, control_key_state, + VK_CONTROL); +} + +// Get without Alt. +static __inline__ size_t _get_non_alt_char(char* const ch, + const KEY_EVENT_RECORD* const key_event, const DWORD control_key_state) { + return _get_char_ignoring_modifier(ch, key_event, control_key_state, + VK_MENU); +} + +// Ignore the control key, find the character from Windows, and apply any +// Control key mappings (for example, Ctrl-2 is a NULL character). Writes to +// *pch and returns number of bytes written. +static size_t _get_control_character(char* const pch, + const KEY_EVENT_RECORD* const key_event, const DWORD control_key_state) { + const size_t len = _get_non_control_char(pch, key_event, + control_key_state); + + if ((len == 1) && _is_ctrl_pressed(control_key_state)) { + char ch = *pch; + switch (ch) { + case '2': + case '@': + case '`': + ch = '\0'; + break; + case '3': + case '[': + case '{': + ch = '\x1b'; + break; + case '4': + case '\\': + case '|': + ch = '\x1c'; + break; + case '5': + case ']': + case '}': + ch = '\x1d'; + break; + case '6': + case '^': + case '~': + ch = '\x1e'; + break; + case '7': + case '-': + case '_': + ch = '\x1f'; + break; + case '8': + ch = '\x7f'; + break; + case '/': + if (!_is_alt_pressed(control_key_state)) { + ch = '\x1f'; + } + break; + case '?': + if (!_is_alt_pressed(control_key_state)) { + ch = '\x7f'; + } + break; + } + *pch = ch; + } + + return len; +} + +static DWORD _normalize_altgr_control_key_state( + const KEY_EVENT_RECORD* const key_event) { + DWORD control_key_state = key_event->dwControlKeyState; + + // If we're in an AltGr situation where the AltGr key is down (depending on + // the keyboard layout, that might be the physical right alt key which + // produces a control_key_state where Right-Alt and Left-Ctrl are down) or + // AltGr-equivalent keys are down (any Ctrl key + any Alt key), and we have + // a character (which indicates that there was an AltGr mapping), then act + // as if alt and control are not really down for the purposes of modifiers. + // This makes it so that if the user with, say, a German keyboard layout + // presses AltGr-] (which we see as Right-Alt + Left-Ctrl + key), we just + // output the key and we don't see the Alt and Ctrl keys. + if (_is_ctrl_pressed(control_key_state) && + _is_alt_pressed(control_key_state) + && (key_event->uChar.AsciiChar != '\0')) { + // Try to remove as few bits as possible to improve our chances of + // detecting combinations like Left-Alt + AltGr, Right-Ctrl + AltGr, or + // Left-Alt + Right-Ctrl + AltGr. + if ((control_key_state & RIGHT_ALT_PRESSED) != 0) { + // Remove Right-Alt. + control_key_state &= ~RIGHT_ALT_PRESSED; + // If uChar is set, a Ctrl key is pressed, and Right-Alt is + // pressed, Left-Ctrl is almost always set, except if the user + // presses Right-Ctrl, then AltGr (in that specific order) for + // whatever reason. At any rate, make sure the bit is not set. + control_key_state &= ~LEFT_CTRL_PRESSED; + } else if ((control_key_state & LEFT_ALT_PRESSED) != 0) { + // Remove Left-Alt. + control_key_state &= ~LEFT_ALT_PRESSED; + // Whichever Ctrl key is down, remove it from the state. We only + // remove one key, to improve our chances of detecting the + // corner-case of Left-Ctrl + Left-Alt + Right-Ctrl. + if ((control_key_state & LEFT_CTRL_PRESSED) != 0) { + // Remove Left-Ctrl. + control_key_state &= ~LEFT_CTRL_PRESSED; + } else if ((control_key_state & RIGHT_CTRL_PRESSED) != 0) { + // Remove Right-Ctrl. + control_key_state &= ~RIGHT_CTRL_PRESSED; + } + } + + // Note that this logic isn't 100% perfect because Windows doesn't + // allow us to detect all combinations because a physical AltGr key + // press shows up as two bits, plus some combinations are ambiguous + // about what is actually physically pressed. + } + + return control_key_state; +} + +// If NumLock is on and Shift is pressed, SHIFT_PRESSED is not set in +// dwControlKeyState for the following keypad keys: period, 0-9. If we detect +// this scenario, set the SHIFT_PRESSED bit so we can add modifiers +// appropriately. +static DWORD _normalize_keypad_control_key_state(const WORD vk, + const DWORD control_key_state) { + if (!_is_numlock_on(control_key_state)) { + return control_key_state; + } + if (!_is_enhanced_key(control_key_state)) { + switch (vk) { + case VK_INSERT: // 0 + case VK_DELETE: // . + case VK_END: // 1 + case VK_DOWN: // 2 + case VK_NEXT: // 3 + case VK_LEFT: // 4 + case VK_CLEAR: // 5 + case VK_RIGHT: // 6 + case VK_HOME: // 7 + case VK_UP: // 8 + case VK_PRIOR: // 9 + return control_key_state | SHIFT_PRESSED; + } + } + + return control_key_state; +} + +static const char* _get_keypad_sequence(const DWORD control_key_state, + const char* const normal, const char* const shifted) { + if (_is_shift_pressed(control_key_state)) { + // Shift is pressed and NumLock is off + return shifted; + } else { + // Shift is not pressed and NumLock is off, or, + // Shift is pressed and NumLock is on, in which case we want the + // NumLock and Shift to neutralize each other, thus, we want the normal + // sequence. + return normal; + } + // If Shift is not pressed and NumLock is on, a different virtual key code + // is returned by Windows, which can be taken care of by a different case + // statement in _console_read(). +} + +// Write sequence to buf and return the number of bytes written. +static size_t _get_modifier_sequence(char* const buf, const WORD vk, + DWORD control_key_state, const char* const normal) { + // Copy the base sequence into buf. + const size_t len = strlen(normal); + memcpy(buf, normal, len); + + int code = 0; + + control_key_state = _normalize_keypad_control_key_state(vk, + control_key_state); + + if (_is_shift_pressed(control_key_state)) { + code |= 0x1; + } + if (_is_alt_pressed(control_key_state)) { // any alt key pressed + code |= 0x2; + } + if (_is_ctrl_pressed(control_key_state)) { // any control key pressed + code |= 0x4; + } + // If some modifier was held down, then we need to insert the modifier code + if (code != 0) { + if (len == 0) { + // Should be impossible because caller should pass a string of + // non-zero length. + return 0; + } + size_t index = len - 1; + const char lastChar = buf[index]; + if (lastChar != '~') { + buf[index++] = '1'; + } + buf[index++] = ';'; // modifier separator + // 2 = shift, 3 = alt, 4 = shift & alt, 5 = control, + // 6 = shift & control, 7 = alt & control, 8 = shift & alt & control + buf[index++] = '1' + code; + buf[index++] = lastChar; // move ~ (or other last char) to the end + return index; + } + return len; +} + +// Write sequence to buf and return the number of bytes written. +static size_t _get_modifier_keypad_sequence(char* const buf, const WORD vk, + const DWORD control_key_state, const char* const normal, + const char shifted) { + if (_is_shift_pressed(control_key_state)) { + // Shift is pressed and NumLock is off + if (shifted != '\0') { + buf[0] = shifted; + return sizeof(buf[0]); + } else { + return 0; + } + } else { + // Shift is not pressed and NumLock is off, or, + // Shift is pressed and NumLock is on, in which case we want the + // NumLock and Shift to neutralize each other, thus, we want the normal + // sequence. + return _get_modifier_sequence(buf, vk, control_key_state, normal); + } + // If Shift is not pressed and NumLock is on, a different virtual key code + // is returned by Windows, which can be taken care of by a different case + // statement in _console_read(). +} + +// The decimal key on the keypad produces a '.' for U.S. English and a ',' for +// Standard German. Figure this out at runtime so we know what to output for +// Shift-VK_DELETE. +static char _get_decimal_char() { + return (char)MapVirtualKeyA(VK_DECIMAL, MAPVK_VK_TO_CHAR); +} + +// Prefix the len bytes in buf with the escape character, and then return the +// new buffer length. +size_t _escape_prefix(char* const buf, const size_t len) { + // If nothing to prefix, don't do anything. We might be called with + // len == 0, if alt was held down with a dead key which produced nothing. + if (len == 0) { + return 0; + } + + memmove(&buf[1], buf, len); + buf[0] = '\x1b'; + return len + 1; +} + +// Writes to buffer buf (of length len), returning number of bytes written or +// -1 on error. Never returns zero because Win32 consoles are never 'closed' +// (as far as I can tell). +static int _console_read(const HANDLE console, void* buf, size_t len) { + for (;;) { + KEY_EVENT_RECORD* const key_event = _get_key_event_record(console); + if (key_event == NULL) { + return -1; + } + + const WORD vk = key_event->wVirtualKeyCode; + const CHAR ch = key_event->uChar.AsciiChar; + const DWORD control_key_state = _normalize_altgr_control_key_state( + key_event); + + // The following emulation code should write the output sequence to + // either seqstr or to seqbuf and seqbuflen. + const char* seqstr = NULL; // NULL terminated C-string + // Enough space for max sequence string below, plus modifiers and/or + // escape prefix. + char seqbuf[16]; + size_t seqbuflen = 0; // Space used in seqbuf. + +#define MATCH(vk, normal) \ + case (vk): \ + { \ + seqstr = (normal); \ + } \ + break; + + // Modifier keys should affect the output sequence. +#define MATCH_MODIFIER(vk, normal) \ + case (vk): \ + { \ + seqbuflen = _get_modifier_sequence(seqbuf, (vk), \ + control_key_state, (normal)); \ + } \ + break; + + // The shift key should affect the output sequence. +#define MATCH_KEYPAD(vk, normal, shifted) \ + case (vk): \ + { \ + seqstr = _get_keypad_sequence(control_key_state, (normal), \ + (shifted)); \ + } \ + break; + + // The shift key and other modifier keys should affect the output + // sequence. +#define MATCH_MODIFIER_KEYPAD(vk, normal, shifted) \ + case (vk): \ + { \ + seqbuflen = _get_modifier_keypad_sequence(seqbuf, (vk), \ + control_key_state, (normal), (shifted)); \ + } \ + break; + +#define ESC "\x1b" +#define CSI ESC "[" +#define SS3 ESC "O" + + // Only support normal mode, not application mode. + + // Enhanced keys: + // * 6-pack: insert, delete, home, end, page up, page down + // * cursor keys: up, down, right, left + // * keypad: divide, enter + // * Undocumented: VK_PAUSE (Ctrl-NumLock), VK_SNAPSHOT, + // VK_CANCEL (Ctrl-Pause/Break), VK_NUMLOCK + if (_is_enhanced_key(control_key_state)) { + switch (vk) { + case VK_RETURN: // Enter key on keypad + if (_is_ctrl_pressed(control_key_state)) { + seqstr = "\n"; + } else { + seqstr = "\r"; + } + break; + + MATCH_MODIFIER(VK_PRIOR, CSI "5~"); // Page Up + MATCH_MODIFIER(VK_NEXT, CSI "6~"); // Page Down + + // gnome-terminal currently sends SS3 "F" and SS3 "H", but that + // will be fixed soon to match xterm which sends CSI "F" and + // CSI "H". https://bugzilla.redhat.com/show_bug.cgi?id=1119764 + MATCH(VK_END, CSI "F"); + MATCH(VK_HOME, CSI "H"); + + MATCH_MODIFIER(VK_LEFT, CSI "D"); + MATCH_MODIFIER(VK_UP, CSI "A"); + MATCH_MODIFIER(VK_RIGHT, CSI "C"); + MATCH_MODIFIER(VK_DOWN, CSI "B"); + + MATCH_MODIFIER(VK_INSERT, CSI "2~"); + MATCH_MODIFIER(VK_DELETE, CSI "3~"); + + MATCH(VK_DIVIDE, "/"); + } + } else { // Non-enhanced keys: + switch (vk) { + case VK_BACK: // backspace + if (_is_alt_pressed(control_key_state)) { + seqstr = ESC "\x7f"; + } else { + seqstr = "\x7f"; + } + break; + + case VK_TAB: + if (_is_shift_pressed(control_key_state)) { + seqstr = CSI "Z"; + } else { + seqstr = "\t"; + } + break; + + // Number 5 key in keypad when NumLock is off, or if NumLock is + // on and Shift is down. + MATCH_KEYPAD(VK_CLEAR, CSI "E", "5"); + + case VK_RETURN: // Enter key on main keyboard + if (_is_alt_pressed(control_key_state)) { + seqstr = ESC "\n"; + } else if (_is_ctrl_pressed(control_key_state)) { + seqstr = "\n"; + } else { + seqstr = "\r"; + } + break; + + // VK_ESCAPE: Don't do any special handling. The OS uses many + // of the sequences with Escape and many of the remaining + // sequences don't produce bKeyDown messages, only !bKeyDown + // for whatever reason. + + case VK_SPACE: + if (_is_alt_pressed(control_key_state)) { + seqstr = ESC " "; + } else if (_is_ctrl_pressed(control_key_state)) { + seqbuf[0] = '\0'; // NULL char + seqbuflen = 1; + } else { + seqstr = " "; + } + break; + + MATCH_MODIFIER_KEYPAD(VK_PRIOR, CSI "5~", '9'); // Page Up + MATCH_MODIFIER_KEYPAD(VK_NEXT, CSI "6~", '3'); // Page Down + + MATCH_KEYPAD(VK_END, CSI "4~", "1"); + MATCH_KEYPAD(VK_HOME, CSI "1~", "7"); + + MATCH_MODIFIER_KEYPAD(VK_LEFT, CSI "D", '4'); + MATCH_MODIFIER_KEYPAD(VK_UP, CSI "A", '8'); + MATCH_MODIFIER_KEYPAD(VK_RIGHT, CSI "C", '6'); + MATCH_MODIFIER_KEYPAD(VK_DOWN, CSI "B", '2'); + + MATCH_MODIFIER_KEYPAD(VK_INSERT, CSI "2~", '0'); + MATCH_MODIFIER_KEYPAD(VK_DELETE, CSI "3~", + _get_decimal_char()); + + case 0x30: // 0 + case 0x31: // 1 + case 0x39: // 9 + case VK_OEM_1: // ;: + case VK_OEM_PLUS: // =+ + case VK_OEM_COMMA: // ,< + case VK_OEM_PERIOD: // .> + case VK_OEM_7: // '" + case VK_OEM_102: // depends on keyboard, could be <> or \| + case VK_OEM_2: // /? + case VK_OEM_3: // `~ + case VK_OEM_4: // [{ + case VK_OEM_5: // \| + case VK_OEM_6: // ]} + { + seqbuflen = _get_control_character(seqbuf, key_event, + control_key_state); + + if (_is_alt_pressed(control_key_state)) { + seqbuflen = _escape_prefix(seqbuf, seqbuflen); + } + } + break; + + case 0x32: // 2 + case 0x36: // 6 + case VK_OEM_MINUS: // -_ + { + seqbuflen = _get_control_character(seqbuf, key_event, + control_key_state); + + // If Alt is pressed and it isn't Ctrl-Alt-ShiftUp, then + // prefix with escape. + if (_is_alt_pressed(control_key_state) && + !(_is_ctrl_pressed(control_key_state) && + !_is_shift_pressed(control_key_state))) { + seqbuflen = _escape_prefix(seqbuf, seqbuflen); + } + } + break; + + case 0x33: // 3 + case 0x34: // 4 + case 0x35: // 5 + case 0x37: // 7 + case 0x38: // 8 + { + seqbuflen = _get_control_character(seqbuf, key_event, + control_key_state); + + // If Alt is pressed and it isn't Ctrl-Alt-ShiftUp, then + // prefix with escape. + if (_is_alt_pressed(control_key_state) && + !(_is_ctrl_pressed(control_key_state) && + !_is_shift_pressed(control_key_state))) { + seqbuflen = _escape_prefix(seqbuf, seqbuflen); + } + } + break; + + case 0x41: // a + case 0x42: // b + case 0x43: // c + case 0x44: // d + case 0x45: // e + case 0x46: // f + case 0x47: // g + case 0x48: // h + case 0x49: // i + case 0x4a: // j + case 0x4b: // k + case 0x4c: // l + case 0x4d: // m + case 0x4e: // n + case 0x4f: // o + case 0x50: // p + case 0x51: // q + case 0x52: // r + case 0x53: // s + case 0x54: // t + case 0x55: // u + case 0x56: // v + case 0x57: // w + case 0x58: // x + case 0x59: // y + case 0x5a: // z + { + seqbuflen = _get_non_alt_char(seqbuf, key_event, + control_key_state); + + // If Alt is pressed, then prefix with escape. + if (_is_alt_pressed(control_key_state)) { + seqbuflen = _escape_prefix(seqbuf, seqbuflen); + } + } + break; + + // These virtual key codes are generated by the keys on the + // keypad *when NumLock is on* and *Shift is up*. + MATCH(VK_NUMPAD0, "0"); + MATCH(VK_NUMPAD1, "1"); + MATCH(VK_NUMPAD2, "2"); + MATCH(VK_NUMPAD3, "3"); + MATCH(VK_NUMPAD4, "4"); + MATCH(VK_NUMPAD5, "5"); + MATCH(VK_NUMPAD6, "6"); + MATCH(VK_NUMPAD7, "7"); + MATCH(VK_NUMPAD8, "8"); + MATCH(VK_NUMPAD9, "9"); + + MATCH(VK_MULTIPLY, "*"); + MATCH(VK_ADD, "+"); + MATCH(VK_SUBTRACT, "-"); + // VK_DECIMAL is generated by the . key on the keypad *when + // NumLock is on* and *Shift is up* and the sequence is not + // Ctrl-Alt-NoShift-. (which causes Ctrl-Alt-Del and the + // Windows Security screen to come up). + case VK_DECIMAL: + // U.S. English uses '.', Germany German uses ','. + seqbuflen = _get_non_control_char(seqbuf, key_event, + control_key_state); + break; + + MATCH_MODIFIER(VK_F1, SS3 "P"); + MATCH_MODIFIER(VK_F2, SS3 "Q"); + MATCH_MODIFIER(VK_F3, SS3 "R"); + MATCH_MODIFIER(VK_F4, SS3 "S"); + MATCH_MODIFIER(VK_F5, CSI "15~"); + MATCH_MODIFIER(VK_F6, CSI "17~"); + MATCH_MODIFIER(VK_F7, CSI "18~"); + MATCH_MODIFIER(VK_F8, CSI "19~"); + MATCH_MODIFIER(VK_F9, CSI "20~"); + MATCH_MODIFIER(VK_F10, CSI "21~"); + MATCH_MODIFIER(VK_F11, CSI "23~"); + MATCH_MODIFIER(VK_F12, CSI "24~"); + + MATCH_MODIFIER(VK_F13, CSI "25~"); + MATCH_MODIFIER(VK_F14, CSI "26~"); + MATCH_MODIFIER(VK_F15, CSI "28~"); + MATCH_MODIFIER(VK_F16, CSI "29~"); + MATCH_MODIFIER(VK_F17, CSI "31~"); + MATCH_MODIFIER(VK_F18, CSI "32~"); + MATCH_MODIFIER(VK_F19, CSI "33~"); + MATCH_MODIFIER(VK_F20, CSI "34~"); + + // MATCH_MODIFIER(VK_F21, ???); + // MATCH_MODIFIER(VK_F22, ???); + // MATCH_MODIFIER(VK_F23, ???); + // MATCH_MODIFIER(VK_F24, ???); + } + } + +#undef MATCH +#undef MATCH_MODIFIER +#undef MATCH_KEYPAD +#undef MATCH_MODIFIER_KEYPAD +#undef ESC +#undef CSI +#undef SS3 + + const char* out; + size_t outlen; + + // Check for output in any of: + // * seqstr is set (and strlen can be used to determine the length). + // * seqbuf and seqbuflen are set + // Fallback to ch from Windows. + if (seqstr != NULL) { + out = seqstr; + outlen = strlen(seqstr); + } else if (seqbuflen > 0) { + out = seqbuf; + outlen = seqbuflen; + } else if (ch != '\0') { + // Use whatever Windows told us it is. + seqbuf[0] = ch; + seqbuflen = 1; + out = seqbuf; + outlen = seqbuflen; + } else { + // No special handling for the virtual key code and Windows isn't + // telling us a character code, then we don't know how to translate + // the key press. + // + // Consume the input and 'continue' to cause us to get a new key + // event. + D("_console_read: unknown virtual key code: %d, enhanced: %s\n", + vk, _is_enhanced_key(control_key_state) ? "true" : "false"); + key_event->wRepeatCount = 0; + continue; + } + + int bytesRead = 0; + + // put output wRepeatCount times into buf/len + while (key_event->wRepeatCount > 0) { + if (len >= outlen) { + // Write to buf/len + memcpy(buf, out, outlen); + buf = (void*)((char*)buf + outlen); + len -= outlen; + bytesRead += outlen; + + // consume the input + --key_event->wRepeatCount; + } else { + // Not enough space, so just leave it in _win32_input_record + // for a subsequent retrieval. + if (bytesRead == 0) { + // We didn't write anything because there wasn't enough + // space to even write one sequence. This should never + // happen if the caller uses sensible buffer sizes + // (i.e. >= maximum sequence length which is probably a + // few bytes long). + D("_console_read: no buffer space to write one sequence; " + "buffer: %ld, sequence: %ld\n", (long)len, + (long)outlen); + errno = ENOMEM; + return -1; + } else { + // Stop trying to write to buf/len, just return whatever + // we wrote so far. + break; + } + } + } + + return bytesRead; + } +} + +static DWORD _old_console_mode; // previous GetConsoleMode() result +static HANDLE _console_handle; // when set, console mode should be restored + +void stdin_raw_init(const int fd) { + if (STDIN_FILENO == fd) { + const HANDLE in = GetStdHandle(STD_INPUT_HANDLE); + if ((in == INVALID_HANDLE_VALUE) || (in == NULL)) { + return; + } + + if (GetFileType(in) != FILE_TYPE_CHAR) { + // stdin might be a file or pipe. + return; + } + + if (!GetConsoleMode(in, &_old_console_mode)) { + // If GetConsoleMode() fails, stdin is probably is not a console. + return; + } + + // Disable ENABLE_PROCESSED_INPUT so that Ctrl-C is read instead of + // calling the process Ctrl-C routine (configured by + // SetConsoleCtrlHandler()). + // Disable ENABLE_LINE_INPUT so that input is immediately sent. + // Disable ENABLE_ECHO_INPUT to disable local echo. Disabling this + // flag also seems necessary to have proper line-ending processing. + if (!SetConsoleMode(in, _old_console_mode & ~(ENABLE_PROCESSED_INPUT | + ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT))) { + // This really should not fail. + D("stdin_raw_init: SetConsoleMode() failure, error %ld\n", + GetLastError()); + } + + // Once this is set, it means that stdin has been configured for + // reading from and that the old console mode should be restored later. + _console_handle = in; + + // Note that we don't need to configure C Runtime line-ending + // translation because _console_read() does not call the C Runtime to + // read from the console. + } +} + +void stdin_raw_restore(const int fd) { + if (STDIN_FILENO == fd) { + if (_console_handle != NULL) { + const HANDLE in = _console_handle; + _console_handle = NULL; // clear state + + if (!SetConsoleMode(in, _old_console_mode)) { + // This really should not fail. + D("stdin_raw_restore: SetConsoleMode() failure, error %ld\n", + GetLastError()); + } + } + } +} + +// Called by 'adb shell' command to read from stdin. +int unix_read(int fd, void* buf, size_t len) { + if ((fd == STDIN_FILENO) && (_console_handle != NULL)) { + // If it is a request to read from stdin, and stdin_raw_init() has been + // called, and it successfully configured the console, then read from + // the console using Win32 console APIs and partially emulate a unix + // terminal. + return _console_read(_console_handle, buf, len); + } else { + // Just call into C Runtime which can read from pipes/files and which + // can do LF/CR translation. +#undef read + return read(fd, buf, len); + } +} diff --git a/adb/test_track_devices.c b/adb/test_track_devices.cpp index 77b3ad9..77b3ad9 100644 --- a/adb/test_track_devices.c +++ b/adb/test_track_devices.cpp diff --git a/adb/test_track_jdwp.c b/adb/test_track_jdwp.cpp index 8ecc6b8..8ecc6b8 100644 --- a/adb/test_track_jdwp.c +++ b/adb/test_track_jdwp.cpp diff --git a/adb/tests/test_adb.py b/adb/tests/test_adb.py new file mode 100755 index 0000000..52d8056 --- /dev/null +++ b/adb/tests/test_adb.py @@ -0,0 +1,412 @@ +#!/usr/bin/env python2 +"""Simple conformance test for adb. + +This script will use the available adb in path and run simple +tests that attempt to touch all accessible attached devices. +""" +import hashlib +import os +import random +import re +import shlex +import subprocess +import sys +import tempfile +import unittest + + +def trace(cmd): + """Print debug message if tracing enabled.""" + if False: + print >> sys.stderr, cmd + + +def call(cmd_str): + """Run process and return output tuple (stdout, stderr, ret code).""" + trace(cmd_str) + process = subprocess.Popen(shlex.split(cmd_str), + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + stdout, stderr = process.communicate() + return stdout, stderr, process.returncode + + +def call_combined(cmd_str): + """Run process and return output tuple (stdout+stderr, ret code).""" + trace(cmd_str) + process = subprocess.Popen(shlex.split(cmd_str), + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + stdout, _ = process.communicate() + return stdout, process.returncode + + +def call_checked(cmd_str): + """Run process and get stdout+stderr, raise an exception on trouble.""" + trace(cmd_str) + return subprocess.check_output(shlex.split(cmd_str), + stderr=subprocess.STDOUT) + + +def call_checked_list(cmd_str): + return call_checked(cmd_str).split('\n') + + +def call_checked_list_skip(cmd_str): + out_list = call_checked_list(cmd_str) + + def is_init_line(line): + if (len(line) >= 3) and (line[0] == "*") and (line[-2] == "*"): + return True + else: + return False + + return [line for line in out_list if not is_init_line(line)] + + +def get_device_list(): + output = call_checked_list_skip("adb devices") + dev_list = [] + for line in output[1:]: + if line.strip() == "": + continue + device, _ = line.split() + dev_list.append(device) + return dev_list + + +def get_attached_device_count(): + return len(get_device_list()) + + +def compute_md5(string): + hsh = hashlib.md5() + hsh.update(string) + return hsh.hexdigest() + + +class HostFile(object): + def __init__(self, handle, md5): + self.handle = handle + self.md5 = md5 + self.full_path = handle.name + self.base_name = os.path.basename(self.full_path) + + +class DeviceFile(object): + def __init__(self, md5, full_path): + self.md5 = md5 + self.full_path = full_path + self.base_name = os.path.basename(self.full_path) + + +def make_random_host_files(in_dir, num_files, rand_size=True): + files = {} + min_size = 1 * (1 << 10) + max_size = 16 * (1 << 10) + fixed_size = min_size + + for _ in range(num_files): + file_handle = tempfile.NamedTemporaryFile(dir=in_dir) + + if rand_size: + size = random.randrange(min_size, max_size, 1024) + else: + size = fixed_size + rand_str = os.urandom(size) + file_handle.write(rand_str) + file_handle.flush() + + md5 = compute_md5(rand_str) + files[file_handle.name] = HostFile(file_handle, md5) + return files + + +def make_random_device_files(adb, in_dir, num_files, rand_size=True): + files = {} + min_size = 1 * (1 << 10) + max_size = 16 * (1 << 10) + fixed_size = min_size + + for i in range(num_files): + if rand_size: + size = random.randrange(min_size, max_size, 1024) + else: + size = fixed_size + + base_name = "device_tmpfile" + str(i) + full_path = in_dir + "/" + base_name + + adb.shell("dd if=/dev/urandom of={} bs={} count=1".format(full_path, + size)) + dev_md5, _ = adb.shell("md5sum {}".format(full_path)).split() + + files[full_path] = DeviceFile(dev_md5, full_path) + return files + + +class AdbWrapper(object): + """Convenience wrapper object for the adb command.""" + def __init__(self, device=None, out_dir=None): + self.device = device + self.out_dir = out_dir + self.adb_cmd = "adb " + if self.device: + self.adb_cmd += "-s {} ".format(device) + if self.out_dir: + self.adb_cmd += "-p {} ".format(out_dir) + + def shell(self, cmd): + return call_checked(self.adb_cmd + "shell " + cmd) + + def shell_nocheck(self, cmd): + return call_combined(self.adb_cmd + "shell " + cmd) + + def push(self, local, remote): + return call_checked(self.adb_cmd + "push {} {}".format(local, remote)) + + def pull(self, remote, local): + return call_checked(self.adb_cmd + "pull {} {}".format(remote, local)) + + def sync(self, directory=""): + return call_checked(self.adb_cmd + "sync {}".format(directory)) + + def forward(self, local, remote): + return call_checked(self.adb_cmd + "forward {} {}".format(local, + remote)) + + def tcpip(self, port): + return call_checked(self.adb_cmd + "tcpip {}".format(port)) + + def usb(self): + return call_checked(self.adb_cmd + "usb") + + def root(self): + return call_checked(self.adb_cmd + "root") + + def unroot(self): + return call_checked(self.adb_cmd + "unroot") + + def forward_remove(self, local): + return call_checked(self.adb_cmd + "forward --remove {}".format(local)) + + def forward_remove_all(self): + return call_checked(self.adb_cmd + "forward --remove-all") + + def connect(self, host): + return call_checked(self.adb_cmd + "connect {}".format(host)) + + def disconnect(self, host): + return call_checked(self.adb_cmd + "disconnect {}".format(host)) + + def reverse(self, remote, local): + return call_checked(self.adb_cmd + "reverse {} {}".format(remote, + local)) + + def reverse_remove_all(self): + return call_checked(self.adb_cmd + "reverse --remove-all") + + def reverse_remove(self, remote): + return call_checked( + self.adb_cmd + "reverse --remove {}".format(remote)) + + def wait(self): + return call_checked(self.adb_cmd + "wait-for-device") + + +class AdbBasic(unittest.TestCase): + def test_shell(self): + """Check that we can at least cat a file.""" + adb = AdbWrapper() + out = adb.shell("cat /proc/uptime") + self.assertEqual(len(out.split()), 2) + self.assertGreater(float(out.split()[0]), 0.0) + self.assertGreater(float(out.split()[1]), 0.0) + + def test_help(self): + """Make sure we get _something_ out of help.""" + out = call_checked("adb help") + self.assertTrue(len(out) > 0) + + def test_version(self): + """Get a version number out of the output of adb.""" + out = call_checked("adb version").split() + version_num = False + for item in out: + if re.match(r"[\d+\.]*\d", item): + version_num = True + self.assertTrue(version_num) + + def _test_root(self): + adb = AdbWrapper() + adb.root() + adb.wait() + self.assertEqual("root", adb.shell("id -un").strip()) + + def _test_unroot(self): + adb = AdbWrapper() + adb.unroot() + adb.wait() + self.assertEqual("shell", adb.shell("id -un").strip()) + + def test_root_unroot(self): + """Make sure that adb root and adb unroot work, using id(1).""" + adb = AdbWrapper() + original_user = adb.shell("id -un").strip() + try: + if original_user == "root": + self._test_unroot() + self._test_root() + elif original_user == "shell": + self._test_root() + self._test_unroot() + finally: + if original_user == "root": + adb.root() + else: + adb.unroot() + adb.wait() + + def test_argument_escaping(self): + """Make sure that argument escaping is somewhat sane.""" + adb = AdbWrapper() + + # http://b/19734868 + result = adb.shell("sh -c 'echo hello; echo world'").splitlines() + self.assertEqual(["hello", "world"], result) + + # http://b/15479704 + self.assertEqual('t', adb.shell("'true && echo t'").strip()) + self.assertEqual('t', adb.shell("sh -c 'true && echo t'").strip()) + + +class AdbFile(unittest.TestCase): + SCRATCH_DIR = "/data/local/tmp" + DEVICE_TEMP_FILE = SCRATCH_DIR + "/adb_test_file" + DEVICE_TEMP_DIR = SCRATCH_DIR + "/adb_test_dir" + + def test_push(self): + """Push a randomly generated file to specified device.""" + kbytes = 512 + adb = AdbWrapper() + with tempfile.NamedTemporaryFile(mode="w") as tmp: + rand_str = os.urandom(1024 * kbytes) + tmp.write(rand_str) + tmp.flush() + + host_md5 = compute_md5(rand_str) + adb.shell_nocheck("rm -r {}".format(AdbFile.DEVICE_TEMP_FILE)) + try: + adb.push(local=tmp.name, remote=AdbFile.DEVICE_TEMP_FILE) + dev_md5, _ = adb.shell( + "md5sum {}".format(AdbFile.DEVICE_TEMP_FILE)).split() + self.assertEqual(host_md5, dev_md5) + finally: + adb.shell_nocheck("rm {}".format(AdbFile.DEVICE_TEMP_FILE)) + + # TODO: write push directory test. + + def test_pull(self): + """Pull a randomly generated file from specified device.""" + kbytes = 512 + adb = AdbWrapper() + adb.shell_nocheck("rm -r {}".format(AdbFile.DEVICE_TEMP_FILE)) + try: + adb.shell("dd if=/dev/urandom of={} bs=1024 count={}".format( + AdbFile.DEVICE_TEMP_FILE, kbytes)) + dev_md5, _ = adb.shell( + "md5sum {}".format(AdbFile.DEVICE_TEMP_FILE)).split() + + with tempfile.NamedTemporaryFile(mode="w") as tmp_write: + adb.pull(remote=AdbFile.DEVICE_TEMP_FILE, local=tmp_write.name) + with open(tmp_write.name) as tmp_read: + host_contents = tmp_read.read() + host_md5 = compute_md5(host_contents) + self.assertEqual(dev_md5, host_md5) + finally: + adb.shell_nocheck("rm {}".format(AdbFile.DEVICE_TEMP_FILE)) + + def test_pull_dir(self): + """Pull a randomly generated directory of files from the device.""" + adb = AdbWrapper() + temp_files = {} + host_dir = None + try: + # create temporary host directory + host_dir = tempfile.mkdtemp() + + # create temporary dir on device + adb.shell_nocheck("rm -r {}".format(AdbFile.DEVICE_TEMP_DIR)) + adb.shell("mkdir -p {}".format(AdbFile.DEVICE_TEMP_DIR)) + + # populate device dir with random files + temp_files = make_random_device_files( + adb, in_dir=AdbFile.DEVICE_TEMP_DIR, num_files=32) + + adb.pull(remote=AdbFile.DEVICE_TEMP_DIR, local=host_dir) + + for device_full_path in temp_files: + host_path = os.path.join( + host_dir, temp_files[device_full_path].base_name) + with open(host_path) as host_file: + host_md5 = compute_md5(host_file.read()) + self.assertEqual(host_md5, + temp_files[device_full_path].md5) + finally: + for dev_file in temp_files.values(): + host_path = os.path.join(host_dir, dev_file.base_name) + os.remove(host_path) + adb.shell_nocheck("rm -r {}".format(AdbFile.DEVICE_TEMP_DIR)) + if host_dir: + os.removedirs(host_dir) + + def test_sync(self): + """Sync a randomly generated directory of files to specified device.""" + try: + adb = AdbWrapper() + temp_files = {} + + # create temporary host directory + base_dir = tempfile.mkdtemp() + + # create mirror device directory hierarchy within base_dir + full_dir_path = base_dir + AdbFile.DEVICE_TEMP_DIR + os.makedirs(full_dir_path) + + # create 32 random files within the host mirror + temp_files = make_random_host_files(in_dir=full_dir_path, + num_files=32) + + # clean up any trash on the device + adb = AdbWrapper(out_dir=base_dir) + adb.shell_nocheck("rm -r {}".format(AdbFile.DEVICE_TEMP_DIR)) + + # issue the sync + adb.sync("data") + + # confirm that every file on the device mirrors that on the host + for host_full_path in temp_files.keys(): + device_full_path = os.path.join( + AdbFile.DEVICE_TEMP_DIR, + temp_files[host_full_path].base_name) + dev_md5, _ = adb.shell( + "md5sum {}".format(device_full_path)).split() + self.assertEqual(temp_files[host_full_path].md5, dev_md5) + + finally: + adb.shell_nocheck("rm -r {}".format(AdbFile.DEVICE_TEMP_DIR)) + if temp_files: + for tf in temp_files.values(): + tf.handle.close() + if base_dir: + os.removedirs(base_dir + AdbFile.DEVICE_TEMP_DIR) + + +if __name__ == '__main__': + random.seed(0) + dev_count = get_attached_device_count() + if dev_count: + suite = unittest.TestLoader().loadTestsFromName(__name__) + unittest.TextTestRunner(verbosity=3).run(suite) + else: + print "Test suite must be run with attached devices" diff --git a/adb/transport.c b/adb/transport.cpp index f35880c..d395a80 100644 --- a/adb/transport.c +++ b/adb/transport.cpp @@ -14,15 +14,18 @@ * limitations under the License. */ +#define TRACE_TAG TRACE_TRANSPORT + +#include "sysdeps.h" +#include "transport.h" + +#include <ctype.h> +#include <errno.h> #include <stdio.h> #include <stdlib.h> -#include <unistd.h> #include <string.h> -#include <errno.h> - -#include "sysdeps.h" +#include <unistd.h> -#define TRACE_TAG TRACE_TRANSPORT #include "adb.h" static void transport_unref(atransport *t); @@ -41,7 +44,7 @@ ADB_MUTEX_DEFINE( transport_lock ); #if ADB_TRACE #define MAX_DUMP_HEX_LEN 16 -static void dump_hex( const unsigned char* ptr, size_t len ) +void dump_hex(const unsigned char* ptr, size_t len) { int nn, len2 = len; // Build a string instead of logging each character. @@ -67,8 +70,7 @@ static void dump_hex( const unsigned char* ptr, size_t len ) } #endif -void -kick_transport(atransport* t) +void kick_transport(atransport* t) { if (t && !t->kicked) { @@ -85,8 +87,25 @@ kick_transport(atransport* t) } } -void -run_transport_disconnects(atransport* t) +// Each atransport contains a list of adisconnects (t->disconnects). +// An adisconnect contains a link to the next/prev adisconnect, a function +// pointer to a disconnect callback which takes a void* piece of user data and +// the atransport, and some user data for the callback (helpfully named +// "opaque"). +// +// The list is circular. New items are added to the entry member of the list +// (t->disconnects) by add_transport_disconnect. +// +// run_transport_disconnects invokes each function in the list. +// +// Gotchas: +// * run_transport_disconnects assumes that t->disconnects is non-null, so +// this can't be run on a zeroed atransport. +// * The callbacks in this list are not removed when called, and this function +// is not guarded against running more than once. As such, ensure that this +// function is not called multiple times on the same atransport. +// TODO(danalbert): Just fix this so that it is guarded once you have tests. +void run_transport_disconnects(atransport* t) { adisconnect* dis = t->disconnects.next; @@ -202,7 +221,7 @@ write_packet(int fd, const char* name, apacket** ppacket) static void transport_socket_events(int fd, unsigned events, void *_t) { - atransport *t = _t; + atransport *t = reinterpret_cast<atransport*>(_t); D("transport_socket_events(fd=%d, events=%04x,...)\n", fd, events); if(events & FDE_READ){ apacket *p = 0; @@ -259,7 +278,7 @@ void send_packet(apacket *p, atransport *t) static void *output_thread(void *_t) { - atransport *t = _t; + atransport *t = reinterpret_cast<atransport*>(_t); apacket *p; D("%s: starting transport output thread on fd %d, SYNC online (%d)\n", @@ -314,7 +333,7 @@ oops: static void *input_thread(void *_t) { - atransport *t = _t; + atransport *t = reinterpret_cast<atransport*>(_t); apacket *p; int active = 0; @@ -387,7 +406,6 @@ static int list_transports_msg(char* buffer, size_t bufferlen) * number of client connections that want it through a single * live TCP connection */ -typedef struct device_tracker device_tracker; struct device_tracker { asocket socket; int update_needed; @@ -475,9 +493,8 @@ device_tracker_ready( asocket* socket ) asocket* create_device_tracker(void) { - device_tracker* tracker = calloc(1,sizeof(*tracker)); - - if(tracker == 0) fatal("cannot allocate device tracker"); + device_tracker* tracker = reinterpret_cast<device_tracker*>(calloc(1, sizeof(*tracker))); + if (tracker == nullptr) fatal("cannot allocate device tracker"); D( "device tracker %p created\n", tracker); @@ -494,8 +511,7 @@ create_device_tracker(void) /* call this function each time the transport list has changed */ -void update_transports(void) -{ +void update_transports(void) { char buffer[1024]; int len; device_tracker* tracker; @@ -517,7 +533,6 @@ void update_transports(void) } #endif // ADB_HOST -typedef struct tmsg tmsg; struct tmsg { atransport *transport; @@ -629,7 +644,7 @@ static void transport_registration_func(int _fd, unsigned ev, void *data) fatal_errno("cannot open transport socketpair"); } - D("transport: %s (%d,%d) starting\n", t->serial, s[0], s[1]); + D("transport: %s socketpair: (%d,%d) starting", t->serial, s[0], s[1]); t->transport_socket = s[0]; t->fd = s[1]; @@ -673,6 +688,7 @@ void init_transport_registration(void) if(adb_socketpair(s)){ fatal_errno("cannot open transport registration socketpair"); } + D("socketpair: (%d,%d)", s[0], s[1]); transport_registration_send = s[0]; transport_registration_recv = s[1]; @@ -751,19 +767,8 @@ 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) + const char *prefix, const char *qual, bool sanitize_qual) { if (!to_test || !*to_test) /* Return true if both the qual and to_test are null strings. */ @@ -781,7 +786,7 @@ static int qual_match(const char *to_test, while (*qual) { char ch = *qual++; - if (sanitize_qual && qual_char_is_invalid(ch)) + if (sanitize_qual && !isalnum(ch)) ch = '_'; if (ch != *to_test++) return 0; @@ -791,21 +796,20 @@ static int qual_match(const char *to_test, return !*to_test; } -atransport *acquire_one_transport(int state, transport_type ttype, const char* serial, char** error_out) +atransport* acquire_one_transport(int state, transport_type ttype, + const char* serial, std::string* error_out) { atransport *t; atransport *result = NULL; int ambiguous = 0; retry: - if (error_out) - *error_out = "device not found"; + if (error_out) *error_out = "device not found"; adb_mutex_lock(&transport_lock); for (t = transport_list.next; t != &transport_list; t = t->next) { if (t->connection_state == CS_NOPERM) { - if (error_out) - *error_out = "insufficient permissions for device"; + if (error_out) *error_out = "insufficient permissions for device"; continue; } @@ -813,12 +817,11 @@ retry: if (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)) { + qual_match(serial, "product:", t->product, false) || + qual_match(serial, "model:", t->model, true) || + qual_match(serial, "device:", t->device, false)) { if (result) { - if (error_out) - *error_out = "more than one device"; + if (error_out) *error_out = "more than one device"; ambiguous = 1; result = NULL; break; @@ -828,8 +831,7 @@ retry: } else { if (ttype == kTransportUsb && t->type == kTransportUsb) { if (result) { - if (error_out) - *error_out = "more than one device"; + if (error_out) *error_out = "more than one device"; ambiguous = 1; result = NULL; break; @@ -837,8 +839,7 @@ retry: result = t; } else if (ttype == kTransportLocal && t->type == kTransportLocal) { if (result) { - if (error_out) - *error_out = "more than one emulator"; + if (error_out) *error_out = "more than one emulator"; ambiguous = 1; result = NULL; break; @@ -846,8 +847,7 @@ retry: result = t; } else if (ttype == kTransportAny) { if (result) { - if (error_out) - *error_out = "more than one device and emulator"; + if (error_out) *error_out = "more than one device and emulator"; ambiguous = 1; result = NULL; break; @@ -860,29 +860,33 @@ retry: if (result) { if (result->connection_state == CS_UNAUTHORIZED) { - if (error_out) - *error_out = "device unauthorized. Please check the confirmation dialog on your device."; + if (error_out) { + *error_out = "device unauthorized.\n"; + char* ADB_VENDOR_KEYS = getenv("ADB_VENDOR_KEYS"); + *error_out += "This adbd's $ADB_VENDOR_KEYS is "; + *error_out += ADB_VENDOR_KEYS ? ADB_VENDOR_KEYS : "not set"; + *error_out += "; try 'adb kill-server' if that seems wrong.\n"; + *error_out += "Otherwise check for a confirmation dialog on your device."; + } result = NULL; } - /* offline devices are ignored -- they are either being born or dying */ + /* offline devices are ignored -- they are either being born or dying */ if (result && result->connection_state == CS_OFFLINE) { - if (error_out) - *error_out = "device offline"; + if (error_out) *error_out = "device offline"; result = NULL; } - /* check for required connection state */ + + /* check for required connection state */ if (result && state != CS_ANY && result->connection_state != state) { - if (error_out) - *error_out = "invalid device state"; + if (error_out) *error_out = "invalid device state"; result = NULL; } } if (result) { /* found one that we can take */ - if (error_out) - *error_out = NULL; + if (error_out) *error_out = "success"; } else if (state != CS_ANY && (serial || !ambiguous)) { adb_sleep_ms(1000); goto retry; @@ -908,20 +912,17 @@ static const char *statename(atransport *t) } static void add_qual(char **buf, size_t *buf_size, - const char *prefix, const char *qual, int sanitize_qual) + const char *prefix, const char *qual, bool 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); + int prefix_len; + size_t 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)) + for (char* cp = *buf + prefix_len; cp < *buf + len; cp++) { + if (!isalnum(*cp)) *cp = '_'; } } @@ -946,10 +947,10 @@ static size_t format_transport(atransport *t, char *buf, size_t bufsize, 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); + add_qual(&buf, &remaining, " ", t->devpath, false); + add_qual(&buf, &remaining, " product:", t->product, false); + add_qual(&buf, &remaining, " model:", t->model, true); + add_qual(&buf, &remaining, " device:", t->device, false); len = snprintf(buf, remaining, "\n"); remaining -= len; @@ -999,7 +1000,11 @@ void close_usb_devices() int register_socket_transport(int s, const char *serial, int port, int local) { - atransport *t = calloc(1, sizeof(atransport)); + atransport *t = reinterpret_cast<atransport*>(calloc(1, sizeof(atransport))); + if (t == nullptr) { + return -1; + } + atransport *n; char buff[32]; @@ -1098,7 +1103,8 @@ void unregister_all_tcp_transports() void register_usb_transport(usb_handle *usb, const char *serial, const char *devpath, unsigned writeable) { - atransport *t = calloc(1, sizeof(atransport)); + atransport *t = reinterpret_cast<atransport*>(calloc(1, sizeof(atransport))); + if (t == nullptr) fatal("cannot allocate USB atransport"); D("transport: %p init'ing for usb_handle %p (sn='%s')\n", t, usb, serial ? serial : ""); init_usb_transport(t, usb, (writeable ? CS_OFFLINE : CS_NOPERM)); @@ -1137,70 +1143,6 @@ void unregister_usb_transport(usb_handle *usb) #undef TRACE_TAG #define TRACE_TAG TRACE_RWX -int readx(int fd, void *ptr, size_t len) -{ - char *p = ptr; - int r; -#if ADB_TRACE - size_t len0 = len; -#endif - D("readx: fd=%d wanted=%zu\n", fd, len); - while(len > 0) { - r = adb_read(fd, p, len); - if(r > 0) { - len -= r; - p += r; - } else { - if (r < 0) { - D("readx: fd=%d error %d: %s\n", fd, errno, strerror(errno)); - if (errno == EINTR) - continue; - } else { - D("readx: fd=%d disconnected\n", fd); - } - return -1; - } - } - -#if ADB_TRACE - D("readx: fd=%d wanted=%zu got=%zu\n", fd, len0, len0 - len); - dump_hex( ptr, len0 ); -#endif - return 0; -} - -int writex(int fd, const void *ptr, size_t len) -{ - char *p = (char*) ptr; - int r; - -#if ADB_TRACE - D("writex: fd=%d len=%d: ", fd, (int)len); - dump_hex( ptr, len ); -#endif - while(len > 0) { - r = adb_write(fd, p, len); - if(r > 0) { - len -= r; - p += r; - } else { - if (r < 0) { - D("writex: fd=%d error %d: %s\n", fd, errno, strerror(errno)); - if (errno == EINTR) - continue; - if (errno == EAGAIN) { - adb_sleep_ms(1); // just yield some cpu time - continue; - } - } else { - D("writex: fd=%d disconnected\n", fd); - } - return -1; - } - } - return 0; -} - int check_header(apacket *p) { if(p->msg.magic != (p->msg.command ^ 0xffffffff)) { diff --git a/adb/transport.h b/adb/transport.h index 992e052..a2077e8 100644 --- a/adb/transport.h +++ b/adb/transport.h @@ -17,10 +17,58 @@ #ifndef __TRANSPORT_H #define __TRANSPORT_H -/* convenience wrappers around read/write that will retry on -** EINTR and/or short read/write. Returns 0 on success, -1 -** on error or EOF. +#include <sys/types.h> + +#include <string> + +#include "adb.h" + +#if ADB_TRACE +void dump_hex(const unsigned char* ptr, size_t len); +#endif + +/* + * Obtain a transport from the available transports. + * If state is != CS_ANY, only transports in that state are considered. + * If serial is non-NULL then only the device with that serial will be chosen. + * If no suitable transport is found, error is set. + */ +atransport* acquire_one_transport(int state, transport_type ttype, + const char* serial, std::string* error_out); +void add_transport_disconnect(atransport* t, adisconnect* dis); +void remove_transport_disconnect(atransport* t, adisconnect* dis); +void kick_transport(atransport* t); +void run_transport_disconnects(atransport* t); +void update_transports(void); + +/* transports are ref-counted +** get_device_transport does an acquire on your behalf before returning */ -int readx(int fd, void *ptr, size_t len); -int writex(int fd, const void *ptr, size_t len); +void init_transport_registration(void); +int list_transports(char* buf, size_t bufsize, int long_listing); +atransport* find_transport(const char* serial); + +void register_usb_transport(usb_handle* h, const char* serial, + const char* devpath, unsigned writeable); + +/* cause new transports to be init'd and added to the list */ +int register_socket_transport(int s, const char* serial, int port, int local); + +/* this should only be used for transports with connection_state == CS_NOPERM */ +void unregister_usb_transport(usb_handle* usb); + +/* these should only be used for the "adb disconnect" command */ +void unregister_transport(atransport* t); +void unregister_all_tcp_transports(); + +int check_header(apacket* p); +int check_data(apacket* p); + +/* for MacOS X cleanup */ +void close_usb_devices(); + +void send_packet(apacket* p, atransport* t); + +asocket* create_device_tracker(void); + #endif /* __TRANSPORT_H */ diff --git a/adb/transport_local.c b/adb/transport_local.cpp index 948cc15..30e6bf5 100644 --- a/adb/transport_local.c +++ b/adb/transport_local.cpp @@ -14,34 +14,23 @@ * limitations under the License. */ +#define TRACE_TAG TRACE_TRANSPORT + +#include "sysdeps.h" +#include "transport.h" + +#include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <errno.h> - -#include "sysdeps.h" #include <sys/types.h> + #if !ADB_HOST -#include <cutils/properties.h> +#include "cutils/properties.h" #endif -#define TRACE_TAG TRACE_TRANSPORT #include "adb.h" - -#ifdef HAVE_BIG_ENDIAN -#define H4(x) (((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24) -static inline void fix_endians(apacket *p) -{ - p->msg.command = H4(p->msg.command); - p->msg.arg0 = H4(p->msg.arg0); - p->msg.arg1 = H4(p->msg.arg1); - p->msg.data_length = H4(p->msg.data_length); - p->msg.data_check = H4(p->msg.data_check); - p->msg.magic = H4(p->msg.magic); -} -#else -#define fix_endians(p) do {} while (0) -#endif +#include "adb_io.h" #if ADB_HOST /* we keep a list of opened transports. The atransport struct knows to which @@ -57,23 +46,17 @@ static atransport* local_transports[ ADB_LOCAL_TRANSPORT_MAX ]; static int remote_read(apacket *p, atransport *t) { - if(readx(t->sfd, &p->msg, sizeof(amessage))){ + if(!ReadFdExactly(t->sfd, &p->msg, sizeof(amessage))){ D("remote local: read terminated (message)\n"); return -1; } - fix_endians(p); - -#if 0 && defined HAVE_BIG_ENDIAN - D("read remote packet: %04x arg0=%0x arg1=%0x data_length=%0x data_check=%0x magic=%0x\n", - p->msg.command, p->msg.arg0, p->msg.arg1, p->msg.data_length, p->msg.data_check, p->msg.magic); -#endif if(check_header(p)) { D("bad header: terminated (data)\n"); return -1; } - if(readx(t->sfd, p->data, p->msg.data_length)){ + if(!ReadFdExactly(t->sfd, p->data, p->msg.data_length)){ D("remote local: terminated (data)\n"); return -1; } @@ -90,13 +73,7 @@ static int remote_write(apacket *p, atransport *t) { int length = p->msg.data_length; - fix_endians(p); - -#if 0 && defined HAVE_BIG_ENDIAN - D("write remote packet: %04x arg0=%0x arg1=%0x data_length=%0x data_check=%0x magic=%0x\n", - p->msg.command, p->msg.arg0, p->msg.arg1, p->msg.data_length, p->msg.data_check, p->msg.magic); -#endif - if(writex(t->sfd, &p->msg, sizeof(amessage) + length)) { + if(!WriteFdExactly(t->sfd, &p->msg, sizeof(amessage) + length)) { D("remote local: write terminated\n"); return -1; } @@ -167,7 +144,7 @@ static void *server_socket_thread(void * arg) if(serverfd == -1) { serverfd = socket_inaddr_any_server(port, SOCK_STREAM); if(serverfd < 0) { - D("server: cannot bind socket yet\n"); + D("server: cannot bind socket yet: %s\n", strerror(errno)); adb_sleep_ms(1000); continue; } diff --git a/adb/transport_test.cpp b/adb/transport_test.cpp new file mode 100644 index 0000000..2b3fe3c --- /dev/null +++ b/adb/transport_test.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2015 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 "transport.h" + +#include <gtest/gtest.h> + +#include "adb.h" + +TEST(transport, kick_transport) { + atransport t = {}; + // Mutate some member so we can test that the function is run. + t.kick = [](atransport* trans) { trans->fd = 42; }; + atransport expected = t; + expected.fd = 42; + expected.kicked = 1; + kick_transport(&t); + ASSERT_EQ(42, t.fd); + ASSERT_EQ(1, t.kicked); + ASSERT_EQ(0, memcmp(&expected, &t, sizeof(atransport))); +} + +TEST(transport, kick_transport_already_kicked) { + // Ensure that the transport is not modified if the transport has already been + // kicked. + atransport t = {}; + t.kicked = 1; + t.kick = [](atransport*) { FAIL() << "Kick should not have been called"; }; + atransport expected = t; + kick_transport(&t); + ASSERT_EQ(0, memcmp(&expected, &t, sizeof(atransport))); +} + +// Disabled because the function currently segfaults for a zeroed atransport. I +// want to make sure I understand how this is working at all before I try fixing +// that. +TEST(transport, DISABLED_run_transport_disconnects_zeroed_atransport) { + atransport t = {}; + run_transport_disconnects(&t); +} diff --git a/adb/transport_usb.c b/adb/transport_usb.cpp index ee6b637..cdabffe 100644 --- a/adb/transport_usb.c +++ b/adb/transport_usb.cpp @@ -14,42 +14,17 @@ * limitations under the License. */ +#define TRACE_TAG TRACE_TRANSPORT + +#include "sysdeps.h" +#include "transport.h" + #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <sysdeps.h> - -#define TRACE_TAG TRACE_TRANSPORT #include "adb.h" -#if ADB_HOST -#include "usb_vendors.h" -#endif - -#ifdef HAVE_BIG_ENDIAN -#define H4(x) (((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24) -static inline void fix_endians(apacket *p) -{ - p->msg.command = H4(p->msg.command); - p->msg.arg0 = H4(p->msg.arg0); - p->msg.arg1 = H4(p->msg.arg1); - p->msg.data_length = H4(p->msg.data_length); - p->msg.data_check = H4(p->msg.data_check); - p->msg.magic = H4(p->msg.magic); -} -unsigned host_to_le32(unsigned n) -{ - return H4(n); -} -#else -#define fix_endians(p) do {} while (0) -unsigned host_to_le32(unsigned n) -{ - return n; -} -#endif - static int remote_read(apacket *p, atransport *t) { if(usb_read(t->usb, &p->msg, sizeof(amessage))){ @@ -57,8 +32,6 @@ static int remote_read(apacket *p, atransport *t) return -1; } - fix_endians(p); - if(check_header(p)) { D("remote usb: check_header failed\n"); return -1; @@ -83,8 +56,6 @@ static int remote_write(apacket *p, atransport *t) { unsigned size = p->msg.data_length; - fix_endians(p); - if(usb_write(t->usb, &p->msg, sizeof(amessage))) { D("remote usb: 1 - write terminated\n"); return -1; @@ -131,18 +102,6 @@ void init_usb_transport(atransport *t, usb_handle *h, int state) #if ADB_HOST int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol) { - unsigned i; - for (i = 0; i < vendorIdCount; i++) { - if (vid == vendorIds[i]) { - if (usb_class == ADB_CLASS && usb_subclass == ADB_SUBCLASS && - usb_protocol == ADB_PROTOCOL) { - return 1; - } - - return 0; - } - } - - return 0; + return (usb_class == ADB_CLASS && usb_subclass == ADB_SUBCLASS && usb_protocol == ADB_PROTOCOL); } #endif diff --git a/adb/usb_libusb.c b/adb/usb_libusb.c deleted file mode 100644 index 06ff5dc..0000000 --- a/adb/usb_libusb.c +++ /dev/null @@ -1,657 +0,0 @@ -/* - * Copyright (C) 2009 bsdroid project - * Alexey Tarasov <tarasov@dodologics.com> - * - * Copyright (C) 2007 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 <sys/endian.h> -#include <sys/ioctl.h> -#include <sys/types.h> -#include <sys/uio.h> - -#include <err.h> -#include <errno.h> -#include <poll.h> -#include <stdio.h> -#include <stdlib.h> -#include <strings.h> -#include <string.h> -#include <sysexits.h> -#include <unistd.h> -#include <libusb.h> -#include "sysdeps.h" - -#define TRACE_TAG TRACE_USB -#include "adb.h" - -static adb_mutex_t usb_lock = ADB_MUTEX_INITIALIZER; -static libusb_context *ctx = NULL; - -struct usb_handle -{ - usb_handle *prev; - usb_handle *next; - - libusb_device *dev; - libusb_device_handle *devh; - int interface; - uint8_t dev_bus; - uint8_t dev_addr; - - int zero_mask; - unsigned char end_point_address[2]; - char serial[128]; - - adb_cond_t notify; - adb_mutex_t lock; -}; - -static struct usb_handle handle_list = { - .prev = &handle_list, - .next = &handle_list, -}; - -void -usb_cleanup() -{ - libusb_exit(ctx); -} - -void -report_bulk_libusb_error(int r) -{ - switch (r) { - case LIBUSB_ERROR_TIMEOUT: - D("Transfer timeout\n"); - break; - - case LIBUSB_ERROR_PIPE: - D("Control request is not supported\n"); - break; - - case LIBUSB_ERROR_OVERFLOW: - D("Device offered more data\n"); - break; - - case LIBUSB_ERROR_NO_DEVICE : - D("Device was disconnected\n"); - break; - - default: - D("Error %d during transfer\n", r); - break; - }; -} - -static int -usb_bulk_write(usb_handle *uh, const void *data, int len) -{ - int r = 0; - int transferred = 0; - - r = libusb_bulk_transfer(uh->devh, uh->end_point_address[1], (void *)data, len, - &transferred, 0); - - if (r != 0) { - D("usb_bulk_write(): "); - report_bulk_libusb_error(r); - return r; - } - - return (transferred); -} - -static int -usb_bulk_read(usb_handle *uh, void *data, int len) -{ - int r = 0; - int transferred = 0; - - r = libusb_bulk_transfer(uh->devh, uh->end_point_address[0], data, len, - &transferred, 0); - - if (r != 0) { - D("usb_bulk_read(): "); - report_bulk_libusb_error(r); - return r; - } - - return (transferred); -} - -int -usb_write(struct usb_handle *uh, const void *_data, int len) -{ - unsigned char *data = (unsigned char*) _data; - int n; - int need_zero = 0; - - if (uh->zero_mask == 1) { - if (!(len & uh->zero_mask)) { - need_zero = 1; - } - } - - D("usb_write(): %p:%d -> transport %p\n", _data, len, uh); - - while (len > 0) { - int xfer = (len > 4096) ? 4096 : len; - - n = usb_bulk_write(uh, data, xfer); - - if (n != xfer) { - D("usb_write(): failed for transport %p (%d bytes left)\n", uh, len); - return -1; - } - - len -= xfer; - data += xfer; - } - - if (need_zero){ - n = usb_bulk_write(uh, _data, 0); - - if (n < 0) { - D("usb_write(): failed to finish operation for transport %p\n", uh); - } - return n; - } - - return 0; -} - -int -usb_read(struct usb_handle *uh, void *_data, int len) -{ - unsigned char *data = (unsigned char*) _data; - int n; - - D("usb_read(): %p:%d <- transport %p\n", _data, len, uh); - - while (len > 0) { - int xfer = (len > 4096) ? 4096 : len; - - n = usb_bulk_read(uh, data, xfer); - - if (n != xfer) { - if (n > 0) { - data += n; - len -= n; - continue; - } - - D("usb_read(): failed for transport %p (%d bytes left)\n", uh, len); - return -1; - } - - len -= xfer; - data += xfer; - } - - return 0; - } - -int -usb_close(struct usb_handle *h) -{ - D("usb_close(): closing transport %p\n", h); - adb_mutex_lock(&usb_lock); - - h->next->prev = h->prev; - h->prev->next = h->next; - h->prev = NULL; - h->next = NULL; - - libusb_release_interface(h->devh, h->interface); - libusb_close(h->devh); - libusb_unref_device(h->dev); - - adb_mutex_unlock(&usb_lock); - - free(h); - - return (0); -} - -void usb_kick(struct usb_handle *h) -{ - D("usb_cick(): kicking transport %p\n", h); - - adb_mutex_lock(&h->lock); - unregister_usb_transport(h); - adb_mutex_unlock(&h->lock); - - h->next->prev = h->prev; - h->prev->next = h->next; - h->prev = NULL; - h->next = NULL; - - libusb_release_interface(h->devh, h->interface); - libusb_close(h->devh); - libusb_unref_device(h->dev); - free(h); -} - -int -check_usb_interface(libusb_interface *interface, - libusb_device_descriptor *desc, - struct usb_handle *uh) -{ - int e; - - if (interface->num_altsetting == 0) { - D("check_usb_interface(): No interface settings\n"); - return -1; - } - - libusb_interface_descriptor *idesc = &interface->altsetting[0]; - - if (idesc->bNumEndpoints != 2) { - D("check_usb_interface(): Interface have not 2 endpoints, ignoring\n"); - return -1; - } - - for (e = 0; e < idesc->bNumEndpoints; e++) { - libusb_endpoint_descriptor *edesc = &idesc->endpoint[e]; - - if (edesc->bmAttributes != LIBUSB_TRANSFER_TYPE_BULK) { - D("check_usb_interface(): Endpoint (%u) is not bulk (%u), ignoring\n", - edesc->bmAttributes, LIBUSB_TRANSFER_TYPE_BULK); - return -1; - } - - if (edesc->bEndpointAddress & LIBUSB_ENDPOINT_IN) - uh->end_point_address[0] = edesc->bEndpointAddress; - else - uh->end_point_address[1] = edesc->bEndpointAddress; - - /* aproto 01 needs 0 termination */ - if (idesc->bInterfaceProtocol == 0x01) { - uh->zero_mask = edesc->wMaxPacketSize - 1; - D("check_usb_interface(): Forced Android interface protocol v.1\n"); - } - } - - D("check_usb_interface(): Device: %04x:%04x " - "iclass: %x, isclass: %x, iproto: %x ep: %x/%x-> ", - desc->idVendor, desc->idProduct, idesc->bInterfaceClass, - idesc->bInterfaceSubClass, idesc->bInterfaceProtocol, - uh->end_point_address[0], uh->end_point_address[1]); - - if (!is_adb_interface(desc->idVendor, desc->idProduct, - idesc->bInterfaceClass, idesc->bInterfaceSubClass, - idesc->bInterfaceProtocol)) - { - D("not matches\n"); - return -1; - } - - D("matches\n"); - return 1; -} - -int -check_usb_interfaces(libusb_config_descriptor *config, - libusb_device_descriptor *desc, struct usb_handle *uh) -{ - int i; - - for (i = 0; i < config->bNumInterfaces; ++i) { - if (check_usb_interface(&config->interface[i], desc, uh) != -1) { - /* found some interface and saved information about it */ - D("check_usb_interfaces(): Interface %d of %04x:%04x " - "matches Android device\n", i, desc->idVendor, - desc->idProduct); - - return i; - } - } - - return -1; -} - -int -register_device(struct usb_handle *uh, const char *serial) -{ - D("register_device(): Registering %p [%s] as USB transport\n", - uh, serial); - - struct usb_handle *usb= NULL; - - usb = calloc(1, sizeof(struct usb_handle)); - memcpy(usb, uh, sizeof(struct usb_handle)); - strcpy(usb->serial, uh->serial); - - adb_cond_init(&usb->notify, 0); - adb_mutex_init(&usb->lock, 0); - - adb_mutex_lock(&usb_lock); - - usb->next = &handle_list; - usb->prev = handle_list.prev; - usb->prev->next = usb; - usb->next->prev = usb; - - adb_mutex_unlock(&usb_lock); - - register_usb_transport(usb, serial, NULL, 1); - - return (1); -} - -int -already_registered(usb_handle *uh) -{ - struct usb_handle *usb= NULL; - int exists = 0; - - adb_mutex_lock(&usb_lock); - - for (usb = handle_list.next; usb != &handle_list; usb = usb->next) { - if ((usb->dev_bus == uh->dev_bus) && - (usb->dev_addr == uh->dev_addr)) - { - exists = 1; - break; - } - } - - adb_mutex_unlock(&usb_lock); - - return exists; -} - -void -check_device(libusb_device *dev) -{ - struct usb_handle uh; - int i = 0; - int found = -1; - char serial[256] = {0}; - - libusb_device_descriptor desc; - libusb_config_descriptor *config = NULL; - - int r = libusb_get_device_descriptor(dev, &desc); - - if (r != LIBUSB_SUCCESS) { - D("check_device(): Failed to get device descriptor\n"); - return; - } - - if ((desc.idVendor == 0) && (desc.idProduct == 0)) - return; - - D("check_device(): Probing usb device %04x:%04x\n", - desc.idVendor, desc.idProduct); - - if (!is_adb_interface (desc.idVendor, desc.idProduct, - ADB_CLASS, ADB_SUBCLASS, ADB_PROTOCOL)) - { - D("check_device(): Ignored due unknown vendor id\n"); - return; - } - - uh.dev_bus = libusb_get_bus_number(dev); - uh.dev_addr = libusb_get_device_address(dev); - - if (already_registered(&uh)) { - D("check_device(): Device (bus: %d, address: %d) " - "is already registered\n", uh.dev_bus, uh.dev_addr); - return; - } - - D("check_device(): Device bus: %d, address: %d\n", - uh.dev_bus, uh.dev_addr); - - r = libusb_get_active_config_descriptor(dev, &config); - - if (r != 0) { - if (r == LIBUSB_ERROR_NOT_FOUND) { - D("check_device(): Device %4x:%4x is unconfigured\n", - desc.idVendor, desc.idProduct); - return; - } - - D("check_device(): Failed to get configuration for %4x:%4x\n", - desc.idVendor, desc.idProduct); - return; - } - - if (config == NULL) { - D("check_device(): Sanity check failed after " - "getting active config\n"); - return; - } - - if (config->interface != NULL) { - found = check_usb_interfaces(config, &desc, &uh); - } - - /* not needed anymore */ - libusb_free_config_descriptor(config); - - r = libusb_open(dev, &uh.devh); - uh.dev = dev; - - if (r != 0) { - switch (r) { - case LIBUSB_ERROR_NO_MEM: - D("check_device(): Memory allocation problem\n"); - break; - - case LIBUSB_ERROR_ACCESS: - D("check_device(): Permissions problem, " - "current user priveleges are messed up?\n"); - break; - - case LIBUSB_ERROR_NO_DEVICE: - D("check_device(): Device disconected, bad cable?\n"); - break; - - default: - D("check_device(): libusb triggered error %d\n", r); - } - // skip rest - found = -1; - } - - if (found >= 0) { - D("check_device(): Device matches Android interface\n"); - // read the device's serial number - memset(serial, 0, sizeof(serial)); - uh.interface = found; - - r = libusb_claim_interface(uh.devh, uh.interface); - - if (r < 0) { - D("check_device(): Failed to claim interface %d\n", - uh.interface); - - goto fail; - } - - if (desc.iSerialNumber) { - // reading serial - uint16_t buffer[128] = {0}; - uint16_t languages[128] = {0}; - int languageCount = 0; - - memset(languages, 0, sizeof(languages)); - r = libusb_control_transfer(uh.devh, - LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE, - LIBUSB_REQUEST_GET_DESCRIPTOR, LIBUSB_DT_STRING << 8, - 0, (uint8_t *)languages, sizeof(languages), 0); - - if (r <= 0) { - D("check_device(): Failed to get languages count\n"); - goto fail; - } - - languageCount = (r - 2) / 2; - - for (i = 1; i <= languageCount; ++i) { - memset(buffer, 0, sizeof(buffer)); - - r = libusb_control_transfer(uh.devh, - LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE, - LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_STRING << 8) | desc.iSerialNumber, - languages[i], (uint8_t *)buffer, sizeof(buffer), 0); - - if (r > 0) { /* converting serial */ - int j = 0; - r /= 2; - - for (j = 1; j < r; ++j) - serial[j - 1] = buffer[j]; - - serial[j - 1] = '\0'; - break; /* languagesCount cycle */ - } - } - - if (register_device(&uh, serial) == 0) { - D("check_device(): Failed to register device\n"); - goto fail_interface; - } - - libusb_ref_device(dev); - } - } - - return; - -fail_interface: - libusb_release_interface(uh.devh, uh.interface); - -fail: - libusb_close(uh.devh); - uh.devh = NULL; -} - -int -check_device_connected(struct usb_handle *uh) -{ - int r = libusb_kernel_driver_active(uh->devh, uh->interface); - - if (r == LIBUSB_ERROR_NO_DEVICE) - return 0; - - if (r < 0) - return -1; - - return 1; -} - -void -kick_disconnected() -{ - struct usb_handle *usb= NULL; - - adb_mutex_lock(&usb_lock); - - for (usb = handle_list.next; usb != &handle_list; usb = usb->next) { - - if (check_device_connected(usb) == 0) { - D("kick_disconnected(): Transport %p is not online anymore\n", - usb); - - usb_kick(usb); - } - } - - adb_mutex_unlock(&usb_lock); -} - -void -scan_usb_devices() -{ - D("scan_usb_devices(): started\n"); - - libusb_device **devs= NULL; - libusb_device *dev= NULL; - ssize_t cnt = libusb_get_device_list(ctx, &devs); - - if (cnt < 0) { - D("scan_usb_devices(): Failed to get device list (error: %d)\n", - cnt); - - return; - } - - int i = 0; - - while ((dev = devs[i++]) != NULL) { - check_device(dev); - } - - libusb_free_device_list(devs, 1); -} - -void * -device_poll_thread(void* unused) -{ - D("device_poll_thread(): Created USB scan thread\n"); - - for (;;) { - sleep(5); - kick_disconnected(); - scan_usb_devices(); - } - - /* never reaching this point */ - return (NULL); -} - -static void -sigalrm_handler(int signo) -{ - /* nothing */ -} - -void -usb_init() -{ - D("usb_init(): started\n"); - adb_thread_t tid; - struct sigaction actions; - - int r = libusb_init(&ctx); - - if (r != LIBUSB_SUCCESS) { - err(EX_IOERR, "Failed to init libusb\n"); - } - - memset(&actions, 0, sizeof(actions)); - - sigemptyset(&actions.sa_mask); - - actions.sa_flags = 0; - actions.sa_handler = sigalrm_handler; - - sigaction(SIGALRM, &actions, NULL); - - /* initial device scan */ - scan_usb_devices(); - - /* starting USB event polling thread */ - if (adb_thread_create(&tid, device_poll_thread, NULL)) { - err(EX_IOERR, "cannot create USB scan thread\n"); - } - - D("usb_init(): finished\n"); -} - diff --git a/adb/usb_linux.c b/adb/usb_linux.cpp index f16bdd0..31fd167 100644 --- a/adb/usb_linux.c +++ b/adb/usb_linux.cpp @@ -14,33 +14,31 @@ * limitations under the License. */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> +#define TRACE_TAG TRACE_USB -#include <sys/ioctl.h> -#include <sys/types.h> -#include <sys/time.h> +#include "sysdeps.h" + +#include <ctype.h> #include <dirent.h> -#include <fcntl.h> #include <errno.h> -#include <ctype.h> - +#include <fcntl.h> #include <linux/usbdevice_fs.h> #include <linux/version.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/time.h> +#include <sys/types.h> +#include <unistd.h> #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20) #include <linux/usb/ch9.h> #else #include <linux/usb_ch9.h> #endif -#include <asm/byteorder.h> -#include "sysdeps.h" - -#define TRACE_TAG TRACE_USB #include "adb.h" - +#include "transport.h" /* usb scan debugging is waaaay too verbose */ #define DBGX(x...) @@ -116,10 +114,6 @@ static void kick_disconnected_devices() } -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) { while(*name) { @@ -237,8 +231,20 @@ static void find_usb_device(const char *base, // looks like ADB... ep1 = (struct usb_endpoint_descriptor *)bufptr; bufptr += USB_DT_ENDPOINT_SIZE; + // For USB 3.0 SuperSpeed devices, skip potential + // USB 3.0 SuperSpeed Endpoint Companion descriptor + if (bufptr+2 <= devdesc + desclength && + bufptr[0] == USB_DT_SS_EP_COMP_SIZE && + bufptr[1] == USB_DT_SS_ENDPOINT_COMP) { + bufptr += USB_DT_SS_EP_COMP_SIZE; + } ep2 = (struct usb_endpoint_descriptor *)bufptr; bufptr += USB_DT_ENDPOINT_SIZE; + if (bufptr+2 <= devdesc + desclength && + bufptr[0] == USB_DT_SS_EP_COMP_SIZE && + bufptr[1] == USB_DT_SS_ENDPOINT_COMP) { + bufptr += USB_DT_SS_EP_COMP_SIZE; + } if (bufptr > devdesc + desclength || ep1->bLength != USB_DT_ENDPOINT_SIZE || @@ -367,6 +373,7 @@ static int usb_bulk_read(usb_handle *h, void *data, int len) struct usbdevfs_urb *out = NULL; int res; + D("++ usb_bulk_read ++\n"); memset(urb, 0, sizeof(*urb)); urb->type = USBDEVFS_URB_TYPE_BULK; urb->endpoint = h->ep_in; @@ -429,6 +436,7 @@ static int usb_bulk_read(usb_handle *h, void *data, int len) } fail: adb_mutex_unlock(&h->lock); + D("-- usb_bulk_read --\n"); return res; } @@ -439,6 +447,7 @@ int usb_write(usb_handle *h, const void *_data, int len) int n; int need_zero = 0; + D("++ usb_write ++\n"); if(h->zero_mask) { /* if we need 0-markers and our transfer ** is an even multiple of the packet size, @@ -468,6 +477,7 @@ int usb_write(usb_handle *h, const void *_data, int len) return n; } + D("-- usb_write --\n"); return 0; } @@ -542,7 +552,7 @@ void usb_kick(usb_handle *h) int usb_close(usb_handle *h) { - D("[ usb close ... ]\n"); + D("++ usb close ++\n"); adb_mutex_lock(&usb_lock); h->next->prev = h->prev; h->prev->next = h->next; @@ -550,7 +560,7 @@ int usb_close(usb_handle *h) h->next = 0; adb_close(h->desc); - D("[ usb closed %p (fd = %d) ]\n", h, h->desc); + D("-- usb closed %p (fd = %d) --\n", h, h->desc); adb_mutex_unlock(&usb_lock); free(h); @@ -561,7 +571,6 @@ 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) { - usb_handle* usb = 0; int n = 0; char serial[256]; @@ -574,17 +583,17 @@ static void register_device(const char *dev_name, const char *devpath, ** name, we have no further work to do. */ adb_mutex_lock(&usb_lock); - for(usb = handle_list.next; usb != &handle_list; usb = usb->next){ - if(!strcmp(usb->fname, dev_name)) { + for (usb_handle* usb = handle_list.next; usb != &handle_list; usb = usb->next) { + if (!strcmp(usb->fname, dev_name)) { adb_mutex_unlock(&usb_lock); return; } } adb_mutex_unlock(&usb_lock); - D("[ usb located new device %s (%d/%d/%d) ]\n", - dev_name, ep_in, ep_out, interface); - usb = calloc(1, sizeof(usb_handle)); + D("[ usb located new device %s (%d/%d/%d) ]\n", dev_name, ep_in, ep_out, interface); + usb_handle* usb = reinterpret_cast<usb_handle*>(calloc(1, sizeof(usb_handle))); + if (usb == nullptr) fatal("couldn't allocate usb_handle"); strcpy(usb->fname, dev_name); usb->ep_in = ep_in; usb->ep_out = ep_out; @@ -598,16 +607,27 @@ static void register_device(const char *dev_name, const char *devpath, usb->reaper_thread = 0; usb->desc = unix_open(usb->fname, O_RDWR | O_CLOEXEC); - if(usb->desc < 0) { - /* if we fail, see if have read-only access */ + if (usb->desc == -1) { + // Opening RW failed, so see if we have RO access. usb->desc = unix_open(usb->fname, O_RDONLY | O_CLOEXEC); - if(usb->desc < 0) goto fail; + if (usb->desc == -1) { + D("[ usb open %s failed: %s]\n", usb->fname, strerror(errno)); + free(usb); + return; + } usb->writeable = 0; - D("[ usb open read-only %s fd = %d]\n", usb->fname, usb->desc); - } else { - D("[ usb open %s fd = %d]\n", usb->fname, usb->desc); + } + + D("[ usb opened %s%s, fd=%d]\n", usb->fname, (usb->writeable ? "" : " (read-only)"), usb->desc); + + if (usb->writeable) { n = ioctl(usb->desc, USBDEVFS_CLAIMINTERFACE, &interface); - if(n != 0) goto fail; + if (n != 0) { + D("[ usb ioctl(%d, USBDEVFS_CLAIMINTERFACE) failed: %s]\n", usb->desc, strerror(errno)); + adb_close(usb->desc); + free(usb); + return; + } } /* read the device's serial number */ @@ -670,15 +690,6 @@ static void register_device(const char *dev_name, const char *devpath, adb_mutex_unlock(&usb_lock); register_usb_transport(usb, serial, devpath, usb->writeable); - return; - -fail: - D("[ usb open %s error=%d, err_str = %s]\n", - usb->fname, errno, strerror(errno)); - if(usb->desc >= 0) { - adb_close(usb->desc); - } - free(usb); } void* device_poll_thread(void* unused) diff --git a/adb/usb_linux_client.c b/adb/usb_linux_client.cpp index 8426e0e..18289e2 100644 --- a/adb/usb_linux_client.c +++ b/adb/usb_linux_client.cpp @@ -14,25 +14,28 @@ * limitations under the License. */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> +#define TRACE_TAG TRACE_USB + +#include "sysdeps.h" +#include <cutils/properties.h> +#include <dirent.h> +#include <errno.h> #include <linux/usb/ch9.h> #include <linux/usb/functionfs.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> #include <sys/ioctl.h> #include <sys/types.h> -#include <dirent.h> -#include <errno.h> - -#include "sysdeps.h" +#include <unistd.h> -#define TRACE_TAG TRACE_USB #include "adb.h" +#include "transport.h" #define MAX_PACKET_SIZE_FS 64 #define MAX_PACKET_SIZE_HS 512 +#define MAX_PACKET_SIZE_SS 1024 #define cpu_to_le16(x) htole16(x) #define cpu_to_le32(x) htole32(x) @@ -55,71 +58,81 @@ struct usb_handle 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, +struct func_desc { + struct usb_interface_descriptor intf; + struct usb_endpoint_descriptor_no_audio source; + struct usb_endpoint_descriptor_no_audio sink; +} __attribute__((packed)); + +struct desc_v1 { + struct usb_functionfs_descs_head_v1 { + __le32 magic; + __le32 length; + __le32 fs_count; + __le32 hs_count; + } __attribute__((packed)) header; + struct func_desc fs_descs, hs_descs; +} __attribute__((packed)); + +struct desc_v2 { + struct usb_functionfs_descs_head_v2 header; + // The rest of the structure depends on the flags in the header. + __le32 fs_count; + __le32 hs_count; + struct func_desc fs_descs, hs_descs; +} __attribute__((packed)); + +struct func_desc fs_descriptors = { + .intf = { + .bLength = sizeof(fs_descriptors.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 */ }, - .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, - }, + .source = { + .bLength = sizeof(fs_descriptors.source), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 1 | USB_DIR_OUT, + .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, - }, + .sink = { + .bLength = sizeof(fs_descriptors.sink), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 2 | USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = MAX_PACKET_SIZE_FS, + }, +}; + +struct func_desc hs_descriptors = { + .intf = { + .bLength = sizeof(hs_descriptors.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(hs_descriptors.source), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 1 | USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = MAX_PACKET_SIZE_HS, + }, + .sink = { + .bLength = sizeof(hs_descriptors.sink), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 2 | USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = MAX_PACKET_SIZE_HS, }, }; @@ -151,7 +164,7 @@ static void *usb_adb_open_thread(void *x) struct usb_handle *usb = (struct usb_handle *)x; int fd; - while (1) { + while (true) { // wait until the USB device needs opening adb_mutex_lock(&usb->lock); while (usb->fd != -1) @@ -227,11 +240,8 @@ static void usb_adb_kick(usb_handle *h) static void usb_adb_init() { - usb_handle *h; - adb_thread_t tid; - int fd; - - h = calloc(1, sizeof(usb_handle)); + usb_handle* h = reinterpret_cast<usb_handle*>(calloc(1, sizeof(usb_handle))); + if (h == nullptr) fatal("couldn't allocate usb_handle"); h->write = usb_adb_write; h->read = usb_adb_read; @@ -241,12 +251,12 @@ static void usb_adb_init() adb_cond_init(&h->notify, 0); adb_mutex_init(&h->lock, 0); - // Open the file /dev/android_adb_enable to trigger + // Open the file /dev/android_adb_enable to trigger // the enabling of the adb USB function in the kernel. // We never touch this file again - just leave it open // indefinitely so the kernel will know when we are running // and when we are not. - fd = unix_open("/dev/android_adb_enable", O_RDWR); + int fd = unix_open("/dev/android_adb_enable", O_RDWR); if (fd < 0) { D("failed to open /dev/android_adb_enable\n"); } else { @@ -254,6 +264,7 @@ static void usb_adb_init() } D("[ usb_init - starting thread ]\n"); + adb_thread_t tid; if(adb_thread_create(&tid, usb_adb_open_thread, h)){ fatal_errno("cannot create usb thread"); } @@ -263,6 +274,16 @@ static void usb_adb_init() static void init_functionfs(struct usb_handle *h) { ssize_t ret; + struct desc_v1 v1_descriptor; + struct desc_v2 v2_descriptor; + + v2_descriptor.header.magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2); + v2_descriptor.header.length = cpu_to_le32(sizeof(v2_descriptor)); + v2_descriptor.header.flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC; + v2_descriptor.fs_count = 3; + v2_descriptor.hs_count = 3; + v2_descriptor.fs_descs = fs_descriptors; + v2_descriptor.hs_descs = hs_descriptors; if (h->control < 0) { // might have already done this before D("OPENING %s\n", USB_FFS_ADB_EP0); @@ -272,10 +293,20 @@ static void init_functionfs(struct usb_handle *h) goto err; } - ret = adb_write(h->control, &descriptors, sizeof(descriptors)); + ret = adb_write(h->control, &v2_descriptor, sizeof(v2_descriptor)); if (ret < 0) { - D("[ %s: write descriptors failed: errno=%d ]\n", USB_FFS_ADB_EP0, errno); - goto err; + v1_descriptor.header.magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC); + v1_descriptor.header.length = cpu_to_le32(sizeof(v1_descriptor)); + v1_descriptor.header.fs_count = 3; + v1_descriptor.header.hs_count = 3; + v1_descriptor.fs_descs = fs_descriptors; + v1_descriptor.hs_descs = hs_descriptors; + D("[ %s: Switching to V1_descriptor format errno=%d ]\n", USB_FFS_ADB_EP0, errno); + ret = adb_write(h->control, &v1_descriptor, sizeof(v1_descriptor)); + 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)); @@ -319,14 +350,14 @@ static void *usb_ffs_open_thread(void *x) { struct usb_handle *usb = (struct usb_handle *)x; - while (1) { + while (true) { // wait until the USB device needs opening adb_mutex_lock(&usb->lock); while (usb->control != -1 && usb->bulk_in != -1 && usb->bulk_out != -1) adb_cond_wait(&usb->notify, &usb->lock); adb_mutex_unlock(&usb->lock); - while (1) { + while (true) { init_functionfs(usb); if (usb->control >= 0 && usb->bulk_in >= 0 && usb->bulk_out >= 0) @@ -334,6 +365,7 @@ static void *usb_ffs_open_thread(void *x) adb_sleep_ms(1000); } + property_set("sys.usb.ffs.ready", "1"); D("[ usb_thread - registering device ]\n"); register_usb_transport(usb, 0, 0, 1); @@ -343,7 +375,7 @@ static void *usb_ffs_open_thread(void *x) return 0; } -static int bulk_write(int bulk_in, const char *buf, size_t length) +static int bulk_write(int bulk_in, const uint8_t* buf, size_t length) { size_t count = 0; int ret; @@ -362,22 +394,19 @@ static int bulk_write(int bulk_in, const char *buf, size_t length) return count; } -static int usb_ffs_write(usb_handle *h, const void *data, int len) +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); + int n = bulk_write(h->bulk_in, reinterpret_cast<const uint8_t*>(data), len); if (n != len) { - D("ERROR: fd = %d, n = %d, errno = %d (%s)\n", - h->bulk_in, n, errno, strerror(errno)); + D("ERROR: fd = %d, n = %d: %s\n", h->bulk_in, n, 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) +static int bulk_read(int bulk_out, uint8_t* buf, size_t length) { size_t count = 0; int ret; @@ -398,15 +427,12 @@ static int bulk_read(int bulk_out, char *buf, size_t length) return count; } -static int usb_ffs_read(usb_handle *h, void *data, int len) +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); + int n = bulk_read(h->bulk_out, reinterpret_cast<uint8_t*>(data), len); if (n != len) { - D("ERROR: fd = %d, n = %d, errno = %d (%s)\n", - h->bulk_out, n, errno, strerror(errno)); + D("ERROR: fd = %d, n = %d: %s\n", h->bulk_out, n, strerror(errno)); return -1; } D("[ done fd=%d ]\n", h->bulk_out); @@ -441,18 +467,15 @@ static void usb_ffs_kick(usb_handle *h) static void usb_ffs_init() { - usb_handle *h; - adb_thread_t tid; - D("[ usb_init - using FunctionFS ]\n"); - h = calloc(1, sizeof(usb_handle)); + usb_handle* h = reinterpret_cast<usb_handle*>(calloc(1, sizeof(usb_handle))); + if (h == nullptr) fatal("couldn't allocate usb_handle"); h->write = usb_ffs_write; h->read = usb_ffs_read; h->kick = usb_ffs_kick; - - h->control = -1; + h->control = -1; h->bulk_out = -1; h->bulk_out = -1; @@ -460,6 +483,7 @@ static void usb_ffs_init() adb_mutex_init(&h->lock, 0); D("[ usb_init - starting thread ]\n"); + adb_thread_t tid; if (adb_thread_create(&tid, usb_ffs_open_thread, h)){ fatal_errno("[ cannot create usb thread ]\n"); } diff --git a/adb/usb_osx.c b/adb/usb_osx.cpp index ca4f2af..a795ce3 100644 --- a/adb/usb_osx.c +++ b/adb/usb_osx.cpp @@ -14,6 +14,10 @@ * limitations under the License. */ +#define TRACE_TAG TRACE_USB + +#include "sysdeps.h" + #include <CoreFoundation/CoreFoundation.h> #include <IOKit/IOKitLib.h> @@ -22,18 +26,16 @@ #include <IOKit/IOMessage.h> #include <mach/mach_port.h> -#include "sysdeps.h" - +#include <inttypes.h> #include <stdio.h> -#define TRACE_TAG TRACE_USB #include "adb.h" -#include "usb_vendors.h" +#include "transport.h" #define DBG D static IONotificationPortRef notificationPort = 0; -static io_iterator_t* notificationIterators; +static io_iterator_t notificationIterator; struct usb_handle { @@ -61,8 +63,6 @@ InitUSB() { CFMutableDictionaryRef matchingDict; CFRunLoopSourceRef runLoopSource; - SInt32 vendor, if_subclass, if_protocol; - unsigned i; //* To set up asynchronous notifications, create a notification port and //* add its run loop event source to the program's run loop @@ -70,47 +70,33 @@ InitUSB() runLoopSource = IONotificationPortGetRunLoopSource(notificationPort); CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode); - memset(notificationIterators, 0, sizeof(notificationIterators)); - - //* loop through all supported vendors - for (i = 0; i < vendorIdCount; i++) { - //* Create our matching dictionary to find the Android device's - //* adb interface - //* IOServiceAddMatchingNotification consumes the reference, so we do - //* not need to release this - matchingDict = IOServiceMatching(kIOUSBInterfaceClassName); + //* Create our matching dictionary to find the Android device's + //* adb interface + //* IOServiceAddMatchingNotification consumes the reference, so we do + //* not need to release this + matchingDict = IOServiceMatching(kIOUSBInterfaceClassName); - if (!matchingDict) { - DBG("ERR: Couldn't create USB matching dictionary.\n"); - return -1; - } - - //* Match based on vendor id, interface subclass and protocol - vendor = vendorIds[i]; - if_subclass = ADB_SUBCLASS; - if_protocol = ADB_PROTOCOL; - CFDictionarySetValue(matchingDict, CFSTR(kUSBVendorID), - CFNumberCreate(kCFAllocatorDefault, - kCFNumberSInt32Type, &vendor)); - CFDictionarySetValue(matchingDict, CFSTR(kUSBInterfaceSubClass), - CFNumberCreate(kCFAllocatorDefault, - kCFNumberSInt32Type, &if_subclass)); - CFDictionarySetValue(matchingDict, CFSTR(kUSBInterfaceProtocol), - CFNumberCreate(kCFAllocatorDefault, - kCFNumberSInt32Type, &if_protocol)); - IOServiceAddMatchingNotification( - notificationPort, - kIOFirstMatchNotification, - matchingDict, - AndroidInterfaceAdded, - NULL, - ¬ificationIterators[i]); - - //* Iterate over set of matching interfaces to access already-present - //* devices and to arm the notification - AndroidInterfaceAdded(NULL, notificationIterators[i]); + if (!matchingDict) { + DBG("ERR: Couldn't create USB matching dictionary.\n"); + return -1; } + //* We have to get notifications for all potential candidates and test them + //* at connection time because the matching rules don't allow for a + //* USB interface class of 0xff for class+subclass+protocol matches + //* See https://developer.apple.com/library/mac/qa/qa1076/_index.html + IOServiceAddMatchingNotification( + notificationPort, + kIOFirstMatchNotification, + matchingDict, + AndroidInterfaceAdded, + NULL, + ¬ificationIterator); + + //* Iterate over set of matching interfaces to access already-present + //* devices and to arm the notification + AndroidInterfaceAdded(NULL, notificationIterator); + return 0; } @@ -126,6 +112,7 @@ AndroidInterfaceAdded(void *refCon, io_iterator_t iterator) HRESULT result; SInt32 score; UInt32 locationId; + UInt8 if_class, subclass, protocol; UInt16 vendor; UInt16 product; UInt8 serialIndex; @@ -146,9 +133,9 @@ AndroidInterfaceAdded(void *refCon, io_iterator_t iterator) } //* This gets us the interface object - result = (*plugInInterface)->QueryInterface(plugInInterface, - CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID) - &iface); + result = (*plugInInterface)->QueryInterface( + plugInInterface, + CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID*)&iface); //* We only needed the plugin to get the interface, so discard it (*plugInInterface)->Release(plugInInterface); if (result || !iface) { @@ -156,6 +143,16 @@ AndroidInterfaceAdded(void *refCon, io_iterator_t iterator) continue; } + kr = (*iface)->GetInterfaceClass(iface, &if_class); + kr = (*iface)->GetInterfaceSubClass(iface, &subclass); + kr = (*iface)->GetInterfaceProtocol(iface, &protocol); + if(if_class != ADB_CLASS || subclass != ADB_SUBCLASS || protocol != ADB_PROTOCOL) { + // Ignore non-ADB devices. + DBG("Ignoring interface with incorrect class/subclass/protocol - %d, %d, %d\n", if_class, subclass, protocol); + (*iface)->Release(iface); + continue; + } + //* this gets us an ioservice, with which we will find the actual //* device; after getting a plugin, and querying the interface, of //* course. @@ -181,7 +178,7 @@ AndroidInterfaceAdded(void *refCon, io_iterator_t iterator) } result = (*plugInInterface)->QueryInterface(plugInInterface, - CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID) &dev); + CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID*)&dev); //* only needed this to query the plugin (*plugInInterface)->Release(plugInInterface); if (result || !dev) { @@ -192,12 +189,12 @@ AndroidInterfaceAdded(void *refCon, io_iterator_t iterator) //* Now after all that, we actually have a ref to the device and //* the interface that matched our criteria - 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); + snprintf(devpathBuf, sizeof(devpathBuf), "usb:%" PRIu32 "X", + (unsigned int)locationId); devpath = devpathBuf; } kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex); @@ -338,7 +335,8 @@ CheckInterface(IOUSBInterfaceInterface **interface, UInt16 vendor, UInt16 produc interfaceSubClass, interfaceProtocol)) goto err_bad_adb_interface; - handle = calloc(1, sizeof(usb_handle)); + handle = reinterpret_cast<usb_handle*>(calloc(1, sizeof(usb_handle))); + if (handle == nullptr) goto err_bad_adb_interface; //* Iterate over the endpoints for this interface and find the first //* bulk in/out pipes available. These will be our read/write pipes. @@ -384,8 +382,6 @@ err_get_num_ep: void* RunLoopThread(void* unused) { - unsigned i; - InitUSB(); currentRunLoop = CFRunLoopGetCurrent(); @@ -398,9 +394,7 @@ void* RunLoopThread(void* unused) CFRunLoopRun(); currentRunLoop = 0; - for (i = 0; i < vendorIdCount; i++) { - IOObjectRelease(notificationIterators[i]); - } + IOObjectRelease(notificationIterator); IONotificationPortDestroy(notificationPort); DBG("RunLoopThread done\n"); @@ -415,9 +409,6 @@ void usb_init() { adb_thread_t tid; - notificationIterators = (io_iterator_t*)malloc( - vendorIdCount * sizeof(io_iterator_t)); - adb_mutex_init(&start_lock, NULL); adb_cond_init(&start_cond, NULL); @@ -442,11 +433,6 @@ void usb_cleanup() close_usb_devices(); if (currentRunLoop) CFRunLoopStop(currentRunLoop); - - if (notificationIterators != NULL) { - free(notificationIterators); - notificationIterators = NULL; - } } int usb_write(usb_handle *handle, const void *buf, int len) diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c deleted file mode 100755 index 19bcae4..0000000 --- a/adb/usb_vendors.c +++ /dev/null @@ -1,370 +0,0 @@ -/* - * Copyright (C) 2009 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 "usb_vendors.h" - -#include <stdio.h> -#include <stdlib.h> - -#ifdef _WIN32 -# ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -# endif -# include "windows.h" -# include "shlobj.h" -#else -# include <unistd.h> -# include <sys/stat.h> -#endif - -#include "sysdeps.h" -#include "adb.h" - -#define ANDROID_PATH ".android" -#define ANDROID_ADB_INI "adb_usb.ini" - -#define TRACE_TAG TRACE_USB - -/* Keep the list below sorted alphabetically by #define name */ -// Acer's USB Vendor ID -#define VENDOR_ID_ACER 0x0502 -// Allwinner's USB Vendor ID -#define VENDOR_ID_ALLWINNER 0x1F3A -// Amlogic's USB Vendor ID -#define VENDOR_ID_AMLOGIC 0x1b8e -// AnyDATA's USB Vendor ID -#define VENDOR_ID_ANYDATA 0x16D5 -// Archos's USB Vendor ID -#define VENDOR_ID_ARCHOS 0x0E79 -// Asus's USB Vendor ID -#define VENDOR_ID_ASUS 0x0b05 -// BYD's USB Vendor ID -#define VENDOR_ID_BYD 0x1D91 -// Compal's USB Vendor ID -#define VENDOR_ID_COMPAL 0x04B7 -// Compalcomm's USB Vendor ID -#define VENDOR_ID_COMPALCOMM 0x1219 -// Dell's USB Vendor ID -#define VENDOR_ID_DELL 0x413c -// ECS's USB Vendor ID -#define VENDOR_ID_ECS 0x03fc -// EMERGING_TECH's USB Vendor ID -#define VENDOR_ID_EMERGING_TECH 0x297F -// Emerson's USB Vendor ID -#define VENDOR_ID_EMERSON 0x2207 -// Foxconn's USB Vendor ID -#define VENDOR_ID_FOXCONN 0x0489 -// Fujitsu's USB Vendor ID -#define VENDOR_ID_FUJITSU 0x04C5 -// Funai's USB Vendor ID -#define VENDOR_ID_FUNAI 0x0F1C -// Garmin-Asus's USB Vendor ID -#define VENDOR_ID_GARMIN_ASUS 0x091E -// Gigabyte's USB Vendor ID -#define VENDOR_ID_GIGABYTE 0x0414 -// Gigaset's USB Vendor ID -#define VENDOR_ID_GIGASET 0x1E85 -// GIONEE's USB Vendor ID -#define VENDOR_ID_GIONEE 0x271D -// Google's USB Vendor ID -#define VENDOR_ID_GOOGLE 0x18d1 -// Haier's USB Vendor ID -#define VENDOR_ID_HAIER 0x201E -// Harris's USB Vendor ID -#define VENDOR_ID_HARRIS 0x19A5 -// Hisense's USB Vendor ID -#define VENDOR_ID_HISENSE 0x109b -// Honeywell's USB Vendor ID -#define VENDOR_ID_HONEYWELL 0x0c2e -// HP's USB Vendor ID -#define VENDOR_ID_HP 0x03f0 -// HTC's USB Vendor ID -#define VENDOR_ID_HTC 0x0bb4 -// Huawei's USB Vendor ID -#define VENDOR_ID_HUAWEI 0x12D1 -// INQ Mobile's USB Vendor ID -#define VENDOR_ID_INQ_MOBILE 0x2314 -// Intel's USB Vendor ID -#define VENDOR_ID_INTEL 0x8087 -// Intermec's USB Vendor ID -#define VENDOR_ID_INTERMEC 0x067e -// IRiver's USB Vendor ID -#define VENDOR_ID_IRIVER 0x2420 -// K-Touch's USB Vendor ID -#define VENDOR_ID_K_TOUCH 0x24E3 -// KT Tech's USB Vendor ID -#define VENDOR_ID_KT_TECH 0x2116 -// Kobo's USB Vendor ID -#define VENDOR_ID_KOBO 0x2237 -// Kyocera's USB Vendor ID -#define VENDOR_ID_KYOCERA 0x0482 -// Lab126's USB Vendor ID -#define VENDOR_ID_LAB126 0x1949 -// Lenovo's USB Vendor ID -#define VENDOR_ID_LENOVO 0x17EF -// LenovoMobile's USB Vendor ID -#define VENDOR_ID_LENOVOMOBILE 0x2006 -// LG's USB Vendor ID -#define VENDOR_ID_LGE 0x1004 -// Lumigon's USB Vendor ID -#define VENDOR_ID_LUMIGON 0x25E3 -// Motorola's USB Vendor ID -#define VENDOR_ID_MOTOROLA 0x22b8 -// MSI's USB Vendor ID -#define VENDOR_ID_MSI 0x0DB0 -// MTK's USB Vendor ID -#define VENDOR_ID_MTK 0x0e8d -// NEC's USB Vendor ID -#define VENDOR_ID_NEC 0x0409 -// B&N Nook's USB Vendor ID -#define VENDOR_ID_NOOK 0x2080 -// Nvidia's USB Vendor ID -#define VENDOR_ID_NVIDIA 0x0955 -// OPPO's USB Vendor ID -#define VENDOR_ID_OPPO 0x22D9 -// On-The-Go-Video's USB Vendor ID -#define VENDOR_ID_OTGV 0x2257 -// OUYA's USB Vendor ID -#define VENDOR_ID_OUYA 0x2836 -// Pantech's USB Vendor ID -#define VENDOR_ID_PANTECH 0x10A9 -// Pegatron's USB Vendor ID -#define VENDOR_ID_PEGATRON 0x1D4D -// Philips's USB Vendor ID -#define VENDOR_ID_PHILIPS 0x0471 -// Panasonic Mobile Communication's USB Vendor ID -#define VENDOR_ID_PMC 0x04DA -// Positivo's USB Vendor ID -#define VENDOR_ID_POSITIVO 0x1662 -// Prestigio's USB Vendor ID -#define VENDOR_ID_PRESTIGIO 0x29e4 -// Qisda's USB Vendor ID -#define VENDOR_ID_QISDA 0x1D45 -// Qualcomm's USB Vendor ID -#define VENDOR_ID_QUALCOMM 0x05c6 -// Quanta's USB Vendor ID -#define VENDOR_ID_QUANTA 0x0408 -// Rockchip's USB Vendor ID -#define VENDOR_ID_ROCKCHIP 0x2207 -// Samsung's USB Vendor ID -#define VENDOR_ID_SAMSUNG 0x04e8 -// Sharp's USB Vendor ID -#define VENDOR_ID_SHARP 0x04dd -// SK Telesys's USB Vendor ID -#define VENDOR_ID_SK_TELESYS 0x1F53 -// Smartisan's USB Vendor ID -#define VENDOR_ID_SMARTISAN 0x29a9 -// Sony's USB Vendor ID -#define VENDOR_ID_SONY 0x054C -// Sony Ericsson's USB Vendor ID -#define VENDOR_ID_SONY_ERICSSON 0x0FCE -// T & A Mobile Phones' USB Vendor ID -#define VENDOR_ID_T_AND_A 0x1BBB -// TechFaith's USB Vendor ID -#define VENDOR_ID_TECHFAITH 0x1d09 -// Teleepoch's USB Vendor ID -#define VENDOR_ID_TELEEPOCH 0x2340 -// Texas Instruments's USB Vendor ID -#define VENDOR_ID_TI 0x0451 -// Toshiba's USB Vendor ID -#define VENDOR_ID_TOSHIBA 0x0930 -// Unowhy's USB Vendor ID -#define VENDOR_ID_UNOWHY 0x2A49 -// Vizio's USB Vendor ID -#define VENDOR_ID_VIZIO 0xE040 -// Wacom's USB Vendor ID -#define VENDOR_ID_WACOM 0x0531 -// Xiaomi's USB Vendor ID -#define VENDOR_ID_XIAOMI 0x2717 -// YotaDevices's USB Vendor ID -#define VENDOR_ID_YOTADEVICES 0x2916 -// Yulong Coolpad's USB Vendor ID -#define VENDOR_ID_YULONG_COOLPAD 0x1EBF -// ZTE's USB Vendor ID -#define VENDOR_ID_ZTE 0x19D2 -/* Keep the list above sorted alphabetically by #define name */ - -/** built-in vendor list */ -/* Keep the list below sorted alphabetically */ -int builtInVendorIds[] = { - VENDOR_ID_ACER, - VENDOR_ID_ALLWINNER, - VENDOR_ID_AMLOGIC, - VENDOR_ID_ANYDATA, - VENDOR_ID_ARCHOS, - VENDOR_ID_ASUS, - VENDOR_ID_BYD, - VENDOR_ID_COMPAL, - VENDOR_ID_COMPALCOMM, - VENDOR_ID_DELL, - VENDOR_ID_ECS, - VENDOR_ID_EMERGING_TECH, - VENDOR_ID_EMERSON, - VENDOR_ID_FOXCONN, - VENDOR_ID_FUJITSU, - VENDOR_ID_FUNAI, - VENDOR_ID_GARMIN_ASUS, - VENDOR_ID_GIGABYTE, - VENDOR_ID_GIGASET, - VENDOR_ID_GIONEE, - VENDOR_ID_GOOGLE, - VENDOR_ID_HAIER, - VENDOR_ID_HARRIS, - VENDOR_ID_HISENSE, - VENDOR_ID_HONEYWELL, - VENDOR_ID_HP, - VENDOR_ID_HTC, - VENDOR_ID_HUAWEI, - VENDOR_ID_INQ_MOBILE, - VENDOR_ID_INTEL, - VENDOR_ID_INTERMEC, - VENDOR_ID_IRIVER, - VENDOR_ID_KOBO, - VENDOR_ID_K_TOUCH, - VENDOR_ID_KT_TECH, - VENDOR_ID_KYOCERA, - VENDOR_ID_LAB126, - VENDOR_ID_LENOVO, - VENDOR_ID_LENOVOMOBILE, - VENDOR_ID_LGE, - VENDOR_ID_LUMIGON, - VENDOR_ID_MOTOROLA, - VENDOR_ID_MSI, - VENDOR_ID_MTK, - VENDOR_ID_NEC, - VENDOR_ID_NOOK, - VENDOR_ID_NVIDIA, - VENDOR_ID_OPPO, - VENDOR_ID_OTGV, - VENDOR_ID_OUYA, - VENDOR_ID_PANTECH, - VENDOR_ID_PEGATRON, - VENDOR_ID_PHILIPS, - VENDOR_ID_PMC, - VENDOR_ID_POSITIVO, - VENDOR_ID_PRESTIGIO, - VENDOR_ID_QISDA, - VENDOR_ID_QUALCOMM, - VENDOR_ID_QUANTA, - VENDOR_ID_ROCKCHIP, - VENDOR_ID_SAMSUNG, - VENDOR_ID_SHARP, - VENDOR_ID_SK_TELESYS, - VENDOR_ID_SMARTISAN, - VENDOR_ID_SONY, - VENDOR_ID_SONY_ERICSSON, - VENDOR_ID_T_AND_A, - VENDOR_ID_TECHFAITH, - VENDOR_ID_TELEEPOCH, - VENDOR_ID_TI, - VENDOR_ID_TOSHIBA, - VENDOR_ID_UNOWHY, - VENDOR_ID_VIZIO, - VENDOR_ID_WACOM, - VENDOR_ID_XIAOMI, - VENDOR_ID_YOTADEVICES, - VENDOR_ID_YULONG_COOLPAD, - VENDOR_ID_ZTE, -}; -/* Keep the list above sorted alphabetically */ - -#define BUILT_IN_VENDOR_COUNT (sizeof(builtInVendorIds)/sizeof(builtInVendorIds[0])) - -/* max number of supported vendor ids (built-in + 3rd party). increase as needed */ -#define VENDOR_COUNT_MAX 128 - -int vendorIds[VENDOR_COUNT_MAX]; -unsigned vendorIdCount = 0; - -int get_adb_usb_ini(char* buff, size_t len); - -void usb_vendors_init(void) -{ - if (VENDOR_COUNT_MAX < BUILT_IN_VENDOR_COUNT) { - fprintf(stderr, "VENDOR_COUNT_MAX not big enough for built-in vendor list.\n"); - exit(2); - } - - /* add the built-in vendors at the beginning of the array */ - memcpy(vendorIds, builtInVendorIds, sizeof(builtInVendorIds)); - - /* default array size is the number of built-in vendors */ - vendorIdCount = BUILT_IN_VENDOR_COUNT; - - if (VENDOR_COUNT_MAX == BUILT_IN_VENDOR_COUNT) - return; - - char temp[PATH_MAX]; - if (get_adb_usb_ini(temp, sizeof(temp)) == 0) { - FILE * f = fopen(temp, "rt"); - - if (f != NULL) { - /* The vendor id file is pretty basic. 1 vendor id per line. - Lines starting with # are comments */ - while (fgets(temp, sizeof(temp), f) != NULL) { - if (temp[0] == '#') - continue; - - long value = strtol(temp, NULL, 0); - if (errno == EINVAL || errno == ERANGE || value > INT_MAX || value < 0) { - fprintf(stderr, "Invalid content in %s. Quitting.\n", ANDROID_ADB_INI); - exit(2); - } - - vendorIds[vendorIdCount++] = (int)value; - - /* make sure we don't go beyond the array */ - if (vendorIdCount == VENDOR_COUNT_MAX) { - break; - } - } - fclose(f); - } - } -} - -/* Utils methods */ - -/* builds the path to the adb vendor id file. returns 0 if success */ -int build_path(char* buff, size_t len, const char* format, const char* home) -{ - if (snprintf(buff, len, format, home, ANDROID_PATH, ANDROID_ADB_INI) >= (signed)len) { - return 1; - } - - return 0; -} - -/* fills buff with the path to the adb vendor id file. returns 0 if success */ -int get_adb_usb_ini(char* buff, size_t len) -{ -#ifdef _WIN32 - const char* home = getenv("ANDROID_SDK_HOME"); - if (home != NULL) { - return build_path(buff, len, "%s\\%s\\%s", home); - } else { - char path[MAX_PATH]; - SHGetFolderPath( NULL, CSIDL_PROFILE, NULL, 0, path); - return build_path(buff, len, "%s\\%s\\%s", path); - } -#else - const char* home = getenv("HOME"); - if (home == NULL) - home = "/tmp"; - - return build_path(buff, len, "%s/%s/%s", home); -#endif -} diff --git a/adb/usb_windows.c b/adb/usb_windows.cpp index a2d7226..d2bd58c 100644 --- a/adb/usb_windows.c +++ b/adb/usb_windows.cpp @@ -14,19 +14,21 @@ * limitations under the License. */ -#include <winsock2.h> -#include <windows.h> -#include <winerror.h> -#include <errno.h> -#include <usb100.h> +#define TRACE_TAG TRACE_USB + +#include "sysdeps.h" + +#include <winsock2.h> // winsock.h *must* be included before windows.h. #include <adb_api.h> +#include <errno.h> #include <stdio.h> #include <stdlib.h> +#include <usb100.h> +#include <windows.h> +#include <winerror.h> -#include "sysdeps.h" - -#define TRACE_TAG TRACE_USB #include "adb.h" +#include "transport.h" /** Structure usb_handle describes our connection to the usb device via AdbWinApi.dll. This structure is returned from usb_open() routine and |