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 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
76 assert(hasattr(self, decorators.DEFAULT_TIMEOUT_ATTR)) | 76 assert(hasattr(self, decorators.DEFAULT_TIMEOUT_ATTR)) |
77 assert(hasattr(self, decorators.DEFAULT_RETRIES_ATTR)) | 77 assert(hasattr(self, decorators.DEFAULT_RETRIES_ATTR)) |
78 | 78 |
79 @decorators.WithTimeoutAndRetriesFromInstance() | 79 @decorators.WithTimeoutAndRetriesFromInstance() |
80 def IsOnline(self, timeout=None, retries=None): | 80 def IsOnline(self, timeout=None, retries=None): |
81 """Checks whether the device is online. | 81 """Checks whether the device is online. |
82 | 82 |
83 Args: | 83 Args: |
84 timeout: timeout in seconds | 84 timeout: timeout in seconds |
85 retries: number of retries | 85 retries: number of retries |
| 86 |
86 Returns: | 87 Returns: |
87 True if the device is online, False otherwise. | 88 True if the device is online, False otherwise. |
| 89 |
88 Raises: | 90 Raises: |
89 CommandTimeoutError on timeout. | 91 CommandTimeoutError on timeout. |
90 """ | 92 """ |
91 return self.old_interface.IsOnline() | 93 return self.old_interface.IsOnline() |
92 | 94 |
93 @decorators.WithTimeoutAndRetriesFromInstance() | 95 @decorators.WithTimeoutAndRetriesFromInstance() |
94 def HasRoot(self, timeout=None, retries=None): | 96 def HasRoot(self, timeout=None, retries=None): |
95 """Checks whether or not adbd has root privileges. | 97 """Checks whether or not adbd has root privileges. |
96 | 98 |
97 Args: | 99 Args: |
98 timeout: timeout in seconds | 100 timeout: timeout in seconds |
99 retries: number of retries | 101 retries: number of retries |
| 102 |
100 Returns: | 103 Returns: |
101 True if adbd has root privileges, False otherwise. | 104 True if adbd has root privileges, False otherwise. |
| 105 |
102 Raises: | 106 Raises: |
103 CommandTimeoutError on timeout. | 107 CommandTimeoutError on timeout. |
104 DeviceUnreachableError on missing device. | 108 DeviceUnreachableError on missing device. |
105 """ | 109 """ |
106 return self._HasRootImpl() | 110 return self._HasRootImpl() |
107 | 111 |
108 def _HasRootImpl(self): | 112 def _HasRootImpl(self): |
109 """Implementation of HasRoot. | 113 """Implementation of HasRoot. |
110 | 114 |
111 This is split from HasRoot to allow other DeviceUtils methods to call | 115 This is split from HasRoot to allow other DeviceUtils methods to call |
112 HasRoot without spawning a new timeout thread. | 116 HasRoot without spawning a new timeout thread. |
113 | 117 |
114 Returns: | 118 Returns: |
115 Same as for |HasRoot|. | 119 Same as for |HasRoot|. |
| 120 |
116 Raises: | 121 Raises: |
117 Same as for |HasRoot|. | 122 Same as for |HasRoot|. |
118 """ | 123 """ |
119 return self.old_interface.IsRootEnabled() | 124 return self.old_interface.IsRootEnabled() |
120 | 125 |
121 @decorators.WithTimeoutAndRetriesFromInstance() | 126 @decorators.WithTimeoutAndRetriesFromInstance() |
122 def EnableRoot(self, timeout=None, retries=None): | 127 def EnableRoot(self, timeout=None, retries=None): |
123 """Restarts adbd with root privileges. | 128 """Restarts adbd with root privileges. |
124 | 129 |
125 Args: | 130 Args: |
126 timeout: timeout in seconds | 131 timeout: timeout in seconds |
127 retries: number of retries | 132 retries: number of retries |
| 133 |
128 Raises: | 134 Raises: |
129 CommandFailedError if root could not be enabled. | 135 CommandFailedError if root could not be enabled. |
130 CommandTimeoutError on timeout. | 136 CommandTimeoutError on timeout. |
131 """ | 137 """ |
132 if not self.old_interface.EnableAdbRoot(): | 138 if not self.old_interface.EnableAdbRoot(): |
133 raise device_errors.CommandFailedError( | 139 raise device_errors.CommandFailedError( |
134 'Could not enable root.', device=str(self)) | 140 'Could not enable root.', device=str(self)) |
135 | 141 |
136 @decorators.WithTimeoutAndRetriesFromInstance() | 142 @decorators.WithTimeoutAndRetriesFromInstance() |
137 def GetExternalStoragePath(self, timeout=None, retries=None): | 143 def GetExternalStoragePath(self, timeout=None, retries=None): |
138 """Get the device's path to its SD card. | 144 """Get the device's path to its SD card. |
139 | 145 |
140 Args: | 146 Args: |
141 timeout: timeout in seconds | 147 timeout: timeout in seconds |
142 retries: number of retries | 148 retries: number of retries |
| 149 |
143 Returns: | 150 Returns: |
144 The device's path to its SD card. | 151 The device's path to its SD card. |
| 152 |
145 Raises: | 153 Raises: |
146 CommandFailedError if the external storage path could not be determined. | 154 CommandFailedError if the external storage path could not be determined. |
147 CommandTimeoutError on timeout. | 155 CommandTimeoutError on timeout. |
148 DeviceUnreachableError on missing device. | 156 DeviceUnreachableError on missing device. |
149 """ | 157 """ |
150 try: | 158 try: |
151 return self.old_interface.GetExternalStorage() | 159 return self.old_interface.GetExternalStorage() |
152 except AssertionError as e: | 160 except AssertionError as e: |
153 raise device_errors.CommandFailedError( | 161 raise device_errors.CommandFailedError( |
154 str(e), device=str(self)), None, sys.exc_info()[2] | 162 str(e), device=str(self)), None, sys.exc_info()[2] |
155 | 163 |
156 @decorators.WithTimeoutAndRetriesFromInstance() | 164 @decorators.WithTimeoutAndRetriesFromInstance() |
157 def WaitUntilFullyBooted(self, wifi=False, timeout=None, retries=None): | 165 def WaitUntilFullyBooted(self, wifi=False, timeout=None, retries=None): |
158 """Wait for the device to fully boot. | 166 """Wait for the device to fully boot. |
159 | 167 |
160 This means waiting for the device to boot, the package manager to be | 168 This means waiting for the device to boot, the package manager to be |
161 available, and the SD card to be ready. It can optionally mean waiting | 169 available, and the SD card to be ready. It can optionally mean waiting |
162 for wifi to come up, too. | 170 for wifi to come up, too. |
163 | 171 |
164 Args: | 172 Args: |
165 wifi: A boolean indicating if we should wait for wifi to come up or not. | 173 wifi: A boolean indicating if we should wait for wifi to come up or not. |
166 timeout: timeout in seconds | 174 timeout: timeout in seconds |
167 retries: number of retries | 175 retries: number of retries |
| 176 |
168 Raises: | 177 Raises: |
169 CommandFailedError on failure. | 178 CommandFailedError on failure. |
170 CommandTimeoutError if one of the component waits times out. | 179 CommandTimeoutError if one of the component waits times out. |
171 DeviceUnreachableError if the device becomes unresponsive. | 180 DeviceUnreachableError if the device becomes unresponsive. |
172 """ | 181 """ |
173 self._WaitUntilFullyBootedImpl(wifi=wifi, timeout=timeout) | 182 self._WaitUntilFullyBootedImpl(wifi=wifi, timeout=timeout) |
174 | 183 |
175 def _WaitUntilFullyBootedImpl(self, wifi=False, timeout=None): | 184 def _WaitUntilFullyBootedImpl(self, wifi=False, timeout=None): |
176 """Implementation of WaitUntilFullyBooted. | 185 """Implementation of WaitUntilFullyBooted. |
177 | 186 |
178 This is split from WaitUntilFullyBooted to allow other DeviceUtils methods | 187 This is split from WaitUntilFullyBooted to allow other DeviceUtils methods |
179 to call WaitUntilFullyBooted without spawning a new timeout thread. | 188 to call WaitUntilFullyBooted without spawning a new timeout thread. |
180 | 189 |
181 TODO(jbudorick) Remove the timeout parameter once this is no longer | 190 TODO(jbudorick) Remove the timeout parameter once this is no longer |
182 implemented via AndroidCommands. | 191 implemented via AndroidCommands. |
183 | 192 |
184 Args: | 193 Args: |
185 wifi: Same as for |WaitUntilFullyBooted|. | 194 wifi: Same as for |WaitUntilFullyBooted|. |
186 timeout: timeout in seconds | 195 timeout: timeout in seconds |
| 196 |
187 Raises: | 197 Raises: |
188 Same as for |WaitUntilFullyBooted|. | 198 Same as for |WaitUntilFullyBooted|. |
189 """ | 199 """ |
190 if timeout is None: | 200 if timeout is None: |
191 timeout = self._default_timeout | 201 timeout = self._default_timeout |
192 self.old_interface.WaitForSystemBootCompleted(timeout) | 202 self.old_interface.WaitForSystemBootCompleted(timeout) |
193 self.old_interface.WaitForDevicePm() | 203 self.old_interface.WaitForDevicePm() |
194 self.old_interface.WaitForSdCardReady(timeout) | 204 self.old_interface.WaitForSdCardReady(timeout) |
195 if wifi: | 205 if wifi: |
196 while not 'Wi-Fi is enabled' in ( | 206 while not 'Wi-Fi is enabled' in ( |
197 self._RunShellCommandImpl('dumpsys wifi')): | 207 self._RunShellCommandImpl('dumpsys wifi')): |
198 time.sleep(1) | 208 time.sleep(1) |
199 | 209 |
200 REBOOT_DEFAULT_TIMEOUT = 10 * _DEFAULT_TIMEOUT | 210 REBOOT_DEFAULT_TIMEOUT = 10 * _DEFAULT_TIMEOUT |
201 REBOOT_DEFAULT_RETRIES = _DEFAULT_RETRIES | 211 REBOOT_DEFAULT_RETRIES = _DEFAULT_RETRIES |
202 | 212 |
203 @decorators.WithTimeoutAndRetriesDefaults( | 213 @decorators.WithTimeoutAndRetriesDefaults( |
204 REBOOT_DEFAULT_TIMEOUT, | 214 REBOOT_DEFAULT_TIMEOUT, |
205 REBOOT_DEFAULT_RETRIES) | 215 REBOOT_DEFAULT_RETRIES) |
206 def Reboot(self, block=True, timeout=None, retries=None): | 216 def Reboot(self, block=True, timeout=None, retries=None): |
207 """Reboot the device. | 217 """Reboot the device. |
208 | 218 |
209 Args: | 219 Args: |
210 block: A boolean indicating if we should wait for the reboot to complete. | 220 block: A boolean indicating if we should wait for the reboot to complete. |
211 timeout: timeout in seconds | 221 timeout: timeout in seconds |
212 retries: number of retries | 222 retries: number of retries |
| 223 |
213 Raises: | 224 Raises: |
214 CommandTimeoutError on timeout. | 225 CommandTimeoutError on timeout. |
215 DeviceUnreachableError on missing device. | 226 DeviceUnreachableError on missing device. |
216 """ | 227 """ |
217 self.old_interface.Reboot() | 228 self.old_interface.Reboot() |
218 if block: | 229 if block: |
219 self._WaitUntilFullyBootedImpl(timeout=timeout) | 230 self._WaitUntilFullyBootedImpl(timeout=timeout) |
220 | 231 |
221 INSTALL_DEFAULT_TIMEOUT = 4 * _DEFAULT_TIMEOUT | 232 INSTALL_DEFAULT_TIMEOUT = 4 * _DEFAULT_TIMEOUT |
222 INSTALL_DEFAULT_RETRIES = _DEFAULT_RETRIES | 233 INSTALL_DEFAULT_RETRIES = _DEFAULT_RETRIES |
223 | 234 |
224 @decorators.WithTimeoutAndRetriesDefaults( | 235 @decorators.WithTimeoutAndRetriesDefaults( |
225 INSTALL_DEFAULT_TIMEOUT, | 236 INSTALL_DEFAULT_TIMEOUT, |
226 INSTALL_DEFAULT_RETRIES) | 237 INSTALL_DEFAULT_RETRIES) |
227 def Install(self, apk_path, reinstall=False, timeout=None, retries=None): | 238 def Install(self, apk_path, reinstall=False, timeout=None, retries=None): |
228 """Install an APK. | 239 """Install an APK. |
229 | 240 |
230 Noop if an identical APK is already installed. | 241 Noop if an identical APK is already installed. |
231 | 242 |
232 Args: | 243 Args: |
233 apk_path: A string containing the path to the APK to install. | 244 apk_path: A string containing the path to the APK to install. |
234 reinstall: A boolean indicating if we should keep any existing app data. | 245 reinstall: A boolean indicating if we should keep any existing app data. |
235 timeout: timeout in seconds | 246 timeout: timeout in seconds |
236 retries: number of retries | 247 retries: number of retries |
| 248 |
237 Raises: | 249 Raises: |
238 CommandFailedError if the installation fails. | 250 CommandFailedError if the installation fails. |
239 CommandTimeoutError if the installation times out. | 251 CommandTimeoutError if the installation times out. |
240 DeviceUnreachableError on missing device. | 252 DeviceUnreachableError on missing device. |
241 """ | 253 """ |
242 package_name = apk_helper.GetPackageName(apk_path) | 254 package_name = apk_helper.GetPackageName(apk_path) |
243 device_path = self.old_interface.GetApplicationPath(package_name) | 255 device_path = self.old_interface.GetApplicationPath(package_name) |
244 if device_path is not None: | 256 if device_path is not None: |
245 files_changed = self.old_interface.GetFilesChanged( | 257 files_changed = self.old_interface.GetFilesChanged( |
246 apk_path, device_path, ignore_filenames=True) | 258 apk_path, device_path, ignore_filenames=True) |
(...skipping 29 matching lines...) Expand all Loading... |
276 AndroidCommands is gone. | 288 AndroidCommands is gone. |
277 | 289 |
278 Args: | 290 Args: |
279 cmd: A list containing the command to run on the device and any arguments. | 291 cmd: A list containing the command to run on the device and any arguments. |
280 check_return: A boolean indicating whether or not the return code should | 292 check_return: A boolean indicating whether or not the return code should |
281 be checked. | 293 be checked. |
282 as_root: A boolean indicating whether the shell command should be run | 294 as_root: A boolean indicating whether the shell command should be run |
283 with root privileges. | 295 with root privileges. |
284 timeout: timeout in seconds | 296 timeout: timeout in seconds |
285 retries: number of retries | 297 retries: number of retries |
| 298 |
286 Returns: | 299 Returns: |
287 The output of the command. | 300 The output of the command. |
| 301 |
288 Raises: | 302 Raises: |
289 CommandFailedError if check_return is True and the return code is nozero. | 303 CommandFailedError if check_return is True and the return code is nozero. |
290 CommandTimeoutError on timeout. | 304 CommandTimeoutError on timeout. |
291 DeviceUnreachableError on missing device. | 305 DeviceUnreachableError on missing device. |
292 """ | 306 """ |
293 return self._RunShellCommandImpl(cmd, check_return=check_return, | 307 return self._RunShellCommandImpl(cmd, check_return=check_return, |
294 as_root=as_root, timeout=timeout) | 308 as_root=as_root, timeout=timeout) |
295 | 309 |
296 def _RunShellCommandImpl(self, cmd, check_return=False, as_root=False, | 310 def _RunShellCommandImpl(self, cmd, check_return=False, as_root=False, |
297 timeout=None): | 311 timeout=None): |
298 """Implementation of RunShellCommand. | 312 """Implementation of RunShellCommand. |
299 | 313 |
300 This is split from RunShellCommand to allow other DeviceUtils methods to | 314 This is split from RunShellCommand to allow other DeviceUtils methods to |
301 call RunShellCommand without spawning a new timeout thread. | 315 call RunShellCommand without spawning a new timeout thread. |
302 | 316 |
303 TODO(jbudorick) Remove the timeout parameter once this is no longer | 317 TODO(jbudorick) Remove the timeout parameter once this is no longer |
304 implemented via AndroidCommands. | 318 implemented via AndroidCommands. |
305 | 319 |
306 Args: | 320 Args: |
307 cmd: Same as for |RunShellCommand|. | 321 cmd: Same as for |RunShellCommand|. |
308 check_return: Same as for |RunShellCommand|. | 322 check_return: Same as for |RunShellCommand|. |
309 as_root: Same as for |RunShellCommand|. | 323 as_root: Same as for |RunShellCommand|. |
310 timeout: timeout in seconds | 324 timeout: timeout in seconds |
| 325 |
311 Raises: | 326 Raises: |
312 Same as for |RunShellCommand|. | 327 Same as for |RunShellCommand|. |
| 328 |
313 Returns: | 329 Returns: |
314 Same as for |RunShellCommand|. | 330 Same as for |RunShellCommand|. |
315 """ | 331 """ |
316 if isinstance(cmd, list): | 332 if isinstance(cmd, list): |
317 cmd = ' '.join(cmd) | 333 cmd = ' '.join(cmd) |
318 if as_root and not self.HasRoot(): | 334 if as_root and not self.HasRoot(): |
319 cmd = 'su -c %s' % cmd | 335 cmd = 'su -c %s' % cmd |
320 if check_return: | 336 if check_return: |
321 code, output = self.old_interface.GetShellCommandStatusAndOutput( | 337 code, output = self.old_interface.GetShellCommandStatusAndOutput( |
322 cmd, timeout_time=timeout) | 338 cmd, timeout_time=timeout) |
(...skipping 12 matching lines...) Expand all Loading... |
335 Args: | 351 Args: |
336 process_name: A string containing the name of the process to kill. | 352 process_name: A string containing the name of the process to kill. |
337 signum: An integer containing the signal number to send to kill. Defaults | 353 signum: An integer containing the signal number to send to kill. Defaults |
338 to 9 (SIGKILL). | 354 to 9 (SIGKILL). |
339 as_root: A boolean indicating whether the kill should be executed with | 355 as_root: A boolean indicating whether the kill should be executed with |
340 root privileges. | 356 root privileges. |
341 blocking: A boolean indicating whether we should wait until all processes | 357 blocking: A boolean indicating whether we should wait until all processes |
342 with the given |process_name| are dead. | 358 with the given |process_name| are dead. |
343 timeout: timeout in seconds | 359 timeout: timeout in seconds |
344 retries: number of retries | 360 retries: number of retries |
| 361 |
345 Raises: | 362 Raises: |
346 CommandFailedError if no process was killed. | 363 CommandFailedError if no process was killed. |
347 CommandTimeoutError on timeout. | 364 CommandTimeoutError on timeout. |
348 DeviceUnreachableError on missing device. | 365 DeviceUnreachableError on missing device. |
349 """ | 366 """ |
350 pids = self.old_interface.ExtractPid(process_name) | 367 pids = self.old_interface.ExtractPid(process_name) |
351 if len(pids) == 0: | 368 if len(pids) == 0: |
352 raise device_errors.CommandFailedError( | 369 raise device_errors.CommandFailedError( |
353 'No process "%s"' % process_name, device=str(self)) | 370 'No process "%s"' % process_name, device=str(self)) |
354 | 371 |
(...skipping 16 matching lines...) Expand all Loading... |
371 intent: An Intent to send. | 388 intent: An Intent to send. |
372 blocking: A boolean indicating whether we should wait for the activity to | 389 blocking: A boolean indicating whether we should wait for the activity to |
373 finish launching. | 390 finish launching. |
374 trace_file_name: If present, a string that both indicates that we want to | 391 trace_file_name: If present, a string that both indicates that we want to |
375 profile the activity and contains the path to which the | 392 profile the activity and contains the path to which the |
376 trace should be saved. | 393 trace should be saved. |
377 force_stop: A boolean indicating whether we should stop the activity | 394 force_stop: A boolean indicating whether we should stop the activity |
378 before starting it. | 395 before starting it. |
379 timeout: timeout in seconds | 396 timeout: timeout in seconds |
380 retries: number of retries | 397 retries: number of retries |
| 398 |
381 Raises: | 399 Raises: |
382 CommandFailedError if the activity could not be started. | 400 CommandFailedError if the activity could not be started. |
383 CommandTimeoutError on timeout. | 401 CommandTimeoutError on timeout. |
384 DeviceUnreachableError on missing device. | 402 DeviceUnreachableError on missing device. |
385 """ | 403 """ |
386 single_category = (intent.category[0] if isinstance(intent.category, list) | 404 single_category = (intent.category[0] if isinstance(intent.category, list) |
387 else intent.category) | 405 else intent.category) |
388 output = self.old_interface.StartActivity( | 406 output = self.old_interface.StartActivity( |
389 intent.package, intent.activity, wait_for_completion=blocking, | 407 intent.package, intent.activity, wait_for_completion=blocking, |
390 action=intent.action, category=single_category, data=intent.data, | 408 action=intent.action, category=single_category, data=intent.data, |
391 extras=intent.extras, trace_file_name=trace_file_name, | 409 extras=intent.extras, trace_file_name=trace_file_name, |
392 force_stop=force_stop, flags=intent.flags) | 410 force_stop=force_stop, flags=intent.flags) |
393 for l in output: | 411 for l in output: |
394 if l.startswith('Error:'): | 412 if l.startswith('Error:'): |
395 raise device_errors.CommandFailedError(l, device=str(self)) | 413 raise device_errors.CommandFailedError(l, device=str(self)) |
396 | 414 |
397 @decorators.WithTimeoutAndRetriesFromInstance() | 415 @decorators.WithTimeoutAndRetriesFromInstance() |
398 def BroadcastIntent(self, intent, timeout=None, retries=None): | 416 def BroadcastIntent(self, intent, timeout=None, retries=None): |
399 """Send a broadcast intent. | 417 """Send a broadcast intent. |
400 | 418 |
401 Args: | 419 Args: |
402 intent: An Intent to broadcast. | 420 intent: An Intent to broadcast. |
403 timeout: timeout in seconds | 421 timeout: timeout in seconds |
404 retries: number of retries | 422 retries: number of retries |
| 423 |
405 Raises: | 424 Raises: |
406 CommandTimeoutError on timeout. | 425 CommandTimeoutError on timeout. |
407 DeviceUnreachableError on missing device. | 426 DeviceUnreachableError on missing device. |
408 """ | 427 """ |
409 package, old_intent = intent.action.rsplit('.', 1) | 428 package, old_intent = intent.action.rsplit('.', 1) |
410 if intent.extras is None: | 429 if intent.extras is None: |
411 args = [] | 430 args = [] |
412 else: | 431 else: |
413 args = ['-e %s%s' % (k, ' "%s"' % v if v else '') | 432 args = ['-e %s%s' % (k, ' "%s"' % v if v else '') |
414 for k, v in intent.extras.items() if len(k) > 0] | 433 for k, v in intent.extras.items() if len(k) > 0] |
415 self.old_interface.BroadcastIntent(package, old_intent, *args) | 434 self.old_interface.BroadcastIntent(package, old_intent, *args) |
416 | 435 |
417 @decorators.WithTimeoutAndRetriesFromInstance() | 436 @decorators.WithTimeoutAndRetriesFromInstance() |
418 def GoHome(self, timeout=None, retries=None): | 437 def GoHome(self, timeout=None, retries=None): |
419 """Return to the home screen. | 438 """Return to the home screen. |
420 | 439 |
421 Args: | 440 Args: |
422 timeout: timeout in seconds | 441 timeout: timeout in seconds |
423 retries: number of retries | 442 retries: number of retries |
| 443 |
424 Raises: | 444 Raises: |
425 CommandTimeoutError on timeout. | 445 CommandTimeoutError on timeout. |
426 DeviceUnreachableError on missing device. | 446 DeviceUnreachableError on missing device. |
427 """ | 447 """ |
428 self.old_interface.GoHome() | 448 self.old_interface.GoHome() |
429 | 449 |
430 @decorators.WithTimeoutAndRetriesFromInstance() | 450 @decorators.WithTimeoutAndRetriesFromInstance() |
431 def ForceStop(self, package, timeout=None, retries=None): | 451 def ForceStop(self, package, timeout=None, retries=None): |
432 """Close the application. | 452 """Close the application. |
433 | 453 |
434 Args: | 454 Args: |
435 package: A string containing the name of the package to stop. | 455 package: A string containing the name of the package to stop. |
436 timeout: timeout in seconds | 456 timeout: timeout in seconds |
437 retries: number of retries | 457 retries: number of retries |
| 458 |
438 Raises: | 459 Raises: |
439 CommandTimeoutError on timeout. | 460 CommandTimeoutError on timeout. |
440 DeviceUnreachableError on missing device. | 461 DeviceUnreachableError on missing device. |
441 """ | 462 """ |
442 self.old_interface.CloseApplication(package) | 463 self.old_interface.CloseApplication(package) |
443 | 464 |
444 @decorators.WithTimeoutAndRetriesFromInstance() | 465 @decorators.WithTimeoutAndRetriesFromInstance() |
445 def ClearApplicationState(self, package, timeout=None, retries=None): | 466 def ClearApplicationState(self, package, timeout=None, retries=None): |
446 """Clear all state for the given package. | 467 """Clear all state for the given package. |
447 | 468 |
448 Args: | 469 Args: |
449 package: A string containing the name of the package to stop. | 470 package: A string containing the name of the package to stop. |
450 timeout: timeout in seconds | 471 timeout: timeout in seconds |
451 retries: number of retries | 472 retries: number of retries |
| 473 |
452 Raises: | 474 Raises: |
453 CommandTimeoutError on timeout. | 475 CommandTimeoutError on timeout. |
454 DeviceUnreachableError on missing device. | 476 DeviceUnreachableError on missing device. |
455 """ | 477 """ |
456 self.old_interface.ClearApplicationState(package) | 478 self.old_interface.ClearApplicationState(package) |
457 | 479 |
458 @decorators.WithTimeoutAndRetriesFromInstance() | 480 @decorators.WithTimeoutAndRetriesFromInstance() |
459 def SendKeyEvent(self, keycode, timeout=None, retries=None): | 481 def SendKeyEvent(self, keycode, timeout=None, retries=None): |
460 """Sends a keycode to the device. | 482 """Sends a keycode to the device. |
461 | 483 |
462 See: http://developer.android.com/reference/android/view/KeyEvent.html | 484 See: http://developer.android.com/reference/android/view/KeyEvent.html |
463 | 485 |
464 Args: | 486 Args: |
465 keycode: A integer keycode to send to the device. | 487 keycode: A integer keycode to send to the device. |
466 timeout: timeout in seconds | 488 timeout: timeout in seconds |
467 retries: number of retries | 489 retries: number of retries |
| 490 |
468 Raises: | 491 Raises: |
469 CommandTimeoutError on timeout. | 492 CommandTimeoutError on timeout. |
470 DeviceUnreachableError on missing device. | 493 DeviceUnreachableError on missing device. |
471 """ | 494 """ |
472 self.old_interface.SendKeyEvent(keycode) | 495 self.old_interface.SendKeyEvent(keycode) |
473 | 496 |
474 PUSH_CHANGED_FILES_DEFAULT_TIMEOUT = 10 * _DEFAULT_TIMEOUT | 497 PUSH_CHANGED_FILES_DEFAULT_TIMEOUT = 10 * _DEFAULT_TIMEOUT |
475 PUSH_CHANGED_FILES_DEFAULT_RETRIES = _DEFAULT_RETRIES | 498 PUSH_CHANGED_FILES_DEFAULT_RETRIES = _DEFAULT_RETRIES |
476 | 499 |
477 @decorators.WithTimeoutAndRetriesDefaults( | 500 @decorators.WithTimeoutAndRetriesDefaults( |
478 PUSH_CHANGED_FILES_DEFAULT_TIMEOUT, | 501 PUSH_CHANGED_FILES_DEFAULT_TIMEOUT, |
479 PUSH_CHANGED_FILES_DEFAULT_RETRIES) | 502 PUSH_CHANGED_FILES_DEFAULT_RETRIES) |
480 def PushChangedFiles(self, host_path, device_path, timeout=None, | 503 def PushChangedFiles(self, host_path, device_path, timeout=None, |
481 retries=None): | 504 retries=None): |
482 """Push files to the device, skipping files that don't need updating. | 505 """Push files to the device, skipping files that don't need updating. |
483 | 506 |
484 Args: | 507 Args: |
485 host_path: A string containing the absolute path to the file or directory | 508 host_path: A string containing the absolute path to the file or directory |
486 on the host that should be minimally pushed to the device. | 509 on the host that should be minimally pushed to the device. |
487 device_path: A string containing the absolute path of the destination on | 510 device_path: A string containing the absolute path of the destination on |
488 the device. | 511 the device. |
489 timeout: timeout in seconds | 512 timeout: timeout in seconds |
490 retries: number of retries | 513 retries: number of retries |
| 514 |
491 Raises: | 515 Raises: |
492 CommandFailedError on failure. | 516 CommandFailedError on failure. |
493 CommandTimeoutError on timeout. | 517 CommandTimeoutError on timeout. |
494 DeviceUnreachableError on missing device. | 518 DeviceUnreachableError on missing device. |
495 """ | 519 """ |
496 self.old_interface.PushIfNeeded(host_path, device_path) | 520 self.old_interface.PushIfNeeded(host_path, device_path) |
497 | 521 |
498 @decorators.WithTimeoutAndRetriesFromInstance() | 522 @decorators.WithTimeoutAndRetriesFromInstance() |
499 def FileExists(self, device_path, timeout=None, retries=None): | 523 def FileExists(self, device_path, timeout=None, retries=None): |
500 """Checks whether the given file exists on the device. | 524 """Checks whether the given file exists on the device. |
501 | 525 |
502 Args: | 526 Args: |
503 device_path: A string containing the absolute path to the file on the | 527 device_path: A string containing the absolute path to the file on the |
504 device. | 528 device. |
505 timeout: timeout in seconds | 529 timeout: timeout in seconds |
506 retries: number of retries | 530 retries: number of retries |
| 531 |
507 Returns: | 532 Returns: |
508 True if the file exists on the device, False otherwise. | 533 True if the file exists on the device, False otherwise. |
| 534 |
509 Raises: | 535 Raises: |
510 CommandTimeoutError on timeout. | 536 CommandTimeoutError on timeout. |
511 DeviceUnreachableError on missing device. | 537 DeviceUnreachableError on missing device. |
512 """ | 538 """ |
513 return self._FileExistsImpl(device_path) | 539 return self._FileExistsImpl(device_path) |
514 | 540 |
515 def _FileExistsImpl(self, device_path): | 541 def _FileExistsImpl(self, device_path): |
516 """Implementation of FileExists. | 542 """Implementation of FileExists. |
517 | 543 |
518 This is split from FileExists to allow other DeviceUtils methods to call | 544 This is split from FileExists to allow other DeviceUtils methods to call |
519 FileExists without spawning a new timeout thread. | 545 FileExists without spawning a new timeout thread. |
520 | 546 |
521 Args: | 547 Args: |
522 device_path: Same as for |FileExists|. | 548 device_path: Same as for |FileExists|. |
| 549 |
523 Returns: | 550 Returns: |
524 True if the file exists on the device, False otherwise. | 551 True if the file exists on the device, False otherwise. |
| 552 |
525 Raises: | 553 Raises: |
526 Same as for |FileExists|. | 554 Same as for |FileExists|. |
527 """ | 555 """ |
528 return self.old_interface.FileExistsOnDevice(device_path) | 556 return self.old_interface.FileExistsOnDevice(device_path) |
529 | 557 |
530 @decorators.WithTimeoutAndRetriesFromInstance() | 558 @decorators.WithTimeoutAndRetriesFromInstance() |
531 def PullFile(self, device_path, host_path, timeout=None, retries=None): | 559 def PullFile(self, device_path, host_path, timeout=None, retries=None): |
532 """Pull a file from the device. | 560 """Pull a file from the device. |
533 | 561 |
534 Args: | 562 Args: |
535 device_path: A string containing the absolute path of the file to pull | 563 device_path: A string containing the absolute path of the file to pull |
536 from the device. | 564 from the device. |
537 host_path: A string containing the absolute path of the destination on | 565 host_path: A string containing the absolute path of the destination on |
538 the host. | 566 the host. |
539 timeout: timeout in seconds | 567 timeout: timeout in seconds |
540 retries: number of retries | 568 retries: number of retries |
| 569 |
541 Raises: | 570 Raises: |
542 CommandFailedError on failure. | 571 CommandFailedError on failure. |
543 CommandTimeoutError on timeout. | 572 CommandTimeoutError on timeout. |
544 """ | 573 """ |
545 try: | 574 try: |
546 self.old_interface.PullFileFromDevice(device_path, host_path) | 575 self.old_interface.PullFileFromDevice(device_path, host_path) |
547 except AssertionError as e: | 576 except AssertionError as e: |
548 raise device_errors.CommandFailedError( | 577 raise device_errors.CommandFailedError( |
549 str(e), device=str(self)), None, sys.exc_info()[2] | 578 str(e), device=str(self)), None, sys.exc_info()[2] |
550 | 579 |
551 @decorators.WithTimeoutAndRetriesFromInstance() | 580 @decorators.WithTimeoutAndRetriesFromInstance() |
552 def ReadFile(self, device_path, as_root=False, timeout=None, retries=None): | 581 def ReadFile(self, device_path, as_root=False, timeout=None, retries=None): |
553 """Reads the contents of a file from the device. | 582 """Reads the contents of a file from the device. |
554 | 583 |
555 Args: | 584 Args: |
556 device_path: A string containing the absolute path of the file to read | 585 device_path: A string containing the absolute path of the file to read |
557 from the device. | 586 from the device. |
558 as_root: A boolean indicating whether the read should be executed with | 587 as_root: A boolean indicating whether the read should be executed with |
559 root privileges. | 588 root privileges. |
560 timeout: timeout in seconds | 589 timeout: timeout in seconds |
561 retries: number of retries | 590 retries: number of retries |
| 591 |
562 Returns: | 592 Returns: |
563 The contents of the file at |device_path| as a list of lines. | 593 The contents of the file at |device_path| as a list of lines. |
| 594 |
564 Raises: | 595 Raises: |
565 CommandFailedError if the file can't be read. | 596 CommandFailedError if the file can't be read. |
566 CommandTimeoutError on timeout. | 597 CommandTimeoutError on timeout. |
567 DeviceUnreachableError on missing device. | 598 DeviceUnreachableError on missing device. |
568 """ | 599 """ |
569 # TODO(jbudorick) Evaluate whether we actually want to return a list of | 600 # TODO(jbudorick) Evaluate whether we actually want to return a list of |
570 # lines after the implementation switch. | 601 # lines after the implementation switch. |
571 if as_root: | 602 if as_root: |
572 if not self.old_interface.CanAccessProtectedFileContents(): | 603 if not self.old_interface.CanAccessProtectedFileContents(): |
573 raise device_errors.CommandFailedError( | 604 raise device_errors.CommandFailedError( |
574 'Cannot read from %s with root privileges.' % device_path) | 605 'Cannot read from %s with root privileges.' % device_path) |
575 return self.old_interface.GetProtectedFileContents(device_path) | 606 return self.old_interface.GetProtectedFileContents(device_path) |
576 else: | 607 else: |
577 return self.old_interface.GetFileContents(device_path) | 608 return self.old_interface.GetFileContents(device_path) |
578 | 609 |
579 @decorators.WithTimeoutAndRetriesFromInstance() | 610 @decorators.WithTimeoutAndRetriesFromInstance() |
580 def WriteFile(self, device_path, contents, as_root=False, timeout=None, | 611 def WriteFile(self, device_path, contents, as_root=False, timeout=None, |
581 retries=None): | 612 retries=None): |
582 """Writes |contents| to a file on the device. | 613 """Writes |contents| to a file on the device. |
583 | 614 |
584 Args: | 615 Args: |
585 device_path: A string containing the absolute path to the file to write | 616 device_path: A string containing the absolute path to the file to write |
586 on the device. | 617 on the device. |
587 contents: A string containing the data to write to the device. | 618 contents: A string containing the data to write to the device. |
588 as_root: A boolean indicating whether the write should be executed with | 619 as_root: A boolean indicating whether the write should be executed with |
589 root privileges. | 620 root privileges. |
590 timeout: timeout in seconds | 621 timeout: timeout in seconds |
591 retries: number of retries | 622 retries: number of retries |
| 623 |
592 Raises: | 624 Raises: |
593 CommandFailedError if the file could not be written on the device. | 625 CommandFailedError if the file could not be written on the device. |
594 CommandTimeoutError on timeout. | 626 CommandTimeoutError on timeout. |
595 DeviceUnreachableError on missing device. | 627 DeviceUnreachableError on missing device. |
596 """ | 628 """ |
597 if as_root: | 629 if as_root: |
598 if not self.old_interface.CanAccessProtectedFileContents(): | 630 if not self.old_interface.CanAccessProtectedFileContents(): |
599 raise device_errors.CommandFailedError( | 631 raise device_errors.CommandFailedError( |
600 'Cannot write to %s with root privileges.' % device_path) | 632 'Cannot write to %s with root privileges.' % device_path) |
601 self.old_interface.SetProtectedFileContents(device_path, contents) | 633 self.old_interface.SetProtectedFileContents(device_path, contents) |
602 else: | 634 else: |
603 self.old_interface.SetFileContents(device_path, contents) | 635 self.old_interface.SetFileContents(device_path, contents) |
604 | 636 |
605 @decorators.WithTimeoutAndRetriesFromInstance() | 637 @decorators.WithTimeoutAndRetriesFromInstance() |
606 def Ls(self, device_path, timeout=None, retries=None): | 638 def Ls(self, device_path, timeout=None, retries=None): |
607 """Lists the contents of a directory on the device. | 639 """Lists the contents of a directory on the device. |
608 | 640 |
609 Args: | 641 Args: |
610 device_path: A string containing the path of the directory on the device | 642 device_path: A string containing the path of the directory on the device |
611 to list. | 643 to list. |
612 timeout: timeout in seconds | 644 timeout: timeout in seconds |
613 retries: number of retries | 645 retries: number of retries |
| 646 |
614 Returns: | 647 Returns: |
615 The contents of the directory specified by |device_path|. | 648 The contents of the directory specified by |device_path|. |
| 649 |
616 Raises: | 650 Raises: |
617 CommandTimeoutError on timeout. | 651 CommandTimeoutError on timeout. |
618 DeviceUnreachableError on missing device. | 652 DeviceUnreachableError on missing device. |
619 """ | 653 """ |
620 return self.old_interface.ListPathContents(device_path) | 654 return self.old_interface.ListPathContents(device_path) |
621 | 655 |
622 @decorators.WithTimeoutAndRetriesFromInstance() | 656 @decorators.WithTimeoutAndRetriesFromInstance() |
623 def SetJavaAsserts(self, enabled, timeout=None, retries=None): | 657 def SetJavaAsserts(self, enabled, timeout=None, retries=None): |
624 """Enables or disables Java asserts. | 658 """Enables or disables Java asserts. |
625 | 659 |
626 Args: | 660 Args: |
627 enabled: A boolean indicating whether Java asserts should be enabled | 661 enabled: A boolean indicating whether Java asserts should be enabled |
628 or disabled. | 662 or disabled. |
629 timeout: timeout in seconds | 663 timeout: timeout in seconds |
630 retries: number of retries | 664 retries: number of retries |
| 665 |
631 Raises: | 666 Raises: |
632 CommandTimeoutError on timeout. | 667 CommandTimeoutError on timeout. |
633 """ | 668 """ |
634 self.old_interface.SetJavaAssertsEnabled(enabled) | 669 self.old_interface.SetJavaAssertsEnabled(enabled) |
635 | 670 |
636 @decorators.WithTimeoutAndRetriesFromInstance() | 671 @decorators.WithTimeoutAndRetriesFromInstance() |
637 def GetProp(self, property_name, timeout=None, retries=None): | 672 def GetProp(self, property_name, timeout=None, retries=None): |
638 """Gets a property from the device. | 673 """Gets a property from the device. |
639 | 674 |
640 Args: | 675 Args: |
641 property_name: A string containing the name of the property to get from | 676 property_name: A string containing the name of the property to get from |
642 the device. | 677 the device. |
643 timeout: timeout in seconds | 678 timeout: timeout in seconds |
644 retries: number of retries | 679 retries: number of retries |
| 680 |
645 Returns: | 681 Returns: |
646 The value of the device's |property_name| property. | 682 The value of the device's |property_name| property. |
| 683 |
647 Raises: | 684 Raises: |
648 CommandTimeoutError on timeout. | 685 CommandTimeoutError on timeout. |
649 """ | 686 """ |
650 return self.old_interface.system_properties[property_name] | 687 return self.old_interface.system_properties[property_name] |
651 | 688 |
652 @decorators.WithTimeoutAndRetriesFromInstance() | 689 @decorators.WithTimeoutAndRetriesFromInstance() |
653 def SetProp(self, property_name, value, timeout=None, retries=None): | 690 def SetProp(self, property_name, value, timeout=None, retries=None): |
654 """Sets a property on the device. | 691 """Sets a property on the device. |
655 | 692 |
656 Args: | 693 Args: |
657 property_name: A string containing the name of the property to set on | 694 property_name: A string containing the name of the property to set on |
658 the device. | 695 the device. |
659 value: A string containing the value to set to the property on the | 696 value: A string containing the value to set to the property on the |
660 device. | 697 device. |
661 timeout: timeout in seconds | 698 timeout: timeout in seconds |
662 retries: number of retries | 699 retries: number of retries |
| 700 |
663 Raises: | 701 Raises: |
664 CommandTimeoutError on timeout. | 702 CommandTimeoutError on timeout. |
665 """ | 703 """ |
666 self.old_interface.system_properties[property_name] = value | 704 self.old_interface.system_properties[property_name] = value |
667 | 705 |
668 @decorators.WithTimeoutAndRetriesFromInstance() | 706 @decorators.WithTimeoutAndRetriesFromInstance() |
669 def GetPids(self, process_name, timeout=None, retries=None): | 707 def GetPids(self, process_name, timeout=None, retries=None): |
670 """Returns the PIDs of processes with the given name. | 708 """Returns the PIDs of processes with the given name. |
671 | 709 |
672 Note that the |process_name| is often the package name. | 710 Note that the |process_name| is often the package name. |
673 | 711 |
674 Args: | 712 Args: |
675 process_name: A string containing the process name to get the PIDs for. | 713 process_name: A string containing the process name to get the PIDs for. |
676 timeout: timeout in seconds | 714 timeout: timeout in seconds |
677 retries: number of retries | 715 retries: number of retries |
| 716 |
678 Returns: | 717 Returns: |
679 A dict mapping process name to PID for each process that contained the | 718 A dict mapping process name to PID for each process that contained the |
680 provided |process_name|. | 719 provided |process_name|. |
| 720 |
681 Raises: | 721 Raises: |
682 CommandTimeoutError on timeout. | 722 CommandTimeoutError on timeout. |
683 DeviceUnreachableError on missing device. | 723 DeviceUnreachableError on missing device. |
684 """ | 724 """ |
685 procs_pids = {} | 725 procs_pids = {} |
686 for line in self._RunShellCommandImpl('ps'): | 726 for line in self._RunShellCommandImpl('ps'): |
687 try: | 727 try: |
688 ps_data = line.split() | 728 ps_data = line.split() |
689 if process_name in ps_data[-1]: | 729 if process_name in ps_data[-1]: |
690 procs_pids[ps_data[-1]] = ps_data[1] | 730 procs_pids[ps_data[-1]] = ps_data[1] |
691 except IndexError: | 731 except IndexError: |
692 pass | 732 pass |
693 return procs_pids | 733 return procs_pids |
694 | 734 |
695 @decorators.WithTimeoutAndRetriesFromInstance() | 735 @decorators.WithTimeoutAndRetriesFromInstance() |
696 def TakeScreenshot(self, host_path=None, timeout=None, retries=None): | 736 def TakeScreenshot(self, host_path=None, timeout=None, retries=None): |
697 """Takes a screenshot of the device. | 737 """Takes a screenshot of the device. |
698 | 738 |
699 Args: | 739 Args: |
700 host_path: A string containing the path on the host to save the | 740 host_path: A string containing the path on the host to save the |
701 screenshot to. If None, a file name will be generated. | 741 screenshot to. If None, a file name will be generated. |
702 timeout: timeout in seconds | 742 timeout: timeout in seconds |
703 retries: number of retries | 743 retries: number of retries |
| 744 |
704 Returns: | 745 Returns: |
705 The name of the file on the host to which the screenshot was saved. | 746 The name of the file on the host to which the screenshot was saved. |
| 747 |
706 Raises: | 748 Raises: |
707 CommandFailedError on failure. | 749 CommandFailedError on failure. |
708 CommandTimeoutError on timeout. | 750 CommandTimeoutError on timeout. |
709 DeviceUnreachableError on missing device. | 751 DeviceUnreachableError on missing device. |
710 """ | 752 """ |
711 return self.old_interface.TakeScreenshot(host_path) | 753 return self.old_interface.TakeScreenshot(host_path) |
712 | 754 |
713 @decorators.WithTimeoutAndRetriesFromInstance() | 755 @decorators.WithTimeoutAndRetriesFromInstance() |
714 def GetIOStats(self, timeout=None, retries=None): | 756 def GetIOStats(self, timeout=None, retries=None): |
715 """Gets cumulative disk IO stats since boot for all processes. | 757 """Gets cumulative disk IO stats since boot for all processes. |
716 | 758 |
717 Args: | 759 Args: |
718 timeout: timeout in seconds | 760 timeout: timeout in seconds |
719 retries: number of retries | 761 retries: number of retries |
| 762 |
720 Returns: | 763 Returns: |
721 A dict containing |num_reads|, |num_writes|, |read_ms|, and |write_ms|. | 764 A dict containing |num_reads|, |num_writes|, |read_ms|, and |write_ms|. |
| 765 |
722 Raises: | 766 Raises: |
723 CommandTimeoutError on timeout. | 767 CommandTimeoutError on timeout. |
724 DeviceUnreachableError on missing device. | 768 DeviceUnreachableError on missing device. |
725 """ | 769 """ |
726 return self.old_interface.GetIoStats() | 770 return self.old_interface.GetIoStats() |
727 | 771 |
| 772 @decorators.WithTimeoutAndRetriesFromInstance() |
| 773 def GetMemoryUsageForPid(self, pid, timeout=None, retries=None): |
| 774 """Gets the memory usage for the given PID. |
| 775 |
| 776 Args: |
| 777 pid: PID of the process. |
| 778 timeout: timeout in seconds |
| 779 retries: number of retries |
| 780 |
| 781 Returns: |
| 782 A 2-tuple containing: |
| 783 - A dict containing the overall memory usage statistics for the PID. |
| 784 - A dict containing memory usage statistics broken down by mapping. |
| 785 |
| 786 Raises: |
| 787 CommandTimeoutError on timeout. |
| 788 """ |
| 789 return self.old_interface.GetMemoryUsageForPid(pid) |
| 790 |
728 def __str__(self): | 791 def __str__(self): |
729 """Returns the device serial.""" | 792 """Returns the device serial.""" |
730 return self.old_interface.GetDevice() | 793 return self.old_interface.GetDevice() |
731 | 794 |
732 @staticmethod | 795 @staticmethod |
733 def parallel(devices=None, async=False): | 796 def parallel(devices=None, async=False): |
734 """Creates a Parallelizer to operate over the provided list of devices. | 797 """Creates a Parallelizer to operate over the provided list of devices. |
735 | 798 |
736 If |devices| is either |None| or an empty list, the Parallelizer will | 799 If |devices| is either |None| or an empty list, the Parallelizer will |
737 operate over all attached devices. | 800 operate over all attached devices. |
738 | 801 |
739 Args: | 802 Args: |
740 devices: A list of either DeviceUtils instances or objects from | 803 devices: A list of either DeviceUtils instances or objects from |
741 from which DeviceUtils instances can be constructed. If None, | 804 from which DeviceUtils instances can be constructed. If None, |
742 all attached devices will be used. | 805 all attached devices will be used. |
743 async: If true, returns a Parallelizer that runs operations | 806 async: If true, returns a Parallelizer that runs operations |
744 asynchronously. | 807 asynchronously. |
| 808 |
745 Returns: | 809 Returns: |
746 A Parallelizer operating over |devices|. | 810 A Parallelizer operating over |devices|. |
747 """ | 811 """ |
748 if not devices or len(devices) == 0: | 812 if not devices or len(devices) == 0: |
749 devices = pylib.android_commands.GetAttachedDevices() | 813 devices = pylib.android_commands.GetAttachedDevices() |
750 parallelizer_type = (parallelizer.Parallelizer if async | 814 parallelizer_type = (parallelizer.Parallelizer if async |
751 else parallelizer.SyncParallelizer) | 815 else parallelizer.SyncParallelizer) |
752 return parallelizer_type([ | 816 return parallelizer_type([ |
753 d if isinstance(d, DeviceUtils) else DeviceUtils(d) | 817 d if isinstance(d, DeviceUtils) else DeviceUtils(d) |
754 for d in devices]) | 818 for d in devices]) |
755 | 819 |
OLD | NEW |