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 b2fa1ff3953a702f6cd3676f495db89144dcf0d7..2c507204e424c34a0424d710e7f6cb7adfed2b5b 100644 |
--- a/build/android/pylib/device/device_utils.py |
+++ b/build/android/pylib/device/device_utils.py |
@@ -26,6 +26,7 @@ from pylib.device.commands import install_commands |
from pylib.utils import apk_helper |
from pylib.utils import host_utils |
from pylib.utils import parallelizer |
+from pylib.utils import timeout_retry |
_DEFAULT_TIMEOUT = 30 |
_DEFAULT_RETRIES = 3 |
@@ -108,10 +109,7 @@ class DeviceUtils(object): |
Raises: |
CommandTimeoutError on timeout. |
""" |
- return self._IsOnlineImpl() |
- |
- def _IsOnlineImpl(self): |
- return self.old_interface.IsOnline() |
+ return self.adb.GetState() == 'device' |
@decorators.WithTimeoutAndRetriesFromInstance() |
def HasRoot(self, timeout=None, retries=None): |
@@ -169,7 +167,7 @@ class DeviceUtils(object): |
CommandTimeoutError on timeout. |
DeviceUnreachableError on missing device. |
""" |
- return self._GetPropImpl('ro.build.type') == 'user' |
+ return self.build_type == 'user' |
@decorators.WithTimeoutAndRetriesFromInstance() |
def GetExternalStoragePath(self, timeout=None, retries=None): |
@@ -203,6 +201,25 @@ class DeviceUtils(object): |
return value |
@decorators.WithTimeoutAndRetriesFromInstance() |
+ def GetApplicationPath(self, package, timeout=None, retries=None): |
+ """Get the path of the installed apk on the device for the given package. |
+ |
+ Args: |
+ package: Name of the package. |
+ |
+ Returns: |
+ Path to the apk on the device if it exists, None otherwise. |
+ """ |
+ output = self.RunShellCommand(['pm', 'path', package], single_line=True, |
+ check_return=True) |
+ if not output: |
+ return None |
+ if not output.startswith('package:'): |
+ raise device_errors.CommandFailedError('pm path returned: %r' % output, |
+ str(self)) |
+ return output[len('package:'):] |
+ |
+ @decorators.WithTimeoutAndRetriesFromInstance() |
def WaitUntilFullyBooted(self, wifi=False, timeout=None, retries=None): |
"""Wait for the device to fully boot. |
@@ -220,18 +237,28 @@ class DeviceUtils(object): |
CommandTimeoutError if one of the component waits times out. |
DeviceUnreachableError if the device becomes unresponsive. |
""" |
- self._WaitUntilFullyBootedImpl(wifi=wifi, timeout=timeout) |
+ def sd_card_ready(): |
+ return self.RunShellCommand(['ls', self.GetExternalStoragePath()], |
+ single_line=True, check_return=True) |
- def _WaitUntilFullyBootedImpl(self, wifi=False, timeout=None): |
- if timeout is None: |
- timeout = self._default_timeout |
- self.old_interface.WaitForSystemBootCompleted(timeout) |
- self.old_interface.WaitForDevicePm() |
- self.old_interface.WaitForSdCardReady(timeout) |
+ def pm_ready(): |
+ try: |
+ return self.GetApplicationPath('android') |
+ except device_errors.CommandFailedError: |
+ return False |
+ |
+ def boot_completed(): |
+ return self.GetProp('sys.boot_completed') == '1' |
+ |
+ def wifi_enabled(): |
+ return 'Wi-Fi is enabled' in self.RunShellCommand(['dumpsys', 'wifi']) |
+ |
+ self.adb.WaitForDevice() |
+ timeout_retry.WaitFor(sd_card_ready) |
+ timeout_retry.WaitFor(pm_ready) |
+ timeout_retry.WaitFor(boot_completed) |
if wifi: |
- while not 'Wi-Fi is enabled' in ( |
- self.old_interface.RunShellCommand('dumpsys wifi')): |
- time.sleep(1) |
+ timeout_retry.WaitFor(wifi_enabled) |
REBOOT_DEFAULT_TIMEOUT = 10 * _DEFAULT_TIMEOUT |
REBOOT_DEFAULT_RETRIES = _DEFAULT_RETRIES |
@@ -251,9 +278,14 @@ class DeviceUtils(object): |
CommandTimeoutError on timeout. |
DeviceUnreachableError on missing device. |
""" |
- self.old_interface.Reboot() |
+ def device_offline(): |
+ return not self.IsOnline() |
+ |
+ self.adb.Reboot() |
+ self._cache = {} |
+ timeout_retry.WaitFor(device_offline, wait_period=1, max_tries=5) |
if block: |
- self._WaitUntilFullyBootedImpl(timeout=timeout) |
+ self.WaitUntilFullyBooted() |
INSTALL_DEFAULT_TIMEOUT = 4 * _DEFAULT_TIMEOUT |
INSTALL_DEFAULT_RETRIES = _DEFAULT_RETRIES |
@@ -339,21 +371,21 @@ class DeviceUtils(object): |
env: The environment variables with which the command should be run. |
as_root: A boolean indicating whether the shell command should be run |
with root privileges. |
- single_line: A boolean indicating if a single line of output is expected, |
- and the caller wants to retrieve the value of that line. The default |
- behaviour is to return a list of output lines. |
+ single_line: A boolean indicating if only a single line of output is |
+ expected. |
timeout: timeout in seconds |
retries: number of retries |
Returns: |
- The output of the command either as list of lines or, when single_line is |
- True, the value contained in the single expected line of output. |
+ If single_line is False, the output of the command as a list of lines, |
+ otherwise, a string with the unique line of output emmited by the command |
+ (with the optional newline at the end stripped). |
Raises: |
AdbShellCommandFailedError if check_return is True and the exit code of |
the command run on the device is non-zero. |
- CommandFailedError if single_line is True but the output consists of |
- either zero or more than one lines. |
+ CommandFailedError if single_line is True but the output contains two or |
+ more lines. |
CommandTimeoutError on timeout. |
DeviceUnreachableError on missing device. |
""" |
@@ -392,10 +424,13 @@ class DeviceUtils(object): |
output = output.splitlines() |
if single_line: |
- if len(output) != 1: |
- msg = 'exactly one line of output expected, but got: %s' |
- raise device_errors.CommandFailedError(msg % output) |
- return output[0] |
+ if not output: |
+ return '' |
+ elif len(output) == 1: |
+ return output[0] |
+ else: |
+ msg = 'one line of output was expected, but got: %s' |
+ raise device_errors.CommandFailedError(msg % output, str(self)) |
else: |
return output |
@@ -619,6 +654,8 @@ class DeviceUtils(object): |
real_device_path = self._RunShellCommandImpl( |
['realpath', device_path], single_line=True, check_return=True) |
except device_errors.CommandFailedError: |
+ real_device_path = None |
+ if not real_device_path: |
return [(host_path, device_path)] |
# TODO(jbudorick): Move the md5 logic up into DeviceUtils or base |
@@ -715,7 +752,7 @@ class DeviceUtils(object): |
finally: |
if zip_proc.is_alive(): |
zip_proc.terminate() |
- if self._IsOnlineImpl(): |
+ if self.IsOnline(): |
self._RunShellCommandImpl(['rm', zip_on_device], check_return=True) |
@staticmethod |
@@ -894,13 +931,18 @@ class DeviceUtils(object): |
""" |
return self.old_interface.SetJavaAssertsEnabled(enabled) |
- @decorators.WithTimeoutAndRetriesFromInstance() |
- def GetProp(self, property_name, timeout=None, retries=None): |
+ @property |
+ def build_type(self): |
+ """Returns the build type of the system (e.g. userdebug).""" |
+ return self.GetProp('ro.build.type', cache=True) |
+ |
+ def GetProp(self, property_name, cache=False, timeout=None, retries=None): |
"""Gets a property from the device. |
Args: |
property_name: A string containing the name of the property to get from |
the device. |
+ cache: A boolean indicating whether to cache the value of this property. |
timeout: timeout in seconds |
retries: number of retries |
@@ -910,13 +952,22 @@ class DeviceUtils(object): |
Raises: |
CommandTimeoutError on timeout. |
""" |
- return self._GetPropImpl(property_name) |
- |
- def _GetPropImpl(self, property_name): |
- return self.old_interface.system_properties[property_name] |
+ cache_key = '_prop:' + property_name |
+ if cache and cache_key in self._cache: |
+ return self._cache[cache_key] |
+ else: |
+ # timeout and retries are handled down at run shell, because we don't |
+ # want to apply them in the other branch when reading from the cache |
+ value = self.RunShellCommand(['getprop', property_name], |
+ single_line=True, check_return=True, |
+ timeout=timeout, retries=retries) |
+ if cache or cache_key in self._cache: |
+ self._cache[cache_key] = value |
+ return value |
@decorators.WithTimeoutAndRetriesFromInstance() |
- def SetProp(self, property_name, value, timeout=None, retries=None): |
+ def SetProp(self, property_name, value, check=False, timeout=None, |
+ retries=None): |
"""Sets a property on the device. |
Args: |
@@ -924,13 +975,25 @@ class DeviceUtils(object): |
the device. |
value: A string containing the value to set to the property on the |
device. |
+ check: A boolean indicating whether to check that the property was |
+ successfully set on the device. |
timeout: timeout in seconds |
retries: number of retries |
Raises: |
+ CommandFailedError if check is true and the property was not correctly |
+ set on the device (e.g. because it is not rooted). |
CommandTimeoutError on timeout. |
""" |
- self.old_interface.system_properties[property_name] = value |
+ self.RunShellCommand(['setprop', property_name, value], check_return=True) |
+ if property_name in self._cache: |
+ del self._cache[property_name] |
+ # TODO(perezju) remove the option and make the check mandatory, but using a |
+ # single shell script to both set- and getprop. |
+ if check and value != self.GetProp(property_name): |
+ raise device_errors.CommandFailedError( |
+ 'Unable to set property %r on the device to %r' |
+ % (property_name, value), str(self)) |
@decorators.WithTimeoutAndRetriesFromInstance() |
def GetABI(self, timeout=None, retries=None): |