Chromium Code Reviews| 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 logging | 11 import logging |
| 12 import multiprocessing | 12 import multiprocessing |
| 13 import os | 13 import os |
| 14 import re | 14 import re |
| 15 import sys | 15 import sys |
| 16 import tempfile | 16 import tempfile |
| 17 import threading | |
| 17 import time | 18 import time |
| 18 import zipfile | 19 import zipfile |
| 19 | 20 |
| 20 import pylib.android_commands | 21 import pylib.android_commands |
| 21 from pylib import cmd_helper | 22 from pylib import cmd_helper |
| 22 from pylib.device import adb_wrapper | 23 from pylib.device import adb_wrapper |
| 23 from pylib.device import decorators | 24 from pylib.device import decorators |
| 24 from pylib.device import device_errors | 25 from pylib.device import device_errors |
| 25 from pylib.device.commands import install_commands | 26 from pylib.device.commands import install_commands |
| 26 from pylib.utils import apk_helper | 27 from pylib.utils import apk_helper |
| (...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 213 Args: | 214 Args: |
| 214 wifi: A boolean indicating if we should wait for wifi to come up or not. | 215 wifi: A boolean indicating if we should wait for wifi to come up or not. |
| 215 timeout: timeout in seconds | 216 timeout: timeout in seconds |
| 216 retries: number of retries | 217 retries: number of retries |
| 217 | 218 |
| 218 Raises: | 219 Raises: |
| 219 CommandFailedError on failure. | 220 CommandFailedError on failure. |
| 220 CommandTimeoutError if one of the component waits times out. | 221 CommandTimeoutError if one of the component waits times out. |
| 221 DeviceUnreachableError if the device becomes unresponsive. | 222 DeviceUnreachableError if the device becomes unresponsive. |
| 222 """ | 223 """ |
| 223 self._WaitUntilFullyBootedImpl(wifi=wifi, timeout=timeout) | 224 def sd_card_ready(): |
| 225 return self.RunShellCommand(['ls', self.GetExternalStoragePath()]) | |
| 224 | 226 |
| 225 def _WaitUntilFullyBootedImpl(self, wifi=False, timeout=None): | 227 def pm_ready(): |
| 226 if timeout is None: | 228 return self.GetApplicationPath('android') |
| 227 timeout = self._default_timeout | 229 |
| 228 self.old_interface.WaitForSystemBootCompleted(timeout) | 230 def boot_completed(): |
| 229 self.old_interface.WaitForDevicePm() | 231 return self.GetProp('sys.boot_completed') == '1' |
| 230 self.old_interface.WaitForSdCardReady(timeout) | 232 |
| 233 def wifi_enabled(): | |
| 234 return 'Wi-Fi is enabled' in self.RunShellCommand(['dumpsys', 'wifi']) | |
| 235 | |
| 236 self.adb.WaitForDevice() | |
| 237 self._WaitFor(sd_card_ready) | |
| 238 self._WaitFor(pm_ready) | |
| 239 self._WaitFor(boot_completed) | |
| 231 if wifi: | 240 if wifi: |
| 232 while not 'Wi-Fi is enabled' in ( | 241 self._WaitFor(wifi_enabled) |
| 233 self.old_interface.RunShellCommand('dumpsys wifi')): | 242 |
| 234 time.sleep(1) | 243 def _WaitFor(self, condition, wait_period=5): |
| 244 start = time.time() | |
| 245 while not threading.current_thread().Stopped(): | |
| 246 try: | |
| 247 r = condition() | |
| 248 except device_errors.CommandFailedError as e: | |
| 249 r = False | |
|
jbudorick
2014/10/24 17:30:51
nit: similarly here w.r.t False v None
| |
| 250 logging.warning('%s at %s', str(e), threading.current_thread().name) | |
| 251 elapsed = time.time() - start | |
| 252 if r: | |
| 253 logging.warning('%s: condition %r met (%1.2f) at %s', str(self), | |
|
jbudorick
2014/10/24 17:30:51
nit: should be info or debug, not warning
perezju
2014/10/27 11:07:07
Yes, I agree these should be info. At the moment t
| |
| 254 condition.__name__, elapsed, threading.current_thread().nam e) | |
| 255 return r | |
| 256 time.sleep(wait_period) | |
| 257 logging.warning('%s: condition %r not yet met (%1.2f) at %s', str(self), | |
| 258 condition.__name__, elapsed, threading.current_thread().name) | |
| 259 return False | |
|
jbudorick
2014/10/24 17:30:51
nit: I think this should return None, as False imp
perezju
2014/10/27 11:07:06
Agree.
| |
| 260 | |
| 261 @decorators.WithTimeoutAndRetriesFromInstance() | |
| 262 def GetApplicationPath(self, package, timeout=None, retries=None): | |
| 263 output = self.RunShellCommand(['pm', 'path', package], single_line=True) | |
| 264 if not output.startswith('package:'): | |
| 265 raise device_errors.CommandFailedError('pm path returned: %r' % output, st r(self)) | |
| 266 return output[len('package:'):] | |
| 267 | |
| 235 | 268 |
| 236 REBOOT_DEFAULT_TIMEOUT = 10 * _DEFAULT_TIMEOUT | 269 REBOOT_DEFAULT_TIMEOUT = 10 * _DEFAULT_TIMEOUT |
| 237 REBOOT_DEFAULT_RETRIES = _DEFAULT_RETRIES | 270 REBOOT_DEFAULT_RETRIES = _DEFAULT_RETRIES |
| 238 | 271 |
| 239 @decorators.WithTimeoutAndRetriesDefaults( | 272 @decorators.WithTimeoutAndRetriesDefaults( |
| 240 REBOOT_DEFAULT_TIMEOUT, | 273 REBOOT_DEFAULT_TIMEOUT, |
| 241 REBOOT_DEFAULT_RETRIES) | 274 REBOOT_DEFAULT_RETRIES) |
| 242 def Reboot(self, block=True, timeout=None, retries=None): | 275 def Reboot(self, block=True, timeout=None, retries=None): |
| 243 """Reboot the device. | 276 """Reboot the device. |
| 244 | 277 |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 387 except device_errors.AdbShellCommandFailedError as e: | 420 except device_errors.AdbShellCommandFailedError as e: |
| 388 if check_return: | 421 if check_return: |
| 389 raise | 422 raise |
| 390 else: | 423 else: |
| 391 output = e.output | 424 output = e.output |
| 392 | 425 |
| 393 output = output.splitlines() | 426 output = output.splitlines() |
| 394 if single_line: | 427 if single_line: |
| 395 if len(output) != 1: | 428 if len(output) != 1: |
| 396 msg = 'exactly one line of output expected, but got: %s' | 429 msg = 'exactly one line of output expected, but got: %s' |
| 397 raise device_errors.CommandFailedError(msg % output) | 430 raise device_errors.CommandFailedError(msg % output, str(self)) |
| 398 return output[0] | 431 return output[0] |
| 399 else: | 432 else: |
| 400 return output | 433 return output |
| 401 | 434 |
| 402 @decorators.WithTimeoutAndRetriesFromInstance() | 435 @decorators.WithTimeoutAndRetriesFromInstance() |
| 403 def KillAll(self, process_name, signum=9, as_root=False, blocking=False, | 436 def KillAll(self, process_name, signum=9, as_root=False, blocking=False, |
| 404 timeout=None, retries=None): | 437 timeout=None, retries=None): |
| 405 """Kill all processes with the given name on the device. | 438 """Kill all processes with the given name on the device. |
| 406 | 439 |
| 407 Args: | 440 Args: |
| (...skipping 479 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 887 | 920 |
| 888 Returns: | 921 Returns: |
| 889 True if the device-side property changed and a restart is required as a | 922 True if the device-side property changed and a restart is required as a |
| 890 result, False otherwise. | 923 result, False otherwise. |
| 891 | 924 |
| 892 Raises: | 925 Raises: |
| 893 CommandTimeoutError on timeout. | 926 CommandTimeoutError on timeout. |
| 894 """ | 927 """ |
| 895 return self.old_interface.SetJavaAssertsEnabled(enabled) | 928 return self.old_interface.SetJavaAssertsEnabled(enabled) |
| 896 | 929 |
| 897 @decorators.WithTimeoutAndRetriesFromInstance() | 930 def GetProp(self, property_name, cache=False, timeout=None, retries=None): |
|
jbudorick
2014/10/24 17:30:51
We should make sure we test the timeout/retries pa
perezju
2014/10/27 11:07:07
Acknowledged.
| |
| 898 def GetProp(self, property_name, timeout=None, retries=None): | |
| 899 """Gets a property from the device. | 931 """Gets a property from the device. |
| 900 | 932 |
| 901 Args: | 933 Args: |
| 902 property_name: A string containing the name of the property to get from | 934 property_name: A string containing the name of the property to get from |
| 903 the device. | 935 the device. |
| 936 cache: A boolean indicating whether to cache the value of this property. | |
| 904 timeout: timeout in seconds | 937 timeout: timeout in seconds |
| 905 retries: number of retries | 938 retries: number of retries |
| 906 | 939 |
| 907 Returns: | 940 Returns: |
| 908 The value of the device's |property_name| property. | 941 The value of the device's |property_name| property. |
| 909 | 942 |
| 910 Raises: | 943 Raises: |
| 911 CommandTimeoutError on timeout. | 944 CommandTimeoutError on timeout. |
| 912 """ | 945 """ |
| 913 return self._GetPropImpl(property_name) | 946 cache_name = '_prop:' + property_name |
| 914 | 947 if cache and cache_name in self._cache: |
|
jbudorick
2014/10/24 17:30:51
I think that, for now, we should limit property ca
perezju
2014/10/27 11:07:07
An idea I had was to provide the class with some p
| |
| 915 def _GetPropImpl(self, property_name): | 948 return self._cache[cache_name] |
| 916 return self.old_interface.system_properties[property_name] | 949 else: |
| 950 # timeout and retries are handled down at run shell, because we don't | |
| 951 # want to apply them in the other branch when reading from the cache | |
| 952 value = self.RunShellCommand(['getprop', property_name], single_line=True, | |
| 953 timeout=timeout, retries=retries) | |
| 954 if cache or cache_name in self._cache: | |
| 955 self._cache[cache_name] = value | |
| 956 return value | |
| 917 | 957 |
| 918 @decorators.WithTimeoutAndRetriesFromInstance() | 958 @decorators.WithTimeoutAndRetriesFromInstance() |
| 919 def SetProp(self, property_name, value, timeout=None, retries=None): | 959 def SetProp(self, property_name, value, check=False, timeout=None, |
|
jbudorick
2014/10/24 17:30:51
What's the motivation behind check?
perezju
2014/10/27 11:07:07
The TODO here https://cs.corp.google.com/#clankium
jbudorick
2014/10/27 19:15:36
Use the public cs for upstream reviews:
https://co
| |
| 960 retries=None): | |
| 920 """Sets a property on the device. | 961 """Sets a property on the device. |
| 921 | 962 |
| 922 Args: | 963 Args: |
| 923 property_name: A string containing the name of the property to set on | 964 property_name: A string containing the name of the property to set on |
| 924 the device. | 965 the device. |
| 925 value: A string containing the value to set to the property on the | 966 value: A string containing the value to set to the property on the |
| 926 device. | 967 device. |
| 927 timeout: timeout in seconds | 968 timeout: timeout in seconds |
| 928 retries: number of retries | 969 retries: number of retries |
| 929 | 970 |
| 930 Raises: | 971 Raises: |
| 931 CommandTimeoutError on timeout. | 972 CommandTimeoutError on timeout. |
| 932 """ | 973 """ |
| 933 self.old_interface.system_properties[property_name] = value | 974 self.RunShellCommand(['setprop', property_name, value]) |
|
jbudorick
2014/10/24 17:30:51
If we expand caching beyond read-only properties,
perezju
2014/10/27 11:07:06
This happens "auto-magically" when check=True. May
| |
| 975 if check and value != self.GetProp(property_name): | |
| 976 raise device_errors.CommandFailedError( | |
| 977 'Unable to set property %r on the device to %r' | |
| 978 % (property_name, value), str(self)) | |
| 934 | 979 |
| 935 @decorators.WithTimeoutAndRetriesFromInstance() | 980 @decorators.WithTimeoutAndRetriesFromInstance() |
| 936 def GetABI(self, timeout=None, retries=None): | 981 def GetABI(self, timeout=None, retries=None): |
| 937 """Gets the device main ABI. | 982 """Gets the device main ABI. |
| 938 | 983 |
| 939 Args: | 984 Args: |
| 940 timeout: timeout in seconds | 985 timeout: timeout in seconds |
| 941 retries: number of retries | 986 retries: number of retries |
| 942 | 987 |
| 943 Returns: | 988 Returns: |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1062 Returns: | 1107 Returns: |
| 1063 A Parallelizer operating over |devices|. | 1108 A Parallelizer operating over |devices|. |
| 1064 """ | 1109 """ |
| 1065 if not devices or len(devices) == 0: | 1110 if not devices or len(devices) == 0: |
| 1066 devices = pylib.android_commands.GetAttachedDevices() | 1111 devices = pylib.android_commands.GetAttachedDevices() |
| 1067 parallelizer_type = (parallelizer.Parallelizer if async | 1112 parallelizer_type = (parallelizer.Parallelizer if async |
| 1068 else parallelizer.SyncParallelizer) | 1113 else parallelizer.SyncParallelizer) |
| 1069 return parallelizer_type([ | 1114 return parallelizer_type([ |
| 1070 d if isinstance(d, DeviceUtils) else DeviceUtils(d) | 1115 d if isinstance(d, DeviceUtils) else DeviceUtils(d) |
| 1071 for d in devices]) | 1116 for d in devices]) |
| OLD | NEW |