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 | |
11 import time | 12 import time |
12 | 13 |
13 import pylib.android_commands | 14 import pylib.android_commands |
14 from pylib.device import adb_wrapper | 15 from pylib.device import adb_wrapper |
15 from pylib.device import decorators | 16 from pylib.device import decorators |
16 from pylib.device import device_errors | 17 from pylib.device import device_errors |
17 from pylib.utils import apk_helper | 18 from pylib.utils import apk_helper |
18 from pylib.utils import parallelizer | 19 from pylib.utils import parallelizer |
19 | 20 |
20 _DEFAULT_TIMEOUT = 30 | 21 _DEFAULT_TIMEOUT = 30 |
(...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
237 out = self.old_interface.Install(apk_path, reinstall=reinstall) | 238 out = self.old_interface.Install(apk_path, reinstall=reinstall) |
238 for line in out.splitlines(): | 239 for line in out.splitlines(): |
239 if 'Failure' in line: | 240 if 'Failure' in line: |
240 raise device_errors.CommandFailedError( | 241 raise device_errors.CommandFailedError( |
241 ['adb', 'install', apk_path], line.strip()) | 242 ['adb', 'install', apk_path], line.strip()) |
242 except AssertionError as e: | 243 except AssertionError as e: |
243 raise device_errors.CommandFailedError( | 244 raise device_errors.CommandFailedError( |
244 ['adb', 'install', apk_path], str(e)) | 245 ['adb', 'install', apk_path], str(e)) |
245 | 246 |
246 @decorators.WithTimeoutAndRetriesFromInstance() | 247 @decorators.WithTimeoutAndRetriesFromInstance() |
247 def RunShellCommand(self, cmd, check_return=False, root=False, timeout=None, | 248 def RunShellCommand(self, cmd, check_return=False, as_root=False, |
248 retries=None): | 249 timeout=None, retries=None): |
249 """Run an ADB shell command. | 250 """Run an ADB shell command. |
250 | 251 |
251 TODO(jbudorick) Switch the default value of check_return to True after | 252 TODO(jbudorick) Switch the default value of check_return to True after |
252 AndroidCommands is gone. | 253 AndroidCommands is gone. |
253 | 254 |
254 Args: | 255 Args: |
255 cmd: A list containing the command to run on the device and any arguments. | 256 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 | 257 check_return: A boolean indicating whether or not the return code should |
257 be checked. | 258 be checked. |
259 as_root: A boolean indicating whether the shell command should be run | |
260 with root privileges. | |
258 timeout: Same as for |IsOnline|. | 261 timeout: Same as for |IsOnline|. |
259 retries: Same as for |IsOnline|. | 262 retries: Same as for |IsOnline|. |
260 Raises: | 263 Raises: |
261 CommandFailedError if check_return is True and the return code is nozero. | 264 CommandFailedError if check_return is True and the return code is nozero. |
262 Returns: | 265 Returns: |
263 The output of the command. | 266 The output of the command. |
264 """ | 267 """ |
265 return self._RunShellCommandImpl(cmd, check_return=check_return, root=root, | 268 return self._RunShellCommandImpl(cmd, check_return=check_return, |
266 timeout=timeout) | 269 as_root=as_root, timeout=timeout) |
267 | 270 |
268 def _RunShellCommandImpl(self, cmd, check_return=False, root=False, | 271 def _RunShellCommandImpl(self, cmd, check_return=False, as_root=False, |
269 timeout=None): | 272 timeout=None): |
270 """Implementation of RunShellCommand. | 273 """Implementation of RunShellCommand. |
271 | 274 |
272 This is split from RunShellCommand to allow other DeviceUtils methods to | 275 This is split from RunShellCommand to allow other DeviceUtils methods to |
273 call RunShellCommand without spawning a new timeout thread. | 276 call RunShellCommand without spawning a new timeout thread. |
274 | 277 |
275 TODO(jbudorick) Remove the timeout parameter once this is no longer | 278 TODO(jbudorick) Remove the timeout parameter once this is no longer |
276 implemented via AndroidCommands. | 279 implemented via AndroidCommands. |
277 | 280 |
278 Args: | 281 Args: |
279 cmd: Same as for |RunShellCommand|. | 282 cmd: Same as for |RunShellCommand|. |
280 check_return: Same as for |RunShellCommand|. | 283 check_return: Same as for |RunShellCommand|. |
284 as_root: Same as for |RunShellCommand|. | |
281 timeout: Same as for |IsOnline|. | 285 timeout: Same as for |IsOnline|. |
282 Raises: | 286 Raises: |
283 Same as for |RunShellCommand|. | 287 Same as for |RunShellCommand|. |
284 Returns: | 288 Returns: |
285 Same as for |RunShellCommand|. | 289 Same as for |RunShellCommand|. |
286 """ | 290 """ |
287 if isinstance(cmd, list): | 291 if isinstance(cmd, list): |
288 cmd = ' '.join(cmd) | 292 cmd = ' '.join(cmd) |
289 if root and not self.HasRoot(): | 293 if as_root and not self.HasRoot(): |
290 cmd = 'su -c %s' % cmd | 294 cmd = 'su -c %s' % cmd |
291 if check_return: | 295 if check_return: |
292 code, output = self.old_interface.GetShellCommandStatusAndOutput( | 296 code, output = self.old_interface.GetShellCommandStatusAndOutput( |
293 cmd, timeout_time=timeout) | 297 cmd, timeout_time=timeout) |
294 if int(code) != 0: | 298 if int(code) != 0: |
295 raise device_errors.CommandFailedError( | 299 raise device_errors.CommandFailedError( |
296 cmd, 'Nonzero exit code (%d)' % code) | 300 cmd, 'Nonzero exit code (%d)' % code) |
297 else: | 301 else: |
298 output = self.old_interface.RunShellCommand(cmd, timeout_time=timeout) | 302 output = self.old_interface.RunShellCommand(cmd, timeout_time=timeout) |
299 return output | 303 return output |
300 | 304 |
305 @decorators.WithTimeoutAndRetriesFromInstance() | |
306 def KillAll(self, process_name, signum=signal.SIGKILL, as_root=False, | |
307 blocking=False, timeout=None, retries=None): | |
308 """Kill all processes with the given name on the device. | |
309 | |
frankf
2014/06/20 00:56:56
Update the docstring to include the exception
jbudorick
2014/06/23 16:44:02
Done.
| |
310 Args: | |
311 process_name: A string containing the name of the process to kill. | |
312 signum: An integer containing the signal number to send to kill. Defaults | |
313 to 9 (SIGKILL). | |
314 as_root: A boolean indicating whether the kill should be executed with | |
315 root priveleges. | |
316 blocking: A boolean indicating whether we should wait until all processes | |
317 with the given |process_name| are dead. | |
318 timeout: Same as for |IsOnline|. | |
319 retries: Same as for |IsOnline|. | |
320 """ | |
321 pids = self.old_interface.ExtractPid(process_name) | |
322 if len(pids) == 0: | |
323 raise device_errors.CommandFailedError( | |
324 ['adb', 'shell', 'kill'], 'No process "%s"' % process_name) | |
frankf
2014/06/20 00:56:55
Why does this include such a command list? You hav
jbudorick
2014/06/23 16:44:02
Created a new AdbCommandFailedError that derives f
| |
325 | |
326 if blocking: | |
327 total_killed = self.old_interface.KillAllBlocking( | |
328 process_name, signum=signum, with_su=as_root, timeout_sec=timeout) | |
329 else: | |
330 total_killed = self.old_interface.KillAll( | |
331 process_name, signum=signum, with_su=as_root) | |
332 if total_killed == 0: | |
333 raise device_errors.CommandFailedError( | |
334 ['adb', 'shell', 'kill'], 'Failed to kill "%s"' % process_name) | |
335 | |
336 @decorators.WithTimeoutAndRetriesFromInstance() | |
337 def StartActivity(self, intent, blocking=False, trace_file_name=None, | |
338 force_stop=False, timeout=None, retries=None): | |
339 """Start package's activity on the device. | |
340 | |
341 Args: | |
342 intent: An Intent to send. | |
343 blocking: A boolean indicating whether we should wait for the activity to | |
344 finish launching. | |
345 trace_file_name: If present, a string that both indicates that we want to | |
346 profile the activity and contains the path to which the | |
347 trace should be saved. | |
348 force_stop: A boolean indicating whether we should stop the activity | |
349 before starting it. | |
350 timeout: Same as for |IsOnline|. | |
351 retries: Same as for |IsOnline|. | |
352 """ | |
353 output = self.old_interface.StartActivity( | |
354 intent.package, intent.activity, wait_for_completion=blocking, | |
355 action=intent.action, category=intent.category, data=intent.data, | |
356 extras=intent.extras, trace_file_name=trace_file_name, | |
357 force_stop=force_stop, flags=intent.flags) | |
358 for l in output: | |
359 if l.startswith('Error:'): | |
360 raise device_errors.CommandFailedError( | |
361 ['adb', 'shell', 'am', 'start'], l) | |
frankf
2014/06/20 00:56:55
same here
jbudorick
2014/06/23 16:44:02
using the reworked CommandFailedError, as describe
| |
362 | |
363 @decorators.WithTimeoutAndRetriesFromInstance() | |
364 def BroadcastIntent(self, intent, timeout=None, retries=None): | |
365 """Send a broadcast intent. | |
366 | |
367 Args: | |
368 intent: An Intent to broadcast. | |
369 timeout: Same as for |IsOnline|. | |
370 retries: Same as for |IsOnline|. | |
371 """ | |
372 package, old_intent = intent.action.rsplit('.', 1) | |
373 if intent.extras is None: | |
374 args = [] | |
375 else: | |
376 args = ['-e %s%s' % (k, ' "%s"' % v if v else '') | |
377 for k, v in intent.extras.items() if len(k) > 0] | |
378 self.old_interface.BroadcastIntent(package, old_intent, *args) | |
379 | |
301 def __str__(self): | 380 def __str__(self): |
302 """Returns the device serial.""" | 381 """Returns the device serial.""" |
303 return self.old_interface.GetDevice() | 382 return self.old_interface.GetDevice() |
304 | 383 |
305 @staticmethod | 384 @staticmethod |
306 def parallel(devices=None, async=False): | 385 def parallel(devices=None, async=False): |
307 """Creates a Parallelizer to operate over the provided list of devices. | 386 """Creates a Parallelizer to operate over the provided list of devices. |
308 | 387 |
309 If |devices| is either |None| or an empty list, the Parallelizer will | 388 If |devices| is either |None| or an empty list, the Parallelizer will |
310 operate over all attached devices. | 389 operate over all attached devices. |
311 | 390 |
312 Args: | 391 Args: |
313 devices: A list of either DeviceUtils instances or objects from | 392 devices: A list of either DeviceUtils instances or objects from |
314 from which DeviceUtils instances can be constructed. If None, | 393 from which DeviceUtils instances can be constructed. If None, |
315 all attached devices will be used. | 394 all attached devices will be used. |
316 async: If true, returns a Parallelizer that runs operations | 395 async: If true, returns a Parallelizer that runs operations |
317 asynchronously. | 396 asynchronously. |
318 Returns: | 397 Returns: |
319 A Parallelizer operating over |devices|. | 398 A Parallelizer operating over |devices|. |
320 """ | 399 """ |
321 if not devices or len(devices) == 0: | 400 if not devices or len(devices) == 0: |
322 devices = pylib.android_commands.GetAttachedDevices() | 401 devices = pylib.android_commands.GetAttachedDevices() |
323 parallelizer_type = (parallelizer.Parallelizer if async | 402 parallelizer_type = (parallelizer.Parallelizer if async |
324 else parallelizer.SyncParallelizer) | 403 else parallelizer.SyncParallelizer) |
325 return parallelizer_type([ | 404 return parallelizer_type([ |
326 d if isinstance(d, DeviceUtils) else DeviceUtils(d) | 405 d if isinstance(d, DeviceUtils) else DeviceUtils(d) |
327 for d in devices]) | 406 for d in devices]) |
328 | 407 |
OLD | NEW |