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 |