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 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
143 files = {} | 143 files = {} |
144 for line in ls_output: | 144 for line in ls_output: |
145 directory_match = re_directory.match(line) | 145 directory_match = re_directory.match(line) |
146 if directory_match: | 146 if directory_match: |
147 current_dir = directory_match.group('dir') | 147 current_dir = directory_match.group('dir') |
148 continue | 148 continue |
149 file_match = re_file.match(line) | 149 file_match = re_file.match(line) |
150 if file_match: | 150 if file_match: |
151 filename = os.path.join(current_dir, file_match.group('filename')) | 151 filename = os.path.join(current_dir, file_match.group('filename')) |
152 if filename.startswith(path_dir): | 152 if filename.startswith(path_dir): |
153 filename = filename[len(path_dir)+1:] | 153 filename = filename[len(path_dir) + 1:] |
154 lastmod = datetime.datetime.strptime( | 154 lastmod = datetime.datetime.strptime( |
155 file_match.group('date') + ' ' + file_match.group('time')[:5], | 155 file_match.group('date') + ' ' + file_match.group('time')[:5], |
156 '%Y-%m-%d %H:%M') | 156 '%Y-%m-%d %H:%M') |
157 if not utc_offset and 'timezone' in re_file.groupindex: | 157 if not utc_offset and 'timezone' in re_file.groupindex: |
158 utc_offset = file_match.group('timezone') | 158 utc_offset = file_match.group('timezone') |
159 if isinstance(utc_offset, str) and len(utc_offset) == 5: | 159 if isinstance(utc_offset, str) and len(utc_offset) == 5: |
160 utc_delta = datetime.timedelta(hours=int(utc_offset[1:3]), | 160 utc_delta = datetime.timedelta(hours=int(utc_offset[1:3]), |
161 minutes=int(utc_offset[3:5])) | 161 minutes=int(utc_offset[3:5])) |
162 if utc_offset[0:1] == '-': | 162 if utc_offset[0:1] == '-': |
163 utc_delta = -utc_delta | 163 utc_delta = -utc_delta |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
219 root_test_output = self.RunShellCommand('ls /root') or [''] | 219 root_test_output = self.RunShellCommand('ls /root') or [''] |
220 return not 'Permission denied' in root_test_output[0] | 220 return not 'Permission denied' in root_test_output[0] |
221 | 221 |
222 def EnableAdbRoot(self): | 222 def EnableAdbRoot(self): |
223 """Enables adb root on the device. | 223 """Enables adb root on the device. |
224 | 224 |
225 Returns: | 225 Returns: |
226 True: if output from executing adb root was as expected. | 226 True: if output from executing adb root was as expected. |
227 False: otherwise. | 227 False: otherwise. |
228 """ | 228 """ |
229 return_value = self._adb.EnableAdbRoot() | 229 if self.GetBuildType() == 'user': |
230 # EnableAdbRoot inserts a call for wait-for-device only when adb logcat | 230 logging.warning("Can't enable root in production builds with type user") |
231 # output matches what is expected. Just to be safe add a call to | 231 return False |
232 # wait-for-device. | 232 else: |
233 self._adb.SendCommand('wait-for-device') | 233 return_value = self._adb.EnableAdbRoot() |
234 return return_value | 234 # EnableAdbRoot inserts a call for wait-for-device only when adb logcat |
| 235 # output matches what is expected. Just to be safe add a call to |
| 236 # wait-for-device. |
| 237 self._adb.SendCommand('wait-for-device') |
| 238 return return_value |
235 | 239 |
236 def GetDeviceYear(self): | 240 def GetDeviceYear(self): |
237 """Returns the year information of the date on device.""" | 241 """Returns the year information of the date on device.""" |
238 return self.RunShellCommand('date +%Y')[0] | 242 return self.RunShellCommand('date +%Y')[0] |
239 | 243 |
240 def GetExternalStorage(self): | 244 def GetExternalStorage(self): |
241 if not self._external_storage: | 245 if not self._external_storage: |
242 self._external_storage = self.RunShellCommand('echo $EXTERNAL_STORAGE')[0] | 246 self._external_storage = self.RunShellCommand('echo $EXTERNAL_STORAGE')[0] |
243 assert self._external_storage, 'Unable to find $EXTERNAL_STORAGE' | 247 assert self._external_storage, 'Unable to find $EXTERNAL_STORAGE' |
244 return self._external_storage | 248 return self._external_storage |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
321 | 325 |
322 install_cmd = ['install'] | 326 install_cmd = ['install'] |
323 | 327 |
324 if reinstall: | 328 if reinstall: |
325 install_cmd.append('-r') | 329 install_cmd.append('-r') |
326 | 330 |
327 install_cmd.append(package_file_path) | 331 install_cmd.append(package_file_path) |
328 install_cmd = ' '.join(install_cmd) | 332 install_cmd = ' '.join(install_cmd) |
329 | 333 |
330 logging.info('>>> $' + install_cmd) | 334 logging.info('>>> $' + install_cmd) |
331 return self._adb.SendCommand(install_cmd, timeout_time=2*60, retry_count=0) | 335 return self._adb.SendCommand(install_cmd, |
| 336 timeout_time=2 * 60, |
| 337 retry_count=0) |
332 | 338 |
333 def ManagedInstall(self, apk_path, keep_data=False, package_name=None, | 339 def ManagedInstall(self, apk_path, keep_data=False, package_name=None, |
334 reboots_on_failure=2): | 340 reboots_on_failure=2): |
335 """Installs specified package and reboots device on timeouts. | 341 """Installs specified package and reboots device on timeouts. |
336 | 342 |
337 Args: | 343 Args: |
338 apk_path: Path to .apk file to install. | 344 apk_path: Path to .apk file to install. |
339 keep_data: Reinstalls instead of uninstalling first, preserving the | 345 keep_data: Reinstalls instead of uninstalling first, preserving the |
340 application data. | 346 application data. |
341 package_name: Package name (only needed if keep_data=False). | 347 package_name: Package name (only needed if keep_data=False). |
(...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
629 assert os.path.exists(local_path), 'Local path not found %s' % local_path | 635 assert os.path.exists(local_path), 'Local path not found %s' % local_path |
630 hashes_on_host = _ComputeFileListHash( | 636 hashes_on_host = _ComputeFileListHash( |
631 subprocess.Popen( | 637 subprocess.Popen( |
632 '%s_host %s' % (self._md5sum_path, local_path), | 638 '%s_host %s' % (self._md5sum_path, local_path), |
633 stdout=subprocess.PIPE, shell=True).stdout) | 639 stdout=subprocess.PIPE, shell=True).stdout) |
634 if hashes_on_device == hashes_on_host: | 640 if hashes_on_device == hashes_on_host: |
635 return | 641 return |
636 | 642 |
637 # They don't match, so remove everything first and then create it. | 643 # They don't match, so remove everything first and then create it. |
638 if os.path.isdir(local_path): | 644 if os.path.isdir(local_path): |
639 self.RunShellCommand('rm -r %s' % device_path, timeout_time=2*60) | 645 self.RunShellCommand('rm -r %s' % device_path, timeout_time=2 * 60) |
640 self.RunShellCommand('mkdir -p %s' % device_path) | 646 self.RunShellCommand('mkdir -p %s' % device_path) |
641 | 647 |
642 # NOTE: We can't use adb_interface.Push() because it hardcodes a timeout of | 648 # NOTE: We can't use adb_interface.Push() because it hardcodes a timeout of |
643 # 60 seconds which isn't sufficient for a lot of users of this method. | 649 # 60 seconds which isn't sufficient for a lot of users of this method. |
644 push_command = 'push %s %s' % (local_path, device_path) | 650 push_command = 'push %s %s' % (local_path, device_path) |
645 logging.info('>>> $' + push_command) | 651 logging.info('>>> $' + push_command) |
646 output = self._adb.SendCommand(push_command, timeout_time=30*60) | 652 output = self._adb.SendCommand(push_command, timeout_time=30 * 60) |
647 assert _HasAdbPushSucceeded(output) | 653 assert _HasAdbPushSucceeded(output) |
648 | 654 |
649 | 655 |
650 def GetFileContents(self, filename, log_result=False): | 656 def GetFileContents(self, filename, log_result=False): |
651 """Gets contents from the file specified by |filename|.""" | 657 """Gets contents from the file specified by |filename|.""" |
652 return self.RunShellCommand('if [ -f "' + filename + '" ]; then cat "' + | 658 return self.RunShellCommand('if [ -f "' + filename + '" ]; then cat "' + |
653 filename + '"; fi', log_result=log_result) | 659 filename + '"; fi', log_result=log_result) |
654 | 660 |
655 def SetFileContents(self, filename, contents): | 661 def SetFileContents(self, filename, contents): |
656 """Writes |contents| to the file specified by |filename|.""" | 662 """Writes |contents| to the file specified by |filename|.""" |
657 with tempfile.NamedTemporaryFile() as f: | 663 with tempfile.NamedTemporaryFile() as f: |
658 f.write(contents) | 664 f.write(contents) |
659 f.flush() | 665 f.flush() |
660 self._adb.Push(f.name, filename) | 666 self._adb.Push(f.name, filename) |
661 | 667 |
| 668 _TEMP_FILE_BASE_FMT = 'temp_file_%d' |
| 669 _TEMP_SCRIPT_FILE_BASE_FMT = 'temp_script_file_%d.sh' |
| 670 |
| 671 def _GetDeviceTempFileName(self, base_name): |
| 672 i = 0 |
| 673 while self.FileExistsOnDevice( |
| 674 self.GetExternalStorage() + '/' + base_name % i): |
| 675 i += 1 |
| 676 return self.GetExternalStorage() + '/' + base_name % i |
| 677 |
| 678 def SetProtectedFileContents(self, filename, contents): |
| 679 """Writes |contents| to the protected file specified by |filename|. |
| 680 |
| 681 This is less efficient than SetFileContents, but will work for protected |
| 682 files and device files. |
| 683 """ |
| 684 temp_file = self._GetDeviceTempFileName(AndroidCommands._TEMP_FILE_BASE_FMT) |
| 685 temp_script = self._GetDeviceTempFileName( |
| 686 AndroidCommands._TEMP_SCRIPT_FILE_BASE_FMT) |
| 687 |
| 688 # Put the contents in a temporary file |
| 689 self.SetFileContents(temp_file, contents) |
| 690 # Create a script to copy the file contents to its final destination |
| 691 self.SetFileContents(temp_script, 'cat %s > %s' % (temp_file, filename)) |
| 692 # Run the script as root |
| 693 self.RunShellCommand('su -c sh %s' % temp_script) |
| 694 # And remove the temporary files |
| 695 self.RunShellCommand('rm ' + temp_file) |
| 696 self.RunShellCommand('rm ' + temp_script) |
| 697 |
662 def RemovePushedFiles(self): | 698 def RemovePushedFiles(self): |
663 """Removes all files pushed with PushIfNeeded() from the device.""" | 699 """Removes all files pushed with PushIfNeeded() from the device.""" |
664 for p in self._pushed_files: | 700 for p in self._pushed_files: |
665 self.RunShellCommand('rm -r %s' % p, timeout_time=2*60) | 701 self.RunShellCommand('rm -r %s' % p, timeout_time=2 * 60) |
666 | 702 |
667 def ListPathContents(self, path): | 703 def ListPathContents(self, path): |
668 """Lists files in all subdirectories of |path|. | 704 """Lists files in all subdirectories of |path|. |
669 | 705 |
670 Args: | 706 Args: |
671 path: The path to list. | 707 path: The path to list. |
672 | 708 |
673 Returns: | 709 Returns: |
674 A dict of {"name": (size, lastmod), ...}. | 710 A dict of {"name": (size, lastmod), ...}. |
675 """ | 711 """ |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
771 else: | 807 else: |
772 logging.critical('Error reading from logcat: ' + str(self._logcat.match)) | 808 logging.critical('Error reading from logcat: ' + str(self._logcat.match)) |
773 sys.exit(1) | 809 sys.exit(1) |
774 | 810 |
775 def GetMonitoredLogCat(self): | 811 def GetMonitoredLogCat(self): |
776 """Returns an "adb logcat" command as created by pexpected.spawn.""" | 812 """Returns an "adb logcat" command as created by pexpected.spawn.""" |
777 if not self._logcat: | 813 if not self._logcat: |
778 self.StartMonitoringLogcat(clear=False) | 814 self.StartMonitoringLogcat(clear=False) |
779 return self._logcat | 815 return self._logcat |
780 | 816 |
781 def WaitForLogMatch(self, success_re, error_re, clear=False): | 817 def WaitForLogMatch(self, success_re, error_re, clear=False, timeout=10): |
782 """Blocks until a matching line is logged or a timeout occurs. | 818 """Blocks until a matching line is logged or a timeout occurs. |
783 | 819 |
784 Args: | 820 Args: |
785 success_re: A compiled re to search each line for. | 821 success_re: A compiled re to search each line for. |
786 error_re: A compiled re which, if found, terminates the search for | 822 error_re: A compiled re which, if found, terminates the search for |
787 |success_re|. If None is given, no error condition will be detected. | 823 |success_re|. If None is given, no error condition will be detected. |
788 clear: If True the existing logcat output will be cleared, defaults to | 824 clear: If True the existing logcat output will be cleared, defaults to |
789 false. | 825 false. |
790 | 826 |
791 Raises: | 827 Raises: |
792 pexpect.TIMEOUT upon the timeout specified by StartMonitoringLogcat(). | 828 pexpect.TIMEOUT upon the timeout specified by StartMonitoringLogcat(). |
793 | 829 |
794 Returns: | 830 Returns: |
795 The re match object if |success_re| is matched first or None if |error_re| | 831 The re match object if |success_re| is matched first or None if |error_re| |
796 is matched first. | 832 is matched first. |
797 """ | 833 """ |
798 logging.info('<<< Waiting for logcat:' + str(success_re.pattern)) | 834 logging.info('<<< Waiting for logcat:' + str(success_re.pattern)) |
799 t0 = time.time() | 835 t0 = time.time() |
800 while True: | 836 while True: |
801 if not self._logcat: | 837 if not self._logcat: |
802 self.StartMonitoringLogcat(clear) | 838 self.StartMonitoringLogcat(clear, timeout=timeout) |
803 try: | 839 try: |
804 while True: | 840 while True: |
805 # Note this will block for upto the timeout _per log line_, so we need | 841 # Note this will block for upto the timeout _per log line_, so we need |
806 # to calculate the overall timeout remaining since t0. | 842 # to calculate the overall timeout remaining since t0. |
807 time_remaining = t0 + self._logcat.timeout - time.time() | 843 time_remaining = t0 + self._logcat.timeout - time.time() |
808 if time_remaining < 0: raise pexpect.TIMEOUT(self._logcat) | 844 if time_remaining < 0: raise pexpect.TIMEOUT(self._logcat) |
809 self._logcat.expect(PEXPECT_LINE_RE, timeout=time_remaining) | 845 self._logcat.expect(PEXPECT_LINE_RE, timeout=time_remaining) |
810 line = self._logcat.match.group(1) | 846 line = self._logcat.match.group(1) |
811 if error_re: | 847 if error_re: |
812 error_match = error_re.search(line) | 848 error_match = error_re.search(line) |
(...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1110 """ | 1146 """ |
1111 def __init__(self, output): | 1147 def __init__(self, output): |
1112 self._output = output | 1148 self._output = output |
1113 | 1149 |
1114 def write(self, data): | 1150 def write(self, data): |
1115 data = data.replace('\r\r\n', '\n') | 1151 data = data.replace('\r\r\n', '\n') |
1116 self._output.write(data) | 1152 self._output.write(data) |
1117 | 1153 |
1118 def flush(self): | 1154 def flush(self): |
1119 self._output.flush() | 1155 self._output.flush() |
OLD | NEW |