OLD | NEW |
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2012 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 """Provides an interface to communicate with the device via the adb command. | 5 """Provides an interface to communicate with the device via the adb command. |
6 | 6 |
7 Assumes adb binary is currently on system path. | 7 Assumes adb binary is currently on system path. |
8 """ | 8 """ |
9 # pylint: disable-all | 9 # pylint: disable-all |
10 | 10 |
(...skipping 21 matching lines...) Expand all Loading... |
32 except ImportError: | 32 except ImportError: |
33 pexpect = None | 33 pexpect = None |
34 | 34 |
35 sys.path.append(os.path.join( | 35 sys.path.append(os.path.join( |
36 constants.DIR_SOURCE_ROOT, 'third_party', 'android_testrunner')) | 36 constants.DIR_SOURCE_ROOT, 'third_party', 'android_testrunner')) |
37 import adb_interface | 37 import adb_interface |
38 import am_instrument_parser | 38 import am_instrument_parser |
39 import errors | 39 import errors |
40 | 40 |
41 from pylib.device import device_blacklist | 41 from pylib.device import device_blacklist |
| 42 from pylib.device import device_errors |
42 | 43 |
43 # Pattern to search for the next whole line of pexpect output and capture it | 44 # Pattern to search for the next whole line of pexpect output and capture it |
44 # into a match group. We can't use ^ and $ for line start end with pexpect, | 45 # into a match group. We can't use ^ and $ for line start end with pexpect, |
45 # see http://www.noah.org/python/pexpect/#doc for explanation why. | 46 # see http://www.noah.org/python/pexpect/#doc for explanation why. |
46 PEXPECT_LINE_RE = re.compile('\n([^\r]*)\r') | 47 PEXPECT_LINE_RE = re.compile('\n([^\r]*)\r') |
47 | 48 |
48 # Set the adb shell prompt to be a unique marker that will [hopefully] not | 49 # Set the adb shell prompt to be a unique marker that will [hopefully] not |
49 # appear at the start of any line of a command's output. | 50 # appear at the start of any line of a command's output. |
50 SHELL_PROMPT = '~+~PQ\x17RS~+~' | 51 SHELL_PROMPT = '~+~PQ\x17RS~+~' |
51 | 52 |
(...skipping 328 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
380 self._adb.SendCommand('wait-for-device') | 381 self._adb.SendCommand('wait-for-device') |
381 return return_value | 382 return return_value |
382 | 383 |
383 def GetDeviceYear(self): | 384 def GetDeviceYear(self): |
384 """Returns the year information of the date on device.""" | 385 """Returns the year information of the date on device.""" |
385 return self.RunShellCommand('date +%Y')[0] | 386 return self.RunShellCommand('date +%Y')[0] |
386 | 387 |
387 def GetExternalStorage(self): | 388 def GetExternalStorage(self): |
388 if not self._external_storage: | 389 if not self._external_storage: |
389 self._external_storage = self.RunShellCommand('echo $EXTERNAL_STORAGE')[0] | 390 self._external_storage = self.RunShellCommand('echo $EXTERNAL_STORAGE')[0] |
390 assert self._external_storage, 'Unable to find $EXTERNAL_STORAGE' | 391 if not self._external_storage: |
| 392 raise device_errors.CommandFailedError( |
| 393 ['shell', "'echo $EXTERNAL_STORAGE'"], |
| 394 'Unable to find $EXTERNAL_STORAGE') |
391 return self._external_storage | 395 return self._external_storage |
392 | 396 |
393 def WaitForDevicePm(self): | 397 def WaitForDevicePm(self): |
394 """Blocks until the device's package manager is available. | 398 """Blocks until the device's package manager is available. |
395 | 399 |
396 To workaround http://b/5201039, we restart the shell and retry if the | 400 To workaround http://b/5201039, we restart the shell and retry if the |
397 package manager isn't back after 120 seconds. | 401 package manager isn't back after 120 seconds. |
398 | 402 |
399 Raises: | 403 Raises: |
400 errors.WaitForResponseTimedOutError after max retries reached. | 404 errors.WaitForResponseTimedOutError after max retries reached. |
(...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
641 output = self.RunShellCommand('ls ' + external_storage) | 645 output = self.RunShellCommand('ls ' + external_storage) |
642 if output: | 646 if output: |
643 sdcard_ready = True | 647 sdcard_ready = True |
644 else: | 648 else: |
645 time.sleep(wait_period) | 649 time.sleep(wait_period) |
646 attempts += 1 | 650 attempts += 1 |
647 if not sdcard_ready: | 651 if not sdcard_ready: |
648 raise errors.WaitForResponseTimedOutError( | 652 raise errors.WaitForResponseTimedOutError( |
649 'SD card not ready after %s seconds' % timeout_time) | 653 'SD card not ready after %s seconds' % timeout_time) |
650 | 654 |
651 def _CheckCommandIsValid(self, command): | |
652 """Raises a ValueError if the command is not valid.""" | |
653 | |
654 # A dict of commands the user should not run directly and a mapping to the | |
655 # API they should use instead. | |
656 preferred_apis = { | |
657 'getprop': 'system_properties[<PROPERTY>]', | |
658 'setprop': 'system_properties[<PROPERTY>]', | |
659 } | |
660 | |
661 # A dict of commands to methods that may call them. | |
662 whitelisted_callers = { | |
663 'getprop': 'ProvisionDevices', | |
664 } | |
665 | |
666 base_command = shlex.split(command)[0].strip(';') | |
667 if (base_command in preferred_apis and | |
668 (base_command not in whitelisted_callers or | |
669 whitelisted_callers[base_command] not in [ | |
670 f[3] for f in inspect.stack()])): | |
671 error_msg = ('%s should not be run directly. Instead use: %s' % | |
672 (base_command, preferred_apis[base_command])) | |
673 raise ValueError(error_msg) | |
674 | |
675 def GetAndroidToolStatusAndOutput(self, command, lib_path=None, *args, **kw): | 655 def GetAndroidToolStatusAndOutput(self, command, lib_path=None, *args, **kw): |
676 """Runs a native Android binary, wrapping the command as necessary. | 656 """Runs a native Android binary, wrapping the command as necessary. |
677 | 657 |
678 This is a specialization of GetShellCommandStatusAndOutput, which is meant | 658 This is a specialization of GetShellCommandStatusAndOutput, which is meant |
679 for running tools/android/ binaries and handle properly: (1) setting the | 659 for running tools/android/ binaries and handle properly: (1) setting the |
680 lib path (for component=shared_library), (2) using the PIE wrapper on ICS. | 660 lib path (for component=shared_library), (2) using the PIE wrapper on ICS. |
681 See crbug.com/373219 for more context. | 661 See crbug.com/373219 for more context. |
682 | 662 |
683 Args: | 663 Args: |
684 command: String containing the command to send. | 664 command: String containing the command to send. |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
717 command: String containing the shell command to send. Must not include | 697 command: String containing the shell command to send. Must not include |
718 the single quotes as we use them to escape the whole command. | 698 the single quotes as we use them to escape the whole command. |
719 timeout_time: Number of seconds to wait for command to respond before | 699 timeout_time: Number of seconds to wait for command to respond before |
720 retrying, used by AdbInterface.SendShellCommand. | 700 retrying, used by AdbInterface.SendShellCommand. |
721 log_result: Boolean to indicate whether we should log the result of the | 701 log_result: Boolean to indicate whether we should log the result of the |
722 shell command. | 702 shell command. |
723 | 703 |
724 Returns: | 704 Returns: |
725 list containing the lines of output received from running the command | 705 list containing the lines of output received from running the command |
726 """ | 706 """ |
727 self._CheckCommandIsValid(command) | |
728 self._LogShell(command) | 707 self._LogShell(command) |
729 if "'" in command: | 708 if "'" in command: |
730 logging.warning(command + " contains ' quotes") | 709 logging.warning(command + " contains ' quotes") |
731 result = self._adb.SendShellCommand( | 710 result = self._adb.SendShellCommand( |
732 "'%s'" % command, timeout_time).splitlines() | 711 "'%s'" % command, timeout_time).splitlines() |
733 # TODO(b.kelemen): we should really be able to drop the stderr of the | 712 # TODO(b.kelemen): we should really be able to drop the stderr of the |
734 # command or raise an exception based on what the caller wants. | 713 # command or raise an exception based on what the caller wants. |
735 result = [ l for l in result if not l.startswith('WARNING') ] | 714 result = [ l for l in result if not l.startswith('WARNING') ] |
736 if ['error: device not found'] == result: | 715 if ['error: device not found'] == result: |
737 raise errors.DeviceUnresponsiveError('device not found') | 716 raise errors.DeviceUnresponsiveError('device not found') |
(...skipping 1159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1897 dest: absolute path of destination directory | 1876 dest: absolute path of destination directory |
1898 """ | 1877 """ |
1899 logging.info('In EfficientDeviceDirectoryCopy %s %s', source, dest) | 1878 logging.info('In EfficientDeviceDirectoryCopy %s %s', source, dest) |
1900 with DeviceTempFile(self, suffix=".sh") as temp_script_file: | 1879 with DeviceTempFile(self, suffix=".sh") as temp_script_file: |
1901 host_script_path = os.path.join(constants.DIR_SOURCE_ROOT, | 1880 host_script_path = os.path.join(constants.DIR_SOURCE_ROOT, |
1902 'build', | 1881 'build', |
1903 'android', | 1882 'android', |
1904 'pylib', | 1883 'pylib', |
1905 'efficient_android_directory_copy.sh') | 1884 'efficient_android_directory_copy.sh') |
1906 self._adb.Push(host_script_path, temp_script_file.name) | 1885 self._adb.Push(host_script_path, temp_script_file.name) |
1907 self.EnableAdbRoot | |
1908 out = self.RunShellCommand( | 1886 out = self.RunShellCommand( |
1909 'sh %s %s %s' % (temp_script_file.name, source, dest), | 1887 'sh %s %s %s' % (temp_script_file.name, source, dest), |
1910 timeout_time=120) | 1888 timeout_time=120) |
1911 if self._device: | 1889 if self._device: |
1912 device_repr = self._device[-4:] | 1890 device_repr = self._device[-4:] |
1913 else: | 1891 else: |
1914 device_repr = '????' | 1892 device_repr = '????' |
1915 for line in out: | 1893 for line in out: |
1916 logging.info('[%s]> %s', device_repr, line) | 1894 logging.info('[%s]> %s', device_repr, line) |
1917 | 1895 |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1983 """ | 1961 """ |
1984 def __init__(self, output): | 1962 def __init__(self, output): |
1985 self._output = output | 1963 self._output = output |
1986 | 1964 |
1987 def write(self, data): | 1965 def write(self, data): |
1988 data = data.replace('\r\r\n', '\n') | 1966 data = data.replace('\r\r\n', '\n') |
1989 self._output.write(data) | 1967 self._output.write(data) |
1990 | 1968 |
1991 def flush(self): | 1969 def flush(self): |
1992 self._output.flush() | 1970 self._output.flush() |
OLD | NEW |