Index: devil/devil/android/device_utils.py |
diff --git a/devil/devil/android/device_utils.py b/devil/devil/android/device_utils.py |
index 097c4f7e44856acb598609af0f8e7caf3aac16aa..0d68b06fef945407777a93c4d072770b7ce4b1cc 100644 |
--- a/devil/devil/android/device_utils.py |
+++ b/devil/devil/android/device_utils.py |
@@ -10,6 +10,7 @@ Eventually, this will be based on adb_wrapper. |
import calendar |
import collections |
+import fnmatch |
import itertools |
import json |
import logging |
@@ -38,7 +39,6 @@ from devil.android import device_temp_file |
from devil.android import install_commands |
from devil.android import logcat_monitor |
from devil.android import md5sum |
-from devil.android.constants import chrome |
from devil.android.sdk import adb_wrapper |
from devil.android.sdk import intent |
from devil.android.sdk import keyevent |
@@ -72,7 +72,7 @@ _RESTART_ADBD_SCRIPT = """ |
""" |
# Not all permissions can be set. |
-_PERMISSIONS_BLACKLIST = [ |
+_PERMISSIONS_BLACKLIST_RE = re.compile('|'.join(fnmatch.translate(p) for p in [ |
'android.permission.ACCESS_LOCATION_EXTRA_COMMANDS', |
'android.permission.ACCESS_MOCK_LOCATION', |
'android.permission.ACCESS_NETWORK_STATE', |
@@ -90,6 +90,7 @@ _PERMISSIONS_BLACKLIST = [ |
'android.permission.EXPAND_STATUS_BAR', |
'android.permission.GET_PACKAGE_SIZE', |
'android.permission.INSTALL_SHORTCUT', |
+ 'android.permission.INJECT_EVENTS', |
'android.permission.INTERNET', |
'android.permission.KILL_BACKGROUND_PROCESSES', |
'android.permission.MANAGE_ACCOUNTS', |
@@ -101,6 +102,7 @@ _PERMISSIONS_BLACKLIST = [ |
'android.permission.RECORD_VIDEO', |
'android.permission.REORDER_TASKS', |
'android.permission.REQUEST_INSTALL_PACKAGES', |
+ 'android.permission.RESTRICTED_VR_ACCESS', |
'android.permission.RUN_INSTRUMENTATION', |
'android.permission.SET_ALARM', |
'android.permission.SET_TIME_ZONE', |
@@ -120,12 +122,13 @@ _PERMISSIONS_BLACKLIST = [ |
'com.google.android.c2dm.permission.RECEIVE', |
'com.google.android.providers.gsf.permission.READ_GSERVICES', |
'com.sec.enterprise.knox.MDM_CONTENT_PROVIDER', |
-] |
-for package_info in chrome.PACKAGE_INFO.itervalues(): |
- _PERMISSIONS_BLACKLIST.extend([ |
- '%s.permission.C2D_MESSAGE' % package_info.package, |
- '%s.permission.READ_WRITE_BOOKMARK_FOLDERS' % package_info.package, |
- '%s.TOS_ACKED' % package_info.package]) |
+ '*.permission.C2D_MESSAGE', |
+ '*.permission.READ_WRITE_BOOKMARK_FOLDERS', |
+ '*.TOS_ACKED', |
+])) |
+_SHELL_OUTPUT_SEPARATOR = '~X~' |
+_PERMISSIONS_EXCEPTION_RE = re.compile( |
+ r'java\.lang\.\w+Exception: .*$', re.MULTILINE) |
_CURRENT_FOCUS_CRASH_RE = re.compile( |
r'\s*mCurrentFocus.*Application (Error|Not Responding): (\S+)}') |
@@ -848,18 +851,19 @@ class DeviceUtils(object): |
else: |
self.adb.Install( |
base_apk.path, reinstall=reinstall, allow_downgrade=allow_downgrade) |
- if (permissions is None |
- and self.build_version_sdk >= version_codes.MARSHMALLOW): |
- permissions = base_apk.GetPermissions() |
- self.GrantPermissions(package_name, permissions) |
- # Upon success, we know the device checksums, but not their paths. |
- if host_checksums is not None: |
- self._cache['package_apk_checksums'][package_name] = host_checksums |
else: |
# Running adb install terminates running instances of the app, so to be |
# consistent, we explicitly terminate it when skipping the install. |
self.ForceStop(package_name) |
+ if (permissions is None |
+ and self.build_version_sdk >= version_codes.MARSHMALLOW): |
+ permissions = base_apk.GetPermissions() |
+ self.GrantPermissions(package_name, permissions) |
+ # Upon success, we know the device checksums, but not their paths. |
+ if host_checksums is not None: |
+ self._cache['package_apk_checksums'][package_name] = host_checksums |
+ |
@decorators.WithTimeoutAndRetriesFromInstance() |
def Uninstall(self, package_name, keep_data=False, timeout=None, |
retries=None): |
@@ -2660,19 +2664,49 @@ class DeviceUtils(object): |
# the permission model. |
if not permissions or self.build_version_sdk < version_codes.MARSHMALLOW: |
return |
- logger.info('Setting permissions for %s.', package) |
- permissions = [p for p in permissions if p not in _PERMISSIONS_BLACKLIST] |
+ |
+ permissions = set( |
+ p for p in permissions if not _PERMISSIONS_BLACKLIST_RE.match(p)) |
+ |
if ('android.permission.WRITE_EXTERNAL_STORAGE' in permissions |
and 'android.permission.READ_EXTERNAL_STORAGE' not in permissions): |
- permissions.append('android.permission.READ_EXTERNAL_STORAGE') |
- cmd = '&&'.join('pm grant %s %s' % (package, p) for p in permissions) |
- if cmd: |
- output = self.RunShellCommand(cmd, shell=True, check_return=True) |
- if output: |
- logger.warning('Possible problem when granting permissions. Blacklist ' |
- 'may need to be updated.') |
- for line in output: |
- logger.warning(' %s', line) |
+ permissions.add('android.permission.READ_EXTERNAL_STORAGE') |
+ |
+ script = ';'.join([ |
+ 'p={package}', |
+ 'for q in {permissions}', |
+ 'do pm grant "$p" "$q"', |
+ 'echo "{sep}$q{sep}$?{sep}"', |
+ 'done' |
+ ]).format( |
+ package=cmd_helper.SingleQuote(package), |
+ permissions=' '.join( |
+ cmd_helper.SingleQuote(p) for p in sorted(permissions)), |
+ sep=_SHELL_OUTPUT_SEPARATOR) |
+ |
+ logger.info('Setting permissions for %s.', package) |
+ res = self.RunShellCommand( |
+ script, shell=True, raw_output=True, large_output=True, |
+ check_return=True) |
+ res = res.split(_SHELL_OUTPUT_SEPARATOR) |
+ failures = [ |
+ (permission, output.strip()) |
+ for permission, status, output in zip(res[1::3], res[2::3], res[0::3]) |
+ if int(status)] |
+ |
+ if failures: |
+ logger.warning( |
+ 'Failed to grant some permissions. Blacklist may need to be updated?') |
+ for permission, output in failures: |
+ # Try to grab the relevant error message from the output. |
+ m = _PERMISSIONS_EXCEPTION_RE.search(output) |
+ if m: |
+ error_msg = m.group(0) |
+ elif len(output) > 200: |
+ error_msg = repr(output[:200]) + ' (truncated)' |
+ else: |
+ error_msg = repr(output) |
+ logger.warning('- %s: %s', permission, error_msg) |
@decorators.WithTimeoutAndRetriesFromInstance() |
def IsScreenOn(self, timeout=None, retries=None): |