def root(self): """Enables ADB root mode on the device. This method will retry to execute the command `adb root` when an AdbError occurs, since sometimes the error `adb: unable to connect for root: closed` is raised when executing `adb root` immediately after the device is booted to OS. Returns: A string that is the stdout of root command. Raises: AdbError: If the command exit code is not 0. """ for attempt in range(ADB_ROOT_RETRY_ATTMEPTS): try: return self._exec_adb_cmd('root', args=None, shell=False, timeout=None, stderr=None) except AdbError as e: if attempt + 1 < ADB_ROOT_RETRY_ATTMEPTS: logging.debug( 'Retry the command "%s" since Error "%s" occurred.' % (utils.cli_cmd_to_string( e.cmd), e.stderr.decode('utf-8').strip())) # Buffer between "adb root" commands. time.sleep(ADB_ROOT_RETRY_ATTEMPT_INTERVAL_SEC) else: raise e
def _execute_and_process_stdout(self, args, shell, handler): """Executes adb commands and processes the stdout with a handler. Args: args: string or list of strings, program arguments. See subprocess.Popen() documentation. shell: bool, True to run this command through the system shell, False to invoke it directly. See subprocess.Popen() docs. handler: func, a function to handle adb stdout line by line. Returns: The stderr of the adb command run if exit code is 0. Raises: AdbError: The adb command exit code is not 0. """ proc = subprocess.Popen( args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=shell, bufsize=1) out = '[elided, processed via handler]' try: # Even if the process dies, stdout.readline still works # and will continue until it runs out of stdout to process. while True: line = proc.stdout.readline() if line: handler(line) else: break finally: # Note, communicate will not contain any buffered output. (unexpected_out, err) = proc.communicate() if unexpected_out: out = '[unexpected stdout] %s' % unexpected_out for line in unexpected_out.splitlines(): handler(line) ret = proc.returncode logging.debug('cmd: %s, stdout: %s, stderr: %s, ret: %s', utils.cli_cmd_to_string(args), out, err, ret) if ret == 0: return err else: raise AdbError(cmd=args, stdout=out, stderr=err, ret_code=ret)
def _exec_cmd(self, args, shell, timeout, stderr): """Executes adb commands. Args: args: string or list of strings, program arguments. See subprocess.Popen() documentation. shell: bool, True to run this command through the system shell, False to invoke it directly. See subprocess.Popen() docs. timeout: float, the number of seconds to wait before timing out. If not specified, no timeout takes effect. stderr: a Byte stream, like io.BytesIO, stderr of the command will be written to this object if provided. Returns: The output of the adb command run if exit code is 0. Raises: ValueError: timeout value is invalid. AdbError: The adb command exit code is not 0. AdbTimeoutError: The adb command timed out. """ if timeout and timeout <= 0: raise ValueError('Timeout is not a positive value: %s' % timeout) try: (ret, out, err) = utils.run_command(args, shell=shell, timeout=timeout) except psutil.TimeoutExpired: raise AdbTimeoutError(cmd=args, timeout=timeout, serial=self.serial) if stderr: stderr.write(err) logging.debug('cmd: %s, stdout: %s, stderr: %s, ret: %s', utils.cli_cmd_to_string(args), out, err, ret) if ret == 0: return out else: raise AdbError(cmd=args, stdout=out, stderr=err, ret_code=ret, serial=self.serial)
def _construct_adb_cmd(self, raw_name, args, shell): """Constructs an adb command with arguments for a subprocess call. Args: raw_name: string, the raw unsanitized name of the adb command to format. args: string or list of strings, arguments to the adb command. See subprocess.Proc() documentation. shell: bool, True to run this command through the system shell, False to invoke it directly. See subprocess.Proc() docs. Returns: The adb command in a format appropriate for subprocess. If shell is True, then this is a string; otherwise, this is a list of strings. """ args = args or '' name = raw_name.replace('_', '-') if shell: args = utils.cli_cmd_to_string(args) # Add quotes around "adb" in case the ADB path contains spaces. This # is pretty common on Windows (e.g. Program Files). if self.serial: adb_cmd = '"%s" -s "%s" %s %s' % (ADB, self.serial, name, args) else: adb_cmd = '"%s" %s %s' % (ADB, name, args) else: adb_cmd = [ADB] if self.serial: adb_cmd.extend(['-s', self.serial]) adb_cmd.append(name) if args: if isinstance(args, str): adb_cmd.append(args) else: adb_cmd.extend(args) return adb_cmd
def test_cli_cmd_to_string(self): cmd = ['"adb"', 'a b', 'c//'] self.assertEqual(utils.cli_cmd_to_string(cmd), '\'"adb"\' \'a b\' c//') cmd = 'adb -s meme do something ab_cd' self.assertEqual(utils.cli_cmd_to_string(cmd), cmd)
def __str__(self): return 'Timed out executing command "%s" after %ss.' % ( utils.cli_cmd_to_string(self.cmd), self.timeout)
def __str__(self): return ('Error executing adb cmd "%s". ret: %d, stdout: %s, stderr: %s' ) % (utils.cli_cmd_to_string( self.cmd), self.ret_code, self.stdout, self.stderr)