From c94ba820fb881781d0d86648bb637d5c2a0f7c63 Mon Sep 17 00:00:00 2001 From: "Philip P. Moltmann" Date: Mon, 4 Mar 2019 16:48:22 -0800 Subject: [PATCH] Implement dual-permission model for storage. - Pre-Q apps use the legacy READ/WRITE_EXTERNAL_STORAGE permissions - Post-Q apps use the READ_MEDIA_* permissions - Grandfathered Q apps have all storage permission granted fixed. In the UI they show only the legacy storage permissions - The OP_LEGACY_STORAGE controls whether an app is grandfathered Data providers should check both old and new permission model as permissions that are not used are set as granted. Test: atest CtsPermissionTestCases:android.permission.cts.DualStoragePermissionModelTest Fixes: 126785920 Change-Id: I668530e62125d95f122a94ae39f17007391bcaa5 --- api/system-current.txt | 4 +- api/test-current.txt | 2 + core/java/android/app/AppOpsManager.java | 3 +- .../android/content/pm/PackageManager.java | 13 +- core/res/AndroidManifest.xml | 6 +- data/etc/platform.xml | 22 ++- .../android/server/StorageManagerService.java | 57 +++++- .../permission/PermissionManagerService.java | 181 ++++++++++++++++++ .../android/server/pm/permission/TEST_MAPPING | 3 + 9 files changed, 271 insertions(+), 20 deletions(-) diff --git a/api/system-current.txt b/api/system-current.txt index 42b8a5d5340ca..45fa19d9df3aa 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -338,6 +338,7 @@ package android.app { field public static final String OPSTR_GET_ACCOUNTS = "android:get_accounts"; field public static final String OPSTR_GPS = "android:gps"; field public static final String OPSTR_INSTANT_APP_START_FOREGROUND = "android:instant_app_start_foreground"; + field public static final String OPSTR_LEGACY_STORAGE = "android:legacy_storage"; field public static final String OPSTR_MANAGE_IPSEC_TUNNELS = "android:manage_ipsec_tunnels"; field public static final String OPSTR_MUTE_MICROPHONE = "android:mute_microphone"; field public static final String OPSTR_NEIGHBORING_CELLS = "android:neighboring_cells"; @@ -1647,6 +1648,7 @@ package android.content.pm { field public static final String FEATURE_BROADCAST_RADIO = "android.hardware.broadcastradio"; field public static final String FEATURE_TELEPHONY_CARRIERLOCK = "android.hardware.telephony.carrierlock"; field public static final int FLAG_PERMISSION_GRANTED_BY_DEFAULT = 32; // 0x20 + field public static final int FLAG_PERMISSION_HIDDEN = 1024; // 0x400 field public static final int FLAG_PERMISSION_POLICY_FIXED = 4; // 0x4 field public static final int FLAG_PERMISSION_REVIEW_REQUIRED = 64; // 0x40 field public static final int FLAG_PERMISSION_REVOKE_ON_UPGRADE = 8; // 0x8 @@ -1717,7 +1719,7 @@ package android.content.pm { method public void onPermissionsChanged(int); } - @IntDef(prefix={"FLAG_PERMISSION_"}, value={android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET, android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE, android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT, android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED, android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface PackageManager.PermissionFlags { + @IntDef(prefix={"FLAG_PERMISSION_"}, value={android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET, android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE, android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT, android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED, android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED, android.content.pm.PackageManager.FLAG_PERMISSION_HIDDEN}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface PackageManager.PermissionFlags { } public class PermissionGroupInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable { diff --git a/api/test-current.txt b/api/test-current.txt index b7555a20f05b2..22ccc19c407e2 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -168,6 +168,7 @@ package android.app { field public static final String OPSTR_GET_ACCOUNTS = "android:get_accounts"; field public static final String OPSTR_GPS = "android:gps"; field public static final String OPSTR_INSTANT_APP_START_FOREGROUND = "android:instant_app_start_foreground"; + field public static final String OPSTR_LEGACY_STORAGE = "android:legacy_storage"; field public static final String OPSTR_MANAGE_IPSEC_TUNNELS = "android:manage_ipsec_tunnels"; field public static final String OPSTR_MUTE_MICROPHONE = "android:mute_microphone"; field public static final String OPSTR_NEIGHBORING_CELLS = "android:neighboring_cells"; @@ -655,6 +656,7 @@ package android.content.pm { method @RequiresPermission(anyOf={"android.permission.GRANT_RUNTIME_PERMISSIONS", "android.permission.REVOKE_RUNTIME_PERMISSIONS"}) public abstract void updatePermissionFlags(String, String, int, int, @NonNull android.os.UserHandle); field public static final String FEATURE_ADOPTABLE_STORAGE = "android.software.adoptable_storage"; field public static final String FEATURE_FILE_BASED_ENCRYPTION = "android.software.file_based_encryption"; + field public static final int FLAG_PERMISSION_HIDDEN = 1024; // 0x400 field public static final int FLAG_PERMISSION_REVIEW_REQUIRED = 64; // 0x40 field public static final int FLAG_PERMISSION_REVOKE_ON_UPGRADE = 8; // 0x8 field public static final int FLAG_PERMISSION_REVOKE_WHEN_REQUESTED = 128; // 0x80 diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 91df05f352951..7ec81e53f2d13 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -48,7 +48,6 @@ import android.util.LongSparseLongArray; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; - import com.android.internal.annotations.Immutable; import com.android.internal.app.IAppOpsActiveCallback; import com.android.internal.app.IAppOpsCallback; @@ -1098,6 +1097,8 @@ public class AppOpsManager { /** @hide Write media of image type. */ public static final String OPSTR_WRITE_MEDIA_IMAGES = "android:write_media_images"; /** @hide Has a legacy (non-isolated) view of storage. */ + @TestApi + @SystemApi public static final String OPSTR_LEGACY_STORAGE = "android:legacy_storage"; /** @hide Interact with accessibility. */ @SystemApi diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 99324ba65f5c0..0613853893f47 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -3072,6 +3072,15 @@ public abstract class PackageManager { @SystemApi public static final int FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED = 1 << 9; + /** + * Permission flag: The permission should not be shown in the UI. + * + * @hide + */ + @SystemApi + @TestApi + public static final int FLAG_PERMISSION_HIDDEN = 1 << 10; + /** * Mask for all permission flags present in Android P * @@ -3090,7 +3099,7 @@ public abstract class PackageManager { * * @hide */ - public static final int MASK_PERMISSION_FLAGS_ALL = 0x3FF; + public static final int MASK_PERMISSION_FLAGS_ALL = 0x7FF; /** * Injected activity in app that forwards user to setting activity of that app. @@ -3801,6 +3810,7 @@ public abstract class PackageManager { FLAG_PERMISSION_GRANTED_BY_DEFAULT, FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED, FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED, + FLAG_PERMISSION_HIDDEN, /* FLAG_PERMISSION_REVOKE_WHEN_REQUESED */ @@ -6594,6 +6604,7 @@ public abstract class PackageManager { case FLAG_PERMISSION_REVOKE_WHEN_REQUESTED: return "REVOKE_WHEN_REQUESTED"; case FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED: return "USER_SENSITIVE_WHEN_GRANTED"; case FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED: return "USER_SENSITIVE_WHEN_DENIED"; + case FLAG_PERMISSION_HIDDEN: return "HIDDEN"; default: return Integer.toString(flag); } } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index c7417bffb7903..e65a9fd0ed61a 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -819,8 +819,7 @@ android:permissionGroup="android.permission-group.UNDEFINED" android:label="@string/permlab_sdcardRead" android:description="@string/permdesc_sdcardRead" - android:protectionLevel="dangerous" - android:permissionFlags="removed" /> + android:protectionLevel="dangerous" /> diff --git a/data/etc/platform.xml b/data/etc/platform.xml index 44d71e269a957..28d311ec065d6 100644 --- a/data/etc/platform.xml +++ b/data/etc/platform.xml @@ -202,17 +202,15 @@ - - + + - + @@ -220,6 +218,20 @@ + + + + + + + + + + + + + + diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index f4161103b699f..8d2c131b0389e 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -21,6 +21,9 @@ import static android.Manifest.permission.WRITE_MEDIA_STORAGE; import static android.app.AppOpsManager.MODE_ALLOWED; import static android.app.AppOpsManager.OP_LEGACY_STORAGE; import static android.app.AppOpsManager.OP_REQUEST_INSTALL_PACKAGES; +import static android.content.pm.PackageManager.FLAG_PERMISSION_HIDDEN; +import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED; +import static android.content.pm.PackageManager.GET_PERMISSIONS; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE; import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES; @@ -74,6 +77,7 @@ import android.content.res.ObbInfo; import android.database.ContentObserver; import android.net.Uri; import android.os.Binder; +import android.os.Build; import android.os.DropBoxManager; import android.os.Environment; import android.os.Environment.UserEnvironment; @@ -294,6 +298,19 @@ class StorageManagerService extends IStorageManager.Stub private static final String ATTR_LAST_TRIM_MILLIS = "lastTrimMillis"; private static final String ATTR_LAST_BENCH_MILLIS = "lastBenchMillis"; + private static final String[] LEGACY_STORAGE_PERMISSIONS = { + Manifest.permission.READ_EXTERNAL_STORAGE, + Manifest.permission.WRITE_EXTERNAL_STORAGE + }; + + private static final String[] ALL_STORAGE_PERMISSIONS = { + Manifest.permission.READ_EXTERNAL_STORAGE, + Manifest.permission.WRITE_EXTERNAL_STORAGE, + Manifest.permission.READ_MEDIA_AUDIO, + Manifest.permission.READ_MEDIA_VIDEO, + Manifest.permission.READ_MEDIA_IMAGES + }; + private final AtomicFile mSettingsFile; /** @@ -1685,23 +1702,27 @@ class StorageManagerService extends IStorageManager.Stub * If we're enabling isolated storage, we need to remember which existing * apps have already been using shared storage, and grant them legacy access * to keep them running smoothly. + * + * @see com.android.server.pm.permission.PermissionManagerService + * #applyLegacyStoragePermissionModel */ private void applyLegacyStorage() { final AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class); final UserManagerInternal um = LocalServices.getService(UserManagerInternal.class); for (int userId : um.getUserIds()) { + final UserHandle user = UserHandle.of(userId); final PackageManager pm; try { - pm = mContext.createPackageContextAsUser(mContext.getPackageName(), - 0, UserHandle.of(userId)).getPackageManager(); + pm = mContext.createPackageContextAsUser(mContext.getPackageName(), 0, + user).getPackageManager(); } catch (PackageManager.NameNotFoundException e) { throw new RuntimeException(e); } - final List pkgs = pm.getPackagesHoldingPermissions(new String[] { - android.Manifest.permission.READ_EXTERNAL_STORAGE, - android.Manifest.permission.WRITE_EXTERNAL_STORAGE - }, MATCH_UNINSTALLED_PACKAGES | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE); + final List pkgs = pm.getPackagesHoldingPermissions( + LEGACY_STORAGE_PERMISSIONS, + MATCH_UNINSTALLED_PACKAGES | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE + | GET_PERMISSIONS); for (PackageInfo pkg : pkgs) { final int uid = pkg.applicationInfo.uid; final String packageName = pkg.applicationInfo.packageName; @@ -1714,8 +1735,28 @@ class StorageManagerService extends IStorageManager.Stub Log.d(TAG, "Found " + uid + " " + packageName + " with granted storage access, last accessed " + lastAccess); if (lastAccess > 0) { - appOps.setMode(AppOpsManager.OP_LEGACY_STORAGE, - uid, packageName, AppOpsManager.MODE_ALLOWED); + appOps.setUidMode(AppOpsManager.OP_LEGACY_STORAGE, uid, + AppOpsManager.MODE_ALLOWED); + + // Grandfather pre-Q app by granting all permissions and fixing them. The user + // needs to uninstall the app to revoke the permissions. + // TODO: Deal with shard Uids + if (pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.Q) { + for (String perm : ALL_STORAGE_PERMISSIONS) { + if (ArrayUtils.contains(pkg.requestedPermissions, perm)) { + pm.grantRuntimePermission(packageName, perm, user); + + int flags = FLAG_PERMISSION_SYSTEM_FIXED; + if (!ArrayUtils.contains(LEGACY_STORAGE_PERMISSIONS, perm)) { + flags |= FLAG_PERMISSION_HIDDEN; + } + + pm.updatePermissionFlags(perm, packageName, + FLAG_PERMISSION_SYSTEM_FIXED | FLAG_PERMISSION_HIDDEN, + flags, user); + } + } + } } } } 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 897b885c5a3cd..e36ac23d64732 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -17,14 +17,20 @@ package com.android.server.pm.permission; import static android.Manifest.permission.READ_EXTERNAL_STORAGE; +import static android.Manifest.permission.READ_MEDIA_AUDIO; +import static android.Manifest.permission.READ_MEDIA_IMAGES; +import static android.Manifest.permission.READ_MEDIA_VIDEO; import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE; import static android.app.AppOpsManager.MODE_ALLOWED; 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_LEGACY_STORAGE; import static android.app.AppOpsManager.OP_NONE; import static android.app.AppOpsManager.permissionToOp; import static android.app.AppOpsManager.permissionToOpCode; import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT; +import static android.content.pm.PackageManager.FLAG_PERMISSION_HIDDEN; import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED; import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED; import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE; @@ -1149,6 +1155,8 @@ public class PermissionManagerService { updatedUserIds); updatedUserIds = setInitialGrantForNewImplicitPermissionsLocked(origPermissions, permissionsState, pkg, updatedUserIds); + updatedUserIds = applyLegacyStoragePermissionModel(origPermissions, permissionsState, + pkg, updatedUserIds); setAppOpsLocked(permissionsState, pkg); } @@ -1467,6 +1475,179 @@ public class PermissionManagerService { return updatedUserIds; } + /** + * Pre-Q apps use READ/WRITE_EXTERNAL_STORAGE, post-Q apps use READ_MEDIA_AUDIO/VIDEO/IMAGES. + * + *

There is the special case of the grandfathered post-Q app that has all legacy and modern + * permissions system-fixed granted. The only way to remove these permissions is to uninstall + * the app. + * + * @param origPs The permission state of the package before the update + * @param ps The permissions state of the package + * @param pkg The package + * @param updatedUserIds The userIds we have already been updated before + * + * @return The userIds that have been updated + * + * @see com.android.server.StorageManagerService#applyLegacyStorage() + */ + private @NonNull int[] applyLegacyStoragePermissionModel(@NonNull PermissionsState origPs, + @NonNull PermissionsState ps, @NonNull PackageParser.Package pkg, + @NonNull int[] updatedUserIds) { + AppOpsManagerInternal appOpsManager = LocalServices.getService(AppOpsManagerInternal.class); + int[] users = UserManagerService.getInstance().getUserIds(); + + boolean isQApp = pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.Q; + boolean isPreMApp = pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M; + int appId = getAppId(pkg.applicationInfo.uid); + + int numRequestedPerms = pkg.requestedPermissions.size(); + for (int i = 0; i < numRequestedPerms; i++) { + String perm = pkg.requestedPermissions.get(i); + + boolean isLegacyStoragePermission = false; + boolean isModernStoragePermission = false; + switch (perm) { + case READ_EXTERNAL_STORAGE: + case WRITE_EXTERNAL_STORAGE: + isLegacyStoragePermission = true; + break; + case READ_MEDIA_AUDIO: + case READ_MEDIA_VIDEO: + case READ_MEDIA_IMAGES: + isModernStoragePermission = true; + break; + default: + // 'perm' is not a storage permission, skip it + continue; + } + + BasePermission bp = mSettings.getPermissionLocked(perm); + + for (int userId : users) { + boolean useLegacyStoragePermissionModel; + if (isQApp) { + useLegacyStoragePermissionModel = appOpsManager.checkOperationUnchecked( + OP_LEGACY_STORAGE, getUid(userId, appId), pkg.packageName) + == MODE_ALLOWED; + } else { + useLegacyStoragePermissionModel = true; + } + + int origCombinedLegacyFlags = + origPs.getPermissionFlags(READ_EXTERNAL_STORAGE, userId) + | origPs.getPermissionFlags(WRITE_EXTERNAL_STORAGE, userId); + + int origCombinedModernFlags = origPs.getPermissionFlags(READ_MEDIA_AUDIO, userId) + | origPs.getPermissionFlags(READ_MEDIA_VIDEO, userId) + | origPs.getPermissionFlags(READ_MEDIA_IMAGES, userId); + + boolean oldPermAreLegacyStorageModel = + (origCombinedLegacyFlags & FLAG_PERMISSION_HIDDEN) == 0; + boolean oldPermAreModernStorageModel = + (origCombinedModernFlags & FLAG_PERMISSION_HIDDEN) == 0; + + if (oldPermAreLegacyStorageModel && oldPermAreModernStorageModel) { + // This only happens after an platform upgrade from before Q + oldPermAreModernStorageModel = false; + } + + boolean shouldBeRestricted; + boolean shouldBeFixed; + boolean shouldBeGranted = false; + boolean shouldBeRevoked = false; + int userFlags = -1; + if (useLegacyStoragePermissionModel) { + shouldBeRestricted = isModernStoragePermission; + shouldBeFixed = isQApp || isModernStoragePermission; + + if (shouldBeFixed) { + userFlags = 0; + shouldBeGranted = true; + shouldBeRevoked = false; + } else if (oldPermAreModernStorageModel) { + // Inherit grant state on permission model change + userFlags = origCombinedModernFlags; + + shouldBeGranted = origPs.hasRuntimePermission(READ_MEDIA_AUDIO, userId) + || origPs.hasRuntimePermission(READ_MEDIA_VIDEO, userId) + || origPs.hasRuntimePermission(READ_MEDIA_IMAGES, userId); + + shouldBeRevoked = !shouldBeGranted; + } + } else { + shouldBeRestricted = isLegacyStoragePermission; + shouldBeFixed = isLegacyStoragePermission; + + if (shouldBeFixed) { + userFlags = 0; + shouldBeGranted = true; + shouldBeRevoked = false; + } else if (oldPermAreLegacyStorageModel) { + // Inherit grant state on permission model change + userFlags = origCombinedLegacyFlags; + + shouldBeGranted = origPs.hasRuntimePermission(READ_EXTERNAL_STORAGE, userId) + || origPs.hasRuntimePermission(WRITE_EXTERNAL_STORAGE, userId); + + if ((origCombinedLegacyFlags & FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0 + && !isPreMApp) { + shouldBeGranted = false; + } + + shouldBeRevoked = !shouldBeGranted; + } + } + + // Granted permissions can never be user fixed + if (shouldBeGranted & userFlags != -1) { + userFlags &= ~FLAG_PERMISSION_USER_FIXED; + } + + boolean changed = false; + synchronized (mLock) { + if (shouldBeGranted) { + if (isPreMApp) { + setAppOpMode(perm, pkg, userId, MODE_ALLOWED); + } else if (!ps.hasRuntimePermission(perm, userId)) { + ps.grantRuntimePermission(bp, userId); + changed = true; + } + } + + if (shouldBeRevoked) { + if (isPreMApp) { + setAppOpMode(perm, pkg, userId, MODE_IGNORED); + } else if (ps.hasRuntimePermission(perm, userId)) { + ps.revokeRuntimePermission(bp, userId); + changed = true; + } + } + + if (shouldBeFixed) { + changed |= ps.updatePermissionFlags(mSettings.getPermissionLocked(perm), + userId, FLAG_PERMISSION_SYSTEM_FIXED, FLAG_PERMISSION_SYSTEM_FIXED); + } + + if (userFlags != -1) { + changed |= ps.updatePermissionFlags(mSettings.getPermissionLocked(perm), + userId, USER_PERMISSION_FLAGS, userFlags); + } + + changed |= ps.updatePermissionFlags(mSettings.getPermissionLocked(perm), userId, + FLAG_PERMISSION_HIDDEN, + shouldBeRestricted ? FLAG_PERMISSION_HIDDEN : 0); + } + + if (changed) { + updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId); + } + } + } + + return updatedUserIds; + } + /** * Fix app-op modes for runtime permissions. * diff --git a/services/core/java/com/android/server/pm/permission/TEST_MAPPING b/services/core/java/com/android/server/pm/permission/TEST_MAPPING index 2280d3fd91343..c610ed09a5a2a 100644 --- a/services/core/java/com/android/server/pm/permission/TEST_MAPPING +++ b/services/core/java/com/android/server/pm/permission/TEST_MAPPING @@ -19,6 +19,9 @@ }, { "include-filter": "android.permission.cts.PermissionFlagsTest" + }, + { + "include-filter": "android.permission.cts.DualStoragePermissionModelTest" } ] },