From cc1de48dcdf06c76ee14abbe2a237aa51b5b3bad Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Thu, 30 Jul 2009 16:23:56 -0700 Subject: [PATCH] adb: Another attempted workaround for the adb disconnect problem. For adb shell commands (as well as shell based commands like logcat and bugreport) we now batch USB writes into 4K chunks instead of sending small packets of data as they come in. A timeout prevents us from blocking for more than 100ms when our 4K buffer is partially full. Signed-off-by: Mike Lockwood --- adb/services.c | 92 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 81 insertions(+), 11 deletions(-) diff --git a/adb/services.c b/adb/services.c index 0a5edcf4b..78d092b83 100644 --- a/adb/services.c +++ b/adb/services.c @@ -31,6 +31,8 @@ # include # include # endif +#else +#include #endif typedef struct stinfo stinfo; @@ -196,12 +198,9 @@ static int create_service_thread(void (*func)(int, void *), void *cookie) return s[0]; } +#if !ADB_HOST static int create_subprocess(const char *cmd, const char *arg0, const char *arg1) { -#ifdef HAVE_WIN32_PROC - fprintf(stderr, "error: create_subprocess not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1); - return -1; -#else /* !HAVE_WIN32_PROC */ char *devname; int ptm; pid_t pid; @@ -244,7 +243,6 @@ static int create_subprocess(const char *cmd, const char *arg0, const char *arg1 cmd, strerror(errno), errno); exit(-1); } else { -#if !ADB_HOST // set child's OOM adjustment to zero char text[64]; snprintf(text, sizeof text, "/proc/%d/oom_adj", pid); @@ -255,11 +253,11 @@ static int create_subprocess(const char *cmd, const char *arg0, const char *arg1 } else { D("adb: unable to open %s\n", text); } -#endif + return ptm; } -#endif /* !HAVE_WIN32_PROC */ } +#endif /* !ADB_HOST */ #if ADB_HOST #define SHELL_COMMAND "/bin/sh" @@ -267,6 +265,76 @@ static int create_subprocess(const char *cmd, const char *arg0, const char *arg1 #define SHELL_COMMAND "/system/bin/sh" #endif +#if !ADB_HOST +static void shell_service(int s, void *command) +{ + char buffer[MAX_PAYLOAD]; + char buffer2[MAX_PAYLOAD]; + struct pollfd ufds[2]; + int fd, ret = 0; + unsigned count = 0; + char** args = (char **)command; + fd = create_subprocess(SHELL_COMMAND, args[0], args[1]); + + while (1) { + while (count < sizeof(buffer)) { + ufds[0].fd = fd; + ufds[0].events = POLLIN | POLLHUP; + ufds[0].revents = 0; + ufds[1].fd = s; + ufds[1].events = POLLIN | POLLHUP; + ufds[1].revents = 0; + // use a 100ms timeout so we don't block indefinitely with our + // buffer partially filled. + ret = poll(ufds, 2, 100); + if (ret <= 0) { + D("poll returned %d\n", ret); + // file has closed or we timed out + // set ret to 1 so we don't exit the outer loop + ret = 1; + break; + } + + if (ufds[0].revents & POLLIN) { + ret = adb_read(fd, buffer + count, sizeof(buffer) - count); + D("read fd ret: %d, count: %d\n", ret, count); + if (ret > 0) + count += ret; + else + break; + } + if (ufds[1].revents & POLLIN) { + ret = adb_read(s, buffer2, sizeof(buffer2)); + D("read s ret: %d\n", ret); + if (ret > 0) + adb_write(fd, buffer2, ret); + else + break; + } + + if ((ufds[0].revents & POLLHUP) || (ufds[1].revents & POLLHUP)) { + // set flag to exit after flushing the buffer + ret = -1; + break; + } + } + + D("writing: %d\n", count); + if (count > 0) { + adb_write(s, buffer, count); + count = 0; + } + if (ret <= 0) + break; + } + + D("shell_service done\n"); + + adb_close(fd); + adb_close(s); +} +#endif // !ADB_HOST + int service_to_fd(const char *name) { int ret = -1; @@ -317,14 +385,16 @@ int service_to_fd(const char *name) ret = create_jdwp_connection_fd(atoi(name+5)); } else if (!strncmp(name, "log:", 4)) { ret = create_service_thread(log_service, get_log_file_path(name + 4)); -#endif } else if(!HOST && !strncmp(name, "shell:", 6)) { + const char* args[2]; if(name[6]) { - ret = create_subprocess(SHELL_COMMAND, "-c", name + 6); + args[0] = "-c"; + args[1] = name + 6; } else { - ret = create_subprocess(SHELL_COMMAND, "-", 0); + args[0] = "-"; + args[1] = 0; } -#if !ADB_HOST + ret = create_service_thread(shell_service, (void *)args); } else if(!strncmp(name, "sync:", 5)) { ret = create_service_thread(file_sync_service, NULL); } else if(!strncmp(name, "remount:", 8)) {