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 |
11 import calendar | 11 import calendar |
12 import collections | 12 import collections |
13 import fnmatch | |
13 import itertools | 14 import itertools |
14 import json | 15 import json |
15 import logging | 16 import logging |
16 import multiprocessing | 17 import multiprocessing |
17 import os | 18 import os |
18 import posixpath | 19 import posixpath |
19 import pprint | 20 import pprint |
20 import re | 21 import re |
21 import shutil | 22 import shutil |
22 import stat | 23 import stat |
23 import tempfile | 24 import tempfile |
24 import time | 25 import time |
25 import threading | 26 import threading |
26 import uuid | 27 import uuid |
27 import zipfile | 28 import zipfile |
28 | 29 |
29 from devil import base_error | 30 from devil import base_error |
30 from devil import devil_env | 31 from devil import devil_env |
31 from devil.utils import cmd_helper | 32 from devil.utils import cmd_helper |
32 from devil.android import apk_helper | 33 from devil.android import apk_helper |
33 from devil.android import device_signal | 34 from devil.android import device_signal |
34 from devil.android import decorators | 35 from devil.android import decorators |
35 from devil.android import device_errors | 36 from devil.android import device_errors |
36 from devil.android import device_temp_file | 37 from devil.android import device_temp_file |
37 from devil.android import install_commands | 38 from devil.android import install_commands |
38 from devil.android import logcat_monitor | 39 from devil.android import logcat_monitor |
39 from devil.android import md5sum | 40 from devil.android import md5sum |
40 from devil.android.constants import chrome | |
41 from devil.android.sdk import adb_wrapper | 41 from devil.android.sdk import adb_wrapper |
42 from devil.android.sdk import intent | 42 from devil.android.sdk import intent |
43 from devil.android.sdk import keyevent | 43 from devil.android.sdk import keyevent |
44 from devil.android.sdk import split_select | 44 from devil.android.sdk import split_select |
45 from devil.android.sdk import version_codes | 45 from devil.android.sdk import version_codes |
46 from devil.utils import host_utils | 46 from devil.utils import host_utils |
47 from devil.utils import parallelizer | 47 from devil.utils import parallelizer |
48 from devil.utils import reraiser_thread | 48 from devil.utils import reraiser_thread |
49 from devil.utils import timeout_retry | 49 from devil.utils import timeout_retry |
50 from devil.utils import zip_utils | 50 from devil.utils import zip_utils |
(...skipping 13 matching lines...) Expand all Loading... | |
64 trap '' TERM | 64 trap '' TERM |
65 trap '' PIPE | 65 trap '' PIPE |
66 function restart() { | 66 function restart() { |
67 stop adbd | 67 stop adbd |
68 start adbd | 68 start adbd |
69 } | 69 } |
70 restart & | 70 restart & |
71 """ | 71 """ |
72 | 72 |
73 # Not all permissions can be set. | 73 # Not all permissions can be set. |
74 _PERMISSIONS_BLACKLIST = [ | 74 _PERMISSIONS_BLACKLIST_RE = re.compile('|'.join(fnmatch.translate(p) for p in [ |
75 'android.permission.ACCESS_LOCATION_EXTRA_COMMANDS', | 75 'android.permission.ACCESS_LOCATION_EXTRA_COMMANDS', |
76 'android.permission.ACCESS_MOCK_LOCATION', | 76 'android.permission.ACCESS_MOCK_LOCATION', |
77 'android.permission.ACCESS_NETWORK_STATE', | 77 'android.permission.ACCESS_NETWORK_STATE', |
78 'android.permission.ACCESS_NOTIFICATION_POLICY', | 78 'android.permission.ACCESS_NOTIFICATION_POLICY', |
79 'android.permission.ACCESS_WIFI_STATE', | 79 'android.permission.ACCESS_WIFI_STATE', |
80 'android.permission.AUTHENTICATE_ACCOUNTS', | 80 'android.permission.AUTHENTICATE_ACCOUNTS', |
81 'android.permission.BLUETOOTH', | 81 'android.permission.BLUETOOTH', |
82 'android.permission.BLUETOOTH_ADMIN', | 82 'android.permission.BLUETOOTH_ADMIN', |
83 'android.permission.BROADCAST_STICKY', | 83 'android.permission.BROADCAST_STICKY', |
84 'android.permission.CHANGE_NETWORK_STATE', | 84 'android.permission.CHANGE_NETWORK_STATE', |
85 'android.permission.CHANGE_WIFI_MULTICAST_STATE', | 85 'android.permission.CHANGE_WIFI_MULTICAST_STATE', |
86 'android.permission.CHANGE_WIFI_STATE', | 86 'android.permission.CHANGE_WIFI_STATE', |
87 'android.permission.DISABLE_KEYGUARD', | 87 'android.permission.DISABLE_KEYGUARD', |
88 'android.permission.DOWNLOAD_WITHOUT_NOTIFICATION', | 88 'android.permission.DOWNLOAD_WITHOUT_NOTIFICATION', |
89 'android.permission.EXPAND_STATUS_BAR', | 89 'android.permission.EXPAND_STATUS_BAR', |
90 'android.permission.GET_PACKAGE_SIZE', | 90 'android.permission.GET_PACKAGE_SIZE', |
91 'android.permission.INSTALL_SHORTCUT', | 91 'android.permission.INSTALL_SHORTCUT', |
92 'android.permission.INJECT_EVENTS', | |
92 'android.permission.INTERNET', | 93 'android.permission.INTERNET', |
93 'android.permission.KILL_BACKGROUND_PROCESSES', | 94 'android.permission.KILL_BACKGROUND_PROCESSES', |
94 'android.permission.MANAGE_ACCOUNTS', | 95 'android.permission.MANAGE_ACCOUNTS', |
95 'android.permission.MODIFY_AUDIO_SETTINGS', | 96 'android.permission.MODIFY_AUDIO_SETTINGS', |
96 'android.permission.NFC', | 97 'android.permission.NFC', |
97 'android.permission.READ_SYNC_SETTINGS', | 98 'android.permission.READ_SYNC_SETTINGS', |
98 'android.permission.READ_SYNC_STATS', | 99 'android.permission.READ_SYNC_STATS', |
99 'android.permission.RECEIVE_BOOT_COMPLETED', | 100 'android.permission.RECEIVE_BOOT_COMPLETED', |
100 'android.permission.RECORD_VIDEO', | 101 'android.permission.RECORD_VIDEO', |
101 'android.permission.REORDER_TASKS', | 102 'android.permission.REORDER_TASKS', |
102 'android.permission.REQUEST_INSTALL_PACKAGES', | 103 'android.permission.REQUEST_INSTALL_PACKAGES', |
104 'android.permission.RESTRICTED_VR_ACCESS', | |
perezju
2017/07/10 12:31:30
These two caused failures on chrome_public_test_vr
| |
103 'android.permission.RUN_INSTRUMENTATION', | 105 'android.permission.RUN_INSTRUMENTATION', |
104 'android.permission.SET_ALARM', | 106 'android.permission.SET_ALARM', |
105 'android.permission.SET_TIME_ZONE', | 107 'android.permission.SET_TIME_ZONE', |
106 'android.permission.SET_WALLPAPER', | 108 'android.permission.SET_WALLPAPER', |
107 'android.permission.SET_WALLPAPER_HINTS', | 109 'android.permission.SET_WALLPAPER_HINTS', |
108 'android.permission.TRANSMIT_IR', | 110 'android.permission.TRANSMIT_IR', |
109 'android.permission.USE_CREDENTIALS', | 111 'android.permission.USE_CREDENTIALS', |
110 'android.permission.USE_FINGERPRINT', | 112 'android.permission.USE_FINGERPRINT', |
111 'android.permission.VIBRATE', | 113 'android.permission.VIBRATE', |
112 'android.permission.WAKE_LOCK', | 114 'android.permission.WAKE_LOCK', |
113 'android.permission.WRITE_SYNC_SETTINGS', | 115 'android.permission.WRITE_SYNC_SETTINGS', |
114 'com.android.browser.permission.READ_HISTORY_BOOKMARKS', | 116 'com.android.browser.permission.READ_HISTORY_BOOKMARKS', |
115 'com.android.browser.permission.WRITE_HISTORY_BOOKMARKS', | 117 'com.android.browser.permission.WRITE_HISTORY_BOOKMARKS', |
116 'com.android.launcher.permission.INSTALL_SHORTCUT', | 118 'com.android.launcher.permission.INSTALL_SHORTCUT', |
117 'com.chrome.permission.DEVICE_EXTRAS', | 119 'com.chrome.permission.DEVICE_EXTRAS', |
118 'com.google.android.apps.now.CURRENT_ACCOUNT_ACCESS', | 120 'com.google.android.apps.now.CURRENT_ACCOUNT_ACCESS', |
119 'com.google.android.c2dm.permission.RECEIVE', | 121 'com.google.android.c2dm.permission.RECEIVE', |
120 'com.google.android.providers.gsf.permission.READ_GSERVICES', | 122 'com.google.android.providers.gsf.permission.READ_GSERVICES', |
121 'com.sec.enterprise.knox.MDM_CONTENT_PROVIDER', | 123 'com.sec.enterprise.knox.MDM_CONTENT_PROVIDER', |
122 ] | 124 '*.permission.C2D_MESSAGE', |
perezju
2017/07/10 12:31:30
Previously this failed to match: org.chromium.chro
| |
123 for package_info in chrome.PACKAGE_INFO.itervalues(): | 125 '*.permission.READ_WRITE_BOOKMARK_FOLDERS', |
124 _PERMISSIONS_BLACKLIST.extend([ | 126 '*.TOS_ACKED', |
125 '%s.permission.C2D_MESSAGE' % package_info.package, | 127 ])) |
126 '%s.permission.READ_WRITE_BOOKMARK_FOLDERS' % package_info.package, | |
127 '%s.TOS_ACKED' % package_info.package]) | |
128 | 128 |
129 _CURRENT_FOCUS_CRASH_RE = re.compile( | 129 _CURRENT_FOCUS_CRASH_RE = re.compile( |
130 r'\s*mCurrentFocus.*Application (Error|Not Responding): (\S+)}') | 130 r'\s*mCurrentFocus.*Application (Error|Not Responding): (\S+)}') |
131 | 131 |
132 _GETPROP_RE = re.compile(r'\[(.*?)\]: \[(.*?)\]') | 132 _GETPROP_RE = re.compile(r'\[(.*?)\]: \[(.*?)\]') |
133 | 133 |
134 # Regex to parse the long (-l) output of 'ls' command, c.f. | 134 # Regex to parse the long (-l) output of 'ls' command, c.f. |
135 # https://github.com/landley/toybox/blob/master/toys/posix/ls.c#L446 | 135 # https://github.com/landley/toybox/blob/master/toys/posix/ls.c#L446 |
136 _LONG_LS_OUTPUT_RE = re.compile( | 136 _LONG_LS_OUTPUT_RE = re.compile( |
137 r'(?P<st_mode>[\w-]{10})\s+' # File permissions | 137 r'(?P<st_mode>[\w-]{10})\s+' # File permissions |
(...skipping 693 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
831 self._cache['package_apk_paths'].pop(package_name, 0) | 831 self._cache['package_apk_paths'].pop(package_name, 0) |
832 self._cache['package_apk_checksums'].pop(package_name, 0) | 832 self._cache['package_apk_checksums'].pop(package_name, 0) |
833 if split_apks: | 833 if split_apks: |
834 partial = package_name if len(apks_to_install) < len(all_apks) else None | 834 partial = package_name if len(apks_to_install) < len(all_apks) else None |
835 self.adb.InstallMultiple( | 835 self.adb.InstallMultiple( |
836 apks_to_install, partial=partial, reinstall=reinstall, | 836 apks_to_install, partial=partial, reinstall=reinstall, |
837 allow_downgrade=allow_downgrade) | 837 allow_downgrade=allow_downgrade) |
838 else: | 838 else: |
839 self.adb.Install( | 839 self.adb.Install( |
840 base_apk.path, reinstall=reinstall, allow_downgrade=allow_downgrade) | 840 base_apk.path, reinstall=reinstall, allow_downgrade=allow_downgrade) |
841 if (permissions is None | |
842 and self.build_version_sdk >= version_codes.MARSHMALLOW): | |
843 permissions = base_apk.GetPermissions() | |
844 self.GrantPermissions(package_name, permissions) | |
845 # Upon success, we know the device checksums, but not their paths. | |
846 if host_checksums is not None: | |
847 self._cache['package_apk_checksums'][package_name] = host_checksums | |
848 else: | 841 else: |
849 # Running adb install terminates running instances of the app, so to be | 842 # Running adb install terminates running instances of the app, so to be |
850 # consistent, we explicitly terminate it when skipping the install. | 843 # consistent, we explicitly terminate it when skipping the install. |
851 self.ForceStop(package_name) | 844 self.ForceStop(package_name) |
852 | 845 |
846 if (permissions is None | |
847 and self.build_version_sdk >= version_codes.MARSHMALLOW): | |
848 permissions = base_apk.GetPermissions() | |
849 self.GrantPermissions(package_name, permissions) | |
850 # Upon success, we know the device checksums, but not their paths. | |
851 if host_checksums is not None: | |
852 self._cache['package_apk_checksums'][package_name] = host_checksums | |
853 | |
853 @decorators.WithTimeoutAndRetriesFromInstance() | 854 @decorators.WithTimeoutAndRetriesFromInstance() |
854 def Uninstall(self, package_name, keep_data=False, timeout=None, | 855 def Uninstall(self, package_name, keep_data=False, timeout=None, |
855 retries=None): | 856 retries=None): |
856 """Remove the app |package_name| from the device. | 857 """Remove the app |package_name| from the device. |
857 | 858 |
858 This is a no-op if the app is not already installed. | 859 This is a no-op if the app is not already installed. |
859 | 860 |
860 Args: | 861 Args: |
861 package_name: The package to uninstall. | 862 package_name: The package to uninstall. |
862 keep_data: (optional) Whether to keep the data and cache directories. | 863 keep_data: (optional) Whether to keep the data and cache directories. |
(...skipping 1771 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2634 self.RunShellCommand( | 2635 self.RunShellCommand( |
2635 ['source', script.name], check_return=True, as_root=True) | 2636 ['source', script.name], check_return=True, as_root=True) |
2636 self.adb.WaitForDevice() | 2637 self.adb.WaitForDevice() |
2637 | 2638 |
2638 @decorators.WithTimeoutAndRetriesFromInstance() | 2639 @decorators.WithTimeoutAndRetriesFromInstance() |
2639 def GrantPermissions(self, package, permissions, timeout=None, retries=None): | 2640 def GrantPermissions(self, package, permissions, timeout=None, retries=None): |
2640 # Permissions only need to be set on M and above because of the changes to | 2641 # Permissions only need to be set on M and above because of the changes to |
2641 # the permission model. | 2642 # the permission model. |
2642 if not permissions or self.build_version_sdk < version_codes.MARSHMALLOW: | 2643 if not permissions or self.build_version_sdk < version_codes.MARSHMALLOW: |
2643 return | 2644 return |
2644 logger.info('Setting permissions for %s.', package) | 2645 |
2645 permissions = [p for p in permissions if p not in _PERMISSIONS_BLACKLIST] | 2646 permissions = set( |
2647 p for p in permissions if not _PERMISSIONS_BLACKLIST_RE.match(p)) | |
2648 | |
2646 if ('android.permission.WRITE_EXTERNAL_STORAGE' in permissions | 2649 if ('android.permission.WRITE_EXTERNAL_STORAGE' in permissions |
2647 and 'android.permission.READ_EXTERNAL_STORAGE' not in permissions): | 2650 and 'android.permission.READ_EXTERNAL_STORAGE' not in permissions): |
2648 permissions.append('android.permission.READ_EXTERNAL_STORAGE') | 2651 permissions.add('android.permission.READ_EXTERNAL_STORAGE') |
2649 cmd = '&&'.join('pm grant %s %s' % (package, p) for p in permissions) | 2652 |
2650 if cmd: | 2653 logger.info('Setting permissions for %s.', package) |
2651 output = self.RunShellCommand(cmd, shell=True, check_return=True) | 2654 for permission in sorted(permissions): |
2652 if output: | 2655 try: |
2653 logger.warning('Possible problem when granting permissions. Blacklist ' | 2656 self.RunShellCommand( |
2654 'may need to be updated.') | 2657 ['pm', 'grant', package, permission], check_return=True) |
perezju
2017/07/10 12:31:30
Unrolling the "pm grant" calls like this has the u
jbudorick
2017/07/14 15:45:28
Could we join the pm grant calls w/ ';' rather tha
| |
2655 for line in output: | 2658 logging.info('- permission %s set.', permission) |
2656 logger.warning(' %s', line) | 2659 except device_errors.AdbShellCommandFailedError as exc: |
2660 m = re.search(r'java\.lang\.\w+Exception: .*$', exc.output) | |
perezju
2017/07/10 12:31:30
Error messages seen from [1], when my previous CL
perezju
2017/07/10 12:33:08
[1]: https://luci-milo.appspot.com/buildbot/chromi
| |
2661 if m: | |
2662 logging.warning('%s may need to be blacklisted.', permission) | |
2663 logging.warning('pm grant raised: %s', m.group(0)) | |
2664 else: | |
2665 raise | |
2657 | 2666 |
2658 @decorators.WithTimeoutAndRetriesFromInstance() | 2667 @decorators.WithTimeoutAndRetriesFromInstance() |
2659 def IsScreenOn(self, timeout=None, retries=None): | 2668 def IsScreenOn(self, timeout=None, retries=None): |
2660 """Determines if screen is on. | 2669 """Determines if screen is on. |
2661 | 2670 |
2662 Dumpsys input_method exposes screen on/off state. Below is an explination of | 2671 Dumpsys input_method exposes screen on/off state. Below is an explination of |
2663 the states. | 2672 the states. |
2664 | 2673 |
2665 Pre-L: | 2674 Pre-L: |
2666 On: mScreenOn=true | 2675 On: mScreenOn=true |
(...skipping 29 matching lines...) Expand all Loading... | |
2696 on: bool to decide state to switch to. True = on False = off. | 2705 on: bool to decide state to switch to. True = on False = off. |
2697 """ | 2706 """ |
2698 def screen_test(): | 2707 def screen_test(): |
2699 return self.IsScreenOn() == on | 2708 return self.IsScreenOn() == on |
2700 | 2709 |
2701 if screen_test(): | 2710 if screen_test(): |
2702 logger.info('Screen already in expected state.') | 2711 logger.info('Screen already in expected state.') |
2703 return | 2712 return |
2704 self.SendKeyEvent(keyevent.KEYCODE_POWER) | 2713 self.SendKeyEvent(keyevent.KEYCODE_POWER) |
2705 timeout_retry.WaitFor(screen_test, wait_period=1) | 2714 timeout_retry.WaitFor(screen_test, wait_period=1) |
OLD | NEW |