OLD | NEW |
1 # Copyright 2014 The Chromium Authors. All rights reserved. | 1 # Copyright 2014 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 a variety of device interactions based on adb. | 5 """Provides a variety of device interactions based on adb. |
6 | 6 |
7 Eventually, this will be based on adb_wrapper. | 7 Eventually, this will be based on adb_wrapper. |
8 """ | 8 """ |
9 # pylint: disable=unused-argument | 9 # pylint: disable=unused-argument |
10 | 10 |
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
168 else: | 168 else: |
169 raise ValueError('Unsupported device value: %r' % device) | 169 raise ValueError('Unsupported device value: %r' % device) |
170 self._commands_installed = None | 170 self._commands_installed = None |
171 self._default_timeout = default_timeout | 171 self._default_timeout = default_timeout |
172 self._default_retries = default_retries | 172 self._default_retries = default_retries |
173 self._cache = {} | 173 self._cache = {} |
174 self._client_caches = {} | 174 self._client_caches = {} |
175 assert hasattr(self, decorators.DEFAULT_TIMEOUT_ATTR) | 175 assert hasattr(self, decorators.DEFAULT_TIMEOUT_ATTR) |
176 assert hasattr(self, decorators.DEFAULT_RETRIES_ATTR) | 176 assert hasattr(self, decorators.DEFAULT_RETRIES_ATTR) |
177 | 177 |
| 178 def __eq__(self, other): |
| 179 """Checks whether |other| refers to the same device as |self|. |
| 180 |
| 181 Args: |
| 182 other: The object to compare to. This can be a basestring, an instance |
| 183 of adb_wrapper.AdbWrapper, or an instance of DeviceUtils. |
| 184 Returns: |
| 185 Whether |other| refers to the same device as |self|. |
| 186 """ |
| 187 return self.adb.GetDeviceSerial() == str(other) |
| 188 |
| 189 def __lt__(self, other): |
| 190 """Compares two instances of DeviceUtils. |
| 191 |
| 192 This merely compares their serial numbers. |
| 193 |
| 194 Args: |
| 195 other: The instance of DeviceUtils to compare to. |
| 196 Returns: |
| 197 Whether |self| is less than |other|. |
| 198 """ |
| 199 return self.adb.GetDeviceSerial() < other.adb.GetDeviceSerial() |
| 200 |
178 def __str__(self): | 201 def __str__(self): |
179 """Returns the device serial.""" | 202 """Returns the device serial.""" |
180 return self.adb.GetDeviceSerial() | 203 return self.adb.GetDeviceSerial() |
181 | 204 |
182 @decorators.WithTimeoutAndRetriesFromInstance() | 205 @decorators.WithTimeoutAndRetriesFromInstance() |
183 def IsOnline(self, timeout=None, retries=None): | 206 def IsOnline(self, timeout=None, retries=None): |
184 """Checks whether the device is online. | 207 """Checks whether the device is online. |
185 | 208 |
186 Args: | 209 Args: |
187 timeout: timeout in seconds | 210 timeout: timeout in seconds |
(...skipping 340 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
528 self._WriteFileWithPush(script.name, cmd) | 551 self._WriteFileWithPush(script.name, cmd) |
529 logging.info('Large shell command will be run from file: %s ...', | 552 logging.info('Large shell command will be run from file: %s ...', |
530 cmd[:100]) | 553 cmd[:100]) |
531 return handle_check_return('sh %s' % script.name_quoted) | 554 return handle_check_return('sh %s' % script.name_quoted) |
532 | 555 |
533 def handle_large_output(cmd, large_output_mode): | 556 def handle_large_output(cmd, large_output_mode): |
534 if large_output_mode: | 557 if large_output_mode: |
535 with device_temp_file.DeviceTempFile(self.adb) as large_output_file: | 558 with device_temp_file.DeviceTempFile(self.adb) as large_output_file: |
536 cmd = '%s > %s' % (cmd, large_output_file.name) | 559 cmd = '%s > %s' % (cmd, large_output_file.name) |
537 logging.info('Large output mode enabled. Will write output to device ' | 560 logging.info('Large output mode enabled. Will write output to device ' |
538 ' and read results from file.') | 561 'and read results from file.') |
539 handle_large_command(cmd) | 562 handle_large_command(cmd) |
540 return self.ReadFile(large_output_file.name) | 563 return self.ReadFile(large_output_file.name, force_pull=True) |
541 else: | 564 else: |
542 try: | 565 try: |
543 return handle_large_command(cmd) | 566 return handle_large_command(cmd) |
544 except device_errors.AdbCommandFailedError as exc: | 567 except device_errors.AdbCommandFailedError as exc: |
545 if exc.status is None: | 568 if exc.status is None: |
546 logging.exception('No output found for %s', cmd) | 569 logging.exception('No output found for %s', cmd) |
547 logging.warning('Attempting to run in large_output mode.') | 570 logging.warning('Attempting to run in large_output mode.') |
548 logging.warning('Use RunShellCommand(..., large_output=True) for ' | 571 logging.warning('Use RunShellCommand(..., large_output=True) for ' |
549 'shell commands that expect a lot of output.') | 572 'shell commands that expect a lot of output.') |
550 return handle_large_output(cmd, True) | 573 return handle_large_output(cmd, True) |
(...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
846 def _GetChangedFilesImpl(self, host_path, device_path): | 869 def _GetChangedFilesImpl(self, host_path, device_path): |
847 real_host_path = os.path.realpath(host_path) | 870 real_host_path = os.path.realpath(host_path) |
848 try: | 871 try: |
849 real_device_path = self.RunShellCommand( | 872 real_device_path = self.RunShellCommand( |
850 ['realpath', device_path], single_line=True, check_return=True) | 873 ['realpath', device_path], single_line=True, check_return=True) |
851 except device_errors.CommandFailedError: | 874 except device_errors.CommandFailedError: |
852 real_device_path = None | 875 real_device_path = None |
853 if not real_device_path: | 876 if not real_device_path: |
854 return [(host_path, device_path)] | 877 return [(host_path, device_path)] |
855 | 878 |
856 host_checksums = md5sum.CalculateHostMd5Sums([real_host_path]) | 879 try: |
857 device_paths_to_md5 = ( | 880 host_checksums = md5sum.CalculateHostMd5Sums([real_host_path]) |
858 real_device_path if os.path.isfile(real_host_path) | 881 device_paths_to_md5 = ( |
859 else ('%s/%s' % (real_device_path, os.path.relpath(p, real_host_path)) | 882 real_device_path if os.path.isfile(real_host_path) |
860 for p in host_checksums.iterkeys())) | 883 else ('%s/%s' % (real_device_path, os.path.relpath(p, real_host_path)) |
861 device_checksums = md5sum.CalculateDeviceMd5Sums( | 884 for p in host_checksums.iterkeys())) |
862 device_paths_to_md5, self) | 885 device_checksums = md5sum.CalculateDeviceMd5Sums( |
| 886 device_paths_to_md5, self) |
| 887 except EnvironmentError as e: |
| 888 logging.warning('Error calculating md5: %s', e) |
| 889 return [(host_path, device_path)] |
863 | 890 |
864 if os.path.isfile(host_path): | 891 if os.path.isfile(host_path): |
865 host_checksum = host_checksums.get(real_host_path) | 892 host_checksum = host_checksums.get(real_host_path) |
866 device_checksum = device_checksums.get(real_device_path) | 893 device_checksum = device_checksums.get(real_device_path) |
867 if host_checksum != device_checksum: | 894 if host_checksum != device_checksum: |
868 return [(host_path, device_path)] | 895 return [(host_path, device_path)] |
869 else: | 896 else: |
870 return [] | 897 return [] |
871 else: | 898 else: |
872 to_push = [] | 899 to_push = [] |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1009 return host_temp.read() | 1036 return host_temp.read() |
1010 finally: | 1037 finally: |
1011 if os.path.exists(d): | 1038 if os.path.exists(d): |
1012 shutil.rmtree(d) | 1039 shutil.rmtree(d) |
1013 | 1040 |
1014 _LS_RE = re.compile( | 1041 _LS_RE = re.compile( |
1015 r'(?P<perms>\S+) +(?P<owner>\S+) +(?P<group>\S+) +(?:(?P<size>\d+) +)?' | 1042 r'(?P<perms>\S+) +(?P<owner>\S+) +(?P<group>\S+) +(?:(?P<size>\d+) +)?' |
1016 + r'(?P<date>\S+) +(?P<time>\S+) +(?P<name>.+)$') | 1043 + r'(?P<date>\S+) +(?P<time>\S+) +(?P<name>.+)$') |
1017 | 1044 |
1018 @decorators.WithTimeoutAndRetriesFromInstance() | 1045 @decorators.WithTimeoutAndRetriesFromInstance() |
1019 def ReadFile(self, device_path, as_root=False, | 1046 def ReadFile(self, device_path, as_root=False, force_pull=False, |
1020 timeout=None, retries=None): | 1047 timeout=None, retries=None): |
1021 """Reads the contents of a file from the device. | 1048 """Reads the contents of a file from the device. |
1022 | 1049 |
1023 Args: | 1050 Args: |
1024 device_path: A string containing the absolute path of the file to read | 1051 device_path: A string containing the absolute path of the file to read |
1025 from the device. | 1052 from the device. |
1026 as_root: A boolean indicating whether the read should be executed with | 1053 as_root: A boolean indicating whether the read should be executed with |
1027 root privileges. | 1054 root privileges. |
| 1055 force_pull: A boolean indicating whether to force the operation to be |
| 1056 performed by pulling a file from the device. The default is, when the |
| 1057 contents are short, to retrieve the contents using cat instead. |
1028 timeout: timeout in seconds | 1058 timeout: timeout in seconds |
1029 retries: number of retries | 1059 retries: number of retries |
1030 | 1060 |
1031 Returns: | 1061 Returns: |
1032 The contents of |device_path| as a string. Contents are intepreted using | 1062 The contents of |device_path| as a string. Contents are intepreted using |
1033 universal newlines, so the caller will see them encoded as '\n'. Also, | 1063 universal newlines, so the caller will see them encoded as '\n'. Also, |
1034 all lines will be terminated. | 1064 all lines will be terminated. |
1035 | 1065 |
1036 Raises: | 1066 Raises: |
1037 AdbCommandFailedError if the file can't be read. | 1067 AdbCommandFailedError if the file can't be read. |
1038 CommandTimeoutError on timeout. | 1068 CommandTimeoutError on timeout. |
1039 DeviceUnreachableError on missing device. | 1069 DeviceUnreachableError on missing device. |
1040 """ | 1070 """ |
1041 # TODO(jbudorick): Implement a generic version of Stat() that handles | 1071 def get_size(path): |
1042 # as_root=True, then switch this implementation to use that. | 1072 # TODO(jbudorick): Implement a generic version of Stat() that handles |
1043 size = None | 1073 # as_root=True, then switch this implementation to use that. |
1044 ls_out = self.RunShellCommand(['ls', '-l', device_path], as_root=as_root, | 1074 ls_out = self.RunShellCommand(['ls', '-l', device_path], as_root=as_root, |
1045 check_return=True) | 1075 check_return=True) |
1046 for line in ls_out: | 1076 for line in ls_out: |
1047 m = self._LS_RE.match(line) | 1077 m = self._LS_RE.match(line) |
1048 if m and m.group('name') == posixpath.basename(device_path): | 1078 if m and m.group('name') == posixpath.basename(device_path): |
1049 size = int(m.group('size')) | 1079 return int(m.group('size')) |
1050 break | |
1051 else: | |
1052 logging.warning('Could not determine size of %s.', device_path) | 1080 logging.warning('Could not determine size of %s.', device_path) |
| 1081 return None |
1053 | 1082 |
1054 if 0 < size <= self._MAX_ADB_OUTPUT_LENGTH: | 1083 if (not force_pull |
| 1084 and 0 < get_size(device_path) <= self._MAX_ADB_OUTPUT_LENGTH): |
1055 return _JoinLines(self.RunShellCommand( | 1085 return _JoinLines(self.RunShellCommand( |
1056 ['cat', device_path], as_root=as_root, check_return=True)) | 1086 ['cat', device_path], as_root=as_root, check_return=True)) |
1057 elif as_root and self.NeedsSU(): | 1087 elif as_root and self.NeedsSU(): |
1058 with device_temp_file.DeviceTempFile(self.adb) as device_temp: | 1088 with device_temp_file.DeviceTempFile(self.adb) as device_temp: |
1059 self.RunShellCommand(['cp', device_path, device_temp.name], | 1089 self.RunShellCommand(['cp', device_path, device_temp.name], |
1060 as_root=True, check_return=True) | 1090 as_root=True, check_return=True) |
1061 return self._ReadFileWithPull(device_temp.name) | 1091 return self._ReadFileWithPull(device_temp.name) |
1062 else: | 1092 else: |
1063 return self._ReadFileWithPull(device_path) | 1093 return self._ReadFileWithPull(device_path) |
1064 | 1094 |
(...skipping 519 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1584 blacklist = device_blacklist.ReadBlacklist() | 1614 blacklist = device_blacklist.ReadBlacklist() |
1585 def blacklisted(adb): | 1615 def blacklisted(adb): |
1586 if adb.GetDeviceSerial() in blacklist: | 1616 if adb.GetDeviceSerial() in blacklist: |
1587 logging.warning('Device %s is blacklisted.', adb.GetDeviceSerial()) | 1617 logging.warning('Device %s is blacklisted.', adb.GetDeviceSerial()) |
1588 return True | 1618 return True |
1589 return False | 1619 return False |
1590 | 1620 |
1591 return [cls(adb) for adb in adb_wrapper.AdbWrapper.Devices() | 1621 return [cls(adb) for adb in adb_wrapper.AdbWrapper.Devices() |
1592 if not blacklisted(adb)] | 1622 if not blacklisted(adb)] |
1593 | 1623 |
OLD | NEW |