Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright 2013 The Chromium Authors. All rights reserved. | 1 # Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 """This module wraps Android's adb tool. | 5 """This module wraps Android's adb tool. |
| 6 | 6 |
| 7 This is a thin wrapper around the adb interface. Any additional complexity | 7 This is a thin wrapper around the adb interface. Any additional complexity |
| 8 should be delegated to a higher level (ex. DeviceUtils). | 8 should be delegated to a higher level (ex. DeviceUtils). |
| 9 """ | 9 """ |
| 10 | 10 |
| 11 import errno | 11 import errno |
| 12 import os | 12 import os |
| 13 | 13 |
| 14 from pylib import cmd_helper | 14 from pylib import cmd_helper |
| 15 from pylib.device import decorators | |
| 16 from pylib.device import device_errors | |
| 15 | 17 |
| 16 from pylib.utils import reraiser_thread | |
| 17 from pylib.utils import timeout_retry | |
| 18 | 18 |
| 19 _DEFAULT_TIMEOUT = 30 | 19 _DEFAULT_TIMEOUT = 30 |
| 20 _DEFAULT_RETRIES = 2 | 20 _DEFAULT_RETRIES = 2 |
| 21 | 21 |
| 22 | 22 |
| 23 class BaseError(Exception): | 23 BaseError = device_errors.BaseError |
|
craigdh
2014/05/13 16:59:42
I don't like this either. Exceptions raised from d
| |
| 24 """Base exception for all device and command errors.""" | 24 CommandFailedError = device_errors.CommandFailedError |
| 25 pass | 25 CommandTimeoutError = device_errors.CommandTimeoutError |
| 26 DeviceUnreachableError = device_errors.DeviceUnreachableError | |
| 26 | 27 |
| 27 | 28 |
| 28 class CommandFailedError(BaseError): | |
| 29 """Exception for command failures.""" | |
| 30 | |
| 31 def __init__(self, cmd, msg, device=None): | |
| 32 super(CommandFailedError, self).__init__( | |
| 33 (('device %s: ' % device) if device else '') + | |
| 34 'adb command \'%s\' failed with message: \'%s\'' % (' '.join(cmd), msg)) | |
| 35 | |
| 36 | |
| 37 class CommandTimeoutError(BaseError): | |
| 38 """Exception for command timeouts.""" | |
| 39 pass | |
| 40 | |
| 41 | |
| 42 class DeviceUnreachableError(BaseError): | |
| 43 """Exception for device unreachable failures.""" | |
| 44 pass | |
| 45 | |
| 46 def _VerifyLocalFileExists(path): | 29 def _VerifyLocalFileExists(path): |
| 47 """Verifies a local file exists. | 30 """Verifies a local file exists. |
| 48 | 31 |
| 49 Args: | 32 Args: |
| 50 path: Path to the local file. | 33 path: Path to the local file. |
| 51 | 34 |
| 52 Raises: | 35 Raises: |
| 53 IOError: If the file doesn't exist. | 36 IOError: If the file doesn't exist. |
| 54 """ | 37 """ |
| 55 if not os.path.exists(path): | 38 if not os.path.exists(path): |
| 56 raise IOError(errno.ENOENT, os.strerror(errno.ENOENT), path) | 39 raise IOError(errno.ENOENT, os.strerror(errno.ENOENT), path) |
| 57 | 40 |
| 58 | 41 |
| 59 class AdbWrapper(object): | 42 class AdbWrapper(object): |
| 60 """A wrapper around a local Android Debug Bridge executable.""" | 43 """A wrapper around a local Android Debug Bridge executable.""" |
| 61 | 44 |
| 62 def __init__(self, device_serial): | 45 def __init__(self, device_serial): |
| 63 """Initializes the AdbWrapper. | 46 """Initializes the AdbWrapper. |
| 64 | 47 |
| 65 Args: | 48 Args: |
| 66 device_serial: The device serial number as a string. | 49 device_serial: The device serial number as a string. |
| 67 """ | 50 """ |
| 68 self._device_serial = str(device_serial) | 51 self._device_serial = str(device_serial) |
| 69 | 52 |
| 53 # pylint: disable=W0613 | |
| 70 @classmethod | 54 @classmethod |
| 71 def _AdbCmd(cls, arg_list, timeout, retries, check_error=True): | 55 @decorators.WithTimeoutAndRetries |
| 72 """Runs an adb command with a timeout and retries. | 56 def _RunAdbCmd(cls, arg_list, timeout=None, retries=None, check_error=True): |
| 73 | |
| 74 Args: | |
| 75 arg_list: A list of arguments to adb. | |
| 76 timeout: Timeout in seconds. | |
| 77 retries: Number of retries. | |
| 78 check_error: Check that the command doesn't return an error message. This | |
| 79 does NOT check the return code of shell commands. | |
| 80 | |
| 81 Returns: | |
| 82 The output of the command. | |
| 83 """ | |
| 84 cmd = ['adb'] + arg_list | 57 cmd = ['adb'] + arg_list |
| 85 | 58 exit_code, output = cmd_helper.GetCmdStatusAndOutput(cmd) |
| 86 # This method runs inside the timeout/retries. | 59 if exit_code != 0: |
| 87 def RunCmd(): | 60 raise CommandFailedError( |
| 88 exit_code, output = cmd_helper.GetCmdStatusAndOutput(cmd) | 61 cmd, 'returned non-zero exit code %s, output: %s' % |
| 89 if exit_code != 0: | 62 (exit_code, output)) |
| 90 raise CommandFailedError( | 63 # This catches some errors, including when the device drops offline; |
| 91 cmd, 'returned non-zero exit code %s, output: %s' % | 64 # unfortunately adb is very inconsistent with error reporting so many |
| 92 (exit_code, output)) | 65 # command failures present differently. |
| 93 # This catches some errors, including when the device drops offline; | 66 if check_error and output[:len('error:')] == 'error:': |
| 94 # unfortunately adb is very inconsistent with error reporting so many | 67 raise CommandFailedError(arg_list, output) |
| 95 # command failures present differently. | 68 return output |
| 96 if check_error and output[:len('error:')] == 'error:': | 69 # pylint: enable=W0613 |
| 97 raise CommandFailedError(arg_list, output) | |
| 98 return output | |
| 99 | |
| 100 try: | |
| 101 return timeout_retry.Run(RunCmd, timeout, retries) | |
| 102 except reraiser_thread.TimeoutError as e: | |
| 103 raise CommandTimeoutError(str(e)) | |
| 104 | 70 |
| 105 def _DeviceAdbCmd(self, arg_list, timeout, retries, check_error=True): | 71 def _DeviceAdbCmd(self, arg_list, timeout, retries, check_error=True): |
| 106 """Runs an adb command on the device associated with this object. | 72 """Runs an adb command on the device associated with this object. |
| 107 | 73 |
| 108 Args: | 74 Args: |
| 109 arg_list: A list of arguments to adb. | 75 arg_list: A list of arguments to adb. |
| 110 timeout: Timeout in seconds. | 76 timeout: Timeout in seconds. |
| 111 retries: Number of retries. | 77 retries: Number of retries. |
| 112 check_error: Check that the command doesn't return an error message. This | 78 check_error: Check that the command doesn't return an error message. This |
| 113 does NOT check the return code of shell commands. | 79 does NOT check the return code of shell commands. |
| 114 | 80 |
| 115 Returns: | 81 Returns: |
| 116 The output of the command. | 82 The output of the command. |
| 117 """ | 83 """ |
| 118 return self._AdbCmd( | 84 return self._RunAdbCmd( |
| 119 ['-s', self._device_serial] + arg_list, timeout, retries, | 85 ['-s', self._device_serial] + arg_list, timeout=timeout, |
| 120 check_error=check_error) | 86 retries=retries, check_error=check_error) |
| 121 | 87 |
| 122 def __eq__(self, other): | 88 def __eq__(self, other): |
| 123 """Consider instances equal if they refer to the same device. | 89 """Consider instances equal if they refer to the same device. |
| 124 | 90 |
| 125 Args: | 91 Args: |
| 126 other: The instance to compare equality with. | 92 other: The instance to compare equality with. |
| 127 | 93 |
| 128 Returns: | 94 Returns: |
| 129 True if the instances are considered equal, false otherwise. | 95 True if the instances are considered equal, false otherwise. |
| 130 """ | 96 """ |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 146 def GetDevices(cls, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES): | 112 def GetDevices(cls, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES): |
| 147 """Get the list of active attached devices. | 113 """Get the list of active attached devices. |
| 148 | 114 |
| 149 Args: | 115 Args: |
| 150 timeout: (optional) Timeout per try in seconds. | 116 timeout: (optional) Timeout per try in seconds. |
| 151 retries: (optional) Number of retries to attempt. | 117 retries: (optional) Number of retries to attempt. |
| 152 | 118 |
| 153 Yields: | 119 Yields: |
| 154 AdbWrapper instances. | 120 AdbWrapper instances. |
| 155 """ | 121 """ |
| 156 output = cls._AdbCmd(['devices'], timeout, retries) | 122 output = cls._RunAdbCmd(['devices'], timeout=timeout, retries=retries) |
| 157 lines = [line.split() for line in output.split('\n')] | 123 lines = [line.split() for line in output.split('\n')] |
| 158 return [AdbWrapper(line[0]) for line in lines | 124 return [AdbWrapper(line[0]) for line in lines |
| 159 if len(line) == 2 and line[1] == 'device'] | 125 if len(line) == 2 and line[1] == 'device'] |
| 160 | 126 |
| 161 def GetDeviceSerial(self): | 127 def GetDeviceSerial(self): |
| 162 """Gets the device serial number associated with this object. | 128 """Gets the device serial number associated with this object. |
| 163 | 129 |
| 164 Returns: | 130 Returns: |
| 165 Device serial number as a string. | 131 Device serial number as a string. |
| 166 """ | 132 """ |
| (...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 417 """Restarts the adbd daemon with root permissions, if possible. | 383 """Restarts the adbd daemon with root permissions, if possible. |
| 418 | 384 |
| 419 Args: | 385 Args: |
| 420 timeout: (optional) Timeout per try in seconds. | 386 timeout: (optional) Timeout per try in seconds. |
| 421 retries: (optional) Number of retries to attempt. | 387 retries: (optional) Number of retries to attempt. |
| 422 """ | 388 """ |
| 423 output = self._DeviceAdbCmd(['root'], timeout, retries) | 389 output = self._DeviceAdbCmd(['root'], timeout, retries) |
| 424 if 'cannot' in output: | 390 if 'cannot' in output: |
| 425 raise CommandFailedError(['root'], output) | 391 raise CommandFailedError(['root'], output) |
| 426 | 392 |
| OLD | NEW |