From 36744c716794df4b64f3975f165a2d7b2299316d Mon Sep 17 00:00:00 2001 From: Hai Zhang Date: Fri, 11 Sep 2020 11:47:51 -0700 Subject: [PATCH] Refactor PermissionsState to be a data class for migration. PackageManager Settings will now read permission state from PermissionManager as well, to maintain compatibility for dump and the package list file. As a result, we no longer need to write back to this legacy state before dump and writing package list. We still need to do so before we finish persistence migration though. The new AppIdPermissionState will be a system API once we finish migration of BasePermission. Bug: 158736025 Test: presubmit Change-Id: I3c7f20cef54084255108a0a889d8a3d7e3ab9d88 --- core/java/android/util/IntArray.java | 11 + .../server/pm/PackageManagerService.java | 17 +- .../com/android/server/pm/PackageSetting.java | 4 +- .../com/android/server/pm/SettingBase.java | 10 +- .../java/com/android/server/pm/Settings.java | 232 ++--- .../pm/permission/AppIdPermissionState.java | 320 ++++++ .../LegacyPermissionDataProvider.java | 44 + .../permission/PermissionManagerService.java | 129 ++- .../PermissionManagerServiceInternal.java | 14 +- .../pm/permission/PermissionsState.java | 970 ------------------ .../pm/PackageManagerSettingsTests.java | 31 +- 11 files changed, 592 insertions(+), 1190 deletions(-) create mode 100644 services/core/java/com/android/server/pm/permission/AppIdPermissionState.java create mode 100644 services/core/java/com/android/server/pm/permission/LegacyPermissionDataProvider.java delete mode 100644 services/core/java/com/android/server/pm/permission/PermissionsState.java diff --git a/core/java/android/util/IntArray.java b/core/java/android/util/IntArray.java index 5a74ec0e52c08..b77265b0ebf66 100644 --- a/core/java/android/util/IntArray.java +++ b/core/java/android/util/IntArray.java @@ -143,6 +143,17 @@ public class IntArray implements Cloneable { mSize += count; } + /** + * Adds the values in the specified array to this array. + */ + public void addAll(int[] values) { + final int count = values.length; + ensureCapacity(count); + + System.arraycopy(values, 0, mValues, mSize, count); + mSize += count; + } + /** * Ensures capacity to append at least count values. */ diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 3ca12ae6b8b95..1b3c0f7a20d78 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -1850,7 +1850,6 @@ public class PackageManagerService extends IPackageManager.Stub Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); synchronized (mLock) { removeMessages(WRITE_PACKAGE_LIST); - mPermissionManager.writeStateToPackageSettingsTEMP(); mSettings.writePackageListLPr(msg.arg1); } Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); @@ -2687,7 +2686,8 @@ public class PackageManagerService extends IPackageManager.Stub (i, pm) -> new Settings(Environment.getDataDirectory(), i.getPermissionManagerServiceInternal().getPermissionSettings(), - RuntimePermissionsPersistence.createInstance(), lock), + RuntimePermissionsPersistence.createInstance(), + i.getPermissionManagerServiceInternal(), lock), new Injector.LocalServicesProducer<>(ActivityTaskManagerInternal.class), new Injector.LocalServicesProducer<>(ActivityManagerInternal.class), new Injector.LocalServicesProducer<>(DeviceIdleInternal.class), @@ -4486,8 +4486,8 @@ public class PackageManagerService extends IPackageManager.Stub AndroidPackage p = ps.pkg; if (p != null) { // Compute GIDs only if requested - final int[] gids = (flags & PackageManager.GET_GIDS) == 0 - ? EMPTY_INT_ARRAY : mPermissionManager.getPackageGids(ps.name, userId); + final int[] gids = (flags & PackageManager.GET_GIDS) == 0 ? EMPTY_INT_ARRAY + : mPermissionManager.getGidsForUid(UserHandle.getUid(userId, ps.appId)); // Compute granted permissions only if package has requested permissions final Set permissions = ArrayUtils.isEmpty(p.getRequestedPermissions()) ? Collections.emptySet() @@ -4962,13 +4962,13 @@ public class PackageManagerService extends IPackageManager.Stub } // TODO: Shouldn't this be checking for package installed state for userId and // return null? - return mPermissionManager.getPackageGids(packageName, userId); + return mPermissionManager.getGidsForUid(UserHandle.getUid(userId, ps.appId)); } if ((flags & MATCH_KNOWN_PACKAGES) != 0) { final PackageSetting ps = mSettings.mPackages.get(packageName); if (ps != null && ps.isMatch(flags) && !shouldFilterApplicationLocked(ps, callingUid, userId)) { - return mPermissionManager.getPackageGids(packageName, userId); + return mPermissionManager.getGidsForUid(UserHandle.getUid(userId, ps.appId)); } } } @@ -18967,7 +18967,7 @@ public class PackageManagerService extends IPackageManager.Stub } if ((deletedPs.sharedUser == null || deletedPs.sharedUser.packages.size() == 0) && !isUpdatedSystemApp(deletedPs)) { - mPermissionManager.removePermissionsStateTEMP(removedAppId); + mPermissionManager.removeAppIdStateTEMP(removedAppId); } mPermissionManager.updatePermissions(deletedPs.name, null); if (deletedPs.sharedUser != null) { @@ -21838,8 +21838,6 @@ public class PackageManagerService extends IPackageManager.Stub protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return; - mPermissionManager.writeStateToPackageSettingsTEMP(); - DumpState dumpState = new DumpState(); boolean fullPreferred = false; boolean checkin = false; @@ -23718,7 +23716,6 @@ public class PackageManagerService extends IPackageManager.Stub mDirtyUsers.remove(userId); mUserNeedsBadging.delete(userId); mPermissionManager.onUserRemoved(userId); - mPermissionManager.writeStateToPackageSettingsTEMP(); mSettings.removeUserLPw(userId); mPendingBroadcasts.remove(userId); mInstantAppRegistry.onUserRemovedLPw(userId); diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java index 276f88082df07..855a5ff524fda 100644 --- a/services/core/java/com/android/server/pm/PackageSetting.java +++ b/services/core/java/com/android/server/pm/PackageSetting.java @@ -28,7 +28,7 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; import com.android.server.pm.parsing.pkg.AndroidPackage; -import com.android.server.pm.permission.PermissionsState; +import com.android.server.pm.permission.AppIdPermissionState; import com.android.server.pm.pkg.PackageStateUnserialized; import java.io.File; @@ -215,7 +215,7 @@ public class PackageSetting extends PackageSettingBase { } @Override - public PermissionsState getPermissionsState() { + public AppIdPermissionState getPermissionsState() { return (sharedUser != null) ? sharedUser.getPermissionsState() : super.getPermissionsState(); diff --git a/services/core/java/com/android/server/pm/SettingBase.java b/services/core/java/com/android/server/pm/SettingBase.java index 3e2ab05e83ecf..c1258b1efd48a 100644 --- a/services/core/java/com/android/server/pm/SettingBase.java +++ b/services/core/java/com/android/server/pm/SettingBase.java @@ -19,23 +19,23 @@ package com.android.server.pm; import android.content.pm.ApplicationInfo; import com.android.internal.annotations.VisibleForTesting; -import com.android.server.pm.permission.PermissionsState; +import com.android.server.pm.permission.AppIdPermissionState; @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public abstract class SettingBase { int pkgFlags; int pkgPrivateFlags; - protected final PermissionsState mPermissionsState; + protected final AppIdPermissionState mPermissionsState; SettingBase(int pkgFlags, int pkgPrivateFlags) { setFlags(pkgFlags); setPrivateFlags(pkgPrivateFlags); - mPermissionsState = new PermissionsState(); + mPermissionsState = new AppIdPermissionState(); } SettingBase(SettingBase orig) { - mPermissionsState = new PermissionsState(); + mPermissionsState = new AppIdPermissionState(); doCopy(orig); } @@ -49,7 +49,7 @@ public abstract class SettingBase { mPermissionsState.copyFrom(orig.mPermissionsState); } - public PermissionsState getPermissionsState() { + public AppIdPermissionState getPermissionsState() { return mPermissionsState; } diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 965430727d3c5..bae36b2ad353f 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -79,6 +79,7 @@ import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.AtomicFile; +import android.util.IntArray; import android.util.Log; import android.util.LogPrinter; import android.util.Pair; @@ -106,10 +107,11 @@ import com.android.server.pm.Installer.InstallerException; import com.android.server.pm.parsing.PackageInfoUtils; import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.pm.parsing.pkg.AndroidPackageUtils; +import com.android.server.pm.permission.AppIdPermissionState; +import com.android.server.pm.permission.AppIdPermissionState.PermissionState; import com.android.server.pm.permission.BasePermission; +import com.android.server.pm.permission.LegacyPermissionDataProvider; import com.android.server.pm.permission.PermissionSettings; -import com.android.server.pm.permission.PermissionsState; -import com.android.server.pm.permission.PermissionsState.PermissionState; import com.android.server.utils.TimingsTraceAndSlog; import libcore.io.IoUtils; @@ -416,9 +418,12 @@ public final class Settings { private final File mSystemDir; public final KeySetManagerService mKeySetManagerService = new KeySetManagerService(mPackages); + /** Settings and other information about permissions */ final PermissionSettings mPermissions; + private final LegacyPermissionDataProvider mPermissionDataProvider; + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) public Settings(Map pkgSettings) { mLock = new Object(); @@ -426,6 +431,7 @@ public final class Settings { mSystemDir = null; mPermissions = null; mRuntimePermissionsPersistence = null; + mPermissionDataProvider = null; mSettingsFilename = null; mBackupSettingsFilename = null; mPackageListFilename = null; @@ -434,12 +440,14 @@ public final class Settings { mKernelMappingFilename = null; } - Settings(File dataDir, PermissionSettings permission, - RuntimePermissionsPersistence runtimePermissionsPersistence, Object lock) { + Settings(File dataDir, PermissionSettings permissionSettings, + RuntimePermissionsPersistence runtimePermissionsPersistence, + LegacyPermissionDataProvider permissionDataProvider, Object lock) { mLock = lock; - mPermissions = permission; + mPermissions = permissionSettings; mRuntimePermissionsPersistence = new RuntimePermissionPersistence( - runtimePermissionsPersistence, mLock); + runtimePermissionsPersistence); + mPermissionDataProvider = permissionDataProvider; mSystemDir = new File(dataDir, "system"); mSystemDir.mkdirs(); @@ -1239,7 +1247,7 @@ public final class Settings { void writeAllRuntimePermissionsLPr() { for (int userId : UserManagerService.getInstance().getUserIds()) { - mRuntimePermissionsPersistence.writePermissionsForUserAsyncLPr(userId); + mRuntimePermissionsPersistence.writeStateForUserAsyncLPr(userId); } } @@ -2102,7 +2110,7 @@ public final class Settings { } void readInstallPermissionsLPr(XmlPullParser parser, - PermissionsState permissionsState) throws IOException, XmlPullParserException { + AppIdPermissionState permissionsState) throws IOException, XmlPullParserException { int outerDepth = parser.getDepth(); int type; while ((type=parser.next()) != XmlPullParser.END_DOCUMENT @@ -2131,25 +2139,7 @@ public final class Settings { final int flags = (flagsStr != null) ? Integer.parseInt(flagsStr, 16) : 0; - if (granted) { - if (permissionsState.grantInstallPermission(bp) == - PermissionsState.PERMISSION_OPERATION_FAILURE) { - Slog.w(PackageManagerService.TAG, "Permission already added: " + name); - XmlUtils.skipCurrentTag(parser); - } else { - permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL, - PackageManager.MASK_PERMISSION_FLAGS_ALL, flags); - } - } else { - if (permissionsState.revokeInstallPermission(bp) == - PermissionsState.PERMISSION_OPERATION_FAILURE) { - Slog.w(PackageManagerService.TAG, "Permission already added: " + name); - XmlUtils.skipCurrentTag(parser); - } else { - permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL, - PackageManager.MASK_PERMISSION_FLAGS_ALL, flags); - } - } + permissionsState.putInstallPermissionState(new PermissionState(bp, granted, flags)); } else { Slog.w(PackageManagerService.TAG, "Unknown element under : " + parser.getName()); @@ -2158,7 +2148,7 @@ public final class Settings { } } - void writePermissionsLPr(XmlSerializer serializer, List permissionStates) + void writePermissionsLPr(XmlSerializer serializer, Collection permissionStates) throws IOException { if (permissionStates.isEmpty()) { return; @@ -2641,7 +2631,11 @@ public final class Settings { } final boolean isDebug = pkg.pkg.isDebuggable(); - final int[] gids = pkg.getPermissionsState().computeGids(userIds); + final IntArray gids = new IntArray(); + for (final int userId : userIds) { + gids.addAll(mPermissionDataProvider.getGidsForUid(UserHandle.getUid(userId, + pkg.appId))); + } // Avoid any application that has a space in its path. if (dataPath.indexOf(' ') >= 0) @@ -2673,11 +2667,12 @@ public final class Settings { sb.append(" "); sb.append(AndroidPackageUtils.getSeInfo(pkg.pkg, pkg)); sb.append(" "); - if (gids != null && gids.length > 0) { - sb.append(gids[0]); - for (int i = 1; i < gids.length; i++) { + final int gidsSize = gids.size(); + if (gids != null && gids.size() > 0) { + sb.append(gids.get(0)); + for (int i = 1; i < gidsSize; i++) { sb.append(","); - sb.append(gids[i]); + sb.append(gids.get(i)); } } else { sb.append("none"); @@ -4482,8 +4477,9 @@ public final class Settings { } void dumpPackageLPr(PrintWriter pw, String prefix, String checkinTag, - ArraySet permissionNames, PackageSetting ps, SimpleDateFormat sdf, - Date date, List users, boolean dumpAll, boolean dumpAllComponents) { + ArraySet permissionNames, PackageSetting ps, + AppIdPermissionState permissionsState, SimpleDateFormat sdf, Date date, + List users, boolean dumpAll, boolean dumpAllComponents) { AndroidPackage pkg = ps.pkg; if (checkinTag != null) { pw.print(checkinTag); @@ -4810,7 +4806,6 @@ public final class Settings { } if (ps.sharedUser == null || permissionNames != null || dumpAll) { - PermissionsState permissionsState = ps.getPermissionsState(); dumpInstallPermissionsLPr(pw, prefix + " ", permissionNames, permissionsState); } @@ -4889,8 +4884,8 @@ public final class Settings { } if (ps.sharedUser == null) { - PermissionsState permissionsState = ps.getPermissionsState(); - dumpGidsLPr(pw, prefix + " ", permissionsState.computeGids(user.id)); + dumpGidsLPr(pw, prefix + " ", mPermissionDataProvider.getGidsForUid( + UserHandle.getUid(user.id, ps.appId))); dumpRuntimePermissionsLPr(pw, prefix + " ", permissionNames, permissionsState .getRuntimePermissionStates(user.id), dumpAll); } @@ -4933,8 +4928,10 @@ public final class Settings { && !packageName.equals(ps.name)) { continue; } + final AppIdPermissionState permissionsState = + mPermissionDataProvider.getAppIdPermissionState(ps.appId); if (permissionNames != null - && !ps.getPermissionsState().hasRequestedPermission(permissionNames)) { + && !permissionsState.hasPermissionState(permissionNames)) { continue; } @@ -4948,8 +4945,8 @@ public final class Settings { pw.println("Packages:"); printedSomething = true; } - dumpPackageLPr(pw, " ", checkin ? "pkg" : null, permissionNames, ps, sdf, date, users, - packageName != null, dumpAllComponents); + dumpPackageLPr(pw, " ", checkin ? "pkg" : null, permissionNames, ps, permissionsState, + sdf, date, users, packageName != null, dumpAllComponents); } printedSomething = false; @@ -4989,8 +4986,10 @@ public final class Settings { pw.println("Hidden system packages:"); printedSomething = true; } - dumpPackageLPr(pw, " ", checkin ? "dis" : null, permissionNames, ps, sdf, date, - users, packageName != null, dumpAllComponents); + final AppIdPermissionState permissionsState = + mPermissionDataProvider.getAppIdPermissionState(ps.appId); + dumpPackageLPr(pw, " ", checkin ? "dis" : null, permissionNames, ps, + permissionsState, sdf, date, users, packageName != null, dumpAllComponents); } } } @@ -5018,8 +5017,10 @@ public final class Settings { if (packageName != null && su != dumpState.getSharedUser()) { continue; } + final AppIdPermissionState permissionsState = + mPermissionDataProvider.getAppIdPermissionState(su.userId); if (permissionNames != null - && !su.getPermissionsState().hasRequestedPermission(permissionNames)) { + && !permissionsState.hasPermissionState(permissionNames)) { continue; } if (!checkin) { @@ -5054,12 +5055,12 @@ public final class Settings { continue; } - final PermissionsState permissionsState = su.getPermissionsState(); dumpInstallPermissionsLPr(pw, prefix, permissionNames, permissionsState); for (int userId : UserManagerService.getInstance().getUserIds()) { - final int[] gids = permissionsState.computeGids(userId); - final List permissions = + final int[] gids = mPermissionDataProvider.getGidsForUid(UserHandle.getUid( + userId, su.userId)); + final Collection permissions = permissionsState.getRuntimePermissionStates(userId); if (!ArrayUtils.isEmpty(gids) || !permissions.isEmpty()) { pw.print(prefix); pw.print("User "); pw.print(userId); pw.println(": "); @@ -5120,7 +5121,7 @@ public final class Settings { } void dumpRuntimePermissionsLPr(PrintWriter pw, String prefix, ArraySet permissionNames, - List permissionStates, boolean dumpAll) { + Collection permissionStates, boolean dumpAll) { if (!permissionStates.isEmpty() || dumpAll) { pw.print(prefix); pw.println("runtime permissions:"); for (PermissionState permissionState : permissionStates) { @@ -5161,8 +5162,9 @@ public final class Settings { } void dumpInstallPermissionsLPr(PrintWriter pw, String prefix, ArraySet permissionNames, - PermissionsState permissionsState) { - List permissionStates = permissionsState.getInstallPermissionStates(); + AppIdPermissionState permissionsState) { + Collection permissionStates = + permissionsState.getInstallPermissionStates(); if (!permissionStates.isEmpty()) { pw.print(prefix); pw.println("install permissions:"); for (PermissionState permissionState : permissionStates) { @@ -5202,9 +5204,9 @@ public final class Settings { public void writeRuntimePermissionsForUserLPr(int userId, boolean sync) { if (sync) { - mRuntimePermissionsPersistence.writePermissionsForUserSyncLPr(userId); + mRuntimePermissionsPersistence.writeStateForUserSyncLPr(userId); } else { - mRuntimePermissionsPersistence.writePermissionsForUserAsyncLPr(userId); + mRuntimePermissionsPersistence.writeStateForUserAsyncLPr(userId); } } @@ -5292,8 +5294,6 @@ public final class Settings { private final Handler mHandler = new MyHandler(); - private final Object mPersistenceLock; - @GuardedBy("mLock") private final SparseBooleanArray mWriteScheduled = new SparseBooleanArray(); @@ -5313,10 +5313,8 @@ public final class Settings { // The mapping keys are user ids. private final SparseBooleanArray mPermissionUpgradeNeeded = new SparseBooleanArray(); - public RuntimePermissionPersistence(RuntimePermissionsPersistence persistence, - Object persistenceLock) { + public RuntimePermissionPersistence(RuntimePermissionsPersistence persistence) { mPersistence = persistence; - mPersistenceLock = persistenceLock; } @GuardedBy("Settings.this.mLock") @@ -5327,7 +5325,7 @@ public final class Settings { @GuardedBy("Settings.this.mLock") void setVersionLPr(int version, int userId) { mVersions.put(userId, version); - writePermissionsForUserAsyncLPr(userId); + writeStateForUserAsyncLPr(userId); } @GuardedBy("Settings.this.mLock") @@ -5342,7 +5340,7 @@ public final class Settings { + "set before trying to update the fingerprint."); } mFingerprints.put(userId, mExtendedFingerprint); - writePermissionsForUserAsyncLPr(userId); + writeStateForUserAsyncLPr(userId); } public void setPermissionControllerVersion(long version) { @@ -5361,13 +5359,7 @@ public final class Settings { return Build.FINGERPRINT + "?pc_version=" + version; } - public void writePermissionsForUserSyncLPr(int userId) { - mHandler.removeMessages(userId); - writePermissionsSync(userId); - } - - @GuardedBy("Settings.this.mLock") - public void writePermissionsForUserAsyncLPr(int userId) { + public void writeStateForUserAsyncLPr(int userId) { final long currentTimeMillis = SystemClock.uptimeMillis(); if (mWriteScheduled.get(userId)) { @@ -5399,59 +5391,53 @@ public final class Settings { } } - private void writePermissionsSync(int userId) { - RuntimePermissionsState runtimePermissions; - synchronized (mPersistenceLock) { - mWriteScheduled.delete(userId); + public void writeStateForUserSyncLPr(int userId) { + mHandler.removeMessages(userId); + mWriteScheduled.delete(userId); - int version = mVersions.get(userId, INITIAL_VERSION); + int version = mVersions.get(userId, INITIAL_VERSION); - String fingerprint = mFingerprints.get(userId); + String fingerprint = mFingerprints.get(userId); - Map> packagePermissions = - new ArrayMap<>(); - int packagesSize = mPackages.size(); - for (int i = 0; i < packagesSize; i++) { - String packageName = mPackages.keyAt(i); - PackageSetting packageSetting = mPackages.valueAt(i); - if (packageSetting.sharedUser == null) { - List permissions = - getPermissionsFromPermissionsState( - packageSetting.getPermissionsState(), userId); - packagePermissions.put(packageName, permissions); - } - } - - Map> sharedUserPermissions = - new ArrayMap<>(); - final int sharedUsersSize = mSharedUsers.size(); - for (int i = 0; i < sharedUsersSize; i++) { - String sharedUserName = mSharedUsers.keyAt(i); - SharedUserSetting sharedUserSetting = mSharedUsers.valueAt(i); + Map> packagePermissions = + new ArrayMap<>(); + int packagesSize = mPackages.size(); + for (int i = 0; i < packagesSize; i++) { + String packageName = mPackages.keyAt(i); + PackageSetting packageSetting = mPackages.valueAt(i); + if (packageSetting.sharedUser == null) { List permissions = getPermissionsFromPermissionsState( - sharedUserSetting.getPermissionsState(), userId); - sharedUserPermissions.put(sharedUserName, permissions); + packageSetting.getPermissionsState(), userId); + packagePermissions.put(packageName, permissions); } - - runtimePermissions = new RuntimePermissionsState(version, fingerprint, - packagePermissions, sharedUserPermissions); } + Map> sharedUserPermissions = + new ArrayMap<>(); + final int sharedUsersSize = mSharedUsers.size(); + for (int i = 0; i < sharedUsersSize; i++) { + String sharedUserName = mSharedUsers.keyAt(i); + SharedUserSetting sharedUserSetting = mSharedUsers.valueAt(i); + List permissions = + getPermissionsFromPermissionsState( + sharedUserSetting.getPermissionsState(), userId); + sharedUserPermissions.put(sharedUserName, permissions); + } + + RuntimePermissionsState runtimePermissions = new RuntimePermissionsState(version, + fingerprint, packagePermissions, sharedUserPermissions); + mPersistence.writeForUser(runtimePermissions, UserHandle.of(userId)); } @NonNull private List getPermissionsFromPermissionsState( - @NonNull PermissionsState permissionsState, @UserIdInt int userId) { - List permissionStates = permissionsState.getRuntimePermissionStates( - userId); - List permissions = - new ArrayList<>(); - int permissionStatesSize = permissionStates.size(); - for (int i = 0; i < permissionStatesSize; i++) { - PermissionState permissionState = permissionStates.get(i); - + @NonNull AppIdPermissionState permissionsState, @UserIdInt int userId) { + Collection permissionStates = + permissionsState.getRuntimePermissionStates(userId); + List permissions = new ArrayList<>(); + for (PermissionState permissionState : permissionStates) { RuntimePermissionsState.PermissionState permission = new RuntimePermissionsState.PermissionState(permissionState.getName(), permissionState.isGranted(), permissionState.getFlags()); @@ -5480,7 +5466,7 @@ public final class Settings { userId)); if (runtimePermissions == null) { readLegacyStateForUserSyncLPr(userId); - writePermissionsForUserAsyncLPr(userId); + writeStateForUserAsyncLPr(userId); return; } @@ -5536,7 +5522,7 @@ public final class Settings { private void readPermissionsStateLpr( @NonNull List permissions, - @NonNull PermissionsState permissionsState, @UserIdInt int userId) { + @NonNull AppIdPermissionState permissionsState, @UserIdInt int userId) { int permissionsSize = permissions.size(); for (int i = 0; i < permissionsSize; i++) { RuntimePermissionsState.PermissionState permission = permissions.get(i); @@ -5550,14 +5536,8 @@ public final class Settings { boolean granted = permission.isGranted(); int flags = permission.getFlags(); - if (granted) { - permissionsState.grantRuntimePermission(basePermission, userId); - permissionsState.updatePermissionFlags(basePermission, userId, - PackageManager.MASK_PERMISSION_FLAGS_ALL, flags); - } else { - permissionsState.updatePermissionFlags(basePermission, userId, - PackageManager.MASK_PERMISSION_FLAGS_ALL, flags); - } + permissionsState.putRuntimePermissionState(new PermissionState(basePermission, + granted, flags), userId); } } @@ -5638,8 +5618,9 @@ public final class Settings { } } - private void parsePermissionsLPr(XmlPullParser parser, PermissionsState permissionsState, - int userId) throws IOException, XmlPullParserException { + private void parsePermissionsLPr(XmlPullParser parser, + AppIdPermissionState permissionsState, int userId) + throws IOException, XmlPullParserException { final int outerDepth = parser.getDepth(); int type; while ((type = parser.next()) != XmlPullParser.END_DOCUMENT @@ -5666,15 +5647,8 @@ public final class Settings { final int flags = (flagsStr != null) ? Integer.parseInt(flagsStr, 16) : 0; - if (granted) { - permissionsState.grantRuntimePermission(bp, userId); - permissionsState.updatePermissionFlags(bp, userId, - PackageManager.MASK_PERMISSION_FLAGS_ALL, flags); - } else { - permissionsState.updatePermissionFlags(bp, userId, - PackageManager.MASK_PERMISSION_FLAGS_ALL, flags); - } - + permissionsState.putRuntimePermissionState(new PermissionState(bp, granted, + flags), userId); } break; } @@ -5690,7 +5664,9 @@ public final class Settings { public void handleMessage(Message message) { final int userId = message.what; Runnable callback = (Runnable) message.obj; - writePermissionsSync(userId); + synchronized (mLock) { + writeStateForUserSyncLPr(userId); + } if (callback != null) { callback.run(); } diff --git a/services/core/java/com/android/server/pm/permission/AppIdPermissionState.java b/services/core/java/com/android/server/pm/permission/AppIdPermissionState.java new file mode 100644 index 0000000000000..aabdafdd453ad --- /dev/null +++ b/services/core/java/com/android/server/pm/permission/AppIdPermissionState.java @@ -0,0 +1,320 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.permission; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.UserIdInt; +import android.os.UserHandle; +import android.util.ArrayMap; +import android.util.SparseArray; +import android.util.SparseBooleanArray; + +import java.util.Collection; +import java.util.Collections; +import java.util.Objects; + +/** + * Legacy permission state that was associated with packages or shared users. + */ +//@SystemApi(client = SystemApi.Client.SYSTEM_SERVER) +public final class AppIdPermissionState { + // Maps from user IDs to user states. + @NonNull + private final SparseArray mUserStates = new SparseArray<>(); + + // Keyed by user IDs. + @NonNull + private final SparseBooleanArray mMissing = new SparseBooleanArray(); + + /** + * Copy from another permission state. + * + * @param other the other permission state. + * + * @hide + */ + public void copyFrom(@NonNull AppIdPermissionState other) { + if (other == this) { + return; + } + + mUserStates.clear(); + final int userStatesSize = other.mUserStates.size(); + for (int i = 0; i < userStatesSize; i++) { + mUserStates.put(other.mUserStates.keyAt(i), + new UserState(other.mUserStates.valueAt(i))); + } + + mMissing.clear(); + final int missingSize = other.mMissing.size(); + for (int i = 0; i < missingSize; i++) { + mMissing.put(other.mMissing.keyAt(i), other.mMissing.valueAt(i)); + } + } + + /** + * Reset this permission state. + * + * @hide + */ + public void reset() { + mUserStates.clear(); + mMissing.clear(); + } + + @Override + public boolean equals(@Nullable Object object) { + if (this == object) { + return true; + } + if (object == null) { + return false; + } + if (getClass() != object.getClass()) { + return false; + } + final AppIdPermissionState other = (AppIdPermissionState) object; + return Objects.equals(mUserStates, other.mUserStates) + && Objects.equals(mMissing, other.mMissing); + } + + /** + * Put a install permission state. + * + * @param permissionState the permission state + */ + public void putInstallPermissionState(@NonNull PermissionState permissionState) { + putPermissionState(permissionState, UserHandle.USER_ALL); + } + + /** + * Put a runtime permission state for a user. + * + * @param permissionState the permission state + * @param userId the user ID + */ + public void putRuntimePermissionState(@NonNull PermissionState permissionState, + @UserIdInt int userId) { + checkUserId(userId); + putPermissionState(permissionState, userId); + } + + private void putPermissionState(@NonNull PermissionState permissionState, + @UserIdInt int userId) { + UserState userState = mUserStates.get(userId); + if (userState == null) { + userState = new UserState(); + mUserStates.put(userId, userState); + } + userState.putPermissionState(permissionState); + } + + /** + * Check whether there are any permission states for the given permissions. + * + * @param permissionNames the permission names + * @return whether there are any permission states + * + * @hide + */ + public boolean hasPermissionState(@NonNull Collection permissionNames) { + final int userStatesSize = mUserStates.size(); + for (int i = 0; i < userStatesSize; i++) { + final UserState userState = mUserStates.valueAt(i); + for (final String permissionName : permissionNames) { + if (userState.getPermissionState(permissionName) != null) { + return true; + } + } + } + return false; + } + + /** + * Get all the install permission states. + * + * @return the install permission states + */ + @NonNull + public Collection getInstallPermissionStates() { + return getPermissionStates(UserHandle.USER_ALL); + } + + /** + * Get all the runtime permission states for a user. + * + * @param userId the user ID + * @return the runtime permission states + */ + @NonNull + public Collection getRuntimePermissionStates(@UserIdInt int userId) { + checkUserId(userId); + return getPermissionStates(userId); + } + + @NonNull + private Collection getPermissionStates(@UserIdInt int userId) { + final UserState userState = mUserStates.get(userId); + if (userState == null) { + return Collections.emptyList(); + } + return userState.getPermissionStates(); + } + + /** + * Check whether the permission state is missing for a user. + *

+ * This can happen if permission state is rolled back and we'll need to generate a reasonable + * default state to keep the app usable. + * + * @param userId the user ID + * @return whether the permission state is missing + */ + public boolean isMissing(@UserIdInt int userId) { + checkUserId(userId); + return mMissing.get(userId); + } + + /** + * Set whether the permission state is missing for a user. + *

+ * This can happen if permission state is rolled back and we'll need to generate a reasonable + * default state to keep the app usable. + * + * @param missing whether the permission state is missing + * @param userId the user ID + */ + public void setMissing(boolean missing, @UserIdInt int userId) { + checkUserId(userId); + if (missing) { + mMissing.put(userId, true); + } else { + mMissing.delete(userId); + } + } + + private static void checkUserId(@UserIdInt int userId) { + if (userId < 0) { + throw new IllegalArgumentException("Invalid user ID " + userId); + } + } + + /** + * Legacy state for permissions for a user. + */ + private static final class UserState { + // Maps from permission names to permission states. + @NonNull + private final ArrayMap mPermissionStates = new ArrayMap<>(); + + public UserState() {} + + public UserState(@NonNull UserState other) { + final int permissionStatesSize = other.mPermissionStates.size(); + for (int i = 0; i < permissionStatesSize; i++) { + mPermissionStates.put(other.mPermissionStates.keyAt(i), + new PermissionState(other.mPermissionStates.valueAt(i))); + } + } + + @Nullable + public PermissionState getPermissionState(@NonNull String permissionName) { + return mPermissionStates.get(permissionName); + } + + public void putPermissionState(@NonNull PermissionState permissionState) { + mPermissionStates.put(permissionState.getName(), permissionState); + } + + @NonNull + public Collection getPermissionStates() { + return Collections.unmodifiableCollection(mPermissionStates.values()); + } + } + + /** + * Legacy state for a single permission. + */ + public static final class PermissionState { + @NonNull + private final BasePermission mPermission; + + private final boolean mGranted; + + private final int mFlags; + + /** + * Create a new instance of this class. + * + * @param permission the {@link BasePermission} for the permission + * @param granted whether the permission is granted + * @param flags the permission flags + */ + public PermissionState(@NonNull BasePermission permission, boolean granted, int flags) { + mPermission = permission; + mGranted = granted; + mFlags = flags; + } + + private PermissionState(@NonNull PermissionState other) { + mPermission = other.mPermission; + mGranted = other.mGranted; + mFlags = other.mFlags; + } + + /** + * Get the {@link BasePermission} for the permission. + * + * @return the {@link BasePermission} + */ + @NonNull + public BasePermission getPermission() { + return mPermission; + } + + /** + * Get the permission name. + * + * @return the permission name + */ + @NonNull + public String getName() { + return mPermission.getName(); + } + + /** + * Get whether the permission is granted. + * + * @return whether the permission is granted + */ + @NonNull + public boolean isGranted() { + return mGranted; + } + + /** + * Get the permission flags. + * + * @return the permission flags + */ + @NonNull + public int getFlags() { + return mFlags; + } + } +} diff --git a/services/core/java/com/android/server/pm/permission/LegacyPermissionDataProvider.java b/services/core/java/com/android/server/pm/permission/LegacyPermissionDataProvider.java new file mode 100644 index 0000000000000..7452b522b20a8 --- /dev/null +++ b/services/core/java/com/android/server/pm/permission/LegacyPermissionDataProvider.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.permission; + +import android.annotation.AppIdInt; +import android.annotation.NonNull; + +/** + * An interface for legacy code to read permission data in order to maintain compatibility. + */ +//@SystemApi(client = SystemApi.Client.SYSTEM_SERVER) +public interface LegacyPermissionDataProvider { + /** + * Get the legacy permission state of an app ID, either a package or a shared user. + * + * @param appId the app ID + * @return the legacy permission state + */ + @NonNull + public abstract AppIdPermissionState getAppIdPermissionState(@AppIdInt int appId); + + /** + * Get the GIDs computed from the permission state of a UID, either a package or a shared user. + * + * @param uid the UID + * @return the GIDs for the UID + */ + @NonNull + public abstract int[] getGidsForUid(int uid); +} 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 2f9e199bc506c..544f1225916ef 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -58,6 +58,7 @@ import static com.android.server.pm.permission.UidPermissionState.PERMISSION_OPE import static java.util.concurrent.TimeUnit.SECONDS; import android.Manifest; +import android.annotation.AppIdInt; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -2514,20 +2515,6 @@ public class PermissionManagerService extends IPermissionManager.Stub { return permission.computeGids(userId); } - @Nullable - private int[] getPackageGids(@NonNull String packageName, @UserIdInt int userId) { - final PackageSetting ps = mPackageManagerInt.getPackageSetting(packageName); - if (ps == null) { - return null; - } - final UidPermissionState uidState = getUidState(ps, userId); - if (uidState == null) { - Slog.e(TAG, "Missing permissions state for " + packageName + " and user " + userId); - return null; - } - return uidState.computeGids(userId); - } - /** * Restore the permission state for a package. * @@ -4766,7 +4753,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } - private void removeAppState(int appId) { + private void removeAppIdState(@AppIdInt int appId) { synchronized (mLock) { final int[] userIds = mState.getUserIds(); for (final int userId : userIds) { @@ -4780,7 +4767,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { final int[] userIds = getAllUserIds(); mPackageManagerInt.forEachPackageSetting(ps -> { final int appId = ps.getAppId(); - final PermissionsState permissionsState = ps.getPermissionsState(); + final AppIdPermissionState appIdState = ps.getPermissionsState(); synchronized (mLock) { for (final int userId : userIds) { @@ -4789,25 +4776,22 @@ public class PermissionManagerService extends IPermissionManager.Stub { userState.setInstallPermissionsFixed(ps.name, ps.areInstallPermissionsFixed()); final UidPermissionState uidState = userState.getOrCreateUidState(appId); uidState.reset(); - uidState.setGlobalGids(permissionsState.getGlobalGids()); - uidState.setMissing(permissionsState.isMissing(userId)); + uidState.setMissing(appIdState.isMissing(userId)); readStateFromPermissionStates(uidState, - permissionsState.getInstallPermissionStates(), false); + appIdState.getInstallPermissionStates(), false); readStateFromPermissionStates(uidState, - permissionsState.getRuntimePermissionStates(userId), true); + appIdState.getRuntimePermissionStates(userId), true); } } }); } private void readStateFromPermissionStates(@NonNull UidPermissionState uidState, - @NonNull List permissionStates, boolean isRuntime) { - final int permissionStatesSize = permissionStates.size(); - for (int i = 0; i < permissionStatesSize; i++) { - final PermissionsState.PermissionState permissionState = permissionStates.get(i); - final BasePermission permission = permissionState.getPermission(); - uidState.putPermissionState(permission, isRuntime, permissionState.isGranted(), - permissionState.getFlags()); + @NonNull Collection permissionStates, + boolean isRuntime) { + for (final AppIdPermissionState.PermissionState permissionState : permissionStates) { + uidState.putPermissionState(permissionState.getPermission(), isRuntime, + permissionState.isGranted(), permissionState.getFlags()); } } @@ -4815,8 +4799,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { final int[] userIds = mState.getUserIds(); mPackageManagerInt.forEachPackageSetting(ps -> { ps.setInstallPermissionsFixed(false); - final PermissionsState permissionsState = ps.getPermissionsState(); - permissionsState.reset(); + final AppIdPermissionState appIdState = ps.getPermissionsState(); + appIdState.reset(); final int appId = ps.getAppId(); synchronized (mLock) { @@ -4838,27 +4822,21 @@ public class PermissionManagerService extends IPermissionManager.Stub { continue; } - permissionsState.setGlobalGids(uidState.getGlobalGids()); - permissionsState.setMissing(uidState.isMissing(), userId); + appIdState.setMissing(uidState.isMissing(), userId); final List permissionStates = uidState.getPermissionStates(); final int permissionStatesSize = permissionStates.size(); for (int i = 0; i < permissionStatesSize; i++) { final PermissionState permissionState = permissionStates.get(i); - final BasePermission permission = permissionState.getPermission(); - if (permissionState.isGranted()) { - if (permissionState.isRuntime()) { - permissionsState.grantRuntimePermission(permission, userId); - } else { - permissionsState.grantInstallPermission(permission); - } - } - final int flags = permissionState.getFlags(); - if (flags != 0) { - final int flagsUserId = permissionState.isRuntime() ? userId - : UserHandle.USER_ALL; - permissionsState.updatePermissionFlags(permission, flagsUserId, flags, - flags); + final AppIdPermissionState.PermissionState legacyPermissionState = + new AppIdPermissionState.PermissionState( + permissionState.getPermission(), + permissionState.isGranted(), permissionState.getFlags()); + if (permissionState.isRuntime()) { + appIdState.putRuntimePermissionState(legacyPermissionState, + userId); + } else { + appIdState.putInstallPermissionState(legacyPermissionState); } } } @@ -4866,6 +4844,48 @@ public class PermissionManagerService extends IPermissionManager.Stub { }); } + @NonNull + private AppIdPermissionState getAppIdPermissionState(@AppIdInt int appId) { + final AppIdPermissionState appIdState = new AppIdPermissionState(); + final int[] userIds = mState.getUserIds(); + for (final int userId : userIds) { + final UidPermissionState uidState = getUidState(appId, userId); + if (uidState == null) { + Slog.e(TAG, "Missing permissions state for app ID " + appId + " and user ID " + + userId); + continue; + } + + final List permissionStates = uidState.getPermissionStates(); + final int permissionStatesSize = permissionStates.size(); + for (int i = 0; i < permissionStatesSize; i++) { + final PermissionState permissionState = permissionStates.get(i); + + final AppIdPermissionState.PermissionState legacyPermissionState = + new AppIdPermissionState.PermissionState(permissionState.getPermission(), + permissionState.isGranted(), permissionState.getFlags()); + if (permissionState.isRuntime()) { + appIdState.putRuntimePermissionState(legacyPermissionState, userId); + } else if (userId == UserHandle.USER_SYSTEM) { + appIdState.putInstallPermissionState(legacyPermissionState); + } + } + } + return appIdState; + } + + @NonNull + private int[] getGidsForUid(int uid) { + final int appId = UserHandle.getAppId(uid); + final int userId = UserHandle.getUserId(uid); + final UidPermissionState uidState = getUidState(appId, userId); + if (uidState == null) { + Slog.e(TAG, "Missing permissions state for app ID " + appId + " and user ID " + userId); + return EMPTY_INT_ARRAY; + } + return uidState.computeGids(userId); + } + private class PermissionManagerServiceInternalImpl extends PermissionManagerServiceInternal { @Override public void systemReady() { @@ -4910,8 +4930,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { PermissionManagerService.this.onUserRemoved(userId); } @Override - public void removePermissionsStateTEMP(int appId) { - PermissionManagerService.this.removeAppState(appId); + public void removeAppIdStateTEMP(@AppIdInt int appId) { + PermissionManagerService.this.removeAppIdState(appId); } @Override @UserIdInt @@ -4931,11 +4951,6 @@ public class PermissionManagerService extends IPermissionManager.Stub { public int[] getPermissionGids(@NonNull String permissionName, @UserIdInt int userId) { return PermissionManagerService.this.getPermissionGids(permissionName, userId); } - @Nullable - @Override - public int[] getPackageGids(@NonNull String packageName, @UserIdInt int userId) { - return PermissionManagerService.this.getPackageGids(packageName, userId); - } @Override public void grantRequestedRuntimePermissions(AndroidPackage pkg, int[] userIds, String[] grantedPermissions, int callingUid) { @@ -5263,6 +5278,16 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } } + + @NonNull + public AppIdPermissionState getAppIdPermissionState(@AppIdInt int appId) { + return PermissionManagerService.this.getAppIdPermissionState(appId); + } + + @NonNull + public int[] getGidsForUid(int uid) { + return PermissionManagerService.this.getGidsForUid(uid); + } } private static final class OnPermissionChangeListeners extends Handler { 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 6d9bd2a1b30d0..5ea3458fcbfa0 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java @@ -37,8 +37,8 @@ import java.util.function.Consumer; * * TODO: Should be merged into PermissionManagerInternal, but currently uses internal classes. */ -public abstract class PermissionManagerServiceInternal extends PermissionManagerInternal { - +public abstract class PermissionManagerServiceInternal extends PermissionManagerInternal + implements LegacyPermissionDataProvider { /** * Provider for package names. */ @@ -288,13 +288,13 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager public abstract void onUserRemoved(@UserIdInt int userId); /** - * Remove the {@code PermissionsState} associated with an app ID, called the same time as the + * Remove the permission state associated with an app ID, called the same time as the * removal of a {@code PackageSetitng}. * * TODO(zhanghai): This is a temporary method before we figure out a way to get notified of app * ID removal via API. */ - public abstract void removePermissionsStateTEMP(int appId); + public abstract void removeAppIdStateTEMP(@AppIdInt int appId); /** * Update the shared user setting when a package with a shared user id is removed. The gids @@ -324,12 +324,6 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager @Nullable public abstract int[] getPermissionGids(@NonNull String permissionName, @UserIdInt int userId); - /** - * Get the GIDs computed from the permission state of a package. - */ - @Nullable - public abstract int[] getPackageGids(@NonNull String packageName, @UserIdInt int userId); - /** Retrieve the packages that have requested the given app op permission */ public abstract @Nullable String[] getAppOpPermissionPackages( @NonNull String permName, int callingUid); diff --git a/services/core/java/com/android/server/pm/permission/PermissionsState.java b/services/core/java/com/android/server/pm/permission/PermissionsState.java deleted file mode 100644 index 4fb2d5fc200e4..0000000000000 --- a/services/core/java/com/android/server/pm/permission/PermissionsState.java +++ /dev/null @@ -1,970 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.pm.permission; - -import android.annotation.Nullable; -import android.annotation.UserIdInt; -import android.content.pm.PackageManager; -import android.os.UserHandle; -import android.util.ArrayMap; -import android.util.ArraySet; -import android.util.SparseArray; -import android.util.SparseBooleanArray; - -import com.android.internal.annotations.GuardedBy; -import com.android.internal.util.ArrayUtils; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import java.util.Set; - -/** - * This class encapsulates the permissions for a package or a shared user. - *

- * There are two types of permissions: install (granted at installation) - * and runtime (granted at runtime). Install permissions are granted to - * all device users while runtime permissions are granted explicitly to - * specific users. - *

- *

- * The permissions are kept on a per device user basis. For example, an - * application may have some runtime permissions granted under the device - * owner but not granted under the secondary user. - *

- * This class is also responsible for keeping track of the Linux gids per - * user for a package or a shared user. The gids are computed as a set of - * the gids for all granted permissions' gids on a per user basis. - *

- */ -public final class PermissionsState { - - /** The permission operation failed. */ - public static final int PERMISSION_OPERATION_FAILURE = -1; - - /** The permission operation succeeded and no gids changed. */ - public static final int PERMISSION_OPERATION_SUCCESS = 0; - - /** The permission operation succeeded and gids changed. */ - public static final int PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED = 1; - - private static final int[] NO_GIDS = {}; - - private final Object mLock = new Object(); - - @GuardedBy("mLock") - private ArrayMap mPermissions; - - private int[] mGlobalGids = NO_GIDS; - - @Nullable - private SparseBooleanArray mMissing; - - private SparseBooleanArray mPermissionReviewRequired; - - public PermissionsState() { - /* do nothing */ - } - - public PermissionsState(PermissionsState prototype) { - copyFrom(prototype); - } - - public int[] getGlobalGids() { - return mGlobalGids; - } - - /** - * Sets the global gids, applicable to all users. - * - * @param globalGids The global gids. - */ - public void setGlobalGids(int[] globalGids) { - if (!ArrayUtils.isEmpty(globalGids)) { - mGlobalGids = Arrays.copyOf(globalGids, globalGids.length); - } - } - - private static void invalidateCache() { - PackageManager.invalidatePackageInfoCache(); - } - - /** - * Initialized this instance from another one. - * - * @param other The other instance. - */ - public void copyFrom(PermissionsState other) { - if (other == this) { - return; - } - - synchronized (mLock) { - if (mPermissions != null) { - if (other.mPermissions == null) { - mPermissions = null; - } else { - mPermissions.clear(); - } - } - if (other.mPermissions != null) { - if (mPermissions == null) { - mPermissions = new ArrayMap<>(); - } - final int permissionCount = other.mPermissions.size(); - for (int i = 0; i < permissionCount; i++) { - String name = other.mPermissions.keyAt(i); - PermissionData permissionData = other.mPermissions.valueAt(i); - mPermissions.put(name, new PermissionData(permissionData)); - } - } - } - - mGlobalGids = NO_GIDS; - if (other.mGlobalGids != NO_GIDS) { - mGlobalGids = Arrays.copyOf(other.mGlobalGids, - other.mGlobalGids.length); - } - - if (mMissing != null) { - if (other.mMissing == null) { - mMissing = null; - } else { - mMissing.clear(); - } - } - if (other.mMissing != null) { - if (mMissing == null) { - mMissing = new SparseBooleanArray(); - } - final int missingSize = other.mMissing.size(); - for (int i = 0; i < missingSize; i++) { - mMissing.put(other.mMissing.keyAt(i), other.mMissing.valueAt(i)); - } - } - - if (mPermissionReviewRequired != null) { - if (other.mPermissionReviewRequired == null) { - mPermissionReviewRequired = null; - } else { - mPermissionReviewRequired.clear(); - } - } - if (other.mPermissionReviewRequired != null) { - if (mPermissionReviewRequired == null) { - mPermissionReviewRequired = new SparseBooleanArray(); - } - final int userCount = other.mPermissionReviewRequired.size(); - for (int i = 0; i < userCount; i++) { - final boolean reviewRequired = other.mPermissionReviewRequired.valueAt(i); - mPermissionReviewRequired.put(other.mPermissionReviewRequired.keyAt(i), - reviewRequired); - } - } - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final PermissionsState other = (PermissionsState) obj; - - synchronized (mLock) { - if (mPermissions == null) { - if (other.mPermissions != null) { - return false; - } - } else if (!mPermissions.equals(other.mPermissions)) { - return false; - } - } - - if (!Objects.equals(mMissing, other.mMissing)) { - return false; - } - - if (mPermissionReviewRequired == null) { - if (other.mPermissionReviewRequired != null) { - return false; - } - } else if (!mPermissionReviewRequired.equals(other.mPermissionReviewRequired)) { - return false; - } - return Arrays.equals(mGlobalGids, other.mGlobalGids); - } - - /** - * Check whether the permissions state is missing for a user. This can happen if permission - * state is rolled back and we'll need to generate a reasonable default state to keep the app - * usable. - */ - public boolean isMissing(@UserIdInt int userId) { - return mMissing != null && mMissing.get(userId); - } - - /** - * Set whether the permissions state is missing for a user. This can happen if permission state - * is rolled back and we'll need to generate a reasonable default state to keep the app usable. - */ - public void setMissing(boolean missing, @UserIdInt int userId) { - if (missing) { - if (mMissing == null) { - mMissing = new SparseBooleanArray(); - } - mMissing.put(userId, true); - } else { - if (mMissing != null) { - mMissing.delete(userId); - if (mMissing.size() == 0) { - mMissing = null; - } - } - } - } - - public boolean isPermissionReviewRequired(int userId) { - return mPermissionReviewRequired != null && mPermissionReviewRequired.get(userId); - } - - /** - * Grant an install permission. - * - * @param permission The permission to grant. - * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS}, - * or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link - * #PERMISSION_OPERATION_FAILURE}. - */ - public int grantInstallPermission(BasePermission permission) { - return grantPermission(permission, UserHandle.USER_ALL); - } - - /** - * Revoke an install permission. - * - * @param permission The permission to revoke. - * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS}, - * or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link - * #PERMISSION_OPERATION_FAILURE}. - */ - public int revokeInstallPermission(BasePermission permission) { - return revokePermission(permission, UserHandle.USER_ALL); - } - - /** - * Grant a runtime permission for a given device user. - * - * @param permission The permission to grant. - * @param userId The device user id. - * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS}, - * or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link - * #PERMISSION_OPERATION_FAILURE}. - */ - public int grantRuntimePermission(BasePermission permission, int userId) { - enforceValidUserId(userId); - if (userId == UserHandle.USER_ALL) { - return PERMISSION_OPERATION_FAILURE; - } - return grantPermission(permission, userId); - } - - /** - * Revoke a runtime permission for a given device user. - * - * @param permission The permission to revoke. - * @param userId The device user id. - * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS}, - * or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link - * #PERMISSION_OPERATION_FAILURE}. - */ - public int revokeRuntimePermission(BasePermission permission, int userId) { - enforceValidUserId(userId); - if (userId == UserHandle.USER_ALL) { - return PERMISSION_OPERATION_FAILURE; - } - return revokePermission(permission, userId); - } - - /** - * Gets whether this state has a given runtime permission for a - * given device user id. - * - * @param name The permission name. - * @param userId The device user id. - * @return Whether this state has the permission. - */ - public boolean hasRuntimePermission(String name, int userId) { - enforceValidUserId(userId); - return !hasInstallPermission(name) && hasPermission(name, userId); - } - - /** - * Gets whether this state has a given install permission. - * - * @param name The permission name. - * @return Whether this state has the permission. - */ - public boolean hasInstallPermission(String name) { - return hasPermission(name, UserHandle.USER_ALL); - } - - /** - * Gets whether the state has a given permission for the specified - * user, regardless if this is an install or a runtime permission. - * - * @param name The permission name. - * @param userId The device user id. - * @return Whether the user has the permission. - */ - public boolean hasPermission(String name, int userId) { - enforceValidUserId(userId); - - synchronized (mLock) { - if (mPermissions == null) { - return false; - } - PermissionData permissionData = mPermissions.get(name); - - return permissionData != null && permissionData.isGranted(userId); - } - - } - - /** - * Returns whether the state has any known request for the given permission name, - * whether or not it has been granted. - */ - public boolean hasRequestedPermission(ArraySet names) { - synchronized (mLock) { - if (mPermissions == null) { - return false; - } - for (int i=names.size()-1; i>=0; i--) { - if (mPermissions.get(names.valueAt(i)) != null) { - return true; - } - } - } - - return false; - } - - /** - * Returns whether the state has any known request for the given permission name, - * whether or not it has been granted. - */ - public boolean hasRequestedPermission(String name) { - return mPermissions != null && (mPermissions.get(name) != null); - } - /** - * Gets all permissions for a given device user id regardless if they - * are install time or runtime permissions. - * - * @param userId The device user id. - * @return The permissions or an empty set. - */ - public Set getPermissions(int userId) { - enforceValidUserId(userId); - - synchronized (mLock) { - if (mPermissions == null) { - return Collections.emptySet(); - } - - Set permissions = new ArraySet<>(mPermissions.size()); - - final int permissionCount = mPermissions.size(); - for (int i = 0; i < permissionCount; i++) { - String permission = mPermissions.keyAt(i); - - if (hasInstallPermission(permission)) { - permissions.add(permission); - continue; - } - - if (userId != UserHandle.USER_ALL) { - if (hasRuntimePermission(permission, userId)) { - permissions.add(permission); - } - } - } - - return permissions; - } - } - - /** - * Gets the state for an install permission or null if no such. - * - * @param name The permission name. - * @return The permission state. - */ - public PermissionState getInstallPermissionState(String name) { - return getPermissionState(name, UserHandle.USER_ALL); - } - - /** - * Gets the state for a runtime permission or null if no such. - * - * @param name The permission name. - * @param userId The device user id. - * @return The permission state. - */ - public PermissionState getRuntimePermissionState(String name, int userId) { - enforceValidUserId(userId); - return getPermissionState(name, userId); - } - - /** - * Gets all install permission states. - * - * @return The permission states or an empty set. - */ - public List getInstallPermissionStates() { - return getPermissionStatesInternal(UserHandle.USER_ALL); - } - - /** - * Gets all runtime permission states. - * - * @return The permission states or an empty set. - */ - public List getRuntimePermissionStates(int userId) { - enforceValidUserId(userId); - return getPermissionStatesInternal(userId); - } - - /** - * Gets the flags for a permission regardless if it is install or - * runtime permission. - * - * @param name The permission name. - * @return The permission state or null if no such. - */ - public int getPermissionFlags(String name, int userId) { - PermissionState installPermState = getInstallPermissionState(name); - if (installPermState != null) { - return installPermState.getFlags(); - } - PermissionState runtimePermState = getRuntimePermissionState(name, userId); - if (runtimePermState != null) { - return runtimePermState.getFlags(); - } - return 0; - } - - /** - * Update the flags associated with a given permission. - * @param permission The permission whose flags to update. - * @param userId The user for which to update. - * @param flagMask Mask for which flags to change. - * @param flagValues New values for the mask flags. - * @return Whether the permission flags changed. - */ - public boolean updatePermissionFlags(BasePermission permission, int userId, - int flagMask, int flagValues) { - enforceValidUserId(userId); - - final boolean mayChangeFlags = flagValues != 0 || flagMask != 0; - - synchronized (mLock) { - if (mPermissions == null) { - if (!mayChangeFlags) { - return false; - } - ensurePermissionData(permission); - } - } - - PermissionData permissionData = null; - synchronized (mLock) { - permissionData = mPermissions.get(permission.getName()); - } - - if (permissionData == null) { - if (!mayChangeFlags) { - return false; - } - permissionData = ensurePermissionData(permission); - } - - final int oldFlags = permissionData.getFlags(userId); - - final boolean updated = permissionData.updateFlags(userId, flagMask, flagValues); - if (updated) { - final int newFlags = permissionData.getFlags(userId); - if ((oldFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) == 0 - && (newFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) { - if (mPermissionReviewRequired == null) { - mPermissionReviewRequired = new SparseBooleanArray(); - } - mPermissionReviewRequired.put(userId, true); - } else if ((oldFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0 - && (newFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) == 0) { - if (mPermissionReviewRequired != null && !hasPermissionRequiringReview(userId)) { - mPermissionReviewRequired.delete(userId); - if (mPermissionReviewRequired.size() <= 0) { - mPermissionReviewRequired = null; - } - } - } - } - return updated; - } - - private boolean hasPermissionRequiringReview(int userId) { - synchronized (mLock) { - final int permissionCount = mPermissions.size(); - for (int i = 0; i < permissionCount; i++) { - final PermissionData permission = mPermissions.valueAt(i); - if ((permission.getFlags(userId) - & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) { - return true; - } - } - } - - return false; - } - - public boolean updatePermissionFlagsForAllPermissions( - int userId, int flagMask, int flagValues) { - enforceValidUserId(userId); - - synchronized (mLock) { - if (mPermissions == null) { - return false; - } - boolean changed = false; - final int permissionCount = mPermissions.size(); - for (int i = 0; i < permissionCount; i++) { - PermissionData permissionData = mPermissions.valueAt(i); - changed |= permissionData.updateFlags(userId, flagMask, flagValues); - } - - return changed; - } - } - - /** - * Compute the Linux gids for a given device user from the permissions - * granted to this user. Note that these are computed to avoid additional - * state as they are rarely accessed. - * - * @param userId The device user id. - * @return The gids for the device user. - */ - public int[] computeGids(int userId) { - enforceValidUserId(userId); - - int[] gids = mGlobalGids; - - synchronized (mLock) { - if (mPermissions != null) { - final int permissionCount = mPermissions.size(); - for (int i = 0; i < permissionCount; i++) { - String permission = mPermissions.keyAt(i); - if (!hasPermission(permission, userId)) { - continue; - } - PermissionData permissionData = mPermissions.valueAt(i); - final int[] permGids = permissionData.computeGids(userId); - if (permGids != NO_GIDS) { - gids = appendInts(gids, permGids); - } - } - } - } - - return gids; - } - - /** - * Compute the Linux gids for all device users from the permissions - * granted to these users. - * - * @return The gids for all device users. - */ - public int[] computeGids(int[] userIds) { - int[] gids = mGlobalGids; - - for (int userId : userIds) { - final int[] userGids = computeGids(userId); - gids = appendInts(gids, userGids); - } - - return gids; - } - - /** - * Resets the internal state of this object. - */ - public void reset() { - mGlobalGids = NO_GIDS; - - synchronized (mLock) { - mPermissions = null; - invalidateCache(); - } - - mMissing = null; - mPermissionReviewRequired = null; - } - - private PermissionState getPermissionState(String name, int userId) { - synchronized (mLock) { - if (mPermissions == null) { - return null; - } - PermissionData permissionData = mPermissions.get(name); - if (permissionData == null) { - return null; - } - - return permissionData.getPermissionState(userId); - } - } - - private List getPermissionStatesInternal(int userId) { - enforceValidUserId(userId); - - synchronized (mLock) { - if (mPermissions == null) { - return Collections.emptyList(); - } - - List permissionStates = new ArrayList<>(); - - final int permissionCount = mPermissions.size(); - for (int i = 0; i < permissionCount; i++) { - PermissionData permissionData = mPermissions.valueAt(i); - - PermissionState permissionState = permissionData.getPermissionState(userId); - if (permissionState != null) { - permissionStates.add(permissionState); - } - } - - return permissionStates; - } - } - - private int grantPermission(BasePermission permission, int userId) { - if (hasPermission(permission.getName(), userId)) { - return PERMISSION_OPERATION_SUCCESS; - } - - final boolean hasGids = !ArrayUtils.isEmpty(permission.computeGids(userId)); - final int[] oldGids = hasGids ? computeGids(userId) : NO_GIDS; - - PermissionData permissionData = ensurePermissionData(permission); - - if (!permissionData.grant(userId)) { - return PERMISSION_OPERATION_FAILURE; - } - - if (hasGids) { - final int[] newGids = computeGids(userId); - if (oldGids.length != newGids.length) { - return PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED; - } - } - - return PERMISSION_OPERATION_SUCCESS; - } - - private int revokePermission(BasePermission permission, int userId) { - final String permName = permission.getName(); - if (!hasPermission(permName, userId)) { - return PERMISSION_OPERATION_SUCCESS; - } - - final boolean hasGids = !ArrayUtils.isEmpty(permission.computeGids(userId)); - final int[] oldGids = hasGids ? computeGids(userId) : NO_GIDS; - - PermissionData permissionData = null; - synchronized (mLock) { - permissionData = mPermissions.get(permName); - } - - if (!permissionData.revoke(userId)) { - return PERMISSION_OPERATION_FAILURE; - } - - if (permissionData.isDefault()) { - ensureNoPermissionData(permName); - } - - if (hasGids) { - final int[] newGids = computeGids(userId); - if (oldGids.length != newGids.length) { - return PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED; - } - } - - return PERMISSION_OPERATION_SUCCESS; - } - - // TODO: fix this to use arraycopy and append all ints in one go - private static int[] appendInts(int[] current, int[] added) { - if (current != null && added != null) { - for (int guid : added) { - current = ArrayUtils.appendInt(current, guid); - } - } - return current; - } - - private static void enforceValidUserId(int userId) { - if (userId != UserHandle.USER_ALL && userId < 0) { - throw new IllegalArgumentException("Invalid userId:" + userId); - } - } - - private PermissionData ensurePermissionData(BasePermission permission) { - final String permName = permission.getName(); - - synchronized (mLock) { - if (mPermissions == null) { - mPermissions = new ArrayMap<>(); - } - PermissionData permissionData = mPermissions.get(permName); - if (permissionData == null) { - permissionData = new PermissionData(permission); - mPermissions.put(permName, permissionData); - } - return permissionData; - } - - } - - private void ensureNoPermissionData(String name) { - synchronized (mLock) { - if (mPermissions == null) { - return; - } - mPermissions.remove(name); - if (mPermissions.isEmpty()) { - mPermissions = null; - } - } - - } - - private static final class PermissionData { - - private final Object mLock = new Object(); - - private final BasePermission mPerm; - @GuardedBy("mLock") - private SparseArray mUserStates = new SparseArray<>(); - - public PermissionData(BasePermission perm) { - mPerm = perm; - } - - public PermissionData(PermissionData other) { - this(other.mPerm); - - synchronized (mLock) { - final int otherStateCount = other.mUserStates.size(); - for (int i = 0; i < otherStateCount; i++) { - final int otherUserId = other.mUserStates.keyAt(i); - PermissionState otherState = other.mUserStates.valueAt(i); - mUserStates.put(otherUserId, new PermissionState(otherState)); - } - } - } - - public int[] computeGids(int userId) { - return mPerm.computeGids(userId); - } - - public boolean isGranted(int userId) { - synchronized (mLock) { - if (isInstallPermission()) { - userId = UserHandle.USER_ALL; - } - - PermissionState userState = mUserStates.get(userId); - if (userState == null) { - return false; - } - - return userState.mGranted; - } - } - - public boolean grant(int userId) { - synchronized (mLock) { - if (!isCompatibleUserId(userId)) { - return false; - } - - if (isGranted(userId)) { - return false; - } - - PermissionState userState = mUserStates.get(userId); - if (userState == null) { - userState = new PermissionState(mPerm); - mUserStates.put(userId, userState); - } - - userState.mGranted = true; - - invalidateCache(); - return true; - } - } - - public boolean revoke(int userId) { - synchronized (mLock) { - if (!isCompatibleUserId(userId)) { - return false; - } - - if (!isGranted(userId)) { - return false; - } - - PermissionState userState = mUserStates.get(userId); - userState.mGranted = false; - - if (userState.isDefault()) { - mUserStates.remove(userId); - } - - invalidateCache(); - return true; - } - } - - public PermissionState getPermissionState(int userId) { - synchronized (mLock) { - return mUserStates.get(userId); - } - } - - public int getFlags(int userId) { - synchronized (mLock) { - PermissionState userState = mUserStates.get(userId); - if (userState != null) { - return userState.mFlags; - } - return 0; - } - } - - public boolean isDefault() { - synchronized (mLock) { - return mUserStates.size() <= 0; - } - } - - public static boolean isInstallPermissionKey(int userId) { - return userId == UserHandle.USER_ALL; - } - - public boolean updateFlags(int userId, int flagMask, int flagValues) { - synchronized (mLock) { - if (isInstallPermission()) { - userId = UserHandle.USER_ALL; - } - - if (!isCompatibleUserId(userId)) { - return false; - } - - final int newFlags = flagValues & flagMask; - - // Okay to do before the modification because we hold the lock. - invalidateCache(); - - PermissionState userState = mUserStates.get(userId); - if (userState != null) { - final int oldFlags = userState.mFlags; - userState.mFlags = (userState.mFlags & ~flagMask) | newFlags; - if (userState.isDefault()) { - mUserStates.remove(userId); - } - return userState.mFlags != oldFlags; - } else if (newFlags != 0) { - userState = new PermissionState(mPerm); - userState.mFlags = newFlags; - mUserStates.put(userId, userState); - return true; - } - - return false; - } - } - - private boolean isCompatibleUserId(int userId) { - return isDefault() || !(isInstallPermission() ^ isInstallPermissionKey(userId)); - } - - private boolean isInstallPermission() { - return mUserStates.size() == 1 - && mUserStates.get(UserHandle.USER_ALL) != null; - } - } - - public static final class PermissionState { - private final BasePermission mPermission; - private boolean mGranted; - private int mFlags; - - public PermissionState(BasePermission permission) { - mPermission = permission; - } - - public PermissionState(PermissionState other) { - mPermission = other.mPermission; - mGranted = other.mGranted; - mFlags = other.mFlags; - } - - public boolean isDefault() { - return !mGranted && mFlags == 0; - } - - public BasePermission getPermission() { - return mPermission; - } - - public String getName() { - return mPermission.getName(); - } - - public boolean isGranted() { - return mGranted; - } - - public int getFlags() { - return mFlags; - } - } -} diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java index dac05424e01f9..bc747832e253a 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java @@ -62,6 +62,7 @@ import com.android.permission.persistence.RuntimePermissionsPersistence; import com.android.server.LocalServices; import com.android.server.pm.parsing.pkg.PackageImpl; import com.android.server.pm.parsing.pkg.ParsedPackage; +import com.android.server.pm.permission.LegacyPermissionDataProvider; import com.android.server.pm.permission.PermissionSettings; import com.google.common.truth.Truth; @@ -94,6 +95,8 @@ public class PackageManagerSettingsTests { PermissionSettings mPermissionSettings; @Mock RuntimePermissionsPersistence mRuntimePermissionsPersistence; + @Mock + LegacyPermissionDataProvider mPermissionDataProvider; @Before public void initializeMocks() { @@ -115,7 +118,7 @@ public class PackageManagerSettingsTests { final Context context = InstrumentationRegistry.getContext(); final Object lock = new Object(); Settings settings = new Settings(context.getFilesDir(), mPermissionSettings, - mRuntimePermissionsPersistence, lock); + mRuntimePermissionsPersistence, mPermissionDataProvider, lock); assertThat(settings.readLPw(createFakeUsers()), is(true)); verifyKeySetMetaData(settings); } @@ -129,7 +132,7 @@ public class PackageManagerSettingsTests { final Context context = InstrumentationRegistry.getContext(); final Object lock = new Object(); Settings settings = new Settings(context.getFilesDir(), mPermissionSettings, - mRuntimePermissionsPersistence, lock); + mRuntimePermissionsPersistence, mPermissionDataProvider, lock); assertThat(settings.readLPw(createFakeUsers()), is(true)); // write out, read back in and verify the same @@ -145,7 +148,7 @@ public class PackageManagerSettingsTests { final Context context = InstrumentationRegistry.getContext(); final Object lock = new Object(); Settings settings = new Settings(context.getFilesDir(), mPermissionSettings, - mRuntimePermissionsPersistence, lock); + mRuntimePermissionsPersistence, mPermissionDataProvider, lock); assertThat(settings.readLPw(createFakeUsers()), is(true)); assertThat(settings.getPackageLPr(PACKAGE_NAME_3), is(notNullValue())); assertThat(settings.getPackageLPr(PACKAGE_NAME_1), is(notNullValue())); @@ -167,13 +170,13 @@ public class PackageManagerSettingsTests { final Context context = InstrumentationRegistry.getContext(); final Object lock = new Object(); Settings settings = new Settings(context.getFilesDir(), mPermissionSettings, - mRuntimePermissionsPersistence, lock); + mRuntimePermissionsPersistence, mPermissionDataProvider, lock); assertThat(settings.readLPw(createFakeUsers()), is(true)); settings.writeLPr(); // Create Settings again to make it read from the new files settings = new Settings(context.getFilesDir(), mPermissionSettings, - mRuntimePermissionsPersistence, lock); + mRuntimePermissionsPersistence, mPermissionDataProvider, lock); assertThat(settings.readLPw(createFakeUsers()), is(true)); PackageSetting ps = settings.getPackageLPr(PACKAGE_NAME_2); @@ -196,7 +199,8 @@ public class PackageManagerSettingsTests { writePackageRestrictions_noSuspendingPackageXml(0); final Object lock = new Object(); final Context context = InstrumentationRegistry.getTargetContext(); - final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null, lock); + final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null, null, + lock); settingsUnderTest.mPackages.put(PACKAGE_NAME_1, createPackageSetting(PACKAGE_NAME_1)); settingsUnderTest.mPackages.put(PACKAGE_NAME_2, createPackageSetting(PACKAGE_NAME_2)); settingsUnderTest.readPackageRestrictionsLPr(0); @@ -219,7 +223,8 @@ public class PackageManagerSettingsTests { writePackageRestrictions_noSuspendParamsMapXml(0); final Object lock = new Object(); final Context context = InstrumentationRegistry.getTargetContext(); - final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null, lock); + final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null, null, + lock); settingsUnderTest.mPackages.put(PACKAGE_NAME_1, createPackageSetting(PACKAGE_NAME_1)); settingsUnderTest.readPackageRestrictionsLPr(0); @@ -246,7 +251,7 @@ public class PackageManagerSettingsTests { @Test public void testReadWritePackageRestrictions_suspendInfo() { final Context context = InstrumentationRegistry.getTargetContext(); - final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null, + final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null, null, new Object()); final PackageSetting ps1 = createPackageSetting(PACKAGE_NAME_1); final PackageSetting ps2 = createPackageSetting(PACKAGE_NAME_2); @@ -344,7 +349,7 @@ public class PackageManagerSettingsTests { @Test public void testReadWritePackageRestrictions_distractionFlags() { final Context context = InstrumentationRegistry.getTargetContext(); - final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null, + final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null, null, new Object()); final PackageSetting ps1 = createPackageSetting(PACKAGE_NAME_1); final PackageSetting ps2 = createPackageSetting(PACKAGE_NAME_2); @@ -389,7 +394,7 @@ public class PackageManagerSettingsTests { final Context context = InstrumentationRegistry.getTargetContext(); final Object lock = new Object(); final Settings settingsUnderTest = new Settings(context.getFilesDir(), mPermissionSettings, - mRuntimePermissionsPersistence, lock); + mRuntimePermissionsPersistence, mPermissionDataProvider, lock); final PackageSetting ps1 = createPackageSetting(PACKAGE_NAME_1); ps1.appId = Process.FIRST_APPLICATION_UID; ps1.pkg = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME_1).hideAsParsed()) @@ -465,7 +470,7 @@ public class PackageManagerSettingsTests { final Context context = InstrumentationRegistry.getContext(); final Object lock = new Object(); Settings settings = new Settings(context.getFilesDir(), mPermissionSettings, - mRuntimePermissionsPersistence, lock); + mRuntimePermissionsPersistence, mPermissionDataProvider, lock); assertThat(settings.readLPw(createFakeUsers()), is(true)); // Enable/Disable a package @@ -638,7 +643,7 @@ public class PackageManagerSettingsTests { final Context context = InstrumentationRegistry.getContext(); final Object lock = new Object(); final Settings testSettings01 = new Settings(context.getFilesDir(), mPermissionSettings, - mRuntimePermissionsPersistence, lock); + mRuntimePermissionsPersistence, mPermissionDataProvider, lock); final SharedUserSetting testUserSetting01 = createSharedUserSetting( testSettings01, "TestUser", 10064, 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/); final PackageSetting testPkgSetting01 = @@ -748,7 +753,7 @@ public class PackageManagerSettingsTests { final Context context = InstrumentationRegistry.getContext(); final Object lock = new Object(); final Settings testSettings01 = new Settings(context.getFilesDir(), mPermissionSettings, - mRuntimePermissionsPersistence, lock); + mRuntimePermissionsPersistence, mPermissionDataProvider, lock); final SharedUserSetting testUserSetting01 = createSharedUserSetting( testSettings01, "TestUser", 10064, 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/); final PackageSetting testPkgSetting01 = Settings.createNewSetting(