Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4902)

Unified Diff: build/android/pylib/device/device_utils.py

Issue 636273004: Make TimeoutRetryThread's stoppable (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: moved check for timed out thread into adb_wrapper Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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..9b42727ab942f1027bc7781273a59e51b4274d03 100644
--- a/build/android/pylib/device/device_utils.py
+++ b/build/android/pylib/device/device_utils.py
@@ -14,6 +14,7 @@ import os
import re
import sys
import tempfile
+import threading
import time
import zipfile
@@ -108,10 +109,8 @@ class DeviceUtils(object):
Raises:
CommandTimeoutError on timeout.
"""
- return self._IsOnlineImpl()
-
- def _IsOnlineImpl(self):
- return self.old_interface.IsOnline()
+ state = self.adb.GetState()
+ return state == 'device'
@decorators.WithTimeoutAndRetriesFromInstance()
def HasRoot(self, timeout=None, retries=None):
@@ -169,7 +168,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 +202,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 +238,61 @@ 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():
+ return self.GetApplicationPath('android')
+
+ 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()
+ self._WaitFor(sd_card_ready)
+ self._WaitFor(pm_ready)
+ self._WaitFor(boot_completed)
if wifi:
- while not 'Wi-Fi is enabled' in (
- self.old_interface.RunShellCommand('dumpsys wifi')):
- time.sleep(1)
+ self._WaitFor(wifi_enabled)
+
+ def _WaitFor(self, condition, wait_period=5, max_tries=None):
+ """Wait for a condition to become true.
+
+ Repeadly call the function condition(), with no arguments, until it returns
+ a true value.
+
+ This method assumes that it is being called within a TimeoutRetryThread.
+
+ Args:
+ condition: function with the condition to check
+ wait_period: how long to wait before retrying to check the condition
+ max_tries: maximum number of checks to make, the default tries forever
+ (usually until a timeout error is raised)
+
+ Returns:
+ The true value returned by the condition, or None if the condition was
+ not met after max_tries.
+ """
+ thread = threading.current_thread()
+ while max_tries is None or max_tries > 0:
+ try:
+ r = condition()
+ except device_errors.CommandFailedError:
+ r = None
perezju 2014/10/28 14:31:18 clients don't need to check whether their thread h
+ if max_tries is not None:
+ max_tries -= 1
+ if r:
+ logging.info('(device: %s) condition %r met (%1.2fs) at %s',
+ str(self), condition.__name__, thread.ElapsedTime(), thread.name)
+ return r
+ else:
+ logging.info('(device: %s) condition %r not yet met (%1.2fs) at %s',
+ str(self), condition.__name__, thread.ElapsedTime(), thread.name)
+ self.adb.Wait(wait_period)
perezju 2014/10/28 14:31:18 well, almost... time.sleep needs would need to be
+ return None
REBOOT_DEFAULT_TIMEOUT = 10 * _DEFAULT_TIMEOUT
REBOOT_DEFAULT_RETRIES = _DEFAULT_RETRIES
@@ -251,9 +312,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 = {}
+ self._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
@@ -392,10 +458,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 ''
perezju 2014/10/28 14:31:18 this is what "pm path" returns for non-existent pa
jbudorick 2014/10/28 17:28:46 sgtm
+ 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
@@ -715,7 +784,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 +963,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 +984,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 +1007,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):

Powered by Google App Engine
This is Rietveld 408576698