Merge changes from topic "revokeLocOnUpgrade"
* changes:
Control revoke-on-upgrade behavior for loc perm
Revoke location permissions on upgrade from Pre-Q
No special case for location permission
Inherit flags when inheriting permission state
diff --git a/api/system-current.txt b/api/system-current.txt
index 805bfb5..a15a8c5 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6117,6 +6117,7 @@
field public static final String LAST_SETUP_SHOWN = "last_setup_shown";
field public static final String LOCATION_ACCESS_CHECK_DELAY_MILLIS = "location_access_check_delay_millis";
field public static final String LOCATION_ACCESS_CHECK_INTERVAL_MILLIS = "location_access_check_interval_millis";
+ field public static final String LOCATION_PERMISSIONS_UPGRADE_TO_Q_MODE = "location_permissions_upgrade_to_q_mode";
field public static final String LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS = "lock_screen_allow_private_notifications";
field public static final String LOCK_SCREEN_SHOW_NOTIFICATIONS = "lock_screen_show_notifications";
field public static final String MANUAL_RINGER_TOGGLE_COUNT = "manual_ringer_toggle_count";
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index f8dfc58..ecbd673 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -8563,6 +8563,19 @@
public static final String LOCATION_ACCESS_CHECK_DELAY_MILLIS =
"location_access_check_delay_millis";
+ /**
+ * What should happen to the location permissions when upgraded to Android Q.
+ *
+ * <ul>
+ * <li>0/unset == revoke permissions</li>
+ * <li>anything else == Don't do anything</li>
+ * </ul>
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String LOCATION_PERMISSIONS_UPGRADE_TO_Q_MODE =
+ "location_permissions_upgrade_to_q_mode";
/**
* Comma separated list of enabled overlay packages for all android.theme.customization.*
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index 6360a5f..08286a1 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -235,6 +235,10 @@
optional SettingProto mode = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
// The App or module that changes the location mode.
optional SettingProto changer = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+ // What should happen to the location permissions when upgraded to Android Q.
+ // 0 == revoke permissions. Anything else == do nothing.
+ optional SettingProto permissions_upgrade_to_q_mode = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
}
optional Location location = 31;
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 67e364b..43f8db1 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -643,6 +643,7 @@
Settings.Secure.LAST_SETUP_SHOWN,
Settings.Secure.LOCATION_CHANGER,
Settings.Secure.LOCATION_MODE,
+ Settings.Secure.LOCATION_PERMISSIONS_UPGRADE_TO_Q_MODE,
Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT, // Candidate?
Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT,
Settings.Secure.LOCK_TO_APP_EXIT_LOCKED,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index f7f34f6..2d5606c 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1977,6 +1977,9 @@
dumpSetting(s, p,
Settings.Secure.LOCATION_CHANGER,
SecureSettingsProto.Location.CHANGER);
+ dumpSetting(s, p,
+ Settings.Secure.LOCATION_PERMISSIONS_UPGRADE_TO_Q_MODE,
+ SecureSettingsProto.Location.PERMISSIONS_UPGRADE_TO_Q_MODE);
p.end(locationToken);
final long locationAccessCheckToken = p.start(SecureSettingsProto.LOCATION_ACCESS_CHECK);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index b64b7c64..251b34bc 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2945,7 +2945,7 @@
+ mSdkVersion + "; regranting permissions for internal storage");
}
mPermissionManager.updateAllPermissions(
- StorageManager.UUID_PRIVATE_INTERNAL, sdkUpdated, mPackages.values(),
+ StorageManager.UUID_PRIVATE_INTERNAL, sdkUpdated, false, mPackages.values(),
mPermissionCallback);
ver.sdkVersion = mSdkVersion;
@@ -5382,7 +5382,7 @@
synchronized (mPackages) {
mPermissionManager.updateAllPermissions(
- StorageManager.UUID_PRIVATE_INTERNAL, false, mPackages.values(),
+ StorageManager.UUID_PRIVATE_INTERNAL, false, false, mPackages.values(),
mPermissionCallback);
for (int userId : UserManagerService.getInstance().getUserIds()) {
final int packageCount = mPackages.size();
@@ -20685,8 +20685,8 @@
// try optimizing this.
synchronized (mPackages) {
mPermissionManager.updateAllPermissions(
- StorageManager.UUID_PRIVATE_INTERNAL, false, mPackages.values(),
- mPermissionCallback);
+ StorageManager.UUID_PRIVATE_INTERNAL, false, mIsPreQUpgrade,
+ mPackages.values(), mPermissionCallback);
}
// Watch for external volumes that come and go over time
@@ -21676,8 +21676,8 @@
logCriticalInfo(Log.INFO, "Platform changed from " + ver.sdkVersion + " to "
+ mSdkVersion + "; regranting permissions for " + volumeUuid);
}
- mPermissionManager.updateAllPermissions(volumeUuid, sdkUpdated, mPackages.values(),
- mPermissionCallback);
+ mPermissionManager.updateAllPermissions(volumeUuid, sdkUpdated, false,
+ mPackages.values(), mPermissionCallback);
// Yay, everything is now upgraded
ver.forceCurrent();
@@ -22676,7 +22676,7 @@
synchronized(mPackages) {
// NOTE: This adds UPDATE_PERMISSIONS_REPLACE_PKG
mPermissionManager.updateAllPermissions(
- StorageManager.UUID_PRIVATE_INTERNAL, true, mPackages.values(),
+ StorageManager.UUID_PRIVATE_INTERNAL, true, false, mPackages.values(),
mPermissionCallback);
}
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 03da962..ac7338e 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -16,14 +16,11 @@
package com.android.server.pm.permission;
-import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION;
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
import static android.app.AppOpsManager.MODE_ALLOWED;
-import static android.app.AppOpsManager.MODE_DEFAULT;
import static android.app.AppOpsManager.MODE_ERRORED;
import static android.app.AppOpsManager.MODE_FOREGROUND;
-import static android.app.AppOpsManager.MODE_IGNORED;
import static android.app.AppOpsManager.OP_NONE;
import static android.app.AppOpsManager.permissionToOp;
import static android.app.AppOpsManager.permissionToOpCode;
@@ -77,6 +74,7 @@
import android.permission.PermissionControllerManager;
import android.permission.PermissionManager;
import android.permission.PermissionManagerInternal;
+import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -140,6 +138,18 @@
/** Empty array to avoid allocations */
private static final int[] EMPTY_INT_ARRAY = new int[0];
+ /**
+ * When these flags are set, the system should not automatically modify the permission grant
+ * state.
+ */
+ private static final int BLOCKING_PERMISSION_FLAGS = FLAG_PERMISSION_SYSTEM_FIXED
+ | FLAG_PERMISSION_POLICY_FIXED
+ | FLAG_PERMISSION_GRANTED_BY_DEFAULT;
+
+ /** Permission flags set by the user */
+ private static final int USER_PERMISSION_FLAGS = FLAG_PERMISSION_USER_SET
+ | FLAG_PERMISSION_USER_FIXED;
+
/** If the permission of the value is granted, so is the key */
private static final Map<String, String> FULLER_PERMISSION_MAP = new HashMap<>();
@@ -1203,9 +1213,8 @@
int flagsToRemove = FLAG_PERMISSION_REVOKE_WHEN_REQUESTED;
- if ((flags & (FLAG_PERMISSION_GRANTED_BY_DEFAULT
- | FLAG_PERMISSION_POLICY_FIXED | FLAG_PERMISSION_SYSTEM_FIXED))
- == 0 && supportsRuntimePermissions) {
+ if ((flags & BLOCKING_PERMISSION_FLAGS) == 0
+ && supportsRuntimePermissions) {
int revokeResult = ps.revokeRuntimePermission(bp, userId);
if (revokeResult != PERMISSION_OPERATION_FAILURE) {
if (DEBUG_PERMISSIONS) {
@@ -1215,8 +1224,7 @@
}
}
- flagsToRemove |=
- FLAG_PERMISSION_USER_FIXED | FLAG_PERMISSION_USER_SET;
+ flagsToRemove |= USER_PERMISSION_FLAGS;
List<String> fgPerms = mBackgroundPermissions.get(permission);
if (fgPerms != null) {
@@ -1271,6 +1279,7 @@
if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
if (permissionToOp(newPerm) != null) {
int mostLenientSourceMode = MODE_ERRORED;
+ int flags = 0;
// Find most lenient source permission state.
int numSourcePerms = sourcePerms.size();
@@ -1284,20 +1293,19 @@
int mode = appOpsManager.unsafeCheckOpRaw(sourceOp,
getUid(userId, getAppId(pkg.applicationInfo.uid)), pkgName);
- if (mode == MODE_FOREGROUND) {
- throw new IllegalArgumentException("split permission" + sourcePerm
- + " has app-op state " + AppOpsManager.MODE_NAMES[mode]);
+ if (mode == MODE_FOREGROUND || mode == MODE_ERRORED) {
+ Log.wtf(TAG, "split permission" + sourcePerm + " has app-op state "
+ + AppOpsManager.MODE_NAMES[mode]);
+
+ continue;
}
- // Leniency order: allowed > ignored > default
- if (mode == MODE_ALLOWED) {
- mostLenientSourceMode = MODE_ALLOWED;
- break;
- } else if (mode == MODE_IGNORED) {
- mostLenientSourceMode = MODE_IGNORED;
- } else if (mode == MODE_DEFAULT
- && mostLenientSourceMode != MODE_IGNORED) {
- mostLenientSourceMode = MODE_DEFAULT;
+ // Leniency order: allowed < ignored < default
+ if (mode < mostLenientSourceMode) {
+ mostLenientSourceMode = mode;
+ flags = ps.getPermissionFlags(sourcePerm, userId);
+ } else if (mode == mostLenientSourceMode) {
+ flags |= ps.getPermissionFlags(sourcePerm, userId);
}
}
}
@@ -1310,21 +1318,31 @@
}
setAppOpMode(newPerm, pkg, userId, mostLenientSourceMode);
+
+ // Add permission flags
+ ps.updatePermissionFlags(mSettings.getPermission(newPerm), userId, flags,
+ flags);
}
}
} else {
boolean isGranted = false;
+ int flags = 0;
int numSourcePerm = sourcePerms.size();
for (int i = 0; i < numSourcePerm; i++) {
String sourcePerm = sourcePerms.valueAt(i);
- if (ps.hasRuntimePermission(sourcePerm, userId)
- && ps.getRuntimePermissionState(sourcePerm, userId).isGranted()) {
+ if ((ps.hasRuntimePermission(sourcePerm, userId))
+ || ps.hasInstallPermission(sourcePerm)) {
+ if (!isGranted) {
+ flags = 0;
+ }
+
isGranted = true;
- break;
- } else if (ps.hasInstallPermission(sourcePerm)) {
- isGranted = true;
- break;
+ flags |= ps.getPermissionFlags(sourcePerm, userId);
+ } else {
+ if (!isGranted) {
+ flags |= ps.getPermissionFlags(sourcePerm, userId);
+ }
}
}
@@ -1336,6 +1354,9 @@
ps.grantRuntimePermission(mSettings.getPermissionLocked(newPerm), userId);
}
+
+ // Add permission flags
+ ps.updatePermissionFlags(mSettings.getPermission(newPerm), userId, flags, flags);
}
}
@@ -1353,8 +1374,6 @@
@NonNull PermissionsState origPs,
@NonNull PermissionsState ps, @NonNull PackageParser.Package pkg,
@NonNull int[] updatedUserIds) {
- AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class);
-
String pkgName = pkg.packageName;
ArraySet<String> newImplicitPermissions = new ArraySet<>();
@@ -1417,49 +1436,29 @@
FLAG_PERMISSION_REVOKE_WHEN_REQUESTED);
updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId);
- // SPECIAL BEHAVIOR for background location. Foreground only by default.
- if (newPerm.equals(ACCESS_BACKGROUND_LOCATION)) {
- int numSourcePerms = sourcePerms.size();
- for (int sourcePermNum = 0; sourcePermNum < numSourcePerms;
- sourcePermNum++) {
- String sourcePerm = sourcePerms.valueAt(sourcePermNum);
-
- if (ps.hasRuntimePermission(sourcePerm, userId)
- && ps.getRuntimePermissionState(sourcePerm, userId)
- .isGranted()
- && appOpsManager.unsafeCheckOpNoThrow(
- permissionToOp(sourcePerm), getUid(userId,
- getAppId(pkg.applicationInfo.uid)), pkgName)
- == MODE_ALLOWED) {
- setAppOpMode(sourcePerm, pkg, userId, MODE_FOREGROUND);
- }
- }
- } else {
- boolean inheritsFromInstallPerm = false;
- for (int sourcePermNum = 0; sourcePermNum < sourcePerms.size();
- sourcePermNum++) {
- if (ps.hasInstallPermission(sourcePerms.valueAt(sourcePermNum))) {
- inheritsFromInstallPerm = true;
- break;
- }
- }
-
- if (!origPs.hasRequestedPermission(sourcePerms)
- && !inheritsFromInstallPerm) {
- // Both permissions are new so nothing to inherit.
- if (DEBUG_PERMISSIONS) {
- Slog.i(TAG, newPerm + " does not inherit from " + sourcePerms
- + " for " + pkgName
- + " as split permission is also new");
- }
-
+ boolean inheritsFromInstallPerm = false;
+ for (int sourcePermNum = 0; sourcePermNum < sourcePerms.size();
+ sourcePermNum++) {
+ if (ps.hasInstallPermission(sourcePerms.valueAt(sourcePermNum))) {
+ inheritsFromInstallPerm = true;
break;
- } else {
- // Inherit from new install or existing runtime permissions
- inheritPermissionStateToNewImplicitPermissionLocked(sourcePerms,
- newPerm, ps, pkg, userId);
}
}
+
+ if (!origPs.hasRequestedPermission(sourcePerms)
+ && !inheritsFromInstallPerm) {
+ // Both permissions are new so nothing to inherit.
+ if (DEBUG_PERMISSIONS) {
+ Slog.i(TAG, newPerm + " does not inherit from " + sourcePerms
+ + " for " + pkgName + " as split permission is also new");
+ }
+
+ break;
+ } else {
+ // Inherit from new install or existing runtime permissions
+ inheritPermissionStateToNewImplicitPermissionLocked(sourcePerms,
+ newPerm, ps, pkg, userId);
+ }
}
}
}
@@ -2275,12 +2274,62 @@
}
private void updateAllPermissions(String volumeUuid, boolean sdkUpdated,
- Collection<PackageParser.Package> allPackages, PermissionCallback callback) {
+ boolean updatePermissionsOnPreQUpdate, Collection<PackageParser.Package> allPackages,
+ PermissionCallback callback) {
final int flags = UPDATE_PERMISSIONS_ALL |
(sdkUpdated
? UPDATE_PERMISSIONS_REPLACE_PKG | UPDATE_PERMISSIONS_REPLACE_ALL
: 0);
updatePermissions(null, null, volumeUuid, flags, allPackages, callback);
+
+ if (updatePermissionsOnPreQUpdate) {
+ final int[] userIds = UserManagerService.getInstance().getUserIds();
+
+ for (PackageParser.Package pkg : allPackages) {
+ final PackageSetting ps = (PackageSetting) pkg.mExtras;
+ if (ps == null) {
+ return;
+ }
+
+ final boolean appSupportsRuntimePermissions =
+ pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.M;
+ final PermissionsState permsState = ps.getPermissionsState();
+
+ for (String permName : new String[]{Manifest.permission.ACCESS_FINE_LOCATION,
+ Manifest.permission.ACCESS_COARSE_LOCATION,
+ Manifest.permission.ACCESS_BACKGROUND_LOCATION}) {
+ final BasePermission bp = mSettings.getPermissionLocked(permName);
+
+ for (int userId : userIds) {
+ if (Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.LOCATION_PERMISSIONS_UPGRADE_TO_Q_MODE, 0, userId)
+ != 0) {
+ continue;
+ }
+
+ final PermissionState permState = permsState.getRuntimePermissionState(
+ permName, userId);
+
+ if (permState != null
+ && (permState.getFlags() & BLOCKING_PERMISSION_FLAGS) == 0) {
+ if (permState.isGranted()) {
+ permsState.updatePermissionFlags(bp, userId,
+ USER_PERMISSION_FLAGS, 0);
+ }
+
+ if (appSupportsRuntimePermissions) {
+ permsState.revokeRuntimePermission(bp, userId);
+ } else {
+ // Force a review even for apps that were already installed
+ permsState.updatePermissionFlags(bp, userId,
+ FLAG_PERMISSION_REVIEW_REQUIRED,
+ FLAG_PERMISSION_REVIEW_REQUIRED);
+ }
+ }
+ }
+ }
+ }
+ }
}
private void updatePermissions(String changingPkgName, PackageParser.Package changingPkg,
@@ -2735,9 +2784,10 @@
}
@Override
public void updateAllPermissions(String volumeUuid, boolean sdkUpdated,
- Collection<PackageParser.Package> allPackages, PermissionCallback callback) {
+ boolean updatePermissionsOnPreQUpdate, Collection<PackageParser.Package> allPackages,
+ PermissionCallback callback) {
PermissionManagerService.this.updateAllPermissions(
- volumeUuid, sdkUpdated, allPackages, callback);
+ volumeUuid, sdkUpdated, updatePermissionsOnPreQUpdate, allPackages, callback);
}
@Override
public String[] getAppOpPermissionPackages(String permName) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index 305f165..6c09fa0 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -83,7 +83,8 @@
public abstract void updatePermissions(@Nullable String packageName,
@Nullable PackageParser.Package pkg, boolean replaceGrant,
@NonNull Collection<PackageParser.Package> allPacakges, PermissionCallback callback);
- public abstract void updateAllPermissions(@Nullable String volumeUuid, boolean sdkUpdated,
+ public abstract void updateAllPermissions(@Nullable String volumeUuid, boolean sdkUpdate,
+ boolean updatePermissionsOnPreQUpdate,
@NonNull Collection<PackageParser.Package> allPacakges, PermissionCallback callback);
/**