| 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=unused-argument | 9 # pylint: disable=unused-argument |
| 10 | 10 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 29 from devil.android import decorators | 29 from devil.android import decorators |
| 30 from devil.android import device_blacklist | 30 from devil.android import device_blacklist |
| 31 from devil.android import device_errors | 31 from devil.android import device_errors |
| 32 from devil.android import device_temp_file | 32 from devil.android import device_temp_file |
| 33 from devil.android import logcat_monitor | 33 from devil.android import logcat_monitor |
| 34 from devil.android import md5sum | 34 from devil.android import md5sum |
| 35 from devil.android.sdk import adb_wrapper | 35 from devil.android.sdk import adb_wrapper |
| 36 from devil.android.sdk import intent | 36 from devil.android.sdk import intent |
| 37 from devil.android.sdk import keyevent | 37 from devil.android.sdk import keyevent |
| 38 from devil.android.sdk import split_select | 38 from devil.android.sdk import split_select |
| 39 from devil.android.sdk import version_codes |
| 39 from devil.utils import host_utils | 40 from devil.utils import host_utils |
| 40 from devil.utils import parallelizer | 41 from devil.utils import parallelizer |
| 41 from devil.utils import reraiser_thread | 42 from devil.utils import reraiser_thread |
| 42 from devil.utils import timeout_retry | 43 from devil.utils import timeout_retry |
| 43 from devil.utils import zip_utils | 44 from devil.utils import zip_utils |
| 44 from pylib import constants | 45 from pylib import constants |
| 45 from pylib.device.commands import install_commands | 46 from pylib.device.commands import install_commands |
| 46 | 47 |
| 47 _DEFAULT_TIMEOUT = 30 | 48 _DEFAULT_TIMEOUT = 30 |
| 48 _DEFAULT_RETRIES = 3 | 49 _DEFAULT_RETRIES = 3 |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 148 | 149 |
| 149 | 150 |
| 150 class DeviceUtils(object): | 151 class DeviceUtils(object): |
| 151 | 152 |
| 152 _MAX_ADB_COMMAND_LENGTH = 512 | 153 _MAX_ADB_COMMAND_LENGTH = 512 |
| 153 _MAX_ADB_OUTPUT_LENGTH = 32768 | 154 _MAX_ADB_OUTPUT_LENGTH = 32768 |
| 154 _LAUNCHER_FOCUSED_RE = re.compile( | 155 _LAUNCHER_FOCUSED_RE = re.compile( |
| 155 '\s*mCurrentFocus.*(Launcher|launcher).*') | 156 '\s*mCurrentFocus.*(Launcher|launcher).*') |
| 156 _VALID_SHELL_VARIABLE = re.compile('^[a-zA-Z_][a-zA-Z0-9_]*$') | 157 _VALID_SHELL_VARIABLE = re.compile('^[a-zA-Z_][a-zA-Z0-9_]*$') |
| 157 | 158 |
| 159 LOCAL_PROPERTIES_PATH = posixpath.join('/', 'data', 'local.prop') |
| 160 |
| 158 # Property in /data/local.prop that controls Java assertions. | 161 # Property in /data/local.prop that controls Java assertions. |
| 159 JAVA_ASSERT_PROPERTY = 'dalvik.vm.enableassertions' | 162 JAVA_ASSERT_PROPERTY = 'dalvik.vm.enableassertions' |
| 160 | 163 |
| 161 def __init__(self, device, default_timeout=_DEFAULT_TIMEOUT, | 164 def __init__(self, device, default_timeout=_DEFAULT_TIMEOUT, |
| 162 default_retries=_DEFAULT_RETRIES): | 165 default_retries=_DEFAULT_RETRIES): |
| 163 """DeviceUtils constructor. | 166 """DeviceUtils constructor. |
| 164 | 167 |
| 165 Args: | 168 Args: |
| 166 device: Either a device serial, an existing AdbWrapper instance, or an | 169 device: Either a device serial, an existing AdbWrapper instance, or an |
| 167 an existing AndroidCommands instance. | 170 an existing AndroidCommands instance. |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 279 self.RunShellCommand( | 282 self.RunShellCommand( |
| 280 '%s && ! ls /root' % self._Su('ls /root'), check_return=True, | 283 '%s && ! ls /root' % self._Su('ls /root'), check_return=True, |
| 281 timeout=self._default_timeout if timeout is DEFAULT else timeout, | 284 timeout=self._default_timeout if timeout is DEFAULT else timeout, |
| 282 retries=self._default_retries if retries is DEFAULT else retries) | 285 retries=self._default_retries if retries is DEFAULT else retries) |
| 283 self._cache['needs_su'] = True | 286 self._cache['needs_su'] = True |
| 284 except device_errors.AdbCommandFailedError: | 287 except device_errors.AdbCommandFailedError: |
| 285 self._cache['needs_su'] = False | 288 self._cache['needs_su'] = False |
| 286 return self._cache['needs_su'] | 289 return self._cache['needs_su'] |
| 287 | 290 |
| 288 def _Su(self, command): | 291 def _Su(self, command): |
| 289 if (self.build_version_sdk | 292 if (self.build_version_sdk >= version_codes.MARSHMALLOW): |
| 290 >= constants.ANDROID_SDK_VERSION_CODES.MARSHMALLOW): | |
| 291 return 'su 0 %s' % command | 293 return 'su 0 %s' % command |
| 292 return 'su -c %s' % command | 294 return 'su -c %s' % command |
| 293 | 295 |
| 294 @decorators.WithTimeoutAndRetriesFromInstance() | 296 @decorators.WithTimeoutAndRetriesFromInstance() |
| 295 def EnableRoot(self, timeout=None, retries=None): | 297 def EnableRoot(self, timeout=None, retries=None): |
| 296 """Restarts adbd with root privileges. | 298 """Restarts adbd with root privileges. |
| 297 | 299 |
| 298 Args: | 300 Args: |
| 299 timeout: timeout in seconds | 301 timeout: timeout in seconds |
| 300 retries: number of retries | 302 retries: number of retries |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 370 return self._GetApplicationPathsInternal(package) | 372 return self._GetApplicationPathsInternal(package) |
| 371 | 373 |
| 372 def _GetApplicationPathsInternal(self, package, skip_cache=False): | 374 def _GetApplicationPathsInternal(self, package, skip_cache=False): |
| 373 cached_result = self._cache['package_apk_paths'].get(package) | 375 cached_result = self._cache['package_apk_paths'].get(package) |
| 374 if cached_result is not None and not skip_cache: | 376 if cached_result is not None and not skip_cache: |
| 375 return list(cached_result) | 377 return list(cached_result) |
| 376 # 'pm path' is liable to incorrectly exit with a nonzero number starting | 378 # 'pm path' is liable to incorrectly exit with a nonzero number starting |
| 377 # in Lollipop. | 379 # in Lollipop. |
| 378 # TODO(jbudorick): Check if this is fixed as new Android versions are | 380 # TODO(jbudorick): Check if this is fixed as new Android versions are |
| 379 # released to put an upper bound on this. | 381 # released to put an upper bound on this. |
| 380 should_check_return = (self.build_version_sdk < | 382 should_check_return = (self.build_version_sdk < version_codes.LOLLIPOP) |
| 381 constants.ANDROID_SDK_VERSION_CODES.LOLLIPOP) | |
| 382 output = self.RunShellCommand( | 383 output = self.RunShellCommand( |
| 383 ['pm', 'path', package], check_return=should_check_return) | 384 ['pm', 'path', package], check_return=should_check_return) |
| 384 apks = [] | 385 apks = [] |
| 385 for line in output: | 386 for line in output: |
| 386 if not line.startswith('package:'): | 387 if not line.startswith('package:'): |
| 387 raise device_errors.CommandFailedError( | 388 raise device_errors.CommandFailedError( |
| 388 'pm path returned: %r' % '\n'.join(output), str(self)) | 389 'pm path returned: %r' % '\n'.join(output), str(self)) |
| 389 apks.append(line[len('package:'):]) | 390 apks.append(line[len('package:'):]) |
| 390 self._cache['package_apk_paths'][package] = list(apks) | 391 self._cache['package_apk_paths'][package] = list(apks) |
| 391 return apks | 392 return apks |
| (...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 568 reinstall: A boolean indicating if we should keep any existing app data. | 569 reinstall: A boolean indicating if we should keep any existing app data. |
| 569 timeout: timeout in seconds | 570 timeout: timeout in seconds |
| 570 retries: number of retries | 571 retries: number of retries |
| 571 | 572 |
| 572 Raises: | 573 Raises: |
| 573 CommandFailedError if the installation fails. | 574 CommandFailedError if the installation fails. |
| 574 CommandTimeoutError if the installation times out. | 575 CommandTimeoutError if the installation times out. |
| 575 DeviceUnreachableError on missing device. | 576 DeviceUnreachableError on missing device. |
| 576 DeviceVersionError if device SDK is less than Android L. | 577 DeviceVersionError if device SDK is less than Android L. |
| 577 """ | 578 """ |
| 578 self._CheckSdkLevel(constants.ANDROID_SDK_VERSION_CODES.LOLLIPOP) | 579 self._CheckSdkLevel(version_codes.LOLLIPOP) |
| 579 | 580 |
| 580 all_apks = [base_apk] + split_select.SelectSplits( | 581 all_apks = [base_apk] + split_select.SelectSplits( |
| 581 self, base_apk, split_apks) | 582 self, base_apk, split_apks) |
| 582 package_name = apk_helper.GetPackageName(base_apk) | 583 package_name = apk_helper.GetPackageName(base_apk) |
| 583 device_apk_paths = self._GetApplicationPathsInternal(package_name) | 584 device_apk_paths = self._GetApplicationPathsInternal(package_name) |
| 584 | 585 |
| 585 if device_apk_paths: | 586 if device_apk_paths: |
| 586 partial_install_package = package_name | 587 partial_install_package = package_name |
| 587 apks_to_install, host_checksums = ( | 588 apks_to_install, host_checksums = ( |
| 588 self._ComputeStaleApks(package_name, all_apks)) | 589 self._ComputeStaleApks(package_name, all_apks)) |
| (...skipping 388 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 977 timeout: timeout in seconds | 978 timeout: timeout in seconds |
| 978 retries: number of retries | 979 retries: number of retries |
| 979 | 980 |
| 980 Raises: | 981 Raises: |
| 981 CommandTimeoutError on timeout. | 982 CommandTimeoutError on timeout. |
| 982 DeviceUnreachableError on missing device. | 983 DeviceUnreachableError on missing device. |
| 983 """ | 984 """ |
| 984 # Check that the package exists before clearing it for android builds below | 985 # Check that the package exists before clearing it for android builds below |
| 985 # JB MR2. Necessary because calling pm clear on a package that doesn't exist | 986 # JB MR2. Necessary because calling pm clear on a package that doesn't exist |
| 986 # may never return. | 987 # may never return. |
| 987 if ((self.build_version_sdk >= | 988 if ((self.build_version_sdk >= version_codes.JELLY_BEAN_MR2) |
| 988 constants.ANDROID_SDK_VERSION_CODES.JELLY_BEAN_MR2) | |
| 989 or self._GetApplicationPathsInternal(package)): | 989 or self._GetApplicationPathsInternal(package)): |
| 990 self.RunShellCommand(['pm', 'clear', package], check_return=True) | 990 self.RunShellCommand(['pm', 'clear', package], check_return=True) |
| 991 | 991 |
| 992 @decorators.WithTimeoutAndRetriesFromInstance() | 992 @decorators.WithTimeoutAndRetriesFromInstance() |
| 993 def SendKeyEvent(self, keycode, timeout=None, retries=None): | 993 def SendKeyEvent(self, keycode, timeout=None, retries=None): |
| 994 """Sends a keycode to the device. | 994 """Sends a keycode to the device. |
| 995 | 995 |
| 996 See the pylib.constants.keyevent module for suitable keycode values. | 996 See the devil.android.sdk.keyevent module for suitable keycode values. |
| 997 | 997 |
| 998 Args: | 998 Args: |
| 999 keycode: A integer keycode to send to the device. | 999 keycode: A integer keycode to send to the device. |
| 1000 timeout: timeout in seconds | 1000 timeout: timeout in seconds |
| 1001 retries: number of retries | 1001 retries: number of retries |
| 1002 | 1002 |
| 1003 Raises: | 1003 Raises: |
| 1004 CommandTimeoutError on timeout. | 1004 CommandTimeoutError on timeout. |
| 1005 DeviceUnreachableError on missing device. | 1005 DeviceUnreachableError on missing device. |
| 1006 """ | 1006 """ |
| (...skipping 463 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1470 continue | 1470 continue |
| 1471 key, value = (s.strip() for s in line.split('=', 1)) | 1471 key, value = (s.strip() for s in line.split('=', 1)) |
| 1472 if key == property_name: | 1472 if key == property_name: |
| 1473 return index, value | 1473 return index, value |
| 1474 return None, '' | 1474 return None, '' |
| 1475 | 1475 |
| 1476 new_value = 'all' if enabled else '' | 1476 new_value = 'all' if enabled else '' |
| 1477 | 1477 |
| 1478 # First ensure the desired property is persisted. | 1478 # First ensure the desired property is persisted. |
| 1479 try: | 1479 try: |
| 1480 properties = self.ReadFile( | 1480 properties = self.ReadFile(self.LOCAL_PROPERTIES_PATH).splitlines() |
| 1481 constants.DEVICE_LOCAL_PROPERTIES_PATH).splitlines() | |
| 1482 except device_errors.CommandFailedError: | 1481 except device_errors.CommandFailedError: |
| 1483 properties = [] | 1482 properties = [] |
| 1484 index, value = find_property(properties, self.JAVA_ASSERT_PROPERTY) | 1483 index, value = find_property(properties, self.JAVA_ASSERT_PROPERTY) |
| 1485 if new_value != value: | 1484 if new_value != value: |
| 1486 if new_value: | 1485 if new_value: |
| 1487 new_line = '%s=%s' % (self.JAVA_ASSERT_PROPERTY, new_value) | 1486 new_line = '%s=%s' % (self.JAVA_ASSERT_PROPERTY, new_value) |
| 1488 if index is None: | 1487 if index is None: |
| 1489 properties.append(new_line) | 1488 properties.append(new_line) |
| 1490 else: | 1489 else: |
| 1491 properties[index] = new_line | 1490 properties[index] = new_line |
| 1492 else: | 1491 else: |
| 1493 assert index is not None # since new_value == '' and new_value != value | 1492 assert index is not None # since new_value == '' and new_value != value |
| 1494 properties.pop(index) | 1493 properties.pop(index) |
| 1495 self.WriteFile(constants.DEVICE_LOCAL_PROPERTIES_PATH, | 1494 self.WriteFile(self.LOCAL_PROPERTIES_PATH, _JoinLines(properties)) |
| 1496 _JoinLines(properties)) | |
| 1497 | 1495 |
| 1498 # Next, check the current runtime value is what we need, and | 1496 # Next, check the current runtime value is what we need, and |
| 1499 # if not, set it and report that a reboot is required. | 1497 # if not, set it and report that a reboot is required. |
| 1500 value = self.GetProp(self.JAVA_ASSERT_PROPERTY) | 1498 value = self.GetProp(self.JAVA_ASSERT_PROPERTY) |
| 1501 if new_value != value: | 1499 if new_value != value: |
| 1502 self.SetProp(self.JAVA_ASSERT_PROPERTY, new_value) | 1500 self.SetProp(self.JAVA_ASSERT_PROPERTY, new_value) |
| 1503 return True | 1501 return True |
| 1504 else: | 1502 else: |
| 1505 return False | 1503 return False |
| 1506 | 1504 |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1561 """Returns the build type of the system (e.g. 'user').""" | 1559 """Returns the build type of the system (e.g. 'user').""" |
| 1562 return self.GetProp('ro.build.type', cache=True) | 1560 return self.GetProp('ro.build.type', cache=True) |
| 1563 | 1561 |
| 1564 @property | 1562 @property |
| 1565 def build_version_sdk(self): | 1563 def build_version_sdk(self): |
| 1566 """Returns the build version sdk of the system as a number (e.g. 19). | 1564 """Returns the build version sdk of the system as a number (e.g. 19). |
| 1567 | 1565 |
| 1568 For version code numbers see: | 1566 For version code numbers see: |
| 1569 http://developer.android.com/reference/android/os/Build.VERSION_CODES.html | 1567 http://developer.android.com/reference/android/os/Build.VERSION_CODES.html |
| 1570 | 1568 |
| 1571 For named constants see: | 1569 For named constants see devil.android.sdk.version_codes |
| 1572 pylib.constants.ANDROID_SDK_VERSION_CODES | |
| 1573 | 1570 |
| 1574 Raises: | 1571 Raises: |
| 1575 CommandFailedError if the build version sdk is not a number. | 1572 CommandFailedError if the build version sdk is not a number. |
| 1576 """ | 1573 """ |
| 1577 value = self.GetProp('ro.build.version.sdk', cache=True) | 1574 value = self.GetProp('ro.build.version.sdk', cache=True) |
| 1578 try: | 1575 try: |
| 1579 return int(value) | 1576 return int(value) |
| 1580 except ValueError: | 1577 except ValueError: |
| 1581 raise device_errors.CommandFailedError( | 1578 raise device_errors.CommandFailedError( |
| 1582 'Invalid build version sdk: %r' % value) | 1579 'Invalid build version sdk: %r' % value) |
| (...skipping 327 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1910 return [cls(adb, **kwargs) for adb in adb_wrapper.AdbWrapper.Devices() | 1907 return [cls(adb, **kwargs) for adb in adb_wrapper.AdbWrapper.Devices() |
| 1911 if not blacklisted(adb)] | 1908 if not blacklisted(adb)] |
| 1912 | 1909 |
| 1913 @decorators.WithTimeoutAndRetriesFromInstance() | 1910 @decorators.WithTimeoutAndRetriesFromInstance() |
| 1914 def RestartAdbd(self, timeout=None, retries=None): | 1911 def RestartAdbd(self, timeout=None, retries=None): |
| 1915 logging.info('Restarting adbd on device.') | 1912 logging.info('Restarting adbd on device.') |
| 1916 with device_temp_file.DeviceTempFile(self.adb, suffix='.sh') as script: | 1913 with device_temp_file.DeviceTempFile(self.adb, suffix='.sh') as script: |
| 1917 self.WriteFile(script.name, _RESTART_ADBD_SCRIPT) | 1914 self.WriteFile(script.name, _RESTART_ADBD_SCRIPT) |
| 1918 self.RunShellCommand(['source', script.name], as_root=True) | 1915 self.RunShellCommand(['source', script.name], as_root=True) |
| 1919 self.adb.WaitForDevice() | 1916 self.adb.WaitForDevice() |
| OLD | NEW |