| 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 | 9 |
| 10 import collections | 10 import collections |
| (...skipping 28 matching lines...) Expand all Loading... |
| 39 # Set the adb shell prompt to be a unique marker that will [hopefully] not | 39 # Set the adb shell prompt to be a unique marker that will [hopefully] not |
| 40 # appear at the start of any line of a command's output. | 40 # appear at the start of any line of a command's output. |
| 41 SHELL_PROMPT = '~+~PQ\x17RS~+~' | 41 SHELL_PROMPT = '~+~PQ\x17RS~+~' |
| 42 | 42 |
| 43 # Java properties file | 43 # Java properties file |
| 44 LOCAL_PROPERTIES_PATH = '/data/local.prop' | 44 LOCAL_PROPERTIES_PATH = '/data/local.prop' |
| 45 | 45 |
| 46 # Property in /data/local.prop that controls Java assertions. | 46 # Property in /data/local.prop that controls Java assertions. |
| 47 JAVA_ASSERT_PROPERTY = 'dalvik.vm.enableassertions' | 47 JAVA_ASSERT_PROPERTY = 'dalvik.vm.enableassertions' |
| 48 | 48 |
| 49 BOOT_COMPLETE_RE = re.compile( | |
| 50 'android.intent.action.MEDIA_MOUNTED path: /\w+/sdcard\d?' | |
| 51 '|PowerManagerService(\(\s+\d+\))?: bootCompleted') | |
| 52 | |
| 53 MEMORY_INFO_RE = re.compile('^(?P<key>\w+):\s+(?P<usage_kb>\d+) kB$') | 49 MEMORY_INFO_RE = re.compile('^(?P<key>\w+):\s+(?P<usage_kb>\d+) kB$') |
| 54 NVIDIA_MEMORY_INFO_RE = re.compile('^\s*(?P<user>\S+)\s*(?P<name>\S+)\s*' | 50 NVIDIA_MEMORY_INFO_RE = re.compile('^\s*(?P<user>\S+)\s*(?P<name>\S+)\s*' |
| 55 '(?P<pid>\d+)\s*(?P<usage_bytes>\d+)$') | 51 '(?P<pid>\d+)\s*(?P<usage_bytes>\d+)$') |
| 56 | 52 |
| 57 # Keycode "enum" suitable for passing to AndroidCommands.SendKey(). | 53 # Keycode "enum" suitable for passing to AndroidCommands.SendKey(). |
| 58 KEYCODE_HOME = 3 | 54 KEYCODE_HOME = 3 |
| 59 KEYCODE_BACK = 4 | 55 KEYCODE_BACK = 4 |
| 60 KEYCODE_DPAD_UP = 19 | 56 KEYCODE_DPAD_UP = 19 |
| 61 KEYCODE_DPAD_DOWN = 20 | 57 KEYCODE_DPAD_DOWN = 20 |
| 62 KEYCODE_DPAD_RIGHT = 22 | 58 KEYCODE_DPAD_RIGHT = 22 |
| (...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 277 # connection; work out if we can handle this better | 273 # connection; work out if we can handle this better |
| 278 if os.environ.get('USING_HIVE'): | 274 if os.environ.get('USING_HIVE'): |
| 279 logging.warning('Ignoring reboot request as we are on hive') | 275 logging.warning('Ignoring reboot request as we are on hive') |
| 280 return | 276 return |
| 281 if full_reboot or not self.IsRootEnabled(): | 277 if full_reboot or not self.IsRootEnabled(): |
| 282 self._adb.SendCommand('reboot') | 278 self._adb.SendCommand('reboot') |
| 283 timeout = 300 | 279 timeout = 300 |
| 284 else: | 280 else: |
| 285 self.RestartShell() | 281 self.RestartShell() |
| 286 timeout = 120 | 282 timeout = 120 |
| 283 # To run tests we need at least the package manager and the sd card (or |
| 284 # other external storage) to be ready. |
| 287 self.WaitForDevicePm() | 285 self.WaitForDevicePm() |
| 288 self.StartMonitoringLogcat(timeout=timeout) | 286 self.WaitForSdCardReady(timeout) |
| 289 self.WaitForLogMatch(BOOT_COMPLETE_RE, None) | |
| 290 | 287 |
| 291 def Uninstall(self, package): | 288 def Uninstall(self, package): |
| 292 """Uninstalls the specified package from the device. | 289 """Uninstalls the specified package from the device. |
| 293 | 290 |
| 294 Args: | 291 Args: |
| 295 package: Name of the package to remove. | 292 package: Name of the package to remove. |
| 296 | 293 |
| 297 Returns: | 294 Returns: |
| 298 A status string returned by adb uninstall | 295 A status string returned by adb uninstall |
| 299 """ | 296 """ |
| (...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 512 elif isinstance(value, int): | 509 elif isinstance(value, int): |
| 513 cmd += ' --ei' | 510 cmd += ' --ei' |
| 514 else: | 511 else: |
| 515 raise NotImplementedError( | 512 raise NotImplementedError( |
| 516 'Need to teach StartActivity how to pass %s extras' % type(value)) | 513 'Need to teach StartActivity how to pass %s extras' % type(value)) |
| 517 cmd += ' %s %s' % (key, value) | 514 cmd += ' %s %s' % (key, value) |
| 518 if trace_file_name: | 515 if trace_file_name: |
| 519 cmd += ' --start-profiler ' + trace_file_name | 516 cmd += ' --start-profiler ' + trace_file_name |
| 520 self.RunShellCommand(cmd) | 517 self.RunShellCommand(cmd) |
| 521 | 518 |
| 519 def GoHome(self): |
| 520 """Tell the device to return to the home screen. Blocks until completion.""" |
| 521 self.RunShellCommand('am start -W ' |
| 522 '-a android.intent.action.MAIN -c android.intent.category.HOME') |
| 523 |
| 522 def CloseApplication(self, package): | 524 def CloseApplication(self, package): |
| 523 """Attempt to close down the application, using increasing violence. | 525 """Attempt to close down the application, using increasing violence. |
| 524 | 526 |
| 525 Args: | 527 Args: |
| 526 package: Name of the process to kill off, e.g. | 528 package: Name of the process to kill off, e.g. |
| 527 com.google.android.apps.chrome | 529 com.google.android.apps.chrome |
| 528 """ | 530 """ |
| 529 self.RunShellCommand('am force-stop ' + package) | 531 self.RunShellCommand('am force-stop ' + package) |
| 530 | 532 |
| 531 def ClearApplicationState(self, package): | 533 def ClearApplicationState(self, package): |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 660 # Next, check the current runtime value is what we need, and | 662 # Next, check the current runtime value is what we need, and |
| 661 # if not, set it and report that a reboot is required. | 663 # if not, set it and report that a reboot is required. |
| 662 was_set = 'all' in self.RunShellCommand('getprop ' + JAVA_ASSERT_PROPERTY) | 664 was_set = 'all' in self.RunShellCommand('getprop ' + JAVA_ASSERT_PROPERTY) |
| 663 if was_set == enable: | 665 if was_set == enable: |
| 664 return False | 666 return False |
| 665 | 667 |
| 666 self.RunShellCommand('setprop %s "%s"' % (JAVA_ASSERT_PROPERTY, | 668 self.RunShellCommand('setprop %s "%s"' % (JAVA_ASSERT_PROPERTY, |
| 667 enable and 'all' or '')) | 669 enable and 'all' or '')) |
| 668 return True | 670 return True |
| 669 | 671 |
| 672 def GetBuildId(self): |
| 673 """Returns the build ID of the system (e.g. JRM79C).""" |
| 674 build_id = self.RunShellCommand('getprop ro.build.id')[0] |
| 675 assert build_id |
| 676 return build_id |
| 677 |
| 678 def GetBuildType(self): |
| 679 """Returns the build type of the system (e.g. eng).""" |
| 680 build_type = self.RunShellCommand('getprop ro.build.type')[0] |
| 681 assert build_type |
| 682 return build_type |
| 670 | 683 |
| 671 def StartMonitoringLogcat(self, clear=True, timeout=10, logfile=None, | 684 def StartMonitoringLogcat(self, clear=True, timeout=10, logfile=None, |
| 672 filters=None): | 685 filters=None): |
| 673 """Starts monitoring the output of logcat, for use with WaitForLogMatch. | 686 """Starts monitoring the output of logcat, for use with WaitForLogMatch. |
| 674 | 687 |
| 675 Args: | 688 Args: |
| 676 clear: If True the existing logcat output will be cleared, to avoiding | 689 clear: If True the existing logcat output will be cleared, to avoiding |
| 677 matching historical output lurking in the log. | 690 matching historical output lurking in the log. |
| 678 timeout: How long WaitForLogMatch will wait for the given match | 691 timeout: How long WaitForLogMatch will wait for the given match |
| 679 filters: A list of logcat filters to be used. | 692 filters: A list of logcat filters to be used. |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 721 clear: If True the existing logcat output will be cleared, defaults to | 734 clear: If True the existing logcat output will be cleared, defaults to |
| 722 false. | 735 false. |
| 723 | 736 |
| 724 Raises: | 737 Raises: |
| 725 pexpect.TIMEOUT upon the timeout specified by StartMonitoringLogcat(). | 738 pexpect.TIMEOUT upon the timeout specified by StartMonitoringLogcat(). |
| 726 | 739 |
| 727 Returns: | 740 Returns: |
| 728 The re match object if |success_re| is matched first or None if |error_re| | 741 The re match object if |success_re| is matched first or None if |error_re| |
| 729 is matched first. | 742 is matched first. |
| 730 """ | 743 """ |
| 731 if not self._logcat: | |
| 732 self.StartMonitoringLogcat(clear) | |
| 733 logging.info('<<< Waiting for logcat:' + str(success_re.pattern)) | 744 logging.info('<<< Waiting for logcat:' + str(success_re.pattern)) |
| 734 t0 = time.time() | 745 t0 = time.time() |
| 735 try: | 746 while True: |
| 736 while True: | 747 if not self._logcat: |
| 737 # Note this will block for upto the timeout _per log line_, so we need | 748 self.StartMonitoringLogcat(clear) |
| 738 # to calculate the overall timeout remaining since t0. | 749 try: |
| 739 time_remaining = t0 + self._logcat.timeout - time.time() | 750 while True: |
| 740 if time_remaining < 0: raise pexpect.TIMEOUT(self._logcat) | 751 # Note this will block for upto the timeout _per log line_, so we need |
| 741 self._logcat.expect(PEXPECT_LINE_RE, timeout=time_remaining) | 752 # to calculate the overall timeout remaining since t0. |
| 742 line = self._logcat.match.group(1) | 753 time_remaining = t0 + self._logcat.timeout - time.time() |
| 743 if error_re: | 754 if time_remaining < 0: raise pexpect.TIMEOUT(self._logcat) |
| 744 error_match = error_re.search(line) | 755 self._logcat.expect(PEXPECT_LINE_RE, timeout=time_remaining) |
| 745 if error_match: | 756 line = self._logcat.match.group(1) |
| 746 return None | 757 if error_re: |
| 747 success_match = success_re.search(line) | 758 error_match = error_re.search(line) |
| 748 if success_match: | 759 if error_match: |
| 749 return success_match | 760 return None |
| 750 logging.info('<<< Skipped Logcat Line:' + str(line)) | 761 success_match = success_re.search(line) |
| 751 except pexpect.TIMEOUT: | 762 if success_match: |
| 752 raise pexpect.TIMEOUT( | 763 return success_match |
| 753 'Timeout (%ds) exceeded waiting for pattern "%s" (tip: use -vv ' | 764 logging.info('<<< Skipped Logcat Line:' + str(line)) |
| 754 'to debug)' % | 765 except pexpect.TIMEOUT: |
| 755 (self._logcat.timeout, success_re.pattern)) | 766 raise pexpect.TIMEOUT( |
| 767 'Timeout (%ds) exceeded waiting for pattern "%s" (tip: use -vv ' |
| 768 'to debug)' % |
| 769 (self._logcat.timeout, success_re.pattern)) |
| 770 except pexpect.EOF: |
| 771 # It seems that sometimes logcat can end unexpectedly. This seems |
| 772 # to happen during Chrome startup after a reboot followed by a cache |
| 773 # clean. I don't understand why this happens, but this code deals with |
| 774 # getting EOF in logcat. |
| 775 logging.critical('Found EOF in adb logcat. Restarting...') |
| 776 # Rerun spawn with original arguments. Note that self._logcat.args[0] is |
| 777 # the path of adb, so we don't want it in the arguments. |
| 778 self._logcat = pexpect.spawn('adb', |
| 779 self._logcat.args[1:], |
| 780 timeout=self._logcat.timeout, |
| 781 logfile=self._logcat.logfile) |
| 756 | 782 |
| 757 def StartRecordingLogcat(self, clear=True, filters=['*:v']): | 783 def StartRecordingLogcat(self, clear=True, filters=['*:v']): |
| 758 """Starts recording logcat output to eventually be saved as a string. | 784 """Starts recording logcat output to eventually be saved as a string. |
| 759 | 785 |
| 760 This call should come before some series of tests are run, with either | 786 This call should come before some series of tests are run, with either |
| 761 StopRecordingLogcat or SearchLogcatRecord following the tests. | 787 StopRecordingLogcat or SearchLogcatRecord following the tests. |
| 762 | 788 |
| 763 Args: | 789 Args: |
| 764 clear: True if existing log output should be cleared. | 790 clear: True if existing log output should be cleared. |
| 765 filters: A list of logcat filters to be used. | 791 filters: A list of logcat filters to be used. |
| (...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1010 """ | 1036 """ |
| 1011 def __init__(self, output): | 1037 def __init__(self, output): |
| 1012 self._output = output | 1038 self._output = output |
| 1013 | 1039 |
| 1014 def write(self, data): | 1040 def write(self, data): |
| 1015 data = data.replace('\r\r\n', '\n') | 1041 data = data.replace('\r\r\n', '\n') |
| 1016 self._output.write(data) | 1042 self._output.write(data) |
| 1017 | 1043 |
| 1018 def flush(self): | 1044 def flush(self): |
| 1019 self._output.flush() | 1045 self._output.flush() |
| 1046 |
| OLD | NEW |