device_utils.py revision cedac228d2dd51db4b79ea1e72c7f249408ee061
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
3# found in the LICENSE file.
4
5"""
6Provides a variety of device interactions based on adb.
7
8Eventually, this will be based on adb_wrapper.
9"""
10# pylint: disable=W0613
11
12import time
13
14import pylib.android_commands
15from pylib.device import adb_wrapper
16from pylib.device import decorators
17from pylib.device import device_errors
18from pylib.utils import parallelizer
19
20_DEFAULT_TIMEOUT = 30
21_DEFAULT_RETRIES = 3
22
23
24@decorators.WithExplicitTimeoutAndRetries(
25    _DEFAULT_TIMEOUT, _DEFAULT_RETRIES)
26def GetAVDs():
27  """ Returns a list of Android Virtual Devices.
28
29  Returns:
30    A list containing the configured AVDs.
31  """
32  return pylib.android_commands.GetAVDs()
33
34
35@decorators.WithExplicitTimeoutAndRetries(
36    _DEFAULT_TIMEOUT, _DEFAULT_RETRIES)
37def RestartServer():
38  """ Restarts the adb server.
39
40  Raises:
41    CommandFailedError if we fail to kill or restart the server.
42  """
43  pylib.android_commands.AndroidCommands().RestartAdbServer()
44
45
46class DeviceUtils(object):
47
48  def __init__(self, device, default_timeout=_DEFAULT_TIMEOUT,
49               default_retries=_DEFAULT_RETRIES):
50    """ DeviceUtils constructor.
51
52    Args:
53      device: Either a device serial, an existing AdbWrapper instance, an
54              an existing AndroidCommands instance, or nothing.
55      default_timeout: An integer containing the default number of seconds to
56                       wait for an operation to complete if no explicit value
57                       is provided.
58      default_retries: An integer containing the default number or times an
59                       operation should be retried on failure if no explicit
60                       value is provided.
61    """
62    self.old_interface = None
63    if isinstance(device, basestring):
64      self.old_interface = pylib.android_commands.AndroidCommands(device)
65    elif isinstance(device, adb_wrapper.AdbWrapper):
66      self.old_interface = pylib.android_commands.AndroidCommands(str(device))
67    elif isinstance(device, pylib.android_commands.AndroidCommands):
68      self.old_interface = device
69    elif not device:
70      self.old_interface = pylib.android_commands.AndroidCommands()
71    else:
72      raise ValueError('Unsupported type passed for argument "device"')
73    self._default_timeout = default_timeout
74    self._default_retries = default_retries
75    assert(hasattr(self, decorators.DEFAULT_TIMEOUT_ATTR))
76    assert(hasattr(self, decorators.DEFAULT_RETRIES_ATTR))
77
78  @decorators.WithTimeoutAndRetriesFromInstance()
79  def IsOnline(self, timeout=None, retries=None):
80    """ Checks whether the device is online.
81
82    Args:
83      timeout: An integer containing the number of seconds to wait for the
84               operation to complete.
85      retries: An integer containing the number of times the operation should
86               be retried if it fails.
87    Returns:
88      True if the device is online, False otherwise.
89    """
90    return self.old_interface.IsOnline()
91
92  @decorators.WithTimeoutAndRetriesFromInstance()
93  def HasRoot(self, timeout=None, retries=None):
94    """ Checks whether or not adbd has root privileges.
95
96    Args:
97      timeout: Same as for |IsOnline|.
98      retries: Same as for |IsOnline|.
99    Returns:
100      True if adbd has root privileges, False otherwise.
101    """
102    return self.old_interface.IsRootEnabled()
103
104  @decorators.WithTimeoutAndRetriesFromInstance()
105  def EnableRoot(self, timeout=None, retries=None):
106    """ Restarts adbd with root privileges.
107
108    Args:
109      timeout: Same as for |IsOnline|.
110      retries: Same as for |IsOnline|.
111    Raises:
112      CommandFailedError if root could not be enabled.
113    """
114    if not self.old_interface.EnableAdbRoot():
115      raise device_errors.CommandFailedError(
116          'adb root', 'Could not enable root.')
117
118  @decorators.WithTimeoutAndRetriesFromInstance()
119  def GetExternalStoragePath(self, timeout=None, retries=None):
120    """ Get the device's path to its SD card.
121
122    Args:
123      timeout: Same as for |IsOnline|.
124      retries: Same as for |IsOnline|.
125    Returns:
126      The device's path to its SD card.
127    """
128    try:
129      return self.old_interface.GetExternalStorage()
130    except AssertionError as e:
131      raise device_errors.CommandFailedError(str(e))
132
133  @decorators.WithTimeoutAndRetriesFromInstance()
134  def WaitUntilFullyBooted(self, wifi=False, timeout=None, retries=None):
135    """ Wait for the device to fully boot.
136
137    This means waiting for the device to boot, the package manager to be
138    available, and the SD card to be ready. It can optionally mean waiting
139    for wifi to come up, too.
140
141    Args:
142      wifi: A boolean indicating if we should wait for wifi to come up or not.
143      timeout: Same as for |IsOnline|.
144      retries: Same as for |IsOnline|.
145    Raises:
146      CommandTimeoutError if one of the component waits times out.
147      DeviceUnreachableError if the device becomes unresponsive.
148    """
149    self.old_interface.WaitForSystemBootCompleted(timeout)
150    self.old_interface.WaitForDevicePm()
151    self.old_interface.WaitForSdCardReady(timeout)
152    if wifi:
153      while not 'Wi-Fi is enabled' in (
154          self.old_interface.RunShellCommand('dumpsys wifi')):
155        time.sleep(0.1)
156
157  def __str__(self):
158    """Returns the device serial."""
159    return self.old_interface.GetDevice()
160
161  @staticmethod
162  def parallel(devices=None, async=False):
163    """ Creates a Parallelizer to operate over the provided list of devices.
164
165    If |devices| is either |None| or an empty list, the Parallelizer will
166    operate over all attached devices.
167
168    Args:
169      devices: A list of either DeviceUtils instances or objects from
170               from which DeviceUtils instances can be constructed. If None,
171               all attached devices will be used.
172      async: If true, returns a Parallelizer that runs operations
173             asynchronously.
174    Returns:
175      A Parallelizer operating over |devices|.
176    """
177    if not devices or len(devices) == 0:
178      devices = pylib.android_commands.GetAttachedDevices()
179    parallelizer_type = (parallelizer.Parallelizer if async
180                         else parallelizer.SyncParallelizer)
181    return parallelizer_type([
182        d if isinstance(d, DeviceUtils) else DeviceUtils(d)
183        for d in devices])
184
185