Loading adb/Android.mk +2 −0 Original line number Diff line number Diff line Loading @@ -132,8 +132,10 @@ LOCAL_CFLAGS := -DADB_HOST=0 $(LIBADB_CFLAGS) LOCAL_SRC_FILES := \ $(LIBADB_TEST_SRCS) \ $(LIBADB_TEST_linux_SRCS) \ shell_service.cpp \ shell_service_protocol.cpp \ shell_service_protocol_test.cpp \ shell_service_test.cpp \ LOCAL_SANITIZE := $(adb_target_sanitize) LOCAL_STATIC_LIBRARIES := libadbd Loading adb/adb.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -501,7 +501,7 @@ void handle_packet(apacket *p, atransport *t) if (t->online && p->msg.arg0 != 0 && p->msg.arg1 == 0) { char *name = (char*) p->data; name[p->msg.data_length > 0 ? p->msg.data_length - 1 : 0] = 0; s = create_local_service_socket(name); s = create_local_service_socket(name, t); if(s == 0) { send_close(0, p->msg.arg0, t); } else { Loading adb/adb.h +3 −2 Original line number Diff line number Diff line Loading @@ -221,7 +221,8 @@ void remove_socket(asocket *s); void close_all_sockets(atransport *t); asocket *create_local_socket(int fd); asocket *create_local_service_socket(const char *destination); asocket *create_local_service_socket(const char* destination, const atransport* transport); asocket *create_remote_socket(unsigned id, atransport *t); void connect_to_remote(asocket *s, const char *destination); Loading @@ -247,7 +248,7 @@ void init_usb_transport(atransport *t, usb_handle *usb, ConnectionState state); atransport* find_emulator_transport_by_adb_port(int adb_port); #endif int service_to_fd(const char *name); int service_to_fd(const char* name, const atransport* transport); #if ADB_HOST asocket *host_service_to_socket(const char* name, const char *serial); #endif Loading adb/commandline.cpp +142 −49 Original line number Diff line number Diff line Loading @@ -31,8 +31,10 @@ #include <sys/stat.h> #include <sys/types.h> #include <memory> #include <string> #include <base/logging.h> #include <base/stringprintf.h> #if !defined(_WIN32) Loading @@ -46,6 +48,8 @@ #include "adb_io.h" #include "adb_utils.h" #include "file_sync_service.h" #include "shell_service.h" #include "transport.h" static int install_app(TransportType t, const char* serial, int argc, const char** argv); static int install_multiple_app(TransportType t, const char* serial, int argc, const char** argv); Loading Loading @@ -256,19 +260,60 @@ static void stdin_raw_restore(int fd) { } #endif static void read_and_dump(int fd) { // Reads from |fd| and prints received data. If |use_shell_protocol| is true // this expects that incoming data will use the shell protocol, in which case // stdout/stderr are routed independently and the remote exit code will be // returned. static int read_and_dump(int fd, bool use_shell_protocol=false) { int exit_code = 0; std::unique_ptr<ShellProtocol> protocol; int length = 0; FILE* outfile = stdout; char raw_buffer[BUFSIZ]; char* buffer_ptr = raw_buffer; if (use_shell_protocol) { protocol.reset(new ShellProtocol(fd)); if (!protocol) { LOG(ERROR) << "failed to allocate memory for ShellProtocol object"; return 1; } buffer_ptr = protocol->data(); } while (fd >= 0) { if (use_shell_protocol) { if (!protocol->Read()) { break; } switch (protocol->id()) { case ShellProtocol::kIdStdout: outfile = stdout; break; case ShellProtocol::kIdStderr: outfile = stderr; break; case ShellProtocol::kIdExit: exit_code = protocol->data()[0]; continue; default: continue; } length = protocol->data_length(); } else { D("read_and_dump(): pre adb_read(fd=%d)", fd); char buf[BUFSIZ]; int len = adb_read(fd, buf, sizeof(buf)); D("read_and_dump(): post adb_read(fd=%d): len=%d", fd, len); if (len <= 0) { length = adb_read(fd, raw_buffer, sizeof(raw_buffer)); D("read_and_dump(): post adb_read(fd=%d): length=%d", fd, length); if (length <= 0) { break; } } fwrite(buf, 1, len, stdout); fflush(stdout); fwrite(buffer_ptr, 1, length, outfile); fflush(outfile); } return exit_code; } static void read_status_line(int fd, char* buf, size_t count) Loading Loading @@ -362,28 +407,41 @@ static void copy_to_file(int inFd, int outFd) { free(buf); } static void *stdin_read_thread(void *x) { int fd, fdi; unsigned char buf[1024]; int r, n; int state = 0; namespace { // Used to pass multiple values to the stdin read thread. struct StdinReadArgs { int stdin_fd, write_fd; std::unique_ptr<ShellProtocol> protocol; }; int *fds = (int*) x; fd = fds[0]; fdi = fds[1]; free(fds); } // namespace // Loops to read from stdin and push the data to the given FD. // The argument should be a pointer to a StdinReadArgs object. This function // will take ownership of the object and delete it when finished. static void* stdin_read_thread(void* x) { std::unique_ptr<StdinReadArgs> args(reinterpret_cast<StdinReadArgs*>(x)); int state = 0; adb_thread_setname("stdin reader"); char raw_buffer[1024]; char* buffer_ptr = raw_buffer; size_t buffer_size = sizeof(raw_buffer); if (args->protocol) { buffer_ptr = args->protocol->data(); buffer_size = args->protocol->data_capacity(); } while (true) { /* fdi is really the client's stdin, so use read, not adb_read here */ D("stdin_read_thread(): pre unix_read(fdi=%d,...)", fdi); r = unix_read(fdi, buf, 1024); D("stdin_read_thread(): post unix_read(fdi=%d,...)", fdi); // Use unix_read() rather than adb_read() for stdin. D("stdin_read_thread(): pre unix_read(fdi=%d,...)", args->stdin_fd); int r = unix_read(args->stdin_fd, buffer_ptr, buffer_size); D("stdin_read_thread(): post unix_read(fdi=%d,...)", args->stdin_fd); if (r <= 0) break; for (n = 0; n < r; n++){ switch(buf[n]) { for (int n = 0; n < r; n++){ switch(buffer_ptr[n]) { case '\n': state = 1; break; Loading @@ -396,47 +454,59 @@ static void *stdin_read_thread(void *x) case '.': if(state == 2) { fprintf(stderr,"\n* disconnect *\n"); stdin_raw_restore(fdi); stdin_raw_restore(args->stdin_fd); exit(0); } default: state = 0; } } r = adb_write(fd, buf, r); if(r <= 0) { if (args->protocol) { if (!args->protocol->Write(ShellProtocol::kIdStdin, r)) { break; } } else { if (!WriteFdExactly(args->write_fd, buffer_ptr, r)) { break; } } return 0; } static int interactive_shell() { int fdi; return nullptr; } static int interactive_shell(bool use_shell_protocol) { std::string error; int fd = adb_connect("shell:", &error); if (fd < 0) { fprintf(stderr,"error: %s\n", error.c_str()); return 1; } fdi = 0; //dup(0); int* fds = reinterpret_cast<int*>(malloc(sizeof(int) * 2)); if (fds == nullptr) { fprintf(stderr, "couldn't allocate fds array: %s\n", strerror(errno)); StdinReadArgs* args = new StdinReadArgs; if (!args) { LOG(ERROR) << "couldn't allocate StdinReadArgs object"; return 1; } args->stdin_fd = 0; args->write_fd = fd; if (use_shell_protocol) { args->protocol.reset(new ShellProtocol(args->write_fd)); } fds[0] = fd; fds[1] = fdi; stdin_raw_init(args->stdin_fd); stdin_raw_init(fdi); int exit_code = 0; if (!adb_thread_create(stdin_read_thread, args)) { PLOG(ERROR) << "error starting stdin read thread"; exit_code = 1; delete args; } else { exit_code = read_and_dump(fd, use_shell_protocol); } adb_thread_create(stdin_read_thread, fds); read_and_dump(fd); stdin_raw_restore(fdi); return 0; stdin_raw_restore(args->stdin_fd); return exit_code; } Loading Loading @@ -943,6 +1013,20 @@ static bool _is_valid_ack_reply_fd(const int ack_reply_fd) { #endif } // Checks whether the device indicated by |transport_type| and |serial| supports // |feature|. Returns the response string, which will be empty if the device // could not be found or the feature is not supported. static std::string CheckFeature(const std::string& feature, TransportType transport_type, const char* serial) { std::string result, error, command("check-feature:" + feature); if (!adb_query(format_host_command(command.c_str(), transport_type, serial), &result, &error)) { return ""; } return result; } int adb_commandline(int argc, const char **argv) { int no_daemon = 0; int is_daemon = 0; Loading Loading @@ -1156,9 +1240,19 @@ int adb_commandline(int argc, const char **argv) { fflush(stdout); } bool use_shell_protocol; if (CheckFeature(kFeatureShell2, transport_type, serial).empty()) { D("shell protocol not supported, using raw data transfer"); use_shell_protocol = false; } else { D("using shell protocol"); use_shell_protocol = true; } if (argc < 2) { D("starting interactive shell"); r = interactive_shell(); r = interactive_shell(use_shell_protocol); if (h) { printf("\x1b[0m"); fflush(stdout); Loading @@ -1176,16 +1270,15 @@ int adb_commandline(int argc, const char **argv) { } while (true) { D("interactive shell loop. cmd=%s", cmd.c_str()); D("non-interactive shell loop. cmd=%s", cmd.c_str()); std::string error; int fd = adb_connect(cmd, &error); int r; if (fd >= 0) { D("about to read_and_dump(fd=%d)", fd); read_and_dump(fd); r = read_and_dump(fd, use_shell_protocol); D("read_and_dump() done."); adb_close(fd); r = 0; } else { fprintf(stderr,"error: %s\n", error.c_str()); r = -1; Loading @@ -1195,7 +1288,7 @@ int adb_commandline(int argc, const char **argv) { printf("\x1b[0m"); fflush(stdout); } D("interactive shell loop. return r=%d", r); D("non-interactive shell loop. return r=%d", r); return r; } } Loading adb/device.py +60 −15 Original line number Diff line number Diff line Loading @@ -36,6 +36,16 @@ class NoUniqueDeviceError(FindDeviceError): super(NoUniqueDeviceError, self).__init__('No unique device') class ShellError(RuntimeError): def __init__(self, cmd, stdout, stderr, exit_code): super(ShellError, self).__init__( '`{0}` exited with code {1}'.format(cmd, exit_code)) self.cmd = cmd self.stdout = stdout self.stderr = stderr self.exit_code = exit_code def get_devices(): with open(os.devnull, 'wb') as devnull: subprocess.check_call(['adb', 'start-server'], stdout=devnull, Loading Loading @@ -146,6 +156,9 @@ class AndroidDevice(object): # adb on Windows returns \r\n even if adbd returns \n. _RETURN_CODE_SEARCH_LENGTH = len('{0}255\r\n'.format(_RETURN_CODE_DELIMITER)) # Shell protocol feature string. SHELL_PROTOCOL_FEATURE = 'shell_2' def __init__(self, serial, product=None): self.serial = serial self.product = product Loading @@ -155,6 +168,7 @@ class AndroidDevice(object): if self.product is not None: self.adb_cmd.extend(['-p', product]) self._linesep = None self._features = None @property def linesep(self): Loading @@ -163,9 +177,20 @@ class AndroidDevice(object): ['shell', 'echo']) return self._linesep @property def features(self): if self._features is None: try: self._features = self._simple_call(['features']).splitlines() except subprocess.CalledProcessError: self._features = [] return self._features def _make_shell_cmd(self, user_cmd): return (self.adb_cmd + ['shell'] + user_cmd + ['; ' + self._RETURN_CODE_PROBE_STRING]) command = self.adb_cmd + ['shell'] + user_cmd if self.SHELL_PROTOCOL_FEATURE not in self.features: command.append('; ' + self._RETURN_CODE_PROBE_STRING) return command def _parse_shell_output(self, out): """Finds the exit code string from shell output. Loading Loading @@ -201,23 +226,43 @@ class AndroidDevice(object): self.adb_cmd + cmd, stderr=subprocess.STDOUT) def shell(self, cmd): logging.info(' '.join(self.adb_cmd + ['shell'] + cmd)) cmd = self._make_shell_cmd(cmd) out = _subprocess_check_output(cmd) rc, out = self._parse_shell_output(out) if rc != 0: error = subprocess.CalledProcessError(rc, cmd) error.out = out raise error return out """Calls `adb shell` Args: cmd: string shell command to execute. Returns: A (stdout, stderr) tuple. Stderr may be combined into stdout if the device doesn't support separate streams. Raises: ShellError: the exit code was non-zero. """ exit_code, stdout, stderr = self.shell_nocheck(cmd) if exit_code != 0: raise ShellError(cmd, stdout, stderr, exit_code) return stdout, stderr def shell_nocheck(self, cmd): """Calls `adb shell` Args: cmd: string shell command to execute. Returns: An (exit_code, stdout, stderr) tuple. Stderr may be combined into stdout if the device doesn't support separate streams. """ cmd = self._make_shell_cmd(cmd) logging.info(' '.join(cmd)) p = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) out, _ = p.communicate() return self._parse_shell_output(out) cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = p.communicate() if self.SHELL_PROTOCOL_FEATURE in self.features: exit_code = p.returncode else: exit_code, stdout = self._parse_shell_output(stdout) return exit_code, stdout, stderr def install(self, filename, replace=False): cmd = ['install'] Loading Loading @@ -281,7 +326,7 @@ class AndroidDevice(object): return self._simple_call(['wait-for-device']) def get_prop(self, prop_name): output = self.shell(['getprop', prop_name]).splitlines() output = self.shell(['getprop', prop_name])[0].splitlines() if len(output) != 1: raise RuntimeError('Too many lines in getprop output:\n' + '\n'.join(output)) Loading Loading
adb/Android.mk +2 −0 Original line number Diff line number Diff line Loading @@ -132,8 +132,10 @@ LOCAL_CFLAGS := -DADB_HOST=0 $(LIBADB_CFLAGS) LOCAL_SRC_FILES := \ $(LIBADB_TEST_SRCS) \ $(LIBADB_TEST_linux_SRCS) \ shell_service.cpp \ shell_service_protocol.cpp \ shell_service_protocol_test.cpp \ shell_service_test.cpp \ LOCAL_SANITIZE := $(adb_target_sanitize) LOCAL_STATIC_LIBRARIES := libadbd Loading
adb/adb.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -501,7 +501,7 @@ void handle_packet(apacket *p, atransport *t) if (t->online && p->msg.arg0 != 0 && p->msg.arg1 == 0) { char *name = (char*) p->data; name[p->msg.data_length > 0 ? p->msg.data_length - 1 : 0] = 0; s = create_local_service_socket(name); s = create_local_service_socket(name, t); if(s == 0) { send_close(0, p->msg.arg0, t); } else { Loading
adb/adb.h +3 −2 Original line number Diff line number Diff line Loading @@ -221,7 +221,8 @@ void remove_socket(asocket *s); void close_all_sockets(atransport *t); asocket *create_local_socket(int fd); asocket *create_local_service_socket(const char *destination); asocket *create_local_service_socket(const char* destination, const atransport* transport); asocket *create_remote_socket(unsigned id, atransport *t); void connect_to_remote(asocket *s, const char *destination); Loading @@ -247,7 +248,7 @@ void init_usb_transport(atransport *t, usb_handle *usb, ConnectionState state); atransport* find_emulator_transport_by_adb_port(int adb_port); #endif int service_to_fd(const char *name); int service_to_fd(const char* name, const atransport* transport); #if ADB_HOST asocket *host_service_to_socket(const char* name, const char *serial); #endif Loading
adb/commandline.cpp +142 −49 Original line number Diff line number Diff line Loading @@ -31,8 +31,10 @@ #include <sys/stat.h> #include <sys/types.h> #include <memory> #include <string> #include <base/logging.h> #include <base/stringprintf.h> #if !defined(_WIN32) Loading @@ -46,6 +48,8 @@ #include "adb_io.h" #include "adb_utils.h" #include "file_sync_service.h" #include "shell_service.h" #include "transport.h" static int install_app(TransportType t, const char* serial, int argc, const char** argv); static int install_multiple_app(TransportType t, const char* serial, int argc, const char** argv); Loading Loading @@ -256,19 +260,60 @@ static void stdin_raw_restore(int fd) { } #endif static void read_and_dump(int fd) { // Reads from |fd| and prints received data. If |use_shell_protocol| is true // this expects that incoming data will use the shell protocol, in which case // stdout/stderr are routed independently and the remote exit code will be // returned. static int read_and_dump(int fd, bool use_shell_protocol=false) { int exit_code = 0; std::unique_ptr<ShellProtocol> protocol; int length = 0; FILE* outfile = stdout; char raw_buffer[BUFSIZ]; char* buffer_ptr = raw_buffer; if (use_shell_protocol) { protocol.reset(new ShellProtocol(fd)); if (!protocol) { LOG(ERROR) << "failed to allocate memory for ShellProtocol object"; return 1; } buffer_ptr = protocol->data(); } while (fd >= 0) { if (use_shell_protocol) { if (!protocol->Read()) { break; } switch (protocol->id()) { case ShellProtocol::kIdStdout: outfile = stdout; break; case ShellProtocol::kIdStderr: outfile = stderr; break; case ShellProtocol::kIdExit: exit_code = protocol->data()[0]; continue; default: continue; } length = protocol->data_length(); } else { D("read_and_dump(): pre adb_read(fd=%d)", fd); char buf[BUFSIZ]; int len = adb_read(fd, buf, sizeof(buf)); D("read_and_dump(): post adb_read(fd=%d): len=%d", fd, len); if (len <= 0) { length = adb_read(fd, raw_buffer, sizeof(raw_buffer)); D("read_and_dump(): post adb_read(fd=%d): length=%d", fd, length); if (length <= 0) { break; } } fwrite(buf, 1, len, stdout); fflush(stdout); fwrite(buffer_ptr, 1, length, outfile); fflush(outfile); } return exit_code; } static void read_status_line(int fd, char* buf, size_t count) Loading Loading @@ -362,28 +407,41 @@ static void copy_to_file(int inFd, int outFd) { free(buf); } static void *stdin_read_thread(void *x) { int fd, fdi; unsigned char buf[1024]; int r, n; int state = 0; namespace { // Used to pass multiple values to the stdin read thread. struct StdinReadArgs { int stdin_fd, write_fd; std::unique_ptr<ShellProtocol> protocol; }; int *fds = (int*) x; fd = fds[0]; fdi = fds[1]; free(fds); } // namespace // Loops to read from stdin and push the data to the given FD. // The argument should be a pointer to a StdinReadArgs object. This function // will take ownership of the object and delete it when finished. static void* stdin_read_thread(void* x) { std::unique_ptr<StdinReadArgs> args(reinterpret_cast<StdinReadArgs*>(x)); int state = 0; adb_thread_setname("stdin reader"); char raw_buffer[1024]; char* buffer_ptr = raw_buffer; size_t buffer_size = sizeof(raw_buffer); if (args->protocol) { buffer_ptr = args->protocol->data(); buffer_size = args->protocol->data_capacity(); } while (true) { /* fdi is really the client's stdin, so use read, not adb_read here */ D("stdin_read_thread(): pre unix_read(fdi=%d,...)", fdi); r = unix_read(fdi, buf, 1024); D("stdin_read_thread(): post unix_read(fdi=%d,...)", fdi); // Use unix_read() rather than adb_read() for stdin. D("stdin_read_thread(): pre unix_read(fdi=%d,...)", args->stdin_fd); int r = unix_read(args->stdin_fd, buffer_ptr, buffer_size); D("stdin_read_thread(): post unix_read(fdi=%d,...)", args->stdin_fd); if (r <= 0) break; for (n = 0; n < r; n++){ switch(buf[n]) { for (int n = 0; n < r; n++){ switch(buffer_ptr[n]) { case '\n': state = 1; break; Loading @@ -396,47 +454,59 @@ static void *stdin_read_thread(void *x) case '.': if(state == 2) { fprintf(stderr,"\n* disconnect *\n"); stdin_raw_restore(fdi); stdin_raw_restore(args->stdin_fd); exit(0); } default: state = 0; } } r = adb_write(fd, buf, r); if(r <= 0) { if (args->protocol) { if (!args->protocol->Write(ShellProtocol::kIdStdin, r)) { break; } } else { if (!WriteFdExactly(args->write_fd, buffer_ptr, r)) { break; } } return 0; } static int interactive_shell() { int fdi; return nullptr; } static int interactive_shell(bool use_shell_protocol) { std::string error; int fd = adb_connect("shell:", &error); if (fd < 0) { fprintf(stderr,"error: %s\n", error.c_str()); return 1; } fdi = 0; //dup(0); int* fds = reinterpret_cast<int*>(malloc(sizeof(int) * 2)); if (fds == nullptr) { fprintf(stderr, "couldn't allocate fds array: %s\n", strerror(errno)); StdinReadArgs* args = new StdinReadArgs; if (!args) { LOG(ERROR) << "couldn't allocate StdinReadArgs object"; return 1; } args->stdin_fd = 0; args->write_fd = fd; if (use_shell_protocol) { args->protocol.reset(new ShellProtocol(args->write_fd)); } fds[0] = fd; fds[1] = fdi; stdin_raw_init(args->stdin_fd); stdin_raw_init(fdi); int exit_code = 0; if (!adb_thread_create(stdin_read_thread, args)) { PLOG(ERROR) << "error starting stdin read thread"; exit_code = 1; delete args; } else { exit_code = read_and_dump(fd, use_shell_protocol); } adb_thread_create(stdin_read_thread, fds); read_and_dump(fd); stdin_raw_restore(fdi); return 0; stdin_raw_restore(args->stdin_fd); return exit_code; } Loading Loading @@ -943,6 +1013,20 @@ static bool _is_valid_ack_reply_fd(const int ack_reply_fd) { #endif } // Checks whether the device indicated by |transport_type| and |serial| supports // |feature|. Returns the response string, which will be empty if the device // could not be found or the feature is not supported. static std::string CheckFeature(const std::string& feature, TransportType transport_type, const char* serial) { std::string result, error, command("check-feature:" + feature); if (!adb_query(format_host_command(command.c_str(), transport_type, serial), &result, &error)) { return ""; } return result; } int adb_commandline(int argc, const char **argv) { int no_daemon = 0; int is_daemon = 0; Loading Loading @@ -1156,9 +1240,19 @@ int adb_commandline(int argc, const char **argv) { fflush(stdout); } bool use_shell_protocol; if (CheckFeature(kFeatureShell2, transport_type, serial).empty()) { D("shell protocol not supported, using raw data transfer"); use_shell_protocol = false; } else { D("using shell protocol"); use_shell_protocol = true; } if (argc < 2) { D("starting interactive shell"); r = interactive_shell(); r = interactive_shell(use_shell_protocol); if (h) { printf("\x1b[0m"); fflush(stdout); Loading @@ -1176,16 +1270,15 @@ int adb_commandline(int argc, const char **argv) { } while (true) { D("interactive shell loop. cmd=%s", cmd.c_str()); D("non-interactive shell loop. cmd=%s", cmd.c_str()); std::string error; int fd = adb_connect(cmd, &error); int r; if (fd >= 0) { D("about to read_and_dump(fd=%d)", fd); read_and_dump(fd); r = read_and_dump(fd, use_shell_protocol); D("read_and_dump() done."); adb_close(fd); r = 0; } else { fprintf(stderr,"error: %s\n", error.c_str()); r = -1; Loading @@ -1195,7 +1288,7 @@ int adb_commandline(int argc, const char **argv) { printf("\x1b[0m"); fflush(stdout); } D("interactive shell loop. return r=%d", r); D("non-interactive shell loop. return r=%d", r); return r; } } Loading
adb/device.py +60 −15 Original line number Diff line number Diff line Loading @@ -36,6 +36,16 @@ class NoUniqueDeviceError(FindDeviceError): super(NoUniqueDeviceError, self).__init__('No unique device') class ShellError(RuntimeError): def __init__(self, cmd, stdout, stderr, exit_code): super(ShellError, self).__init__( '`{0}` exited with code {1}'.format(cmd, exit_code)) self.cmd = cmd self.stdout = stdout self.stderr = stderr self.exit_code = exit_code def get_devices(): with open(os.devnull, 'wb') as devnull: subprocess.check_call(['adb', 'start-server'], stdout=devnull, Loading Loading @@ -146,6 +156,9 @@ class AndroidDevice(object): # adb on Windows returns \r\n even if adbd returns \n. _RETURN_CODE_SEARCH_LENGTH = len('{0}255\r\n'.format(_RETURN_CODE_DELIMITER)) # Shell protocol feature string. SHELL_PROTOCOL_FEATURE = 'shell_2' def __init__(self, serial, product=None): self.serial = serial self.product = product Loading @@ -155,6 +168,7 @@ class AndroidDevice(object): if self.product is not None: self.adb_cmd.extend(['-p', product]) self._linesep = None self._features = None @property def linesep(self): Loading @@ -163,9 +177,20 @@ class AndroidDevice(object): ['shell', 'echo']) return self._linesep @property def features(self): if self._features is None: try: self._features = self._simple_call(['features']).splitlines() except subprocess.CalledProcessError: self._features = [] return self._features def _make_shell_cmd(self, user_cmd): return (self.adb_cmd + ['shell'] + user_cmd + ['; ' + self._RETURN_CODE_PROBE_STRING]) command = self.adb_cmd + ['shell'] + user_cmd if self.SHELL_PROTOCOL_FEATURE not in self.features: command.append('; ' + self._RETURN_CODE_PROBE_STRING) return command def _parse_shell_output(self, out): """Finds the exit code string from shell output. Loading Loading @@ -201,23 +226,43 @@ class AndroidDevice(object): self.adb_cmd + cmd, stderr=subprocess.STDOUT) def shell(self, cmd): logging.info(' '.join(self.adb_cmd + ['shell'] + cmd)) cmd = self._make_shell_cmd(cmd) out = _subprocess_check_output(cmd) rc, out = self._parse_shell_output(out) if rc != 0: error = subprocess.CalledProcessError(rc, cmd) error.out = out raise error return out """Calls `adb shell` Args: cmd: string shell command to execute. Returns: A (stdout, stderr) tuple. Stderr may be combined into stdout if the device doesn't support separate streams. Raises: ShellError: the exit code was non-zero. """ exit_code, stdout, stderr = self.shell_nocheck(cmd) if exit_code != 0: raise ShellError(cmd, stdout, stderr, exit_code) return stdout, stderr def shell_nocheck(self, cmd): """Calls `adb shell` Args: cmd: string shell command to execute. Returns: An (exit_code, stdout, stderr) tuple. Stderr may be combined into stdout if the device doesn't support separate streams. """ cmd = self._make_shell_cmd(cmd) logging.info(' '.join(cmd)) p = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) out, _ = p.communicate() return self._parse_shell_output(out) cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = p.communicate() if self.SHELL_PROTOCOL_FEATURE in self.features: exit_code = p.returncode else: exit_code, stdout = self._parse_shell_output(stdout) return exit_code, stdout, stderr def install(self, filename, replace=False): cmd = ['install'] Loading Loading @@ -281,7 +326,7 @@ class AndroidDevice(object): return self._simple_call(['wait-for-device']) def get_prop(self, prop_name): output = self.shell(['getprop', prop_name]).splitlines() output = self.shell(['getprop', prop_name])[0].splitlines() if len(output) != 1: raise RuntimeError('Too many lines in getprop output:\n' + '\n'.join(output)) Loading