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=W0613 | 9 # pylint: disable=W0613 |
10 | 10 |
(...skipping 16 matching lines...) Loading... |
27 from pylib.utils import apk_helper | 27 from pylib.utils import apk_helper |
28 from pylib.utils import device_temp_file | 28 from pylib.utils import device_temp_file |
29 from pylib.utils import host_utils | 29 from pylib.utils import host_utils |
30 from pylib.utils import md5sum | 30 from pylib.utils import md5sum |
31 from pylib.utils import parallelizer | 31 from pylib.utils import parallelizer |
32 from pylib.utils import timeout_retry | 32 from pylib.utils import timeout_retry |
33 | 33 |
34 _DEFAULT_TIMEOUT = 30 | 34 _DEFAULT_TIMEOUT = 30 |
35 _DEFAULT_RETRIES = 3 | 35 _DEFAULT_RETRIES = 3 |
36 | 36 |
| 37 # A sentinel object for default values |
| 38 # TODO(jbudorick,perezju): revisit how default values are handled by |
| 39 # the timeout_retry decorators. |
| 40 DEFAULT = object() |
| 41 |
37 | 42 |
38 @decorators.WithExplicitTimeoutAndRetries( | 43 @decorators.WithExplicitTimeoutAndRetries( |
39 _DEFAULT_TIMEOUT, _DEFAULT_RETRIES) | 44 _DEFAULT_TIMEOUT, _DEFAULT_RETRIES) |
40 def GetAVDs(): | 45 def GetAVDs(): |
41 """Returns a list of Android Virtual Devices. | 46 """Returns a list of Android Virtual Devices. |
42 | 47 |
43 Returns: | 48 Returns: |
44 A list containing the configured AVDs. | 49 A list containing the configured AVDs. |
45 """ | 50 """ |
46 lines = cmd_helper.GetCmdOutput([ | 51 lines = cmd_helper.GetCmdOutput([ |
(...skipping 92 matching lines...) Loading... |
139 Raises: | 144 Raises: |
140 CommandTimeoutError on timeout. | 145 CommandTimeoutError on timeout. |
141 DeviceUnreachableError on missing device. | 146 DeviceUnreachableError on missing device. |
142 """ | 147 """ |
143 try: | 148 try: |
144 self.RunShellCommand('ls /root', check_return=True) | 149 self.RunShellCommand('ls /root', check_return=True) |
145 return True | 150 return True |
146 except device_errors.AdbCommandFailedError: | 151 except device_errors.AdbCommandFailedError: |
147 return False | 152 return False |
148 | 153 |
149 def NeedsSU(self, timeout=None, retries=None): | 154 def NeedsSU(self, timeout=DEFAULT, retries=DEFAULT): |
150 """Checks whether 'su' is needed to access protected resources. | 155 """Checks whether 'su' is needed to access protected resources. |
151 | 156 |
152 Args: | 157 Args: |
153 timeout: timeout in seconds | 158 timeout: timeout in seconds |
154 retries: number of retries | 159 retries: number of retries |
155 | 160 |
156 Returns: | 161 Returns: |
157 True if 'su' is available on the device and is needed to to access | 162 True if 'su' is available on the device and is needed to to access |
158 protected resources; False otherwise if either 'su' is not available | 163 protected resources; False otherwise if either 'su' is not available |
159 (e.g. because the device has a user build), or not needed (because adbd | 164 (e.g. because the device has a user build), or not needed (because adbd |
160 already has root privileges). | 165 already has root privileges). |
161 | 166 |
162 Raises: | 167 Raises: |
163 CommandTimeoutError on timeout. | 168 CommandTimeoutError on timeout. |
164 DeviceUnreachableError on missing device. | 169 DeviceUnreachableError on missing device. |
165 """ | 170 """ |
166 if 'needs_su' not in self._cache: | 171 if 'needs_su' not in self._cache: |
167 try: | 172 try: |
168 self.RunShellCommand('su -c ls /root && ! ls /root', check_return=True, | 173 self.RunShellCommand( |
169 timeout=timeout, retries=retries) | 174 'su -c ls /root && ! ls /root', check_return=True, |
| 175 timeout=self._default_timeout if timeout is DEFAULT else timeout, |
| 176 retries=self._default_retries if retries is DEFAULT else retries) |
170 self._cache['needs_su'] = True | 177 self._cache['needs_su'] = True |
171 except device_errors.AdbCommandFailedError: | 178 except device_errors.AdbCommandFailedError: |
172 self._cache['needs_su'] = False | 179 self._cache['needs_su'] = False |
173 return self._cache['needs_su'] | 180 return self._cache['needs_su'] |
174 | 181 |
175 | 182 |
176 @decorators.WithTimeoutAndRetriesFromInstance() | 183 @decorators.WithTimeoutAndRetriesFromInstance() |
177 def EnableRoot(self, timeout=None, retries=None): | 184 def EnableRoot(self, timeout=None, retries=None): |
178 """Restarts adbd with root privileges. | 185 """Restarts adbd with root privileges. |
179 | 186 |
(...skipping 62 matching lines...) Loading... |
242 @decorators.WithTimeoutAndRetriesFromInstance() | 249 @decorators.WithTimeoutAndRetriesFromInstance() |
243 def GetApplicationPath(self, package, timeout=None, retries=None): | 250 def GetApplicationPath(self, package, timeout=None, retries=None): |
244 """Get the path of the installed apk on the device for the given package. | 251 """Get the path of the installed apk on the device for the given package. |
245 | 252 |
246 Args: | 253 Args: |
247 package: Name of the package. | 254 package: Name of the package. |
248 | 255 |
249 Returns: | 256 Returns: |
250 Path to the apk on the device if it exists, None otherwise. | 257 Path to the apk on the device if it exists, None otherwise. |
251 """ | 258 """ |
| 259 # 'pm path' is liable to incorrectly exit with a nonzero number starting |
| 260 # in Lollipop. |
| 261 # TODO(jbudorick): Check if this is fixed as new Android versions are |
| 262 # released to put an upper bound on this. |
| 263 should_check_return = (self.build_version_sdk < |
| 264 constants.ANDROID_SDK_VERSION_CODES.LOLLIPOP) |
252 output = self.RunShellCommand(['pm', 'path', package], single_line=True, | 265 output = self.RunShellCommand(['pm', 'path', package], single_line=True, |
253 check_return=True) | 266 check_return=should_check_return) |
254 if not output: | 267 if not output: |
255 return None | 268 return None |
256 if not output.startswith('package:'): | 269 if not output.startswith('package:'): |
257 raise device_errors.CommandFailedError('pm path returned: %r' % output, | 270 raise device_errors.CommandFailedError('pm path returned: %r' % output, |
258 str(self)) | 271 str(self)) |
259 return output[len('package:'):] | 272 return output[len('package:'):] |
260 | 273 |
261 @decorators.WithTimeoutAndRetriesFromInstance() | 274 @decorators.WithTimeoutAndRetriesFromInstance() |
262 def WaitUntilFullyBooted(self, wifi=False, timeout=None, retries=None): | 275 def WaitUntilFullyBooted(self, wifi=False, timeout=None, retries=None): |
263 """Wait for the device to fully boot. | 276 """Wait for the device to fully boot. |
(...skipping 723 matching lines...) Loading... |
987 | 1000 |
988 Returns: | 1001 Returns: |
989 True if the device-side property changed and a restart is required as a | 1002 True if the device-side property changed and a restart is required as a |
990 result, False otherwise. | 1003 result, False otherwise. |
991 | 1004 |
992 Raises: | 1005 Raises: |
993 CommandTimeoutError on timeout. | 1006 CommandTimeoutError on timeout. |
994 """ | 1007 """ |
995 return self.old_interface.SetJavaAssertsEnabled(enabled) | 1008 return self.old_interface.SetJavaAssertsEnabled(enabled) |
996 | 1009 |
| 1010 |
| 1011 @property |
| 1012 def build_description(self): |
| 1013 """Returns the build description of the system. |
| 1014 |
| 1015 For example: |
| 1016 nakasi-user 4.4.4 KTU84P 1227136 release-keys |
| 1017 """ |
| 1018 return self.GetProp('ro.build.description', cache=True) |
| 1019 |
| 1020 @property |
| 1021 def build_fingerprint(self): |
| 1022 """Returns the build fingerprint of the system. |
| 1023 |
| 1024 For example: |
| 1025 google/nakasi/grouper:4.4.4/KTU84P/1227136:user/release-keys |
| 1026 """ |
| 1027 return self.GetProp('ro.build.fingerprint', cache=True) |
| 1028 |
| 1029 @property |
| 1030 def build_id(self): |
| 1031 """Returns the build ID of the system (e.g. 'KTU84P').""" |
| 1032 return self.GetProp('ro.build.id', cache=True) |
| 1033 |
| 1034 @property |
| 1035 def build_product(self): |
| 1036 """Returns the build product of the system (e.g. 'grouper').""" |
| 1037 return self.GetProp('ro.build.product', cache=True) |
| 1038 |
997 @property | 1039 @property |
998 def build_type(self): | 1040 def build_type(self): |
999 """Returns the build type of the system (e.g. userdebug).""" | 1041 """Returns the build type of the system (e.g. 'user').""" |
1000 return self.GetProp('ro.build.type', cache=True) | 1042 return self.GetProp('ro.build.type', cache=True) |
1001 | 1043 |
1002 def GetProp(self, property_name, cache=False, timeout=None, retries=None): | 1044 @property |
| 1045 def build_version_sdk(self): |
| 1046 """Returns the build version sdk of the system as a number (e.g. 19). |
| 1047 |
| 1048 For version code numbers see: |
| 1049 http://developer.android.com/reference/android/os/Build.VERSION_CODES.html |
| 1050 |
| 1051 For named constants see: |
| 1052 pylib.constants.ANDROID_SDK_VERSION_CODES |
| 1053 |
| 1054 Raises: |
| 1055 CommandFailedError if the build version sdk is not a number. |
| 1056 """ |
| 1057 value = self.GetProp('ro.build.version.sdk', cache=True) |
| 1058 try: |
| 1059 return int(value) |
| 1060 except ValueError: |
| 1061 raise device_errors.CommandFailedError( |
| 1062 'Invalid build version sdk: %r' % value) |
| 1063 |
| 1064 @property |
| 1065 def product_cpu_abi(self): |
| 1066 """Returns the product cpu abi of the device (e.g. 'armeabi-v7a').""" |
| 1067 return self.GetProp('ro.product.cpu.abi', cache=True) |
| 1068 |
| 1069 @property |
| 1070 def product_model(self): |
| 1071 """Returns the name of the product model (e.g. 'Nexus 7').""" |
| 1072 return self.GetProp('ro.product.model', cache=True) |
| 1073 |
| 1074 @property |
| 1075 def product_name(self): |
| 1076 """Returns the product name of the device (e.g. 'nakasi').""" |
| 1077 return self.GetProp('ro.product.name', cache=True) |
| 1078 |
| 1079 def GetProp(self, property_name, cache=False, timeout=DEFAULT, |
| 1080 retries=DEFAULT): |
1003 """Gets a property from the device. | 1081 """Gets a property from the device. |
1004 | 1082 |
1005 Args: | 1083 Args: |
1006 property_name: A string containing the name of the property to get from | 1084 property_name: A string containing the name of the property to get from |
1007 the device. | 1085 the device. |
1008 cache: A boolean indicating whether to cache the value of this property. | 1086 cache: A boolean indicating whether to cache the value of this property. |
1009 timeout: timeout in seconds | 1087 timeout: timeout in seconds |
1010 retries: number of retries | 1088 retries: number of retries |
1011 | 1089 |
1012 Returns: | 1090 Returns: |
1013 The value of the device's |property_name| property. | 1091 The value of the device's |property_name| property. |
1014 | 1092 |
1015 Raises: | 1093 Raises: |
1016 CommandTimeoutError on timeout. | 1094 CommandTimeoutError on timeout. |
1017 """ | 1095 """ |
1018 assert isinstance(property_name, basestring), ( | 1096 assert isinstance(property_name, basestring), ( |
1019 "property_name is not a string: %r" % property_name) | 1097 "property_name is not a string: %r" % property_name) |
1020 | 1098 |
1021 cache_key = '_prop:' + property_name | 1099 cache_key = '_prop:' + property_name |
1022 if cache and cache_key in self._cache: | 1100 if cache and cache_key in self._cache: |
1023 return self._cache[cache_key] | 1101 return self._cache[cache_key] |
1024 else: | 1102 else: |
1025 # timeout and retries are handled down at run shell, because we don't | 1103 # timeout and retries are handled down at run shell, because we don't |
1026 # want to apply them in the other branch when reading from the cache | 1104 # want to apply them in the other branch when reading from the cache |
1027 value = self.RunShellCommand(['getprop', property_name], | 1105 value = self.RunShellCommand( |
1028 single_line=True, check_return=True, | 1106 ['getprop', property_name], single_line=True, check_return=True, |
1029 timeout=timeout, retries=retries) | 1107 timeout=self._default_timeout if timeout is DEFAULT else timeout, |
| 1108 retries=self._default_retries if retries is DEFAULT else retries) |
1030 if cache or cache_key in self._cache: | 1109 if cache or cache_key in self._cache: |
1031 self._cache[cache_key] = value | 1110 self._cache[cache_key] = value |
1032 return value | 1111 return value |
1033 | 1112 |
1034 @decorators.WithTimeoutAndRetriesFromInstance() | 1113 @decorators.WithTimeoutAndRetriesFromInstance() |
1035 def SetProp(self, property_name, value, check=False, timeout=None, | 1114 def SetProp(self, property_name, value, check=False, timeout=None, |
1036 retries=None): | 1115 retries=None): |
1037 """Sets a property on the device. | 1116 """Sets a property on the device. |
1038 | 1117 |
1039 Args: | 1118 Args: |
(...skipping 150 matching lines...) Loading... |
1190 Returns: | 1269 Returns: |
1191 A Parallelizer operating over |devices|. | 1270 A Parallelizer operating over |devices|. |
1192 """ | 1271 """ |
1193 if not devices: | 1272 if not devices: |
1194 devices = adb_wrapper.AdbWrapper.GetDevices() | 1273 devices = adb_wrapper.AdbWrapper.GetDevices() |
1195 devices = [d if isinstance(d, cls) else cls(d) for d in devices] | 1274 devices = [d if isinstance(d, cls) else cls(d) for d in devices] |
1196 if async: | 1275 if async: |
1197 return parallelizer.Parallelizer(devices) | 1276 return parallelizer.Parallelizer(devices) |
1198 else: | 1277 else: |
1199 return parallelizer.SyncParallelizer(devices) | 1278 return parallelizer.SyncParallelizer(devices) |
OLD | NEW |