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 |
11 import signal | |
12 import sys | |
11 import time | 13 import time |
12 | 14 |
13 import pylib.android_commands | 15 import pylib.android_commands |
14 from pylib.device import adb_wrapper | 16 from pylib.device import adb_wrapper |
15 from pylib.device import decorators | 17 from pylib.device import decorators |
16 from pylib.device import device_errors | 18 from pylib.device import device_errors |
17 from pylib.utils import apk_helper | 19 from pylib.utils import apk_helper |
18 from pylib.utils import parallelizer | 20 from pylib.utils import parallelizer |
19 | 21 |
20 _DEFAULT_TIMEOUT = 30 | 22 _DEFAULT_TIMEOUT = 30 |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
117 """Restarts adbd with root privileges. | 119 """Restarts adbd with root privileges. |
118 | 120 |
119 Args: | 121 Args: |
120 timeout: Same as for |IsOnline|. | 122 timeout: Same as for |IsOnline|. |
121 retries: Same as for |IsOnline|. | 123 retries: Same as for |IsOnline|. |
122 Raises: | 124 Raises: |
123 CommandFailedError if root could not be enabled. | 125 CommandFailedError if root could not be enabled. |
124 """ | 126 """ |
125 if not self.old_interface.EnableAdbRoot(): | 127 if not self.old_interface.EnableAdbRoot(): |
126 raise device_errors.CommandFailedError( | 128 raise device_errors.CommandFailedError( |
127 ['adb', 'root'], 'Could not enable root.') | 129 'Could not enable root.', device=str(self)) |
128 | 130 |
129 @decorators.WithTimeoutAndRetriesFromInstance() | 131 @decorators.WithTimeoutAndRetriesFromInstance() |
130 def GetExternalStoragePath(self, timeout=None, retries=None): | 132 def GetExternalStoragePath(self, timeout=None, retries=None): |
131 """Get the device's path to its SD card. | 133 """Get the device's path to its SD card. |
132 | 134 |
133 Args: | 135 Args: |
134 timeout: Same as for |IsOnline|. | 136 timeout: Same as for |IsOnline|. |
135 retries: Same as for |IsOnline|. | 137 retries: Same as for |IsOnline|. |
136 Returns: | 138 Returns: |
137 The device's path to its SD card. | 139 The device's path to its SD card. |
138 """ | 140 """ |
139 try: | 141 try: |
140 return self.old_interface.GetExternalStorage() | 142 return self.old_interface.GetExternalStorage() |
141 except AssertionError as e: | 143 except AssertionError as e: |
142 raise device_errors.CommandFailedError( | 144 raise device_errors.CommandFailedError( |
143 ['adb', 'shell', 'echo', '$EXTERNAL_STORAGE'], str(e)) | 145 str(e), device=str(self)), None, sys.exc_info()[2] |
144 | 146 |
145 @decorators.WithTimeoutAndRetriesFromInstance() | 147 @decorators.WithTimeoutAndRetriesFromInstance() |
146 def WaitUntilFullyBooted(self, wifi=False, timeout=None, retries=None): | 148 def WaitUntilFullyBooted(self, wifi=False, timeout=None, retries=None): |
147 """Wait for the device to fully boot. | 149 """Wait for the device to fully boot. |
148 | 150 |
149 This means waiting for the device to boot, the package manager to be | 151 This means waiting for the device to boot, the package manager to be |
150 available, and the SD card to be ready. It can optionally mean waiting | 152 available, and the SD card to be ready. It can optionally mean waiting |
151 for wifi to come up, too. | 153 for wifi to come up, too. |
152 | 154 |
153 Args: | 155 Args: |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
220 if device_path is not None: | 222 if device_path is not None: |
221 files_changed = self.old_interface.GetFilesChanged( | 223 files_changed = self.old_interface.GetFilesChanged( |
222 apk_path, device_path, ignore_filenames=True) | 224 apk_path, device_path, ignore_filenames=True) |
223 if len(files_changed) > 0: | 225 if len(files_changed) > 0: |
224 should_install = True | 226 should_install = True |
225 if not reinstall: | 227 if not reinstall: |
226 out = self.old_interface.Uninstall(package_name) | 228 out = self.old_interface.Uninstall(package_name) |
227 for line in out.splitlines(): | 229 for line in out.splitlines(): |
228 if 'Failure' in line: | 230 if 'Failure' in line: |
229 raise device_errors.CommandFailedError( | 231 raise device_errors.CommandFailedError( |
230 ['adb', 'uninstall', package_name], line.strip()) | 232 line.strip(), device=str(self)) |
231 else: | 233 else: |
232 should_install = False | 234 should_install = False |
233 else: | 235 else: |
234 should_install = True | 236 should_install = True |
235 if should_install: | 237 if should_install: |
236 try: | 238 try: |
237 out = self.old_interface.Install(apk_path, reinstall=reinstall) | 239 out = self.old_interface.Install(apk_path, reinstall=reinstall) |
238 for line in out.splitlines(): | 240 for line in out.splitlines(): |
239 if 'Failure' in line: | 241 if 'Failure' in line: |
240 raise device_errors.CommandFailedError( | 242 raise device_errors.CommandFailedError( |
241 ['adb', 'install', apk_path], line.strip()) | 243 line.strip(), device=str(self)) |
242 except AssertionError as e: | 244 except AssertionError as e: |
243 raise device_errors.CommandFailedError( | 245 raise device_errors.CommandFailedError( |
244 ['adb', 'install', apk_path], str(e)) | 246 str(e), device=str(self)), None, sys.exc_info()[2] |
245 | 247 |
246 @decorators.WithTimeoutAndRetriesFromInstance() | 248 @decorators.WithTimeoutAndRetriesFromInstance() |
247 def RunShellCommand(self, cmd, check_return=False, root=False, timeout=None, | 249 def RunShellCommand(self, cmd, check_return=False, as_root=False, |
248 retries=None): | 250 timeout=None, retries=None): |
249 """Run an ADB shell command. | 251 """Run an ADB shell command. |
250 | 252 |
251 TODO(jbudorick) Switch the default value of check_return to True after | 253 TODO(jbudorick) Switch the default value of check_return to True after |
252 AndroidCommands is gone. | 254 AndroidCommands is gone. |
253 | 255 |
254 Args: | 256 Args: |
255 cmd: A list containing the command to run on the device and any arguments. | 257 cmd: A list containing the command to run on the device and any arguments. |
256 check_return: A boolean indicating whether or not the return code should | 258 check_return: A boolean indicating whether or not the return code should |
257 be checked. | 259 be checked. |
260 as_root: A boolean indicating whether the shell command should be run | |
261 with root privileges. | |
258 timeout: Same as for |IsOnline|. | 262 timeout: Same as for |IsOnline|. |
259 retries: Same as for |IsOnline|. | 263 retries: Same as for |IsOnline|. |
260 Raises: | 264 Raises: |
261 CommandFailedError if check_return is True and the return code is nozero. | 265 CommandFailedError if check_return is True and the return code is nozero. |
262 Returns: | 266 Returns: |
263 The output of the command. | 267 The output of the command. |
264 """ | 268 """ |
265 return self._RunShellCommandImpl(cmd, check_return=check_return, root=root, | 269 return self._RunShellCommandImpl(cmd, check_return=check_return, |
266 timeout=timeout) | 270 as_root=as_root, timeout=timeout) |
267 | 271 |
268 def _RunShellCommandImpl(self, cmd, check_return=False, root=False, | 272 def _RunShellCommandImpl(self, cmd, check_return=False, as_root=False, |
269 timeout=None): | 273 timeout=None): |
270 """Implementation of RunShellCommand. | 274 """Implementation of RunShellCommand. |
271 | 275 |
272 This is split from RunShellCommand to allow other DeviceUtils methods to | 276 This is split from RunShellCommand to allow other DeviceUtils methods to |
273 call RunShellCommand without spawning a new timeout thread. | 277 call RunShellCommand without spawning a new timeout thread. |
274 | 278 |
275 TODO(jbudorick) Remove the timeout parameter once this is no longer | 279 TODO(jbudorick) Remove the timeout parameter once this is no longer |
276 implemented via AndroidCommands. | 280 implemented via AndroidCommands. |
277 | 281 |
278 Args: | 282 Args: |
279 cmd: Same as for |RunShellCommand|. | 283 cmd: Same as for |RunShellCommand|. |
280 check_return: Same as for |RunShellCommand|. | 284 check_return: Same as for |RunShellCommand|. |
285 as_root: Same as for |RunShellCommand|. | |
281 timeout: Same as for |IsOnline|. | 286 timeout: Same as for |IsOnline|. |
282 Raises: | 287 Raises: |
283 Same as for |RunShellCommand|. | 288 Same as for |RunShellCommand|. |
284 Returns: | 289 Returns: |
285 Same as for |RunShellCommand|. | 290 Same as for |RunShellCommand|. |
286 """ | 291 """ |
287 if isinstance(cmd, list): | 292 if isinstance(cmd, list): |
288 cmd = ' '.join(cmd) | 293 cmd = ' '.join(cmd) |
289 if root and not self.HasRoot(): | 294 if as_root and not self.HasRoot(): |
290 cmd = 'su -c %s' % cmd | 295 cmd = 'su -c %s' % cmd |
291 if check_return: | 296 if check_return: |
292 code, output = self.old_interface.GetShellCommandStatusAndOutput( | 297 code, output = self.old_interface.GetShellCommandStatusAndOutput( |
293 cmd, timeout_time=timeout) | 298 cmd, timeout_time=timeout) |
294 if int(code) != 0: | 299 if int(code) != 0: |
295 raise device_errors.CommandFailedError( | 300 raise device_errors.AdbCommandFailedError( |
296 cmd, 'Nonzero exit code (%d)' % code) | 301 cmd.split(), 'Nonzero exit code (%d)' % code, device=str(self)) |
297 else: | 302 else: |
298 output = self.old_interface.RunShellCommand(cmd, timeout_time=timeout) | 303 output = self.old_interface.RunShellCommand(cmd, timeout_time=timeout) |
299 return output | 304 return output |
300 | 305 |
306 @decorators.WithTimeoutAndRetriesFromInstance() | |
307 def KillAll(self, process_name, signum=signal.SIGKILL, as_root=False, | |
308 blocking=False, timeout=None, retries=None): | |
309 """Kill all processes with the given name on the device. | |
310 | |
311 Args: | |
312 process_name: A string containing the name of the process to kill. | |
313 signum: An integer containing the signal number to send to kill. Defaults | |
314 to 9 (SIGKILL). | |
315 as_root: A boolean indicating whether the kill should be executed with | |
316 root priveleges. | |
317 blocking: A boolean indicating whether we should wait until all processes | |
318 with the given |process_name| are dead. | |
319 timeout: Same as for |IsOnline|. | |
320 retries: Same as for |IsOnline|. | |
321 Raises: | |
322 CommandFailedError if no process was killed. | |
323 """ | |
324 pids = self.old_interface.ExtractPid(process_name) | |
325 if len(pids) == 0: | |
326 raise device_errors.CommandFailedError( | |
327 'No process "%s"' % process_name, device=str(self)) | |
328 | |
329 if blocking: | |
330 total_killed = self.old_interface.KillAllBlocking( | |
331 process_name, signum=signum, with_su=as_root, timeout_sec=timeout) | |
332 else: | |
333 total_killed = self.old_interface.KillAll( | |
334 process_name, signum=signum, with_su=as_root) | |
335 if total_killed == 0: | |
336 raise device_errors.CommandFailedError( | |
337 'Failed to kill "%s"' % process_name, device=str(self)) | |
338 | |
339 @decorators.WithTimeoutAndRetriesFromInstance() | |
340 def StartActivity(self, intent, blocking=False, trace_file_name=None, | |
341 force_stop=False, timeout=None, retries=None): | |
342 """Start package's activity on the device. | |
343 | |
344 Args: | |
345 intent: An Intent to send. | |
346 blocking: A boolean indicating whether we should wait for the activity to | |
347 finish launching. | |
348 trace_file_name: If present, a string that both indicates that we want to | |
349 profile the activity and contains the path to which the | |
350 trace should be saved. | |
351 force_stop: A boolean indicating whether we should stop the activity | |
352 before starting it. | |
353 timeout: Same as for |IsOnline|. | |
354 retries: Same as for |IsOnline|. | |
frankf
2014/06/23 18:13:36
add Raises
jbudorick
2014/06/24 19:38:26
Done.
| |
355 """ | |
356 output = self.old_interface.StartActivity( | |
357 intent.package, intent.activity, wait_for_completion=blocking, | |
358 action=intent.action, category=intent.category, data=intent.data, | |
359 extras=intent.extras, trace_file_name=trace_file_name, | |
360 force_stop=force_stop, flags=intent.flags) | |
361 for l in output: | |
362 if l.startswith('Error:'): | |
363 raise device_errors.CommandFailedError(l, device=str(self)) | |
364 | |
365 @decorators.WithTimeoutAndRetriesFromInstance() | |
366 def BroadcastIntent(self, intent, timeout=None, retries=None): | |
367 """Send a broadcast intent. | |
368 | |
369 Args: | |
370 intent: An Intent to broadcast. | |
371 timeout: Same as for |IsOnline|. | |
372 retries: Same as for |IsOnline|. | |
373 """ | |
374 package, old_intent = intent.action.rsplit('.', 1) | |
375 if intent.extras is None: | |
376 args = [] | |
377 else: | |
378 args = ['-e %s%s' % (k, ' "%s"' % v if v else '') | |
379 for k, v in intent.extras.items() if len(k) > 0] | |
380 self.old_interface.BroadcastIntent(package, old_intent, *args) | |
381 | |
301 def __str__(self): | 382 def __str__(self): |
302 """Returns the device serial.""" | 383 """Returns the device serial.""" |
303 return self.old_interface.GetDevice() | 384 return self.old_interface.GetDevice() |
304 | 385 |
305 @staticmethod | 386 @staticmethod |
306 def parallel(devices=None, async=False): | 387 def parallel(devices=None, async=False): |
307 """Creates a Parallelizer to operate over the provided list of devices. | 388 """Creates a Parallelizer to operate over the provided list of devices. |
308 | 389 |
309 If |devices| is either |None| or an empty list, the Parallelizer will | 390 If |devices| is either |None| or an empty list, the Parallelizer will |
310 operate over all attached devices. | 391 operate over all attached devices. |
311 | 392 |
312 Args: | 393 Args: |
313 devices: A list of either DeviceUtils instances or objects from | 394 devices: A list of either DeviceUtils instances or objects from |
314 from which DeviceUtils instances can be constructed. If None, | 395 from which DeviceUtils instances can be constructed. If None, |
315 all attached devices will be used. | 396 all attached devices will be used. |
316 async: If true, returns a Parallelizer that runs operations | 397 async: If true, returns a Parallelizer that runs operations |
317 asynchronously. | 398 asynchronously. |
318 Returns: | 399 Returns: |
319 A Parallelizer operating over |devices|. | 400 A Parallelizer operating over |devices|. |
320 """ | 401 """ |
321 if not devices or len(devices) == 0: | 402 if not devices or len(devices) == 0: |
322 devices = pylib.android_commands.GetAttachedDevices() | 403 devices = pylib.android_commands.GetAttachedDevices() |
323 parallelizer_type = (parallelizer.Parallelizer if async | 404 parallelizer_type = (parallelizer.Parallelizer if async |
324 else parallelizer.SyncParallelizer) | 405 else parallelizer.SyncParallelizer) |
325 return parallelizer_type([ | 406 return parallelizer_type([ |
326 d if isinstance(d, DeviceUtils) else DeviceUtils(d) | 407 d if isinstance(d, DeviceUtils) else DeviceUtils(d) |
327 for d in devices]) | 408 for d in devices]) |
328 | 409 |
OLD | NEW |