Index: build/android/pylib/device/device_utils.py |
diff --git a/build/android/pylib/device/device_utils.py b/build/android/pylib/device/device_utils.py |
index 27e3d418d1d5f5aa960adadd81d6912076da691c..e4c66525d193bf972989dd889a04672d0f8f04f4 100644 |
--- a/build/android/pylib/device/device_utils.py |
+++ b/build/android/pylib/device/device_utils.py |
@@ -8,6 +8,7 @@ Eventually, this will be based on adb_wrapper. |
""" |
# pylint: disable=W0613 |
+import sys |
import time |
import pylib.android_commands |
@@ -124,7 +125,7 @@ class DeviceUtils(object): |
""" |
if not self.old_interface.EnableAdbRoot(): |
raise device_errors.CommandFailedError( |
- ['adb', 'root'], 'Could not enable root.') |
+ 'Could not enable root.', device=str(self)) |
@decorators.WithTimeoutAndRetriesFromInstance() |
def GetExternalStoragePath(self, timeout=None, retries=None): |
@@ -140,7 +141,7 @@ class DeviceUtils(object): |
return self.old_interface.GetExternalStorage() |
except AssertionError as e: |
raise device_errors.CommandFailedError( |
- ['adb', 'shell', 'echo', '$EXTERNAL_STORAGE'], str(e)) |
+ str(e), device=str(self)), None, sys.exc_info()[2] |
@decorators.WithTimeoutAndRetriesFromInstance() |
def WaitUntilFullyBooted(self, wifi=False, timeout=None, retries=None): |
@@ -235,7 +236,7 @@ class DeviceUtils(object): |
for line in out.splitlines(): |
if 'Failure' in line: |
raise device_errors.CommandFailedError( |
- ['adb', 'uninstall', package_name], line.strip()) |
+ line.strip(), device=str(self)) |
else: |
should_install = False |
else: |
@@ -246,14 +247,14 @@ class DeviceUtils(object): |
for line in out.splitlines(): |
if 'Failure' in line: |
raise device_errors.CommandFailedError( |
- ['adb', 'install', apk_path], line.strip()) |
+ line.strip(), device=str(self)) |
except AssertionError as e: |
raise device_errors.CommandFailedError( |
- ['adb', 'install', apk_path], str(e)) |
+ str(e), device=str(self)), None, sys.exc_info()[2] |
@decorators.WithTimeoutAndRetriesFromInstance() |
- def RunShellCommand(self, cmd, check_return=False, root=False, timeout=None, |
- retries=None): |
+ def RunShellCommand(self, cmd, check_return=False, as_root=False, |
+ timeout=None, retries=None): |
"""Run an ADB shell command. |
TODO(jbudorick) Switch the default value of check_return to True after |
@@ -263,6 +264,8 @@ class DeviceUtils(object): |
cmd: A list containing the command to run on the device and any arguments. |
check_return: A boolean indicating whether or not the return code should |
be checked. |
+ as_root: A boolean indicating whether the shell command should be run |
+ with root privileges. |
timeout: Same as for |IsOnline|. |
retries: Same as for |IsOnline|. |
Raises: |
@@ -270,10 +273,10 @@ class DeviceUtils(object): |
Returns: |
The output of the command. |
""" |
- return self._RunShellCommandImpl(cmd, check_return=check_return, root=root, |
- timeout=timeout) |
+ return self._RunShellCommandImpl(cmd, check_return=check_return, |
+ as_root=as_root, timeout=timeout) |
- def _RunShellCommandImpl(self, cmd, check_return=False, root=False, |
+ def _RunShellCommandImpl(self, cmd, check_return=False, as_root=False, |
timeout=None): |
"""Implementation of RunShellCommand. |
@@ -286,6 +289,7 @@ class DeviceUtils(object): |
Args: |
cmd: Same as for |RunShellCommand|. |
check_return: Same as for |RunShellCommand|. |
+ as_root: Same as for |RunShellCommand|. |
timeout: Same as for |IsOnline|. |
Raises: |
Same as for |RunShellCommand|. |
@@ -294,18 +298,98 @@ class DeviceUtils(object): |
""" |
if isinstance(cmd, list): |
cmd = ' '.join(cmd) |
- if root and not self.HasRoot(): |
+ if as_root and not self.HasRoot(): |
cmd = 'su -c %s' % cmd |
if check_return: |
code, output = self.old_interface.GetShellCommandStatusAndOutput( |
cmd, timeout_time=timeout) |
if int(code) != 0: |
- raise device_errors.CommandFailedError( |
- cmd.split(), 'Nonzero exit code (%d)' % code) |
+ raise device_errors.AdbCommandFailedError( |
+ cmd.split(), 'Nonzero exit code (%d)' % code, device=str(self)) |
else: |
output = self.old_interface.RunShellCommand(cmd, timeout_time=timeout) |
return output |
+ @decorators.WithTimeoutAndRetriesFromInstance() |
+ def KillAll(self, process_name, signum=9, as_root=False, blocking=False, |
+ timeout=None, retries=None): |
+ """Kill all processes with the given name on the device. |
+ |
+ Args: |
+ process_name: A string containing the name of the process to kill. |
+ signum: An integer containing the signal number to send to kill. Defaults |
+ to 9 (SIGKILL). |
+ as_root: A boolean indicating whether the kill should be executed with |
+ root priveleges. |
+ blocking: A boolean indicating whether we should wait until all processes |
+ with the given |process_name| are dead. |
+ timeout: Same as for |IsOnline|. |
+ retries: Same as for |IsOnline|. |
+ Raises: |
+ CommandFailedError if no process was killed. |
+ """ |
+ pids = self.old_interface.ExtractPid(process_name) |
+ if len(pids) == 0: |
+ raise device_errors.CommandFailedError( |
+ 'No process "%s"' % process_name, device=str(self)) |
+ |
+ if blocking: |
+ total_killed = self.old_interface.KillAllBlocking( |
+ process_name, signum=signum, with_su=as_root, timeout_sec=timeout) |
+ else: |
+ total_killed = self.old_interface.KillAll( |
+ process_name, signum=signum, with_su=as_root) |
+ if total_killed == 0: |
+ raise device_errors.CommandFailedError( |
+ 'Failed to kill "%s"' % process_name, device=str(self)) |
+ |
+ @decorators.WithTimeoutAndRetriesFromInstance() |
+ def StartActivity(self, intent, blocking=False, trace_file_name=None, |
+ force_stop=False, timeout=None, retries=None): |
+ """Start package's activity on the device. |
+ |
+ Args: |
+ intent: An Intent to send. |
+ blocking: A boolean indicating whether we should wait for the activity to |
+ finish launching. |
+ trace_file_name: If present, a string that both indicates that we want to |
+ profile the activity and contains the path to which the |
+ trace should be saved. |
+ force_stop: A boolean indicating whether we should stop the activity |
+ before starting it. |
+ timeout: Same as for |IsOnline|. |
+ retries: Same as for |IsOnline|. |
+ Raises: |
+ CommandFailedError if the activity could not be started. |
+ """ |
+ single_category = (intent.category[0] if isinstance(intent.category, list) |
+ else intent.category) |
+ output = self.old_interface.StartActivity( |
+ intent.package, intent.activity, wait_for_completion=blocking, |
+ action=intent.action, category=single_category, data=intent.data, |
+ extras=intent.extras, trace_file_name=trace_file_name, |
+ force_stop=force_stop, flags=intent.flags) |
+ for l in output: |
+ if l.startswith('Error:'): |
+ raise device_errors.CommandFailedError(l, device=str(self)) |
+ |
+ @decorators.WithTimeoutAndRetriesFromInstance() |
+ def BroadcastIntent(self, intent, timeout=None, retries=None): |
+ """Send a broadcast intent. |
+ |
+ Args: |
+ intent: An Intent to broadcast. |
+ timeout: Same as for |IsOnline|. |
+ retries: Same as for |IsOnline|. |
+ """ |
+ package, old_intent = intent.action.rsplit('.', 1) |
+ if intent.extras is None: |
+ args = [] |
+ else: |
+ args = ['-e %s%s' % (k, ' "%s"' % v if v else '') |
+ for k, v in intent.extras.items() if len(k) > 0] |
+ self.old_interface.BroadcastIntent(package, old_intent, *args) |
+ |
def __str__(self): |
"""Returns the device serial.""" |
return self.old_interface.GetDevice() |