diff options
Diffstat (limited to 'adb')
-rw-r--r-- | adb/Android.mk | 18 | ||||
-rw-r--r-- | adb/adb.c | 41 | ||||
-rw-r--r-- | adb/adb.h | 92 | ||||
-rw-r--r-- | adb/adb_auth_client.c | 7 | ||||
-rw-r--r-- | adb/adb_auth_host.c | 66 | ||||
-rw-r--r-- | adb/adb_client.c | 3 | ||||
-rw-r--r-- | adb/adb_trace.h | 143 | ||||
-rw-r--r-- | adb/backup_service.c | 152 | ||||
-rw-r--r-- | adb/commandline.c | 627 | ||||
-rw-r--r-- | adb/fdevent.c | 13 | ||||
-rw-r--r-- | adb/file_sync_client.c | 166 | ||||
-rw-r--r-- | adb/file_sync_service.c | 17 | ||||
-rw-r--r-- | adb/file_sync_service.h | 4 | ||||
-rw-r--r-- | adb/remount_service.c | 45 | ||||
-rw-r--r-- | adb/services.c | 169 | ||||
-rw-r--r-- | adb/sockets.c | 13 | ||||
-rw-r--r-- | adb/sysdeps.h | 3 | ||||
-rw-r--r-- | adb/sysdeps_win32.c | 4 | ||||
-rw-r--r-- | adb/usb_linux.c | 6 | ||||
-rw-r--r-- | adb/usb_osx.c | 17 | ||||
-rwxr-xr-x | adb/usb_vendors.c | 18 | ||||
-rw-r--r-- | adb/usb_windows.c | 1 |
22 files changed, 956 insertions, 669 deletions
diff --git a/adb/Android.mk b/adb/Android.mk index 50e28a6..3828ed3 100644 --- a/adb/Android.mk +++ b/adb/Android.mk @@ -24,6 +24,7 @@ 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_CFLAGS += -Wno-sizeof-pointer-memaccess -Wno-unused-parameter endif ifeq ($(HOST_OS),freebsd) @@ -39,13 +40,11 @@ ifeq ($(HOST_OS),windows) ifneq ($(strip $(USE_CYGWIN)),) # Pure cygwin case LOCAL_LDLIBS += -lpthread -lgdi32 - LOCAL_C_INCLUDES += /usr/include/w32api/ddk endif ifneq ($(strip $(USE_MINGW)),) # MinGW under Linux case LOCAL_LDLIBS += -lws2_32 -lgdi32 USE_SYSDEPS_WIN32 := 1 - LOCAL_C_INCLUDES += /usr/i586-mingw32msvc/include/ddk endif LOCAL_C_INCLUDES += development/host/windows/usb/api/ endif @@ -84,6 +83,7 @@ ifeq ($(USE_SYSDEPS_WIN32),) LOCAL_STATIC_LIBRARIES += libcutils endif +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk include $(BUILD_HOST_EXECUTABLE) $(call dist-for-goals,dist_files sdk,$(LOCAL_BUILT_MODULE)) @@ -102,7 +102,6 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := \ adb.c \ - backup_service.c \ fdevent.c \ transport.c \ transport_local.c \ @@ -116,8 +115,13 @@ LOCAL_SRC_FILES := \ remount_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 +LOCAL_CFLAGS := \ + -O2 \ + -g \ + -DADB_HOST=0 \ + -D_XOPEN_SOURCE \ + -D_GNU_SOURCE \ + -Wall -Wno-unused-parameter -Werror -Wno-deprecated-declarations \ ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT))) LOCAL_CFLAGS += -DALLOW_ADBD_ROOT=1 @@ -130,6 +134,7 @@ LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN) LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED) LOCAL_STATIC_LIBRARIES := liblog libcutils libc libmincrypt libselinux +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk include $(BUILD_EXECUTABLE) @@ -168,9 +173,10 @@ LOCAL_C_INCLUDES += external/openssl/include LOCAL_MODULE := adb -LOCAL_STATIC_LIBRARIES := libzipfile libunz libcutils +LOCAL_STATIC_LIBRARIES := libzipfile libunz libcutils liblog LOCAL_SHARED_LIBRARIES := libcrypto +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk include $(BUILD_EXECUTABLE) endif @@ -37,8 +37,8 @@ #include <cutils/properties.h> #include <private/android_filesystem_config.h> #include <sys/capability.h> -#include <linux/prctl.h> #include <sys/mount.h> +#include <sys/prctl.h> #include <getopt.h> #include <selinux/selinux.h> #else @@ -329,6 +329,7 @@ static void send_msg_with_header(int fd, const char* msg, size_t 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) @@ -337,6 +338,7 @@ static void send_msg_with_okay(int fd, const char* msg, size_t msglen) { writex(fd, header, 8); writex(fd, msg, msglen); } +#endif // ADB_HOST static void send_connect(atransport *t) { @@ -414,6 +416,7 @@ void adb_auth_verified(atransport *t) send_connect(t); } +#if ADB_HOST static char *connection_state_name(atransport *t) { if (t == NULL) { @@ -437,6 +440,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 @@ -943,7 +947,7 @@ nomem: return INSTALL_STATUS_INTERNAL_ERROR; } -#ifdef HAVE_WIN32_PROC +#if defined(_WIN32) static BOOL WINAPI ctrlc_handler(DWORD type) { exit(STATUS_CONTROL_C_EXIT); @@ -958,7 +962,7 @@ static void adb_cleanup(void) void start_logging(void) { -#ifdef HAVE_WIN32_PROC +#if defined(_WIN32) char temp[ MAX_PATH ]; FILE* fnul; FILE* flog; @@ -1066,7 +1070,7 @@ void adb_set_affinity(void) 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 */ @@ -1165,7 +1169,7 @@ int launch_server(int server_port) return -1; } } -#elif defined(HAVE_FORKEXEC) +#else /* !defined(_WIN32) */ char path[PATH_MAX]; int fd[2]; @@ -1216,12 +1220,10 @@ int launch_server(int server_port) setsid(); } -#else -#error "cannot implement background server start on this platform" -#endif +#endif /* !defined(_WIN32) */ return 0; } -#endif +#endif /* ADB_HOST */ /* Constructs a local name of form tcp:port. * target_str points to the target string, it's content will be overwritten. @@ -1303,9 +1305,9 @@ int adb_main(int is_daemon, int server_port) #endif atexit(adb_cleanup); -#ifdef HAVE_WIN32_PROC +#if defined(_WIN32) SetConsoleCtrlHandler( ctrlc_handler, TRUE ); -#elif defined(HAVE_FORKEXEC) +#else // No SIGCHLD. Let the service subproc handle its children. signal(SIGPIPE, SIG_IGN); #endif @@ -1421,10 +1423,10 @@ int adb_main(int is_daemon, int server_port) if (is_daemon) { // inform our parent that we are up and running. -#ifdef HAVE_WIN32_PROC +#if defined(_WIN32) DWORD count; WriteFile( GetStdHandle( STD_OUTPUT_HANDLE ), "OK\n", 3, &count, NULL ); -#elif defined(HAVE_FORKEXEC) +#else fprintf(stderr, "OK\n"); #endif start_logging(); @@ -1554,8 +1556,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,6 +1565,7 @@ 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 @@ -1670,11 +1671,6 @@ int handle_host_request(char *service, transport_type ttype, char* serial, int r /* we don't even need to send a reply */ return 0; } -#endif // ADB_HOST - - int ret = handle_forward_request(service, ttype, serial, reply_fd); - if (ret >= 0) - return ret - 1; if(!strncmp(service,"get-state",strlen("get-state"))) { transport = acquire_one_transport(CS_ANY, ttype, serial, NULL); @@ -1682,6 +1678,11 @@ int handle_host_request(char *service, transport_type ttype, char* serial, int r send_msg_with_okay(reply_fd, state, strlen(state)); return 0; } +#endif // ADB_HOST + + int ret = handle_forward_request(service, ttype, serial, reply_fd); + if (ret >= 0) + return ret - 1; return -1; } @@ -19,6 +19,7 @@ #include <limits.h> +#include "adb_trace.h" #include "transport.h" /* readx(), writex() */ #define MAX_PAYLOAD 4096 @@ -36,7 +37,7 @@ #define ADB_VERSION_MAJOR 1 // Used for help/version information #define ADB_VERSION_MINOR 0 // Used for help/version information -#define ADB_SERVER_VERSION 31 // Increment this when we want to force users to start a new adb server +#define ADB_SERVER_VERSION 32 // Increment this when we want to force users to start a new adb server typedef struct amessage amessage; typedef struct apacket apacket; @@ -326,11 +327,6 @@ int create_jdwp_connection_fd(int jdwp_pid); int handle_forward_request(const char* service, transport_type ttype, char* serial, int reply_fd); #if !ADB_HOST -typedef enum { - BACKUP, - RESTORE -} BackupOperation; -int backup_service(BackupOperation operation, char* args); void framebuffer_service(int fd, void *cookie); void remount_service(int fd, void *cookie); #endif @@ -342,85 +338,6 @@ void put_apacket(apacket *p); int check_header(apacket *p); int check_data(apacket *p); -/* define ADB_TRACE to 1 to enable tracing support, or 0 to disable it */ - -#define ADB_TRACE 1 - -/* IMPORTANT: if you change the following list, don't - * forget to update the corresponding 'tags' table in - * the adb_trace_init() function implemented in adb.c - */ -typedef enum { - TRACE_ADB = 0, /* 0x001 */ - TRACE_SOCKETS, - TRACE_PACKETS, - TRACE_TRANSPORT, - TRACE_RWX, /* 0x010 */ - TRACE_USB, - TRACE_SYNC, - TRACE_SYSDEPS, - TRACE_JDWP, /* 0x100 */ - TRACE_SERVICES, - TRACE_AUTH, -} AdbTrace; - -#if ADB_TRACE - -#if !ADB_HOST -/* - * When running inside the emulator, guest's adbd can connect to 'adb-debug' - * qemud service that can display adb trace messages (on condition that emulator - * has been started with '-debug adb' option). - */ - -/* Delivers a trace message to the emulator via QEMU pipe. */ -void adb_qemu_trace(const char* fmt, ...); -/* Macro to use to send ADB trace messages to the emulator. */ -#define DQ(...) adb_qemu_trace(__VA_ARGS__) -#else -#define DQ(...) ((void)0) -#endif /* !ADB_HOST */ - - extern int adb_trace_mask; - extern unsigned char adb_trace_output_count; - void adb_trace_init(void); - -# define ADB_TRACING ((adb_trace_mask & (1 << TRACE_TAG)) != 0) - - /* you must define TRACE_TAG before using this macro */ -# define D(...) \ - do { \ - if (ADB_TRACING) { \ - 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; \ - } \ - } while (0) -# define DR(...) \ - do { \ - if (ADB_TRACING) { \ - int save_errno = errno; \ - adb_mutex_lock(&D_lock); \ - errno = save_errno; \ - fprintf(stderr, __VA_ARGS__ ); \ - fflush(stderr); \ - adb_mutex_unlock(&D_lock); \ - errno = save_errno; \ - } \ - } while (0) -#else -# define D(...) ((void)0) -# define DR(...) ((void)0) -# define ADB_TRACING 0 -#endif - - #if !DEBUG_PACKETS #define print_packet(tag,p) do {} while (0) #endif @@ -476,6 +393,11 @@ int connection_state(atransport *t); extern int HOST; extern int SHELL_EXIT_NOTIFY_FD; +typedef enum { + SUBPROC_PTY = 0, + SUBPROC_RAW = 1, +} subproc_mode; + #define CHUNK_SIZE (64*1024) #if !ADB_HOST diff --git a/adb/adb_auth_client.c b/adb/adb_auth_client.c index f8d7306..55e9dca 100644 --- a/adb/adb_auth_client.c +++ b/adb/adb_auth_client.c @@ -57,7 +57,7 @@ static void read_keys(const char *file, struct listnode *list) char *sep; int ret; - f = fopen(file, "r"); + f = fopen(file, "re"); if (!f) { D("Can't open '%s'\n", file); return; @@ -126,7 +126,7 @@ int adb_auth_generate_token(void *token, size_t token_size) FILE *f; int ret; - f = fopen("/dev/urandom", "r"); + f = fopen("/dev/urandom", "re"); if (!f) return 0; @@ -175,7 +175,7 @@ static void adb_auth_event(int fd, unsigned events, void *data) if (events & FDE_READ) { ret = unix_read(fd, response, sizeof(response)); - if (ret < 0) { + if (ret <= 0) { D("Framework disconnect\n"); if (usb_transport) fdevent_remove(&usb_transport->auth_fde); @@ -257,6 +257,7 @@ void adb_auth_init(void) D("Failed to get adbd socket\n"); return; } + fcntl(fd, F_SETFD, FD_CLOEXEC); ret = listen(fd, 4); if (ret < 0) { diff --git a/adb/adb_auth_host.c b/adb/adb_auth_host.c index 783774a..c72fe42 100644 --- a/adb/adb_auth_host.c +++ b/adb/adb_auth_host.c @@ -45,6 +45,10 @@ #include <openssl/rsa.h> #include <openssl/sha.h> +#if defined(OPENSSL_IS_BORINGSSL) +#include <openssl/base64.h> +#endif + #define TRACE_TAG TRACE_AUTH #define ANDROID_PATH ".android" @@ -132,43 +136,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 = NULL; + 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 = malloc(encoded_length); + if (encoded == NULL) { + 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) diff --git a/adb/adb_client.c b/adb/adb_client.c index 1e47486..eb1720d 100644 --- a/adb/adb_client.c +++ b/adb/adb_client.c @@ -279,7 +279,7 @@ int adb_connect(const char *service) fd = _adb_connect(service); if(fd == -1) { - fprintf(stderr,"error: %s\n", __adb_error); + D("_adb_connect error: %s\n", __adb_error); } else if(fd == -2) { fprintf(stderr,"** daemon still not running\n"); } @@ -296,6 +296,7 @@ int adb_command(const char *service) { int fd = adb_connect(service); if(fd < 0) { + fprintf(stderr, "error: %s\n", adb_error()); return -1; } diff --git a/adb/adb_trace.h b/adb/adb_trace.h new file mode 100644 index 0000000..8a5d9f8 --- /dev/null +++ b/adb/adb_trace.h @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2014 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_TRACE_H +#define __ADB_TRACE_H + +#if !ADB_HOST +#include <android/log.h> +#endif + +/* define ADB_TRACE to 1 to enable tracing support, or 0 to disable it */ +#define ADB_TRACE 1 + +/* IMPORTANT: if you change the following list, don't + * forget to update the corresponding 'tags' table in + * the adb_trace_init() function implemented in adb.c + */ +typedef enum { + TRACE_ADB = 0, /* 0x001 */ + TRACE_SOCKETS, + TRACE_PACKETS, + TRACE_TRANSPORT, + TRACE_RWX, /* 0x010 */ + TRACE_USB, + TRACE_SYNC, + TRACE_SYSDEPS, + TRACE_JDWP, /* 0x100 */ + TRACE_SERVICES, + TRACE_AUTH, + TRACE_FDEVENT, +} AdbTrace; + +#if ADB_TRACE + +#if !ADB_HOST +/* + * When running inside the emulator, guest's adbd can connect to 'adb-debug' + * qemud service that can display adb trace messages (on condition that emulator + * has been started with '-debug adb' option). + */ + +/* Delivers a trace message to the emulator via QEMU pipe. */ +void adb_qemu_trace(const char* fmt, ...); +/* Macro to use to send ADB trace messages to the emulator. */ +#define DQ(...) adb_qemu_trace(__VA_ARGS__) +#else +#define DQ(...) ((void)0) +#endif /* !ADB_HOST */ + +extern int adb_trace_mask; +extern unsigned char adb_trace_output_count; +void adb_trace_init(void); + +# define ADB_TRACING ((adb_trace_mask & (1 << TRACE_TAG)) != 0) + +/* you must define TRACE_TAG before using this macro */ +#if ADB_HOST +# define D(...) \ + do { \ + if (ADB_TRACING) { \ + 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; \ + } \ + } while (0) +# define DR(...) \ + do { \ + if (ADB_TRACING) { \ + int save_errno = errno; \ + adb_mutex_lock(&D_lock); \ + errno = save_errno; \ + fprintf(stderr, __VA_ARGS__ ); \ + fflush(stderr); \ + adb_mutex_unlock(&D_lock); \ + errno = save_errno; \ + } \ + } 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; \ + } while (0) +#else +# define D(...) \ + do { \ + if (ADB_TRACING) { \ + __android_log_print( \ + ANDROID_LOG_INFO, \ + __FUNCTION__, \ + __VA_ARGS__ ); \ + } \ + } while (0) +# define DR(...) \ + do { \ + if (ADB_TRACING) { \ + __android_log_print( \ + ANDROID_LOG_INFO, \ + __FUNCTION__, \ + __VA_ARGS__ ); \ + } \ + } while (0) +# define DD(...) \ + do { \ + __android_log_print( \ + ANDROID_LOG_INFO, \ + __FUNCTION__, \ + __VA_ARGS__ ); \ + } while (0) +#endif /* ADB_HOST */ +#else +# define D(...) ((void)0) +# define DR(...) ((void)0) +# define DD(...) ((void)0) +# define ADB_TRACING 0 +#endif /* ADB_TRACE */ + +#endif /* __ADB_TRACE_H */ diff --git a/adb/backup_service.c b/adb/backup_service.c deleted file mode 100644 index 654e0f3..0000000 --- a/adb/backup_service.c +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (C) 2011 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 <unistd.h> -#include <stdio.h> - -#include "sysdeps.h" - -#define TRACE_TAG TRACE_ADB -#include "adb.h" - -typedef struct { - pid_t pid; - int fd; -} backup_harvest_params; - -// socketpair but do *not* mark as close_on_exec -static int backup_socketpair(int sv[2]) { - int rc = unix_socketpair( AF_UNIX, SOCK_STREAM, 0, sv ); - if (rc < 0) - return -1; - - return 0; -} - -// harvest the child process then close the read end of the socketpair -static void* backup_child_waiter(void* args) { - int status; - backup_harvest_params* params = (backup_harvest_params*) args; - - waitpid(params->pid, &status, 0); - adb_close(params->fd); - free(params); - return NULL; -} - -/* returns the data socket passing the backup data here for forwarding */ -int backup_service(BackupOperation op, char* args) { - pid_t pid; - int s[2]; - char* operation; - - // Command string depends on our invocation - if (op == BACKUP) { - operation = "backup"; - } else { - operation = "restore"; - } - - D("backup_service(%s, %s)\n", operation, args); - - // set up the pipe from the subprocess to here - // parent will read s[0]; child will write s[1] - if (backup_socketpair(s)) { - D("can't create backup/restore socketpair\n"); - fprintf(stderr, "unable to create backup/restore socketpair\n"); - return -1; - } - - D("Backup/restore socket pair: (send=%d, receive=%d)\n", s[1], s[0]); - close_on_exec(s[0]); // only the side we hold on to - - // spin off the child process to run the backup command - pid = fork(); - if (pid < 0) { - // failure - D("can't fork for %s\n", operation); - fprintf(stderr, "unable to fork for %s\n", operation); - adb_close(s[0]); - adb_close(s[1]); - return -1; - } - - // Great, we're off and running. - if (pid == 0) { - // child -- actually run the backup here - char* p; - int argc; - char portnum[16]; - char** bu_args; - - // fixed args: [0] is 'bu', [1] is the port number, [2] is the 'operation' string - argc = 3; - for (p = (char*)args; p && *p; ) { - argc++; - while (*p && *p != ':') p++; - if (*p == ':') p++; - } - - bu_args = (char**) alloca(argc*sizeof(char*) + 1); - - // run through again to build the argv array - argc = 0; - bu_args[argc++] = "bu"; - snprintf(portnum, sizeof(portnum), "%d", s[1]); - bu_args[argc++] = portnum; - bu_args[argc++] = operation; - for (p = (char*)args; p && *p; ) { - bu_args[argc++] = p; - while (*p && *p != ':') p++; - if (*p == ':') { - *p = 0; - p++; - } - } - bu_args[argc] = NULL; - - // Close the half of the socket that we don't care about, route 'bu's console - // to the output socket, and off we go - adb_close(s[0]); - - // off we go - execvp("/system/bin/bu", (char * const *)bu_args); - // oops error - close up shop and go home - fprintf(stderr, "Unable to exec 'bu', bailing\n"); - exit(-1); - } else { - adb_thread_t t; - backup_harvest_params* params; - - // parent, i.e. adbd -- close the sending half of the socket - D("fork() returned pid %d\n", pid); - adb_close(s[1]); - - // spin a thread to harvest the child process - params = (backup_harvest_params*) malloc(sizeof(backup_harvest_params)); - params->pid = pid; - params->fd = s[0]; - if (adb_thread_create(&t, backup_child_waiter, params)) { - adb_close(s[0]); - free(params); - D("Unable to create child harvester\n"); - return -1; - } - } - - // we'll be reading from s[0] as the data is sent by the child process - return s[0]; -} diff --git a/adb/commandline.c b/adb/commandline.c index 18dc6e0..23e9ea4 100644 --- a/adb/commandline.c +++ b/adb/commandline.c @@ -15,6 +15,7 @@ */ #include <stdio.h> +#include <stdint.h> #include <stdlib.h> #include <string.h> #include <errno.h> @@ -28,7 +29,7 @@ #include "sysdeps.h" -#ifdef HAVE_TERMIO_H +#if !defined(_WIN32) #include <termios.h> #endif @@ -41,8 +42,9 @@ static int do_cmd(transport_type ttype, char* serial, 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 **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 const char *gProductOutPath = NULL; @@ -110,9 +112,10 @@ void help() " adb push [-p] <local> <remote>\n" " - copy file/dir to device\n" " ('-p' to display the transfer progress)\n" - " adb pull [-p] <remote> [<local>]\n" + " adb pull [-p] [-a] <remote> [<local>]\n" " - copy file/dir from device\n" " ('-p' to display the transfer progress)\n" + " ('-a' means copy timestamp and mode)\n" " adb sync [ <directory> ] - copy host->device only if changed\n" " (-l means list but don't copy)\n" " (see 'adb help all')\n" @@ -150,12 +153,15 @@ void help() " - remove a specific reversed socket connection\n" " adb reverse --remove-all - remove all reversed socket connections from device\n" " adb jdwp - list PIDs of processes hosting a JDWP transport\n" - " adb install [-l] [-r] [-s] [--algo <algorithm name> --key <hex-encoded key> --iv <hex-encoded iv>] <file>\n" + " adb install [-lrtsd] <file>\n" + " adb install-multiple [-lrtsdp] <file...>\n" " - push this package file to the device and install it\n" - " ('-l' means forward-lock the app)\n" - " ('-r' means reinstall the app, keeping its data)\n" - " ('-s' means install on SD card instead of internal storage)\n" - " ('--algo', '--key', and '--iv' mean the file is encrypted already)\n" + " (-l: forward lock application)\n" + " (-r: replace existing application)\n" + " (-t: allow test packages)\n" + " (-s: install application on sdcard)\n" + " (-d: allow version code downgrade)\n" + " (-p: partial application install)\n" " adb uninstall [-k] <package> - remove this app package from the device\n" " ('-k' means keep the data and cache directories)\n" " adb bugreport - return all information from the device\n" @@ -194,7 +200,7 @@ 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 partition on the device read-write\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 reboot-bootloader - reboots the device into the bootloader\n" " adb root - restarts the adbd daemon with root permissions\n" @@ -210,9 +216,9 @@ void help() "adb sync notes: adb sync [ <directory> ]\n" " <localdir> can be interpreted in several ways:\n" "\n" - " - If <directory> is not specified, both /system and /data partitions will be updated.\n" + " - If <directory> is not specified, /system, /vendor (if present), and /data partitions will be updated.\n" "\n" - " - If it is \"system\" or \"data\", only the corresponding partition\n" + " - If it is \"system\", \"vendor\" or \"data\", only the corresponding partition\n" " is updated.\n" "\n" "environmental variables:\n" @@ -229,7 +235,18 @@ int usage() return 1; } -#ifdef HAVE_TERMIO_H +#if defined(_WIN32) + +// Windows does not have <termio.h>. +static void stdin_raw_init(int fd) { + +} + +static void stdin_raw_restore(int fd) { + +} + +#else static struct termios tio_save; static void stdin_raw_init(int fd) @@ -278,6 +295,24 @@ static void read_and_dump(int fd) } } +static void read_status_line(int fd, char* buf, size_t count) +{ + count--; + while (count > 0) { + int len = adb_read(fd, buf, count); + if (len == 0) { + break; + } else if (len < 0) { + if (errno == EINTR) continue; + break; + } + + buf += len; + count -= len; + } + *buf = '\0'; +} + static void copy_to_file(int inFd, int outFd) { const size_t BUFSIZE = 32 * 1024; char* buf = (char*) malloc(BUFSIZE); @@ -285,8 +320,17 @@ static void copy_to_file(int inFd, int outFd) { long total = 0; D("copy_to_file(%d -> %d)\n", inFd, outFd); + + if (inFd == STDIN_FILENO) { + stdin_raw_init(STDIN_FILENO); + } + for (;;) { - len = adb_read(inFd, buf, BUFSIZE); + if (inFd == STDIN_FILENO) { + len = unix_read(inFd, buf, BUFSIZE); + } else { + len = adb_read(inFd, buf, BUFSIZE); + } if (len == 0) { D("copy_to_file() : read 0 bytes; exiting\n"); break; @@ -299,9 +343,19 @@ static void copy_to_file(int inFd, int outFd) { D("copy_to_file() : error %d\n", errno); break; } - adb_write(outFd, buf, len); + if (outFd == STDOUT_FILENO) { + fwrite(buf, 1, len, stdout); + fflush(stdout); + } else { + adb_write(outFd, buf, len); + } total += len; } + + if (inFd == STDIN_FILENO) { + stdin_raw_restore(STDIN_FILENO); + } + D("copy_to_file() finished after %lu bytes\n", total); free(buf); } @@ -342,9 +396,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: @@ -376,14 +428,10 @@ int interactive_shell(void) 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; } @@ -480,6 +528,115 @@ int adb_download(const char *service, const char *fn, unsigned progress) return status; } +#define SIDELOAD_HOST_BLOCK_SIZE (CHUNK_SIZE) + +/* + * The sideload-host protocol serves the data in a file (given on the + * command line) to the client, using a simple protocol: + * + * - The connect message includes the total number of bytes in the + * file and a block size chosen by us. + * + * - The other side sends the desired block number as eight decimal + * digits (eg "00000023" for block 23). Blocks are numbered from + * zero. + * + * - We send back the data of the requested block. The last block is + * likely to be partial; when the last block is requested we only + * send the part of the block that exists, it's not padded up to the + * block size. + * + * - When the other side sends "DONEDONE" instead of a block number, + * we hang up. + */ +int adb_sideload_host(const char* fn) { + uint8_t* data; + unsigned sz; + size_t xfer = 0; + int status; + + printf("loading: '%s'", fn); + fflush(stdout); + data = load_file(fn, &sz); + if (data == 0) { + printf("\n"); + fprintf(stderr, "* cannot read '%s' *\n", fn); + return -1; + } + + char buf[100]; + sprintf(buf, "sideload-host:%d:%d", sz, SIDELOAD_HOST_BLOCK_SIZE); + int fd = adb_connect(buf); + if (fd < 0) { + // Try falling back to the older sideload method. Maybe this + // is an older device that doesn't support sideload-host. + printf("\n"); + status = adb_download_buffer("sideload", fn, data, sz, 1); + goto done; + } + + int opt = SIDELOAD_HOST_BLOCK_SIZE; + opt = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *) &opt, sizeof(opt)); + + int last_percent = -1; + for (;;) { + if (readx(fd, buf, 8)) { + fprintf(stderr, "* failed to read command: %s\n", adb_error()); + status = -1; + goto done; + } + + if (strncmp("DONEDONE", buf, 8) == 0) { + status = 0; + break; + } + + buf[8] = '\0'; + int block = strtol(buf, NULL, 10); + + size_t offset = block * SIDELOAD_HOST_BLOCK_SIZE; + if (offset >= sz) { + fprintf(stderr, "* attempt to read past end: %s\n", adb_error()); + status = -1; + goto done; + } + uint8_t* start = data + offset; + size_t offset_end = offset + SIDELOAD_HOST_BLOCK_SIZE; + size_t to_write = SIDELOAD_HOST_BLOCK_SIZE; + if (offset_end > sz) { + to_write = sz - offset; + } + + if(writex(fd, start, to_write)) { + adb_status(fd); + fprintf(stderr,"* failed to write data '%s' *\n", adb_error()); + status = -1; + goto done; + } + xfer += to_write; + + // For normal OTA packages, we expect to transfer every byte + // twice, plus a bit of overhead (one read during + // verification, one read of each byte for installation, plus + // extra access to things like the zip central directory). + // This estimate of the completion becomes 100% when we've + // transferred ~2.13 (=100/47) times the package size. + int percent = (int)(xfer * 47LL / (sz ? sz : 1)); + if (percent != last_percent) { + printf("\rserving: '%s' (~%d%%) ", fn, percent); + fflush(stdout); + last_percent = percent; + } + } + + printf("\rTotal xfer: %.2fx%*s\n", (double)xfer / (sz ? sz : 1), (int)strlen(fn)+10, ""); + + done: + if (fd >= 0) adb_close(fd); + free(data); + return status; +} + static void status_window(transport_type ttype, const char* serial) { char command[4096]; @@ -524,39 +681,45 @@ static void status_window(transport_type ttype, const char* serial) } } -/** duplicate string and quote all \ " ( ) chars + space character. */ -static char * -dupAndQuote(const char *s) +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; - ts = s; - alloc_len = 0; - - for( ;*ts != '\0'; ts++) { + for (ts = s; *ts != '\0'; ts++) { alloc_len++; - if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') { + if (should_escape(*ts)) { alloc_len++; } } - ret = (char *)malloc(alloc_len + 1); + if (alloc_len == 0) { + // Preserve empty arguments + ret = (char *) malloc(3); + ret[0] = '\"'; + ret[1] = '\"'; + ret[2] = '\0'; + return ret; + } - ts = s; + ret = (char *) malloc(alloc_len + 1); dest = ret; - for ( ;*ts != '\0'; ts++) { - if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') { + for (ts = s; *ts != '\0'; ts++) { + if (should_escape(*ts)) { *dest++ = '\\'; } - *dest++ = *ts; } - *dest++ = '\0'; return ret; @@ -571,7 +734,7 @@ dupAndQuote(const char *s) */ int ppp(int argc, char **argv) { -#ifdef HAVE_WIN32_PROC +#if defined(_WIN32) fprintf(stderr, "error: adb %s not implemented on Win32\n", argv[0]); return -1; #else @@ -634,7 +797,7 @@ 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) @@ -663,30 +826,24 @@ static int logcat(transport_type transport, char* serial, int argc, char **argv) char buf[4096]; char *log_tags; - char *quoted_log_tags; + char *quoted; log_tags = getenv("ANDROID_LOG_TAGS"); - quoted_log_tags = dupAndQuote(log_tags == NULL ? "" : log_tags); - + quoted = escape_arg(log_tags == NULL ? "" : log_tags); snprintf(buf, sizeof(buf), - "shell:export ANDROID_LOG_TAGS=\"\%s\" ; exec logcat", - quoted_log_tags); - - free(quoted_log_tags); + "shell:export ANDROID_LOG_TAGS=\"%s\"; exec logcat", quoted); + free(quoted); - if (!strcmp(argv[0],"longcat")) { - strncat(buf, " -v long", sizeof(buf)-1); + if (!strcmp(argv[0], "longcat")) { + strncat(buf, " -v long", sizeof(buf) - 1); } argc -= 1; argv += 1; while(argc-- > 0) { - char *quoted; - - quoted = dupAndQuote (*argv++); - - strncat(buf, " ", sizeof(buf)-1); - strncat(buf, quoted, sizeof(buf)-1); + quoted = escape_arg(*argv++); + strncat(buf, " ", sizeof(buf) - 1); + strncat(buf, quoted, sizeof(buf) - 1); free(quoted); } @@ -938,13 +1095,19 @@ static const char *find_product_out_path(const char *hint) return path_buf; } - -static void parse_push_pull_args(char** arg, int narg, char const** path1, char const** path2, - int* show_progress) { +static void parse_push_pull_args(char **arg, int narg, char const **path1, char const **path2, + int *show_progress, int *copy_attrs) { *show_progress = 0; + *copy_attrs = 0; - if ((narg > 0) && !strcmp(*arg, "-p")) { - *show_progress = 1; + while (narg > 0) { + if (!strcmp(*arg, "-p")) { + *show_progress = 1; + } else if (!strcmp(*arg, "-a")) { + *copy_attrs = 1; + } else { + break; + } ++arg; --narg; } @@ -968,7 +1131,6 @@ int adb_commandline(int argc, char **argv) int is_server = 0; int persist = 0; int r; - int quote; transport_type ttype = kTransportAny; char* serial = NULL; char* server_port_str = NULL; @@ -1189,19 +1351,14 @@ top: return r; } - snprintf(buf, sizeof buf, "shell:%s", argv[1]); + snprintf(buf, sizeof(buf), "shell:%s", argv[1]); argc -= 2; argv += 2; - while(argc-- > 0) { - strcat(buf, " "); - - /* quote empty strings and strings with spaces */ - quote = (**argv == 0 || strchr(*argv, ' ')); - if (quote) - strcat(buf, "\""); - strcat(buf, *argv++); - if (quote) - strcat(buf, "\""); + while (argc-- > 0) { + char *quoted = escape_arg(*argv++); + strncat(buf, " ", sizeof(buf) - 1); + strncat(buf, quoted, sizeof(buf) - 1); + free(quoted); } for(;;) { @@ -1233,6 +1390,36 @@ top: } } + 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]); + 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); + } + + fd = adb_connect(buf); + if (fd < 0) { + fprintf(stderr, "error: %s\n", adb_error()); + return -1; + } + + if (exec_in) { + copy_to_file(STDIN_FILENO, fd); + } else { + copy_to_file(fd, STDOUT_FILENO); + } + + adb_close(fd); + return 0; + } + if(!strcmp(argv[0], "kill-server")) { int fd; fd = _adb_connect("host:kill"); @@ -1245,7 +1432,7 @@ top: if(!strcmp(argv[0], "sideload")) { if(argc != 2) return usage(); - if(adb_download("sideload", argv[1], 1)) { + if (adb_sideload_host(argv[1])) { return 1; } else { return 0; @@ -1415,12 +1602,13 @@ top: if(!strcmp(argv[0], "push")) { int show_progress = 0; + int copy_attrs = 0; // unused const char* lpath = NULL, *rpath = NULL; - parse_push_pull_args(&argv[1], argc - 1, &lpath, &rpath, &show_progress); + parse_push_pull_args(&argv[1], argc - 1, &lpath, &rpath, &show_progress, ©_attrs); if ((lpath != NULL) && (rpath != NULL)) { - return do_sync_push(lpath, rpath, 0 /* no verify APK */, show_progress); + return do_sync_push(lpath, rpath, show_progress); } return usage(); @@ -1428,29 +1616,35 @@ top: if(!strcmp(argv[0], "pull")) { int show_progress = 0; + int copy_attrs = 0; const char* rpath = NULL, *lpath = "."; - parse_push_pull_args(&argv[1], argc - 1, &rpath, &lpath, &show_progress); + parse_push_pull_args(&argv[1], argc - 1, &rpath, &lpath, &show_progress, ©_attrs); if (rpath != NULL) { - return do_sync_pull(rpath, lpath, show_progress); + return do_sync_pull(rpath, lpath, show_progress, copy_attrs); } return usage(); } - if(!strcmp(argv[0], "install")) { + if (!strcmp(argv[0], "install")) { if (argc < 2) return usage(); return install_app(ttype, serial, argc, argv); } - if(!strcmp(argv[0], "uninstall")) { + if (!strcmp(argv[0], "install-multiple")) { + if (argc < 2) return usage(); + return install_multiple_app(ttype, serial, argc, argv); + } + + 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; + char *srcarg, *android_srcpath, *data_srcpath, *vendor_srcpath; int listonly = 0; int ret; @@ -1470,15 +1664,18 @@ top: } else { return usage(); } - ret = find_sync_dirs(srcarg, &android_srcpath, &data_srcpath); + 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); free(android_srcpath); + free(vendor_srcpath); free(data_srcpath); return ret; } @@ -1555,9 +1752,10 @@ top: return 1; } +#define MAX_ARGV_LENGTH 16 static int do_cmd(transport_type ttype, char* serial, char *cmd, ...) { - char *argv[16]; + char *argv[MAX_ARGV_LENGTH]; int argc; va_list ap; @@ -1574,7 +1772,9 @@ static int do_cmd(transport_type ttype, char* serial, char *cmd, ...) } argv[argc++] = cmd; - while((argv[argc] = va_arg(ap, char*)) != 0) argc++; + while(argc < MAX_ARGV_LENGTH && + (argv[argc] = va_arg(ap, char*)) != 0) argc++; + assert(argc < MAX_ARGV_LENGTH); va_end(ap); #if 0 @@ -1589,25 +1789,30 @@ static int do_cmd(transport_type ttype, char* serial, char *cmd, ...) } int find_sync_dirs(const char *srcarg, - char **android_srcdir_out, char **data_srcdir_out) + char **android_srcdir_out, char **data_srcdir_out, char **vendor_srcdir_out) { - char *android_srcdir, *data_srcdir; + 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"); - data_srcdir = NULL; } else if(strcmp(srcarg, "data") == 0) { - android_srcdir = NULL; data_srcdir = product_file("data"); + } else if(strcmp(srcarg, "vendor") == 0) { + vendor_srcdir = product_file("vendor"); } else { - /* It's not "system" or "data". + /* It's not "system", "vendor", or "data". */ return 1; } @@ -1618,11 +1823,15 @@ int find_sync_dirs(const char *srcarg, else free(android_srcdir); - if(data_srcdir_out != NULL) - *data_srcdir_out = data_srcdir; + if(vendor_srcdir_out != NULL) + *vendor_srcdir_out = vendor_srcdir; else - free(data_srcdir); + free(vendor_srcdir); + if(data_srcdir_out != NULL) + *data_srcdir_out = data_srcdir; + else + free(data_srcdir); return 0; } @@ -1634,12 +1843,9 @@ static int pm_command(transport_type transport, char* serial, snprintf(buf, sizeof(buf), "shell:pm"); while(argc-- > 0) { - char *quoted; - - quoted = dupAndQuote(*argv++); - - strncat(buf, " ", sizeof(buf)-1); - strncat(buf, quoted, sizeof(buf)-1); + char *quoted = escape_arg(*argv++); + strncat(buf, " ", sizeof(buf) - 1); + strncat(buf, quoted, sizeof(buf) - 1); free(quoted); } @@ -1670,8 +1876,8 @@ static int delete_file(transport_type transport, char* serial, char* filename) char buf[4096]; char* quoted; - snprintf(buf, sizeof(buf), "shell:rm "); - quoted = dupAndQuote(filename); + snprintf(buf, sizeof(buf), "shell:rm -f "); + quoted = escape_arg(filename); strncat(buf, quoted, sizeof(buf)-1); free(quoted); @@ -1690,117 +1896,186 @@ static const char* get_basename(const char* filename) } } -static int check_file(const char* filename) +int install_app(transport_type transport, char* serial, int argc, char** argv) { - struct stat st; + static const char *const DATA_DEST = "/data/local/tmp/%s"; + static const char *const SD_DEST = "/sdcard/tmp/%s"; + const char* where = DATA_DEST; + int i; + struct stat sb; - if (filename == NULL) { - return 0; + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-s")) { + where = SD_DEST; + } } - if (stat(filename, &st) != 0) { - fprintf(stderr, "can't find '%s' to install\n", filename); - return 1; + // Find last APK argument. + // All other arguments passed through verbatim. + int last_apk = -1; + for (i = argc - 1; i >= 0; i--) { + char* file = argv[i]; + char* dot = strrchr(file, '.'); + if (dot && !strcasecmp(dot, ".apk")) { + if (stat(file, &sb) == -1 || !S_ISREG(sb.st_mode)) { + fprintf(stderr, "Invalid APK file: %s\n", file); + return -1; + } + + last_apk = i; + break; + } } - if (!S_ISREG(st.st_mode)) { - fprintf(stderr, "can't install '%s' because it's not a file\n", filename); - return 1; + if (last_apk == -1) { + fprintf(stderr, "Missing APK file\n"); + return -1; } - return 0; + 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 */); + if (err) { + goto cleanup_apk; + } else { + argv[last_apk] = apk_dest; /* destination name, not source location */ + } + + pm_command(transport, serial, argc, argv); + +cleanup_apk: + delete_file(transport, serial, apk_dest); + return err; } -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) { - static const char *const DATA_DEST = "/data/local/tmp/%s"; - static const char *const SD_DEST = "/sdcard/tmp/%s"; - const char* where = DATA_DEST; - char apk_dest[PATH_MAX]; - char verification_dest[PATH_MAX]; - char* apk_file; - char* verification_file = NULL; - int file_arg = -1; - int err; + char buf[1024]; int i; - int verify_apk = 1; + struct stat sb; + unsigned long long 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]; + char* dot = strrchr(file, '.'); + if (dot && !strcasecmp(dot, ".apk")) { + if (stat(file, &sb) == -1 || !S_ISREG(sb.st_mode)) { + fprintf(stderr, "Invalid APK file: %s\n", file); + return -1; + } - for (i = 1; i < argc; i++) { - if (*argv[i] != '-') { - file_arg = i; + total_size += sb.st_size; + first_apk = i; + } else { break; - } else if (!strcmp(argv[i], "-i")) { - // Skip the installer package name. - i++; - } else if (!strcmp(argv[i], "-s")) { - where = SD_DEST; - } else if (!strcmp(argv[i], "--algo")) { - verify_apk = 0; - i++; - } else if (!strcmp(argv[i], "--iv")) { - verify_apk = 0; - i++; - } else if (!strcmp(argv[i], "--key")) { - verify_apk = 0; - i++; - } else if (!strcmp(argv[i], "--abi")) { - i++; - } - } - - if (file_arg < 0) { - fprintf(stderr, "can't find filename in arguments\n"); - return 1; - } else if (file_arg + 2 < argc) { - fprintf(stderr, "too many files specified; only takes APK file and verifier file\n"); + } + } + + if (first_apk == -1) { + fprintf(stderr, "Missing APK file\n"); return 1; } - apk_file = argv[file_arg]; + snprintf(buf, sizeof(buf), "exec:pm install-create -S %lld", total_size); + 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); + } - if (file_arg != argc - 1) { - verification_file = argv[file_arg + 1]; + // Create install session + int fd = adb_connect(buf); + if (fd < 0) { + fprintf(stderr, "Connect error for create: %s\n", adb_error()); + return -1; } + read_status_line(fd, buf, sizeof(buf)); + adb_close(fd); - if (check_file(apk_file) || check_file(verification_file)) { - return 1; + int session_id = -1; + if (!strncmp("Success", buf, 7)) { + char* start = strrchr(buf, '['); + char* end = strrchr(buf, ']'); + if (start && end) { + *end = '\0'; + session_id = strtol(start + 1, NULL, 10); + } + } + if (session_id < 0) { + fprintf(stderr, "Failed to create session\n"); + fputs(buf, stderr); + return -1; } - snprintf(apk_dest, sizeof apk_dest, where, get_basename(apk_file)); - if (verification_file != NULL) { - snprintf(verification_dest, sizeof(verification_dest), where, get_basename(verification_file)); + // Valid session, now stream the APKs + int success = 1; + for (i = first_apk; i < argc; i++) { + char* file = argv[i]; + if (stat(file, &sb) == -1) { + fprintf(stderr, "Failed to stat %s\n", file); + success = 0; + goto finalize_session; + } - if (!strcmp(apk_dest, verification_dest)) { - fprintf(stderr, "APK and verification file can't have the same name\n"); - return 1; + 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)); + + int localFd = adb_open(file, O_RDONLY); + if (localFd < 0) { + fprintf(stderr, "Failed to open %s: %s\n", file, adb_error()); + success = 0; + goto finalize_session; } - } - err = do_sync_push(apk_file, apk_dest, verify_apk, 0 /* no show progress */); - if (err) { - goto cleanup_apk; - } else { - argv[file_arg] = apk_dest; /* destination name, not source location */ - } + int remoteFd = adb_connect(buf); + if (remoteFd < 0) { + fprintf(stderr, "Connect error for write: %s\n", adb_error()); + adb_close(localFd); + success = 0; + goto finalize_session; + } - if (verification_file != NULL) { - err = do_sync_push(verification_file, verification_dest, 0 /* no verify APK */, - 0 /* no show progress */); - if (err) { - goto cleanup_apk; - } else { - argv[file_arg + 1] = verification_dest; /* destination name, not source location */ + copy_to_file(localFd, remoteFd); + read_status_line(remoteFd, buf, sizeof(buf)); + + adb_close(localFd); + adb_close(remoteFd); + + if (strncmp("Success", buf, 7)) { + fprintf(stderr, "Failed to write %s\n", file); + fputs(buf, stderr); + success = 0; + goto finalize_session; } } - pm_command(transport, serial, argc, argv); - -cleanup_apk: - if (verification_file != NULL) { - delete_file(transport, serial, verification_dest); +finalize_session: + // Commit session if we streamed everything okay; otherwise abandon + if (success) { + snprintf(buf, sizeof(buf), "exec:pm install-commit %d", session_id); + } else { + snprintf(buf, sizeof(buf), "exec:pm install-abandon %d", session_id); } - delete_file(transport, serial, apk_dest); + fd = adb_connect(buf); + if (fd < 0) { + fprintf(stderr, "Connect error for finalize: %s\n", adb_error()); + return -1; + } + read_status_line(fd, buf, sizeof(buf)); + adb_close(fd); - return err; + if (!strncmp("Success", buf, 7)) { + fputs(buf, stderr); + return 0; + } else { + fprintf(stderr, "Failed to finalize session\n"); + fputs(buf, stderr); + return -1; + } } diff --git a/adb/fdevent.c b/adb/fdevent.c index 5c374a7..43e600c 100644 --- a/adb/fdevent.c +++ b/adb/fdevent.c @@ -28,10 +28,12 @@ #include <stdarg.h> #include <stddef.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 @@ -57,16 +59,6 @@ static void fatal(const char *fn, const char *fmt, ...) #define FATAL(x...) fatal(__FUNCTION__, x) #if DEBUG -#define D(...) \ - do { \ - adb_mutex_lock(&D_lock); \ - int save_errno = errno; \ - fprintf(stderr, "%s::%s():", __FILE__, __FUNCTION__); \ - errno = save_errno; \ - fprintf(stderr, __VA_ARGS__); \ - adb_mutex_unlock(&D_lock); \ - errno = save_errno; \ - } while(0) static void dump_fde(fdevent *fde, const char *info) { adb_mutex_lock(&D_lock); @@ -78,7 +70,6 @@ static void dump_fde(fdevent *fde, const char *info) adb_mutex_unlock(&D_lock); } #else -#define D(...) ((void)0) #define dump_fde(fde, info) do { } while(0) #endif diff --git a/adb/file_sync_client.c b/adb/file_sync_client.c index dc4e77f..ad59e81 100644 --- a/adb/file_sync_client.c +++ b/adb/file_sync_client.c @@ -25,6 +25,7 @@ #include <limits.h> #include <sys/types.h> #include <zipfile/zipfile.h> +#include <utime.h> #include "sysdeps.h" #include "adb.h" @@ -139,7 +140,8 @@ struct syncsendbuf { static syncsendbuf send_buffer; -int sync_readtime(int fd, const char *path, unsigned *timestamp) +int sync_readtime(int fd, const char *path, unsigned int *timestamp, + unsigned int *mode) { syncmsg msg; int len = strlen(path); @@ -161,6 +163,7 @@ int sync_readtime(int fd, const char *path, unsigned *timestamp) } *timestamp = ltohl(msg.stat.time); + *mode = ltohl(msg.stat.mode); return 0; } @@ -237,7 +240,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 (lstat(path, &st)) { + if (fstat(lfd, &st)) { fprintf(stderr,"cannot stat '%s': %s\n", path, strerror(errno)); return -1; } @@ -332,7 +335,7 @@ static int write_data_link(int fd, const char *path, syncsendbuf *sbuf) #endif static int sync_send(int fd, const char *lpath, const char *rpath, - unsigned mtime, mode_t mode, int verifyApk, int show_progress) + unsigned mtime, mode_t mode, int show_progress) { syncmsg msg; int len, r; @@ -347,63 +350,6 @@ static int sync_send(int fd, const char *lpath, const char *rpath, snprintf(tmp, sizeof(tmp), ",%d", mode); r = strlen(tmp); - if (verifyApk) { - int lfd; - zipfile_t zip; - zipentry_t entry; - int amt; - - // if we are transferring an APK file, then sanity check to make sure - // we have a real zip file that contains an AndroidManifest.xml - // this requires that we read the entire file into memory. - lfd = adb_open(lpath, O_RDONLY); - if(lfd < 0) { - fprintf(stderr,"cannot open '%s': %s\n", lpath, strerror(errno)); - return -1; - } - - size = adb_lseek(lfd, 0, SEEK_END); - if (size == -1 || -1 == adb_lseek(lfd, 0, SEEK_SET)) { - fprintf(stderr, "error seeking in file '%s'\n", lpath); - adb_close(lfd); - return 1; - } - - file_buffer = (char *)malloc(size); - if (file_buffer == NULL) { - fprintf(stderr, "could not allocate buffer for '%s'\n", - lpath); - adb_close(lfd); - return 1; - } - amt = adb_read(lfd, file_buffer, size); - if (amt != size) { - fprintf(stderr, "error reading from file: '%s'\n", lpath); - adb_close(lfd); - free(file_buffer); - return 1; - } - - adb_close(lfd); - - zip = init_zipfile(file_buffer, size); - if (zip == NULL) { - fprintf(stderr, "file '%s' is not a valid zip file\n", - lpath); - free(file_buffer); - return 1; - } - - entry = lookup_zipentry(zip, "AndroidManifest.xml"); - release_zipfile(zip); - if (entry == NULL) { - fprintf(stderr, "file '%s' does not contain AndroidManifest.xml\n", - lpath); - free(file_buffer); - return 1; - } - } - msg.req.id = ID_SEND; msg.req.namelen = htoll(len + r); @@ -694,30 +640,33 @@ static int local_build_list(copyinfo **filelist, continue; strcpy(stat_path, lpath); strcat(stat_path, de->d_name); - stat(stat_path, &st); - if (S_ISDIR(st.st_mode)) { - ci = mkcopyinfo(lpath, rpath, name, 1); - ci->next = dirlist; - dirlist = ci; - } else { - ci = mkcopyinfo(lpath, rpath, name, 0); - if(lstat(ci->src, &st)) { - fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno)); - free(ci); - closedir(d); - return -1; - } - if(!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) { - fprintf(stderr, "skipping special file '%s'\n", ci->src); - free(ci); + if(!lstat(stat_path, &st)) { + if (S_ISDIR(st.st_mode)) { + ci = mkcopyinfo(lpath, rpath, name, 1); + ci->next = dirlist; + dirlist = ci; } else { - ci->time = st.st_mtime; - ci->mode = st.st_mode; - ci->size = st.st_size; - ci->next = *filelist; - *filelist = ci; + ci = mkcopyinfo(lpath, rpath, name, 0); + if(lstat(ci->src, &st)) { + fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno)); + free(ci); + closedir(d); + return -1; + } + if(!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) { + fprintf(stderr, "skipping special file '%s'\n", ci->src); + free(ci); + } else { + ci->time = st.st_mtime; + ci->mode = st.st_mode; + ci->size = st.st_size; + ci->next = *filelist; + *filelist = ci; + } } + } else { + fprintf(stderr, "cannot lstat '%s': %s\n",stat_path , strerror(errno)); } } @@ -783,7 +732,7 @@ static int copy_local_dir_remote(int fd, const char *lpath, const char *rpath, i if(ci->flag == 0) { fprintf(stderr,"%spush: %s -> %s\n", listonly ? "would " : "", ci->src, ci->dst); if(!listonly && - sync_send(fd, ci->src, ci->dst, ci->time, ci->mode, 0 /* no verify APK */, + sync_send(fd, ci->src, ci->dst, ci->time, ci->mode, 0 /* no show progress */)) { return 1; } @@ -802,7 +751,7 @@ static int copy_local_dir_remote(int fd, const char *lpath, const char *rpath, i } -int do_sync_push(const char *lpath, const char *rpath, int verifyApk, int show_progress) +int do_sync_push(const char *lpath, const char *rpath, int show_progress) { struct stat st; unsigned mode; @@ -849,7 +798,7 @@ int do_sync_push(const char *lpath, const char *rpath, int verifyApk, int show_p rpath = tmp; } BEGIN(); - if(sync_send(fd, lpath, rpath, st.st_mtime, st.st_mode, verifyApk, show_progress)) { + if(sync_send(fd, lpath, rpath, st.st_mtime, st.st_mode, show_progress)) { return 1; } else { END(); @@ -931,8 +880,21 @@ 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) +{ + struct utimbuf times = { time, time }; + int r1 = utime(lpath, ×); + + /* use umask for permissions */ + mode_t mask=umask(0000); + umask(mask); + int r2 = chmod(lpath, mode & ~mask); + + return r1 ? : r2; +} + static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath, - int checktimestamps) + int copy_attrs) { copyinfo *filelist = 0; copyinfo *ci, *next; @@ -962,26 +924,6 @@ static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath, return -1; } -#if 0 - if (checktimestamps) { - for (ci = filelist; ci != 0; ci = ci->next) { - if (sync_start_readtime(fd, ci->dst)) { - return 1; - } - } - for (ci = filelist; ci != 0; ci = ci->next) { - unsigned int timestamp, mode, size; - if (sync_finish_readtime(fd, ×tamp, &mode, &size)) - return 1; - if (size == ci->size) { - /* for links, we cannot update the atime/mtime */ - if ((S_ISREG(ci->mode & mode) && timestamp == ci->time) || - (S_ISLNK(ci->mode & mode) && timestamp >= ci->time)) - ci->flag = 1; - } - } - } -#endif for (ci = filelist; ci != 0; ci = next) { next = ci->next; if (ci->flag == 0) { @@ -989,6 +931,10 @@ static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath, if (sync_recv(fd, ci->src, ci->dst, 0 /* no show progress */)) { return 1; } + + if (copy_attrs && set_time_and_mode(ci->dst, ci->time, ci->mode)) { + return 1; + } pulled++; } else { skipped++; @@ -1003,9 +949,9 @@ static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath, return 0; } -int do_sync_pull(const char *rpath, const char *lpath, int show_progress) +int do_sync_pull(const char *rpath, const char *lpath, int show_progress, int copy_attrs) { - unsigned mode; + unsigned mode, time; struct stat st; int fd; @@ -1016,7 +962,7 @@ int do_sync_pull(const char *rpath, const char *lpath, int show_progress) return 1; } - if(sync_readmode(fd, rpath, &mode)) { + if(sync_readtime(fd, rpath, &time, &mode)) { return 1; } if(mode == 0) { @@ -1047,13 +993,15 @@ int do_sync_pull(const char *rpath, const char *lpath, int show_progress) if (sync_recv(fd, rpath, lpath, show_progress)) { return 1; } else { + if (copy_attrs && set_time_and_mode(lpath, time, mode)) + return 1; END(); sync_quit(fd); return 0; } } else if(S_ISDIR(mode)) { BEGIN(); - if (copy_remote_dir_local(fd, rpath, lpath, 0)) { + if (copy_remote_dir_local(fd, rpath, lpath, copy_attrs)) { return 1; } else { END(); diff --git a/adb/file_sync_service.c b/adb/file_sync_service.c index 1d80d26..7933858 100644 --- a/adb/file_sync_service.c +++ b/adb/file_sync_service.c @@ -39,6 +39,11 @@ static bool is_on_system(const char *name) { 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); +} + static int mkdirs(char *name) { int ret; @@ -54,7 +59,7 @@ static int mkdirs(char *name) x = adb_dirstart(x); if(x == 0) return 0; *x = 0; - if (is_on_system(name)) { + if (is_on_system(name) || is_on_vendor(name)) { fs_config(name, 1, &uid, &gid, &mode, &cap); } ret = adb_mkdir(name, mode); @@ -178,18 +183,18 @@ static int handle_send_file(int s, char *path, uid_t uid, unsigned int timestamp = 0; int fd; - fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL, mode); + fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode); if(fd < 0 && errno == ENOENT) { if(mkdirs(path) != 0) { if(fail_errno(s)) return -1; fd = -1; } else { - fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL, mode); + fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode); } } if(fd < 0 && errno == EEXIST) { - fd = adb_open_mode(path, O_WRONLY, mode); + fd = adb_open_mode(path, O_WRONLY | O_CLOEXEC, mode); } if(fd < 0) { if(fail_errno(s)) @@ -369,7 +374,7 @@ static int do_send(int s, char *path, char *buffer) if(*tmp == '/') { tmp++; } - if (is_on_system(path)) { + 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); @@ -383,7 +388,7 @@ static int do_recv(int s, const char *path, char *buffer) syncmsg msg; int fd, r; - fd = adb_open(path, O_RDONLY); + fd = adb_open(path, O_RDONLY | O_CLOEXEC); if(fd < 0) { if(fail_errno(s)) return -1; return 0; diff --git a/adb/file_sync_service.h b/adb/file_sync_service.h index 3e7e096..5dd2e80 100644 --- a/adb/file_sync_service.h +++ b/adb/file_sync_service.h @@ -78,9 +78,9 @@ typedef union { 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 verifyApk, int show_progress); +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_pull(const char *rpath, const char *lpath, int show_progress); +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/remount_service.c b/adb/remount_service.c index d3a649b..72d15a1 100644 --- a/adb/remount_service.c +++ b/adb/remount_service.c @@ -29,6 +29,7 @@ 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) @@ -39,7 +40,7 @@ static char *find_mount(const char *dir) const char delims[] = "\n"; char buf[4096]; - fd = unix_open("/proc/mounts", O_RDONLY); + fd = unix_open("/proc/mounts", O_RDONLY | O_CLOEXEC); if (fd < 0) return NULL; @@ -67,34 +68,43 @@ static char *find_mount(const char *dir) 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_system() +static int remount(const char* dir, int* dir_ro) { char *dev; int fd; int OFF = 0; - if (system_ro == 0) { + if (dir_ro == 0) { return 0; } - dev = find_mount("/system"); + dev = find_mount(dir); if (!dev) return -1; - fd = unix_open(dev, O_RDONLY); + fd = unix_open(dev, O_RDONLY | O_CLOEXEC); if (fd < 0) return -1; ioctl(fd, BLKROSET, &OFF); adb_close(fd); - system_ro = mount(dev, "/system", "none", MS_REMOUNT, NULL); + *dir_ro = mount(dev, dir, "none", MS_REMOUNT, NULL); free(dev); - return system_ro; + return *dir_ro; } static void write_string(int fd, const char* str) @@ -104,14 +114,23 @@ static void write_string(int fd, const char* str) void remount_service(int fd, void *cookie) { - int ret = remount_system(); + char buffer[200]; + 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 (!ret) - write_string(fd, "remount succeeded\n"); + if (!system_ro && (!vendor_ro || !hasVendorPartition())) + write_string(fd, "remount succeeded\n"); else { - char buffer[200]; - snprintf(buffer, sizeof(buffer), "remount failed: %s\n", strerror(errno)); - write_string(fd, buffer); + write_string(fd, "remount failed\n"); } adb_close(fd); diff --git a/adb/services.c b/adb/services.c index 7b809da..bcfc163 100644 --- a/adb/services.c +++ b/adb/services.c @@ -184,25 +184,38 @@ static int create_service_thread(void (*func)(int, void *), void *cookie) } #if !ADB_HOST -static int create_subprocess(const char *cmd, const char *arg0, const char *arg1, pid_t *pid) + +static void init_subproc_child() +{ + setsid(); + + // Set OOM score adjustment to prevent killing + int fd = adb_open("/proc/self/oom_score_adj", O_WRONLY | O_CLOEXEC); + if (fd >= 0) { + adb_write(fd, "0", 1); + adb_close(fd); + } else { + D("adb: unable to update oom_score_adj\n"); + } +} + +static int create_subproc_pty(const char *cmd, const char *arg0, const char *arg1, pid_t *pid) { -#ifdef HAVE_WIN32_PROC - D("create_subprocess(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1); - fprintf(stderr, "error: create_subprocess not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1); + D("create_subproc_pty(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1); +#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 */ - char *devname; +#else int ptm; - ptm = unix_open("/dev/ptmx", O_RDWR); // | O_NOCTTY); + ptm = unix_open("/dev/ptmx", O_RDWR | O_CLOEXEC); // | O_NOCTTY); if(ptm < 0){ printf("[ cannot open /dev/ptmx - %s ]\n",strerror(errno)); return -1; } - fcntl(ptm, F_SETFD, FD_CLOEXEC); - if(grantpt(ptm) || unlockpt(ptm) || - ((devname = (char*) ptsname(ptm)) == 0)){ + char devname[64]; + if(grantpt(ptm) || unlockpt(ptm) || ptsname_r(ptm, devname, sizeof(devname)) != 0) { printf("[ trouble with /dev/ptmx - %s ]\n", strerror(errno)); adb_close(ptm); return -1; @@ -215,46 +228,74 @@ static int create_subprocess(const char *cmd, const char *arg0, const char *arg1 return -1; } - if(*pid == 0){ - int pts; + if (*pid == 0) { + init_subproc_child(); - setsid(); - - pts = unix_open(devname, O_RDWR); - if(pts < 0) { + int pts = unix_open(devname, O_RDWR | O_CLOEXEC); + if (pts < 0) { fprintf(stderr, "child failed to open pseudo-term slave: %s\n", devname); exit(-1); } - dup2(pts, 0); - dup2(pts, 1); - dup2(pts, 2); + dup2(pts, STDIN_FILENO); + dup2(pts, STDOUT_FILENO); + dup2(pts, STDERR_FILENO); adb_close(pts); adb_close(ptm); - // set OOM adjustment to zero - char text[64]; - snprintf(text, sizeof text, "/proc/%d/oom_adj", getpid()); - int fd = adb_open(text, O_WRONLY); - if (fd >= 0) { - adb_write(fd, "0", 1); - adb_close(fd); - } else { - D("adb: unable to open %s\n", text); - } execl(cmd, cmd, arg0, arg1, NULL); fprintf(stderr, "- exec '%s' failed: %s (%d) -\n", cmd, strerror(errno), errno); exit(-1); } else { - // Don't set child's OOM adjustment to zero. - // Let the child do it itself, as sometimes the parent starts - // running before the child has a /proc/pid/oom_adj. - // """adb: unable to open /proc/644/oom_adj""" seen in some logs. 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); +#if defined(_WIN32) + fprintf(stderr, "error: create_subproc_raw not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1); + return -1; +#else + + // 0 is parent socket, 1 is child socket + int sv[2]; + if (unix_socketpair(AF_UNIX, SOCK_STREAM, 0, sv) < 0) { + printf("[ cannot create socket pair - %s ]\n", strerror(errno)); + return -1; + } + + *pid = fork(); + if (*pid < 0) { + printf("- fork failed: %s -\n", strerror(errno)); + adb_close(sv[0]); + adb_close(sv[1]); + return -1; + } + + if (*pid == 0) { + adb_close(sv[0]); + init_subproc_child(); + + dup2(sv[1], STDIN_FILENO); + dup2(sv[1], STDOUT_FILENO); + dup2(sv[1], STDERR_FILENO); + + adb_close(sv[1]); + + execl(cmd, cmd, arg0, arg1, NULL); + fprintf(stderr, "- exec '%s' failed: %s (%d) -\n", + cmd, strerror(errno), errno); + exit(-1); + } else { + adb_close(sv[1]); + return sv[0]; + } +#endif /* !defined(_WIN32) */ } #endif /* !ABD_HOST */ @@ -296,18 +337,32 @@ static void subproc_waiter_service(int fd, void *cookie) } } -static int create_subproc_thread(const char *name) +static int create_subproc_thread(const char *name, const subproc_mode mode) { stinfo *sti; adb_thread_t t; int ret_fd; - pid_t pid; - if(name) { - ret_fd = create_subprocess(SHELL_COMMAND, "-c", name, &pid); + pid_t pid = -1; + + const char *arg0, *arg1; + if (name == 0 || *name == 0) { + arg0 = "-"; arg1 = 0; } else { - ret_fd = create_subprocess(SHELL_COMMAND, "-", 0, &pid); + arg0 = "-c"; arg1 = name; + } + + switch (mode) { + case SUBPROC_PTY: + ret_fd = create_subproc_pty(SHELL_COMMAND, arg0, arg1, &pid); + break; + case SUBPROC_RAW: + ret_fd = create_subproc_raw(SHELL_COMMAND, arg0, arg1, &pid); + break; + default: + fprintf(stderr, "invalid subproc_mode %d\n", mode); + return -1; } - D("create_subprocess() ret_fd=%d pid=%d\n", ret_fd, pid); + D("create_subproc ret_fd=%d pid=%d\n", ret_fd, pid); sti = malloc(sizeof(stinfo)); if(sti == 0) fatal("cannot allocate stinfo"); @@ -315,14 +370,14 @@ static int create_subproc_thread(const char *name) sti->cookie = (void*) (uintptr_t) pid; sti->fd = ret_fd; - if(adb_thread_create( &t, service_bootstrap_func, sti)){ + if (adb_thread_create(&t, service_bootstrap_func, sti)) { free(sti); adb_close(ret_fd); - printf("cannot create service thread\n"); + fprintf(stderr, "cannot create service thread\n"); return -1; } - D("service thread started, fd=%d pid=%d\n",ret_fd, pid); + D("service thread started, fd=%d pid=%d\n", ret_fd, pid); return ret_fd; } #endif @@ -361,33 +416,41 @@ int service_to_fd(const char *name) #endif #if !ADB_HOST } else if(!strncmp("dev:", name, 4)) { - ret = unix_open(name + 4, O_RDWR); + ret = unix_open(name + 4, O_RDWR | O_CLOEXEC); } else if(!strncmp(name, "framebuffer:", 12)) { ret = create_service_thread(framebuffer_service, 0); } else if (!strncmp(name, "jdwp:", 5)) { ret = create_jdwp_connection_fd(atoi(name+5)); } else if(!HOST && !strncmp(name, "shell:", 6)) { - if(name[6]) { - ret = create_subproc_thread(name + 6); - } else { - ret = create_subproc_thread(0); - } + ret = create_subproc_thread(name + 6, SUBPROC_PTY); + } else if(!HOST && !strncmp(name, "exec:", 5)) { + ret = create_subproc_thread(name + 5, SUBPROC_RAW); } else if(!strncmp(name, "sync:", 5)) { ret = create_service_thread(file_sync_service, NULL); } else if(!strncmp(name, "remount:", 8)) { ret = create_service_thread(remount_service, NULL); } else if(!strncmp(name, "reboot:", 7)) { void* arg = strdup(name + 7); - if(arg == 0) return -1; + if (arg == NULL) return -1; 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, "backup:", 7)) { - char* arg = strdup(name+7); + char* arg = strdup(name + 7); if (arg == NULL) return -1; - ret = backup_service(BACKUP, arg); + 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); } else if(!strncmp(name, "restore:", 8)) { - ret = backup_service(RESTORE, NULL); + 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) { diff --git a/adb/sockets.c b/adb/sockets.c index de14a22..faa9564 100644 --- a/adb/sockets.c +++ b/adb/sockets.c @@ -23,6 +23,10 @@ #include "sysdeps.h" +#if !ADB_HOST +#include <cutils/properties.h> +#endif + #define TRACE_TAG TRACE_SOCKETS #include "adb.h" @@ -428,6 +432,9 @@ 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")) { @@ -444,7 +451,11 @@ asocket *create_local_service_socket(const char *name) D("LS(%d): bound to '%s' via %d\n", s->id, name, fd); #if !ADB_HOST - if ((!strncmp(name, "root:", 5) && getuid() != 0) + if (!strncmp(name, "root:", 5)) + property_get("ro.debuggable", debug, ""); + + if ((!strncmp(name, "root:", 5) && getuid() != 0 + && strcmp(debug, "1") == 0) || !strncmp(name, "usb:", 4) || !strncmp(name, "tcpip:", 6)) { D("LS(%d): enabling exit_on_close\n", s->id); diff --git a/adb/sysdeps.h b/adb/sysdeps.h index ba4306f..cc1f839 100644 --- a/adb/sysdeps.h +++ b/adb/sysdeps.h @@ -26,8 +26,8 @@ #ifdef _WIN32 -#include <windows.h> #include <winsock2.h> +#include <windows.h> #include <ws2tcpip.h> #include <process.h> #include <fcntl.h> @@ -35,6 +35,7 @@ #include <sys/stat.h> #include <errno.h> #include <ctype.h> +#include <direct.h> #define OS_PATH_SEPARATOR '\\' #define OS_PATH_SEPARATOR_STR "\\" diff --git a/adb/sysdeps_win32.c b/adb/sysdeps_win32.c index 29f58ec..b082c6d 100644 --- a/adb/sysdeps_win32.c +++ b/adb/sysdeps_win32.c @@ -1,6 +1,6 @@ #include "sysdeps.h" -#include <windows.h> #include <winsock2.h> +#include <windows.h> #include <stdio.h> #include <errno.h> #define TRACE_TAG TRACE_SYSDEPS @@ -1549,7 +1549,7 @@ _wait_for_all(HANDLE* handles, int handles_count) * reset" event that will remain set once it was set. */ main_event = CreateEvent(NULL, TRUE, FALSE, NULL); if (main_event == NULL) { - D("Unable to create main event. Error: %d", GetLastError()); + D("Unable to create main event. Error: %d", (int)GetLastError()); free(threads); return (int)WAIT_FAILED; } diff --git a/adb/usb_linux.c b/adb/usb_linux.c index 8ff753e..f16bdd0 100644 --- a/adb/usb_linux.c +++ b/adb/usb_linux.c @@ -170,7 +170,7 @@ static void find_usb_device(const char *base, } // DBGX("[ scanning %s ]\n", devname); - if((fd = unix_open(devname, O_RDONLY)) < 0) { + if((fd = unix_open(devname, O_RDONLY | O_CLOEXEC)) < 0) { continue; } @@ -597,10 +597,10 @@ static void register_device(const char *dev_name, const char *devpath, usb->mark = 1; usb->reaper_thread = 0; - usb->desc = unix_open(usb->fname, O_RDWR); + usb->desc = unix_open(usb->fname, O_RDWR | O_CLOEXEC); if(usb->desc < 0) { /* if we fail, see if have read-only access */ - usb->desc = unix_open(usb->fname, O_RDONLY); + usb->desc = unix_open(usb->fname, O_RDONLY | O_CLOEXEC); if(usb->desc < 0) goto fail; usb->writeable = 0; D("[ usb open read-only %s fd = %d]\n", usb->fname, usb->desc); diff --git a/adb/usb_osx.c b/adb/usb_osx.c index 45ce444..ee893f5 100644 --- a/adb/usb_osx.c +++ b/adb/usb_osx.c @@ -197,7 +197,8 @@ AndroidInterfaceAdded(void *refCon, io_iterator_t iterator) 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); @@ -512,14 +513,18 @@ int usb_read(usb_handle *handle, void *buf, int len) return -1; } - result = - (*handle->interface)->ReadPipe(handle->interface, - handle->bulkIn, buf, &numBytes); + result = (*handle->interface)->ReadPipe(handle->interface, handle->bulkIn, buf, &numBytes); - if (0 == result) + if (kIOUSBPipeStalled == result) { + DBG(" Pipe stalled, clearing stall.\n"); + (*handle->interface)->ClearPipeStall(handle->interface, handle->bulkIn); + result = (*handle->interface)->ReadPipe(handle->interface, handle->bulkIn, buf, &numBytes); + } + + if (kIOReturnSuccess == result) return 0; else { - DBG("ERR: usb_read failed with status %d\n", result); + DBG("ERR: usb_read failed with status %x\n", result); } return -1; diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c index 705f02b..3b08907 100755 --- a/adb/usb_vendors.c +++ b/adb/usb_vendors.c @@ -38,6 +38,8 @@ /* Keep the list below sorted alphabetically by #define name */ // Acer's USB Vendor ID #define VENDOR_ID_ACER 0x0502 +// Alco's USB Vendor ID +#define VENDOR_ID_ALCO 0x1914 // Allwinner's USB Vendor ID #define VENDOR_ID_ALLWINNER 0x1F3A // Amlogic's USB Vendor ID @@ -116,6 +118,8 @@ #define VENDOR_ID_LGE 0x1004 // Lumigon's USB Vendor ID #define VENDOR_ID_LUMIGON 0x25E3 +// Micromax's USB Vendor ID +#define VENDOR_ID_MICROMAX 0x2A96 // Motorola's USB Vendor ID #define VENDOR_ID_MOTOROLA 0x22b8 // MSI's USB Vendor ID @@ -152,6 +156,8 @@ #define VENDOR_ID_QUALCOMM 0x05c6 // Quanta's USB Vendor ID #define VENDOR_ID_QUANTA 0x0408 +// Razer's USB Vendor ID +#define VENDOR_ID_RAZER 0x1532 // Rockchip's USB Vendor ID #define VENDOR_ID_ROCKCHIP 0x2207 // Samsung's USB Vendor ID @@ -160,6 +166,10 @@ #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 +// Sonim Tech's USB Vendor ID +#define VENDOR_ID_SONIM_TECH 0x1d9c // Sony's USB Vendor ID #define VENDOR_ID_SONY 0x054C // Sony Ericsson's USB Vendor ID @@ -174,6 +184,8 @@ #define VENDOR_ID_TI 0x0451 // Toshiba's USB Vendor ID #define VENDOR_ID_TOSHIBA 0x0930 +// TrekStor's USB Vendor ID +#define VENDOR_ID_TREKSTOR 0x1E68 // Unowhy's USB Vendor ID #define VENDOR_ID_UNOWHY 0x2A49 // Vizio's USB Vendor ID @@ -194,6 +206,7 @@ /* Keep the list below sorted alphabetically */ int builtInVendorIds[] = { VENDOR_ID_ACER, + VENDOR_ID_ALCO, VENDOR_ID_ALLWINNER, VENDOR_ID_AMLOGIC, VENDOR_ID_ANYDATA, @@ -233,6 +246,7 @@ int builtInVendorIds[] = { VENDOR_ID_LENOVOMOBILE, VENDOR_ID_LGE, VENDOR_ID_LUMIGON, + VENDOR_ID_MICROMAX, VENDOR_ID_MOTOROLA, VENDOR_ID_MSI, VENDOR_ID_MTK, @@ -251,10 +265,13 @@ int builtInVendorIds[] = { VENDOR_ID_QISDA, VENDOR_ID_QUALCOMM, VENDOR_ID_QUANTA, + VENDOR_ID_RAZER, VENDOR_ID_ROCKCHIP, VENDOR_ID_SAMSUNG, VENDOR_ID_SHARP, VENDOR_ID_SK_TELESYS, + VENDOR_ID_SMARTISAN, + VENDOR_ID_SONIM_TECH, VENDOR_ID_SONY, VENDOR_ID_SONY_ERICSSON, VENDOR_ID_T_AND_A, @@ -262,6 +279,7 @@ int builtInVendorIds[] = { VENDOR_ID_TELEEPOCH, VENDOR_ID_TI, VENDOR_ID_TOSHIBA, + VENDOR_ID_TREKSTOR, VENDOR_ID_UNOWHY, VENDOR_ID_VIZIO, VENDOR_ID_WACOM, diff --git a/adb/usb_windows.c b/adb/usb_windows.c index 1309a78..b7ad913 100644 --- a/adb/usb_windows.c +++ b/adb/usb_windows.c @@ -14,6 +14,7 @@ * limitations under the License. */ +#include <winsock2.h> #include <windows.h> #include <winerror.h> #include <errno.h> |