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 |