From c82b3c669ed29718b8e7f74c7a9b5883a0d70b14 Mon Sep 17 00:00:00 2001 From: Winson Date: Tue, 21 Dec 2021 14:40:04 -0800 Subject: [PATCH] Introduce package state mutation APIs Adds APIs to record a state at some time and use that state to commit changes to package state. Which allows reconcilation and retry of competing changes without needing to take the data model lock unless absolutely necessary. Also copies over data model/settings changes to make it compile. Split from actual usage to make review easier. Bug: 202291547 Test: presubmit, no usages yet Change-Id: I6738829185022efef4add1805b5a52b3de3d173a --- .../content/pm/PackageManagerInternal.java | 82 ++- .../server/pm/DeletePackageHelper.java | 1 - .../server/pm/PackageManagerService.java | 350 +++++++--- .../com/android/server/pm/PackageSetting.java | 30 +- .../com/android/server/pm/SettingBase.java | 6 +- .../java/com/android/server/pm/Settings.java | 632 ++++++++++-------- .../server/pm/pkg/PackageStateInternal.java | 4 + .../server/pm/pkg/PackageUserStateImpl.java | 42 +- .../pm/pkg/PackageUserStateInternal.java | 1 + .../android/server/pm/pkg/SuspendParams.java | 30 +- .../pm/pkg/mutate/PackageStateMutator.java | 333 +++++++++ .../pm/pkg/mutate/PackageStateWrite.java | 41 ++ .../pm/pkg/mutate/PackageUserStateWrite.java | 63 ++ .../pm/PackageManagerSettingsTests.java | 42 +- .../server/pm/PackageUserStateTest.java | 4 +- 15 files changed, 1196 insertions(+), 465 deletions(-) create mode 100644 services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java create mode 100644 services/core/java/com/android/server/pm/pkg/mutate/PackageStateWrite.java create mode 100644 services/core/java/com/android/server/pm/pkg/mutate/PackageUserStateWrite.java diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java index 6fe2806e81392..9b2948f42ed86 100644 --- a/services/core/java/android/content/pm/PackageManagerInternal.java +++ b/services/core/java/android/content/pm/PackageManagerInternal.java @@ -50,6 +50,7 @@ import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.pm.pkg.AndroidPackageApi; import com.android.server.pm.pkg.PackageState; import com.android.server.pm.pkg.PackageStateInternal; +import com.android.server.pm.pkg.mutate.PackageStateMutator; import java.io.IOException; import java.lang.annotation.Retention; @@ -884,17 +885,6 @@ public abstract class PackageManagerInternal implements PackageSettingsSnapshotP /** Returns {@code true} if the given user requires extra badging for icons. */ public abstract boolean userNeedsBadging(int userId); - /** - * Perform the given action for each package. - * Note that packages lock will be held while performing the actions. - * - * If the caller does not need all packages, prefer the potentially non-locking - * {@link #withPackageSettingsSnapshot(Consumer)}. - * - * @param actionLocked action to be performed - */ - public abstract void forEachPackage(Consumer actionLocked); - /** * Perform the given action for each {@link PackageSetting}. * Note that packages lock will be held while performing the actions. @@ -917,6 +907,12 @@ public abstract class PackageManagerInternal implements PackageSettingsSnapshotP */ public abstract void forEachPackageState(boolean locked, Consumer action); + /** + * {@link #forEachPackageState(boolean, Consumer)} but filtered to only states with packages + * on device where {@link PackageStateInternal#getPkg()} is not null. + */ + public abstract void forEachPackage(Consumer action); + /** * Perform the given action for each installed package for a user. * Note that packages lock will be held while performing the actions. @@ -924,6 +920,12 @@ public abstract class PackageManagerInternal implements PackageSettingsSnapshotP public abstract void forEachInstalledPackage( @NonNull Consumer actionLocked, @UserIdInt int userId); + /** + * Perform the given action for each installed package for a user. + */ + public abstract void forEachInstalledPackage(boolean locked, + @NonNull Consumer action, @UserIdInt int userId); + /** Returns the list of enabled components */ public abstract ArraySet getEnabledComponents(String packageName, int userId); @@ -1265,4 +1267,62 @@ public abstract class PackageManagerInternal implements PackageSettingsSnapshotP */ public abstract void reconcileAppsData(int userId, @StorageManager.StorageFlags int flags, boolean migrateAppsData); + + /** + * Initiates a package state mutation request, returning the current state as known by + * PackageManager. This allows the later commit request to compare the initial values and + * determine if any state was changed or any packages were updated since the whole request + * was initiated. + * + * As a concrete example, consider the following steps: + *
    + *
  1. Read a package state without taking a lock
  2. + *
  3. Check some values in that state, determine that a mutation needs to occur
  4. + *
  5. Call to commit the change with the new value, takes lock
  6. + *
+ * + * Between steps 1 and 3, because the lock was not taken for the entire flow, it's possible + * a package state was changed by another consumer or a package was updated/installed. + * + * If anything has changed, + * {@link #commitPackageStateMutation(PackageStateMutator.InitialState, Consumer)} will return + * a {@link PackageStateMutator.Result} indicating so. If the caller has not indicated it can + * ignore changes, it can opt to re-run the commit logic from the top with a true write lock + * around all of its read-logic-commit loop. + * + * Note that if the caller does not care about potential race conditions or package/state + * changes between steps 1 and 3, it can simply opt to not call this method and pass in null + * for the initial state. This is useful to avoid long running data structure locks when the + * caller is changing a value as part of a one-off request. Perhaps from an app side API which + * mutates only a single package, where it doesn't care what the state of that package is or + * any other packages on the devices. + * + * Important to note is that if no locking is enforced, callers themselves will not be + * synchronized with themselves. The caller may be relying on the PackageManager lock to + * enforce ordering within their own code path, and that has to be adjusted if migrated off + * the lock. + */ + @NonNull + public abstract PackageStateMutator.InitialState recordInitialState(); + + /** + * Some questions to ask when designing a mutation: + *
    + *
  1. What external system state is required and is it synchronized properly?
  2. + *
  3. Are there any package/state changes that could happen to the target (or another) + * package that could result in the commit being invalid?
  4. + *
  5. Is the caller synchronized with itself and can handle multiple mutations being + * requested from different threads?
  6. + *
  7. What should be done in case of a conflict and the commit can't be finished?
  8. + *
+ * + * @param state See {@link #recordInitialState()}. If null, no result is returned. + * @param consumer Lean wrapper around just the logic that changes state values + * @return result if anything changed since initial state, or null if nothing changed and + * commit was successful + */ + @Nullable + public abstract PackageStateMutator.Result commitPackageStateMutation( + @Nullable PackageStateMutator.InitialState state, + @NonNull Consumer consumer); } diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java index e84d990b5d219..c26f3b3b2cf28 100644 --- a/services/core/java/com/android/server/pm/DeletePackageHelper.java +++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java @@ -547,7 +547,6 @@ final class DeletePackageHelper { true /*notLaunched*/, false /*hidden*/, 0 /*distractionFlags*/, - false /*suspended*/, null /*suspendParams*/, false /*instantApp*/, false /*virtualPreload*/, diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index c6ec59a5811f2..d73eb0e2a049a 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -239,6 +239,9 @@ import com.android.server.pm.pkg.PackageStateUtils; import com.android.server.pm.pkg.PackageUserState; import com.android.server.pm.pkg.PackageUserStateInternal; import com.android.server.pm.pkg.SuspendParams; +import com.android.server.pm.pkg.mutate.PackageStateMutator; +import com.android.server.pm.pkg.mutate.PackageStateWrite; +import com.android.server.pm.pkg.mutate.PackageUserStateWrite; import com.android.server.pm.verify.domain.DomainVerificationManagerInternal; import com.android.server.pm.verify.domain.DomainVerificationService; import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy; @@ -597,6 +600,16 @@ public class PackageManagerService extends IPackageManager.Stub // the suffix "Locked". Some methods may use the legacy suffix "LP" final PackageManagerTracedLock mLock; + // Lock alias for doing package state mutation + private final PackageManagerTracedLock mPackageStateWriteLock; + + // Lock alias to track syncing a consistent Computer + private final PackageManagerTracedLock mLiveComputerSyncLock; + + private final PackageStateMutator mPackageStateMutator = new PackageStateMutator( + this::getPackageSettingForMutation, + this::getDisabledPackageSettingForMutation); + // Keys are String (package name), values are Package. @Watched @GuardedBy("mLock") @@ -1626,6 +1639,8 @@ public class PackageManagerService extends IPackageManager.Stub mInstaller = injector.getInstaller(); mInstallLock = injector.getInstallLock(); mLock = injector.getLock(); + mPackageStateWriteLock = mLock; + mLiveComputerSyncLock = mLock; mPermissionManager = injector.getPermissionManagerServiceInternal(); mSettings = injector.getSettings(); mUserManager = injector.getUserManagerService(); @@ -1729,6 +1744,8 @@ public class PackageManagerService extends IPackageManager.Stub mInjector.bootstrap(this); mLock = injector.getLock(); + mPackageStateWriteLock = mLock; + mLiveComputerSyncLock = mLock; mInstallLock = injector.getInstallLock(); LockGuard.installLock(mLock, LockGuard.INDEX_PACKAGES); EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START, @@ -4909,8 +4926,8 @@ public class PackageManagerService extends IPackageManager.Stub if (pus.isSuspended()) { for (int i = 0; i < pus.getSuspendParams().size(); i++) { final SuspendParams params = pus.getSuspendParams().valueAt(i); - if (params != null && params.appExtras != null) { - allExtras.putAll(params.appExtras); + if (params != null && params.getAppExtras() != null) { + allExtras.putAll(params.getAppExtras()); } } } @@ -4983,9 +5000,9 @@ public class PackageManagerService extends IPackageManager.Stub synchronized (mLock) { for (String packageName : packagesToChange) { final PackageSetting ps = mSettings.getPackageLPr(packageName); - if (ps != null && ps.getSuspended(userId)) { + if (ps != null && ps.getUserStateOrDefault(userId).isSuspended()) { ps.removeSuspension(suspendingPackagePredicate, userId); - if (!ps.getSuspended(userId)) { + if (!ps.getUserStateOrDefault(userId).isSuspended()) { unsuspendedPackages.add(ps.getPackageName()); unsuspendedUids.add(UserHandle.getUid(userId, ps.getAppId())); } @@ -7769,8 +7786,8 @@ public class PackageManagerService extends IPackageManager.Stub if (userState.isSuspended()) { for (int i = 0; i < userState.getSuspendParams().size(); i++) { final SuspendParams params = userState.getSuspendParams().valueAt(i); - if (params != null && params.launcherExtras != null) { - allExtras.putAll(params.launcherExtras); + if (params != null && params.getLauncherExtras() != null) { + allExtras.putAll(params.getLauncherExtras()); } } } @@ -7859,7 +7876,7 @@ public class PackageManagerService extends IPackageManager.Stub } final SuspendParams suspendParams = suspendParamsMap.get(suspendingPackage); - return (suspendParams != null) ? suspendParams.dialogInfo : null; + return (suspendParams != null) ? suspendParams.getDialogInfo() : null; } @Override @@ -8305,7 +8322,13 @@ public class PackageManagerService extends IPackageManager.Stub @Override public void forEachInstalledPackage(@NonNull Consumer actionLocked, @UserIdInt int userId) { - PackageManagerService.this.forEachInstalledPackage(actionLocked, userId); + forEachInstalledPackage(true, actionLocked, userId); + } + + @Override + public void forEachInstalledPackage(boolean locked, + @NonNull Consumer action, int userId) { + PackageManagerService.this.forEachInstalledPackage(locked, action, userId); } @Override @@ -8578,51 +8601,24 @@ public class PackageManagerService extends IPackageManager.Stub @Override public void withPackageSettingsSnapshot( @NonNull Consumer> block) { - final Computer snapshot = snapshotComputer(); - - // This method needs to either lock or not lock consistently throughout the method, - // so if the live computer is returned, force a wrapping sync block. - if (snapshot == mLiveComputer) { - synchronized (mLock) { - block.accept(snapshot::getPackageStateInternal); - } - } else { - block.accept(snapshot::getPackageStateInternal); - } + executeWithConsistentComputer(computer -> + block.accept(computer::getPackageStateInternal)); } @Override public Output withPackageSettingsSnapshotReturning( @NonNull FunctionalUtils.ThrowingFunction, Output> block) { - final Computer snapshot = snapshotComputer(); - - // This method needs to either lock or not lock consistently throughout the method, - // so if the live computer is returned, force a wrapping sync block. - if (snapshot == mLiveComputer) { - synchronized (mLock) { - return block.apply(snapshot::getPackageStateInternal); - } - } else { - return block.apply(snapshot::getPackageStateInternal); - } + return executeWithConsistentComputerReturning(computer -> + block.apply(computer::getPackageStateInternal)); } @Override public void withPackageSettingsSnapshotThrowing( @NonNull FunctionalUtils.ThrowingCheckedConsumer, ExceptionType> block) throws ExceptionType { - final Computer snapshot = snapshotComputer(); - - // This method needs to either lock or not lock consistently throughout the method, - // so if the live computer is returned, force a wrapping sync block. - if (snapshot == mLiveComputer) { - synchronized (mLock) { - block.accept(snapshot::getPackageStateInternal); - } - } else { - block.accept(snapshot::getPackageStateInternal); - } + executeWithConsistentComputerThrowing(computer -> + block.accept(computer::getPackageStateInternal)); } @Override @@ -8632,17 +8628,9 @@ public class PackageManagerService extends IPackageManager.Stub Function, ExceptionOne, ExceptionTwo> block) throws ExceptionOne, ExceptionTwo { - final Computer snapshot = snapshotComputer(); - - // This method needs to either lock or not lock consistently throughout the method, - // so if the live computer is returned, force a wrapping sync block. - if (snapshot == mLiveComputer) { - synchronized (mLock) { - block.accept(snapshot::getPackageStateInternal); - } - } else { - block.accept(snapshot::getPackageStateInternal); - } + executeWithConsistentComputerThrowing2( + (FunctionalUtils.ThrowingChecked2Consumer) computer -> block.accept(computer::getPackageStateInternal)); } @Override @@ -8652,17 +8640,8 @@ public class PackageManagerService extends IPackageManager.Stub Function, Output, ExceptionType> block) throws ExceptionType { - final Computer snapshot = snapshotComputer(); - - // This method needs to either lock or not lock consistently throughout the method, - // so if the live computer is returned, force a wrapping sync block. - if (snapshot == mLiveComputer) { - synchronized (mLock) { - return block.apply(snapshot::getPackageStateInternal); - } - } else { - return block.apply(snapshot::getPackageStateInternal); - } + return executeWithConsistentComputerReturningThrowing(computer -> + block.apply(computer::getPackageStateInternal)); } @Override @@ -8671,6 +8650,20 @@ public class PackageManagerService extends IPackageManager.Stub PackageManagerService.this.mAppDataHelper.reconcileAppsData(userId, flags, migrateAppsData); } + + @NonNull + @Override + public PackageStateMutator.InitialState recordInitialState() { + return PackageManagerService.this.recordInitialState(); + } + + @Nullable + @Override + public PackageStateMutator.Result commitPackageStateMutation( + @Nullable PackageStateMutator.InitialState state, + @NonNull Consumer consumer) { + return PackageManagerService.this.commitPackageStateMutation(state, consumer); + } } @Override @@ -8713,7 +8706,15 @@ public class PackageManagerService extends IPackageManager.Stub @Nullable @GuardedBy("mLock") PackageSetting getPackageSettingForMutation(String packageName) { - return (PackageSetting) mComputer.getPackageStateInternal(packageName); + return mSettings.getPackageLPr(packageName); + } + + // TODO: Remove + @Deprecated + @Nullable + @GuardedBy("mLock") + PackageSetting getDisabledPackageSettingForMutation(String packageName) { + return mSettings.getDisabledSystemPkgLPr(packageName); } @VisibleForTesting(visibility = Visibility.PRIVATE) @@ -8721,7 +8722,7 @@ public class PackageManagerService extends IPackageManager.Stub PackageStateInternal getPackageStateInternal(String packageName) { Computer computer = snapshotComputer(); if (computer == mLiveComputer) { - synchronized (mLock) { + synchronized (mLiveComputerSyncLock) { PackageSetting pkgSetting = (PackageSetting) computer.getPackageStateInternal(packageName); if (pkgSetting == null) { @@ -8730,15 +8731,16 @@ public class PackageManagerService extends IPackageManager.Stub return new PackageSetting(pkgSetting); } + } else { + return computer.getPackageStateInternal(packageName); } - return computer.getPackageStateInternal(packageName); } @Nullable PackageStateInternal getPackageStateInternal(String packageName, int callingUid) { Computer computer = snapshotComputer(); if (computer == mLiveComputer) { - synchronized (mLock) { + synchronized (mLiveComputerSyncLock) { PackageSetting pkgSetting = (PackageSetting) computer.getPackageStateInternal(packageName, callingUid); if (pkgSetting == null) { @@ -8747,8 +8749,9 @@ public class PackageManagerService extends IPackageManager.Stub return new PackageSetting(pkgSetting); } + } else { + return computer.getPackageStateInternal(packageName, callingUid); } - return computer.getPackageStateInternal(packageName, callingUid); } @Nullable @@ -8756,7 +8759,7 @@ public class PackageManagerService extends IPackageManager.Stub int callingUid, @UserIdInt int userId) { Computer computer = snapshotComputer(); if (computer == mLiveComputer) { - synchronized (mLock) { + synchronized (mLiveComputerSyncLock) { PackageSetting pkgSetting = (PackageSetting) filterPackageStateForInstalledAndFiltered(computer, packageName, callingUid, userId); @@ -8765,9 +8768,10 @@ public class PackageManagerService extends IPackageManager.Stub } return new PackageSetting(pkgSetting); } + } else { + return filterPackageStateForInstalledAndFiltered(computer, packageName, callingUid, + userId); } - - return filterPackageStateForInstalledAndFiltered(computer, packageName, callingUid, userId); } @Nullable @@ -8795,16 +8799,8 @@ public class PackageManagerService extends IPackageManager.Stub Computer computer = snapshotComputer(); if (computer == mLiveComputer) { return new ArrayMap<>(computer.getPackageStates()); - } - return computer.getPackageStates(); - } - - void forEachPackage(Consumer actionLocked) { - synchronized (mLock) { - int numPackages = mPackages.size(); - for (int i = 0; i < numPackages; i++) { - actionLocked.accept(mPackages.valueAt(i)); - } + } else { + return computer.getPackageStates(); } } @@ -8817,17 +8813,31 @@ public class PackageManagerService extends IPackageManager.Stub } } - private void forEachPackageState(boolean locked, Consumer action) { + void forEachPackageState(boolean locked, Consumer action) { if (locked) { - forEachPackageSetting(action::accept); + synchronized (mLiveComputerSyncLock) { + forEachPackageState(mComputer.getPackageStates(), action); + } } else { Computer computer = snapshotComputer(); if (computer == mLiveComputer) { - synchronized (mLock) { + synchronized (mLiveComputerSyncLock) { forEachPackageState(computer.getPackageStates(), action); - }; + } + } else { + forEachPackageState(computer.getPackageStates(), action); } - forEachPackageState(computer.getPackageStates(), action); + } + } + + void forEachPackage(Consumer action) { + Computer computer = snapshotComputer(); + if (computer == mLiveComputer) { + synchronized (mLiveComputerSyncLock) { + forEachPackage(computer.getPackageStates(), action); + } + } else { + forEachPackage(computer.getPackageStates(), action); } } @@ -8841,21 +8851,106 @@ public class PackageManagerService extends IPackageManager.Stub } } - void forEachInstalledPackage(@NonNull Consumer actionLocked, - @UserIdInt int userId) { - synchronized (mLock) { - int numPackages = mPackages.size(); - for (int i = 0; i < numPackages; i++) { - AndroidPackage pkg = mPackages.valueAt(i); - PackageSetting setting = mSettings.getPackageLPr(pkg.getPackageName()); - if (setting == null || !setting.getInstalled(userId)) { - continue; - } - actionLocked.accept(pkg); + private void forEachPackage( + @NonNull ArrayMap packageStates, + @NonNull Consumer consumer) { + int size = packageStates.size(); + for (int index = 0; index < size; index++) { + PackageStateInternal packageState = packageStates.valueAt(index); + if (packageState.getPkg() != null) { + consumer.accept(packageState.getPkg()); } } } + void forEachInstalledPackage(boolean locked, @NonNull Consumer action, + @UserIdInt int userId) { + Consumer actionWrapped = packageState -> { + if (packageState.getPkg() != null + && packageState.getUserStateOrDefault(userId).isInstalled()) { + action.accept(packageState.getPkg()); + } + }; + if (locked) { + synchronized (mLiveComputerSyncLock) { + forEachPackageState(mComputer.getPackageStates(), actionWrapped); + } + } else { + Computer computer = snapshotComputer(); + if (computer == mLiveComputer) { + synchronized (mLiveComputerSyncLock) { + forEachPackageState(computer.getPackageStates(), actionWrapped); + } + } else { + forEachPackageState(computer.getPackageStates(), actionWrapped); + } + } + } + + private void executeWithConsistentComputer( + @NonNull FunctionalUtils.ThrowingConsumer consumer) { + Computer computer = snapshotComputer(); + if (computer == mLiveComputer) { + synchronized (mLiveComputerSyncLock) { + consumer.accept(computer); + } + } else { + consumer.accept(computer); + } + } + + private T executeWithConsistentComputerReturning( + @NonNull FunctionalUtils.ThrowingFunction function) { + Computer computer = snapshotComputer(); + if (computer == mLiveComputer) { + synchronized (mLiveComputerSyncLock) { + return function.apply(computer); + } + } else { + return function.apply(computer); + } + } + + private void executeWithConsistentComputerThrowing( + @NonNull FunctionalUtils.ThrowingCheckedConsumer consumer) + throws ExceptionType { + Computer computer = snapshotComputer(); + if (computer == mLiveComputer) { + synchronized (mLiveComputerSyncLock) { + consumer.accept(computer); + } + } else { + consumer.accept(computer); + } + } + + private void + executeWithConsistentComputerThrowing2( + @NonNull FunctionalUtils.ThrowingChecked2Consumer consumer) throws ExceptionOne, ExceptionTwo { + Computer computer = snapshotComputer(); + if (computer == mLiveComputer) { + synchronized (mLiveComputerSyncLock) { + consumer.accept(computer); + } + } else { + consumer.accept(computer); + } + } + + private T executeWithConsistentComputerReturningThrowing( + @NonNull FunctionalUtils.ThrowingCheckedFunction function) + throws ExceptionType { + Computer computer = snapshotComputer(); + if (computer == mLiveComputer) { + synchronized (mLiveComputerSyncLock) { + return function.apply(computer); + } + } else { + return function.apply(computer); + } + } + boolean isHistoricalPackageUsageAvailable() { return mPackageUsage.isHistoricalPackageUsageAvailable(); } @@ -9051,7 +9146,8 @@ public class PackageManagerService extends IPackageManager.Stub enforceOwnerRights(packageName, Binder.getCallingUid()); final boolean changed; synchronized (mLock) { - changed = mSettings.getPackageLPr(packageName).setMimeGroup(mimeGroup, mimeTypes); + changed = mSettings.getPackageLPr(packageName).setMimeGroup(mimeGroup, + new ArraySet<>(mimeTypes)); } if (changed) { applyMimeGroupChanges(packageName, mimeGroup); @@ -9553,4 +9649,62 @@ public class PackageManagerService extends IPackageManager.Stub return new Pair<>(rescanFlags, reparseFlags); } + + /** + * @see PackageManagerInternal#recordInitialState() + */ + @NonNull + public PackageStateMutator.InitialState recordInitialState() { + return mPackageStateMutator.initialState(mChangedPackagesSequenceNumber); + } + + /** + * @see PackageManagerInternal#commitPackageStateMutation(PackageStateMutator.InitialState, + * Consumer) + */ + @NonNull + public PackageStateMutator.Result commitPackageStateMutation( + @Nullable PackageStateMutator.InitialState initialState, + @NonNull Consumer consumer) { + synchronized (mPackageStateWriteLock) { + final PackageStateMutator.Result result = mPackageStateMutator.generateResult( + initialState, mChangedPackagesSequenceNumber); + if (result != PackageStateMutator.Result.SUCCESS) { + return result; + } + + consumer.accept(mPackageStateMutator); + onChanged(); + } + + return PackageStateMutator.Result.SUCCESS; + } + + /** + * @see PackageManagerInternal#commitPackageStateMutation(PackageStateMutator.InitialState, + * Consumer) + */ + @NonNull + public PackageStateMutator.Result commitPackageStateMutation( + @Nullable PackageStateMutator.InitialState initialState, @NonNull String packageName, + @NonNull Consumer consumer) { + synchronized (mPackageStateWriteLock) { + final PackageStateMutator.Result result = mPackageStateMutator.generateResult( + initialState, mChangedPackagesSequenceNumber); + if (result != PackageStateMutator.Result.SUCCESS) { + return result; + } + + PackageStateWrite state = mPackageStateMutator.forPackage(packageName); + if (state == null) { + return PackageStateMutator.Result.SPECIFIC_PACKAGE_NULL; + } else { + consumer.accept(state); + } + + onChanged(); + } + + return PackageStateMutator.Result.SUCCESS; + } } diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java index 923a133338ab6..0da57bcf9c0ab 100644 --- a/services/core/java/com/android/server/pm/PackageSetting.java +++ b/services/core/java/com/android/server/pm/PackageSetting.java @@ -395,14 +395,13 @@ public class PackageSetting extends SettingBase implements PackageStateInternal return this; } - public boolean setMimeGroup(String mimeGroup, List mimeTypes) { + public boolean setMimeGroup(String mimeGroup, ArraySet newMimeTypes) { Set oldMimeTypes = mimeGroups == null ? null : mimeGroups.get(mimeGroup); if (oldMimeTypes == null) { throw new IllegalArgumentException("Unknown MIME group " + mimeGroup + " for package " + mName); } - ArraySet newMimeTypes = new ArraySet<>(mimeTypes); boolean hasChanges = !newMimeTypes.equals(oldMimeTypes); mimeGroups.put(mimeGroup, newMimeTypes); if (hasChanges) { @@ -670,6 +669,15 @@ public class PackageSetting extends SettingBase implements PackageStateInternal return state; } + public PackageUserStateImpl getOrCreateUserState(@UserIdInt int userId) { + PackageUserStateImpl state = mUserStates.get(userId); + if (state == null) { + state = new PackageUserStateImpl(); + mUserStates.put(userId, state); + } + return state; + } + @NonNull public PackageUserStateInternal readUserState(int userId) { PackageUserStateInternal state = mUserStates.get(userId); @@ -832,7 +840,6 @@ public class PackageSetting extends SettingBase implements PackageStateInternal } final SuspendParams oldSuspendParams = existingUserState.getSuspendParams().put(suspendingPackage, newSuspendParams); - existingUserState.setSuspended(true); onChanged(); return !Objects.equals(oldSuspendParams, newSuspendParams); } @@ -848,7 +855,6 @@ public class PackageSetting extends SettingBase implements PackageStateInternal existingUserState.setSuspendParams(null); } } - existingUserState.setSuspended((existingUserState.getSuspendParams() != null)); onChanged(); return wasModified; } @@ -866,7 +872,6 @@ public class PackageSetting extends SettingBase implements PackageStateInternal existingUserState.setSuspendParams(null); } } - existingUserState.setSuspended((existingUserState.getSuspendParams() != null)); onChanged(); } @@ -889,7 +894,7 @@ public class PackageSetting extends SettingBase implements PackageStateInternal } void setUserState(int userId, long ceDataInode, int enabled, boolean installed, boolean stopped, - boolean notLaunched, boolean hidden, int distractionFlags, boolean suspended, + boolean notLaunched, boolean hidden, int distractionFlags, ArrayMap suspendParams, boolean instantApp, boolean virtualPreload, String lastDisableAppCaller, ArraySet enabledComponents, ArraySet disabledComponents, @@ -904,7 +909,6 @@ public class PackageSetting extends SettingBase implements PackageStateInternal .setNotLaunched(notLaunched) .setHidden(hidden) .setDistractionFlags(distractionFlags) - .setSuspended(suspended) .setLastDisableAppCaller(lastDisableAppCaller) .setEnabledComponents(enabledComponents) .setDisabledComponents(disabledComponents) @@ -919,11 +923,9 @@ public class PackageSetting extends SettingBase implements PackageStateInternal void setUserState(int userId, PackageUserStateInternal otherState) { setUserState(userId, otherState.getCeDataInode(), otherState.getEnabledState(), - otherState.isInstalled(), - otherState.isStopped(), otherState.isNotLaunched(), otherState.isHidden(), - otherState.getDistractionFlags(), otherState.isSuspended(), - otherState.getSuspendParams(), - otherState.isInstantApp(), + otherState.isInstalled(), otherState.isStopped(), otherState.isNotLaunched(), + otherState.isHidden(), otherState.getDistractionFlags(), + otherState.getSuspendParams(), otherState.isInstantApp(), otherState.isVirtualPreload(), otherState.getLastDisableAppCaller(), new ArraySet<>(otherState.getEnabledComponentsNoCopy()), new ArraySet<>(otherState.getDisabledComponentsNoCopy()), @@ -1553,10 +1555,10 @@ public class PackageSetting extends SettingBase implements PackageStateInternal } @DataClass.Generated( - time = 1635870549646L, + time = 1636145878985L, codegenVersion = "1.0.23", sourceFile = "frameworks/base/services/core/java/com/android/server/pm/PackageSetting.java", - inputSignatures = "private int sharedUserId\nprivate @android.annotation.Nullable java.util.Map> mimeGroups\nprivate @java.lang.Deprecated @android.annotation.Nullable java.util.Set mOldCodePaths\nprivate @android.annotation.Nullable java.lang.String[] usesStaticLibraries\nprivate @android.annotation.Nullable long[] usesStaticLibrariesVersions\nprivate @android.annotation.Nullable @java.lang.Deprecated java.lang.String legacyNativeLibraryPath\nprivate @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.Nullable java.lang.String mRealName\nprivate int mAppId\nprivate @android.annotation.Nullable com.android.server.pm.parsing.pkg.AndroidPackage pkg\nprivate @android.annotation.Nullable com.android.server.pm.SharedUserSetting sharedUser\nprivate @android.annotation.NonNull java.io.File mPath\nprivate @android.annotation.NonNull java.lang.String mPathString\nprivate float mLoadingProgress\nprivate @android.annotation.Nullable java.lang.String mPrimaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mSecondaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mCpuAbiOverride\nprivate long mLastModifiedTime\nprivate long firstInstallTime\nprivate long lastUpdateTime\nprivate long versionCode\nprivate @android.annotation.NonNull com.android.server.pm.PackageSignatures signatures\nprivate boolean installPermissionsFixed\nprivate @android.annotation.NonNull com.android.server.pm.PackageKeySetData keySetData\nprivate final @android.annotation.NonNull android.util.SparseArray mUserStates\nprivate @android.annotation.NonNull com.android.server.pm.InstallSource installSource\nprivate @android.annotation.Nullable java.lang.String volumeUuid\nprivate int categoryOverride\nprivate boolean updateAvailable\nprivate boolean forceQueryableOverride\nprivate @android.annotation.NonNull com.android.server.pm.pkg.PackageStateUnserialized pkgState\nprivate @android.annotation.NonNull java.util.UUID mDomainSetId\nprivate final @android.annotation.NonNull com.android.server.utils.SnapshotCache mSnapshot\nprivate com.android.server.utils.SnapshotCache makeCache()\npublic com.android.server.pm.PackageSetting snapshot()\npublic void dumpDebug(android.util.proto.ProtoOutputStream,long,java.util.List,com.android.server.pm.permission.LegacyPermissionDataProvider)\npublic java.util.List getMimeGroup(java.lang.String)\nprivate java.util.Set getMimeGroupInternal(java.lang.String)\npublic boolean isSharedUser()\npublic com.android.server.pm.PackageSetting setAppId(int)\npublic com.android.server.pm.PackageSetting setCpuAbiOverride(java.lang.String)\npublic com.android.server.pm.PackageSetting setFirstInstallTime(long)\npublic com.android.server.pm.PackageSetting setForceQueryableOverride(boolean)\npublic com.android.server.pm.PackageSetting setInstallerPackageName(java.lang.String)\npublic com.android.server.pm.PackageSetting setInstallSource(com.android.server.pm.InstallSource)\n com.android.server.pm.PackageSetting removeInstallerPackage(java.lang.String)\npublic com.android.server.pm.PackageSetting setIsOrphaned(boolean)\npublic com.android.server.pm.PackageSetting setKeySetData(com.android.server.pm.PackageKeySetData)\npublic com.android.server.pm.PackageSetting setLastModifiedTime(long)\npublic com.android.server.pm.PackageSetting setLastUpdateTime(long)\npublic com.android.server.pm.PackageSetting setLongVersionCode(long)\npublic boolean setMimeGroup(java.lang.String,java.util.List)\npublic com.android.server.pm.PackageSetting setPkg(com.android.server.pm.parsing.pkg.AndroidPackage)\npublic com.android.server.pm.PackageSetting setPrimaryCpuAbi(java.lang.String)\npublic com.android.server.pm.PackageSetting setSecondaryCpuAbi(java.lang.String)\npublic com.android.server.pm.PackageSetting setSignatures(com.android.server.pm.PackageSignatures)\npublic com.android.server.pm.PackageSetting setVolumeUuid(java.lang.String)\npublic @java.lang.Override boolean isExternalStorage()\npublic com.android.server.pm.PackageSetting setUpdateAvailable(boolean)\npublic int getSharedUserIdInt()\npublic @java.lang.Override java.lang.String toString()\nprotected void copyMimeGroups(java.util.Map>)\npublic void updateFrom(com.android.server.pm.PackageSetting)\n com.android.server.pm.PackageSetting updateMimeGroups(java.util.Set)\npublic @java.lang.Deprecated @java.lang.Override com.android.server.pm.permission.LegacyPermissionState getLegacyPermissionState()\npublic com.android.server.pm.PackageSetting setInstallPermissionsFixed(boolean)\npublic boolean isPrivileged()\npublic boolean isOem()\npublic boolean isVendor()\npublic boolean isProduct()\npublic @java.lang.Override boolean isRequiredForSystemUser()\npublic boolean isSystemExt()\npublic boolean isOdm()\npublic boolean isSystem()\npublic android.content.pm.SigningDetails getSigningDetails()\npublic com.android.server.pm.PackageSetting setSigningDetails(android.content.pm.SigningDetails)\npublic void copyPackageSetting(com.android.server.pm.PackageSetting)\n @com.android.internal.annotations.VisibleForTesting com.android.server.pm.pkg.PackageUserStateImpl modifyUserState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateInternal readUserState(int)\n void setEnabled(int,int,java.lang.String)\n int getEnabled(int)\n java.lang.String getLastDisabledAppCaller(int)\n void setInstalled(boolean,int)\n boolean getInstalled(int)\n int getInstallReason(int)\n void setInstallReason(int,int)\n int getUninstallReason(int)\n void setUninstallReason(int,int)\n boolean setOverlayPaths(android.content.pm.overlay.OverlayPaths,int)\n @android.annotation.NonNull android.content.pm.overlay.OverlayPaths getOverlayPaths(int)\n boolean setOverlayPathsForLibrary(java.lang.String,android.content.pm.overlay.OverlayPaths,int)\n @android.annotation.NonNull java.util.Map getOverlayPathsForLibrary(int)\n boolean isAnyInstalled(int[])\n int[] queryInstalledUsers(int[],boolean)\n long getCeDataInode(int)\n void setCeDataInode(long,int)\n boolean getStopped(int)\n void setStopped(boolean,int)\n boolean getNotLaunched(int)\n void setNotLaunched(boolean,int)\n boolean getHidden(int)\n void setHidden(boolean,int)\n int getDistractionFlags(int)\n void setDistractionFlags(int,int)\n boolean getSuspended(int)\n boolean addOrUpdateSuspension(java.lang.String,android.content.pm.SuspendDialogInfo,android.os.PersistableBundle,android.os.PersistableBundle,int)\n boolean removeSuspension(java.lang.String,int)\n void removeSuspension(java.util.function.Predicate,int)\npublic boolean getInstantApp(int)\n void setInstantApp(boolean,int)\n boolean getVirtualPreload(int)\n void setVirtualPreload(boolean,int)\n void setUserState(int,long,int,boolean,boolean,boolean,boolean,int,boolean,android.util.ArrayMap,boolean,boolean,java.lang.String,android.util.ArraySet,android.util.ArraySet,int,int,java.lang.String,java.lang.String)\n void setUserState(int,com.android.server.pm.pkg.PackageUserStateInternal)\n android.util.ArraySet getEnabledComponents(int)\n android.util.ArraySet getDisabledComponents(int)\n void setEnabledComponents(android.util.ArraySet,int)\n void setDisabledComponents(android.util.ArraySet,int)\n void setEnabledComponentsCopy(android.util.ArraySet,int)\n void setDisabledComponentsCopy(android.util.ArraySet,int)\n com.android.server.pm.pkg.PackageUserStateImpl modifyUserStateComponents(int,boolean,boolean)\n void addDisabledComponent(java.lang.String,int)\n void addEnabledComponent(java.lang.String,int)\n boolean enableComponentLPw(java.lang.String,int)\n boolean disableComponentLPw(java.lang.String,int)\n boolean restoreComponentLPw(java.lang.String,int)\n int getCurrentEnabledStateLPr(java.lang.String,int)\n void removeUser(int)\npublic int[] getNotInstalledUserIds()\n void writePackageUserPermissionsProto(android.util.proto.ProtoOutputStream,long,java.util.List,com.android.server.pm.permission.LegacyPermissionDataProvider)\nprotected void writeUsersInfoToProto(android.util.proto.ProtoOutputStream,long)\n void setHarmfulAppWarning(int,java.lang.String)\n java.lang.String getHarmfulAppWarning(int)\n com.android.server.pm.PackageSetting setPath(java.io.File)\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideNonLocalizedLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer,int)\npublic void resetOverrideComponentLabelIcon(int)\npublic void setSplashScreenTheme(int,java.lang.String)\npublic @android.annotation.Nullable java.lang.String getSplashScreenTheme(int)\npublic boolean isLoading()\npublic com.android.server.pm.PackageSetting setLoadingProgress(float)\npublic @android.annotation.NonNull @java.lang.Override long getVersionCode()\npublic @android.annotation.Nullable @java.lang.Override java.util.Map> getMimeGroups()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String getPackageName()\npublic @android.annotation.Nullable @java.lang.Override com.android.server.pm.pkg.AndroidPackageApi getAndroidPackage()\npublic @android.annotation.Nullable @java.lang.Override java.lang.Integer getSharedUserId()\npublic @android.annotation.NonNull android.content.pm.SigningInfo getSigningInfo()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesStaticLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesStaticLibrariesVersions()\npublic @android.annotation.NonNull @java.lang.Override java.util.List getUsesLibraryInfos()\npublic @android.annotation.NonNull @java.lang.Override java.util.List getUsesLibraryFiles()\npublic @java.lang.Override boolean isHiddenUntilInstalled()\npublic @android.annotation.NonNull @java.lang.Override long[] getLastPackageUsageTime()\npublic @java.lang.Override boolean isUpdatedSystemApp()\npublic com.android.server.pm.PackageSetting setDomainSetId(java.util.UUID)\npublic com.android.server.pm.PackageSetting setSharedUser(com.android.server.pm.SharedUserSetting)\npublic com.android.server.pm.PackageSetting setCategoryOverride(int)\npublic com.android.server.pm.PackageSetting setLegacyNativeLibraryPath(java.lang.String)\npublic com.android.server.pm.PackageSetting setMimeGroups(java.util.Map>)\npublic com.android.server.pm.PackageSetting setOldCodePaths(java.util.Set)\npublic com.android.server.pm.PackageSetting setUsesStaticLibraries(java.lang.String[])\npublic com.android.server.pm.PackageSetting setUsesStaticLibrariesVersions(long[])\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageStateUnserialized getTransientState()\npublic @android.annotation.NonNull android.util.SparseArray getUserStates()\nclass PackageSetting extends com.android.server.pm.SettingBase implements [com.android.server.pm.pkg.PackageStateInternal]\n@com.android.internal.util.DataClass(genGetters=true, genConstructor=false, genSetters=false, genBuilder=false)") + inputSignatures = "private int sharedUserId\nprivate @android.annotation.Nullable java.util.Map> mimeGroups\nprivate @java.lang.Deprecated @android.annotation.Nullable java.util.Set mOldCodePaths\nprivate @android.annotation.Nullable java.lang.String[] usesStaticLibraries\nprivate @android.annotation.Nullable long[] usesStaticLibrariesVersions\nprivate @android.annotation.Nullable @java.lang.Deprecated java.lang.String legacyNativeLibraryPath\nprivate @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.Nullable java.lang.String mRealName\nprivate int mAppId\nprivate @android.annotation.Nullable com.android.server.pm.parsing.pkg.AndroidPackage pkg\nprivate @android.annotation.Nullable com.android.server.pm.SharedUserSetting sharedUser\nprivate @android.annotation.NonNull java.io.File mPath\nprivate @android.annotation.NonNull java.lang.String mPathString\nprivate float mLoadingProgress\nprivate @android.annotation.Nullable java.lang.String mPrimaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mSecondaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mCpuAbiOverride\nprivate long mLastModifiedTime\nprivate long firstInstallTime\nprivate long lastUpdateTime\nprivate long versionCode\nprivate @android.annotation.NonNull com.android.server.pm.PackageSignatures signatures\nprivate boolean installPermissionsFixed\nprivate @android.annotation.NonNull com.android.server.pm.PackageKeySetData keySetData\nprivate final @android.annotation.NonNull android.util.SparseArray mUserStates\nprivate @android.annotation.NonNull com.android.server.pm.InstallSource installSource\nprivate @android.annotation.Nullable java.lang.String volumeUuid\nprivate int categoryOverride\nprivate boolean updateAvailable\nprivate boolean forceQueryableOverride\nprivate @android.annotation.NonNull com.android.server.pm.pkg.PackageStateUnserialized pkgState\nprivate @android.annotation.NonNull java.util.UUID mDomainSetId\nprivate final @android.annotation.NonNull com.android.server.utils.SnapshotCache mSnapshot\nprivate com.android.server.utils.SnapshotCache makeCache()\npublic com.android.server.pm.PackageSetting snapshot()\npublic void dumpDebug(android.util.proto.ProtoOutputStream,long,java.util.List,com.android.server.pm.permission.LegacyPermissionDataProvider)\npublic boolean isSharedUser()\npublic com.android.server.pm.PackageSetting setAppId(int)\npublic com.android.server.pm.PackageSetting setCpuAbiOverride(java.lang.String)\npublic com.android.server.pm.PackageSetting setFirstInstallTime(long)\npublic com.android.server.pm.PackageSetting setForceQueryableOverride(boolean)\npublic com.android.server.pm.PackageSetting setInstallerPackageName(java.lang.String)\npublic com.android.server.pm.PackageSetting setInstallSource(com.android.server.pm.InstallSource)\n com.android.server.pm.PackageSetting removeInstallerPackage(java.lang.String)\npublic com.android.server.pm.PackageSetting setIsOrphaned(boolean)\npublic com.android.server.pm.PackageSetting setKeySetData(com.android.server.pm.PackageKeySetData)\npublic com.android.server.pm.PackageSetting setLastModifiedTime(long)\npublic com.android.server.pm.PackageSetting setLastUpdateTime(long)\npublic com.android.server.pm.PackageSetting setLongVersionCode(long)\npublic boolean setMimeGroup(java.lang.String,java.util.List)\npublic com.android.server.pm.PackageSetting setPkg(com.android.server.pm.parsing.pkg.AndroidPackage)\npublic com.android.server.pm.PackageSetting setPrimaryCpuAbi(java.lang.String)\npublic com.android.server.pm.PackageSetting setSecondaryCpuAbi(java.lang.String)\npublic com.android.server.pm.PackageSetting setSignatures(com.android.server.pm.PackageSignatures)\npublic com.android.server.pm.PackageSetting setVolumeUuid(java.lang.String)\npublic @java.lang.Override boolean isExternalStorage()\npublic com.android.server.pm.PackageSetting setUpdateAvailable(boolean)\npublic int getSharedUserIdInt()\npublic @java.lang.Override java.lang.String toString()\nprotected void copyMimeGroups(java.util.Map>)\npublic void updateFrom(com.android.server.pm.PackageSetting)\n com.android.server.pm.PackageSetting updateMimeGroups(java.util.Set)\npublic @java.lang.Deprecated @java.lang.Override com.android.server.pm.permission.LegacyPermissionState getLegacyPermissionState()\npublic com.android.server.pm.PackageSetting setInstallPermissionsFixed(boolean)\npublic boolean isPrivileged()\npublic boolean isOem()\npublic boolean isVendor()\npublic boolean isProduct()\npublic @java.lang.Override boolean isRequiredForSystemUser()\npublic boolean isSystemExt()\npublic boolean isOdm()\npublic boolean isSystem()\npublic android.content.pm.SigningDetails getSigningDetails()\npublic com.android.server.pm.PackageSetting setSigningDetails(android.content.pm.SigningDetails)\npublic void copyPackageSetting(com.android.server.pm.PackageSetting)\n @com.android.internal.annotations.VisibleForTesting com.android.server.pm.pkg.PackageUserStateImpl modifyUserState(int)\npublic com.android.server.pm.pkg.PackageUserStateImpl getOrCreateUserState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateInternal readUserState(int)\n void setEnabled(int,int,java.lang.String)\n int getEnabled(int)\n java.lang.String getLastDisabledAppCaller(int)\n void setInstalled(boolean,int)\n boolean getInstalled(int)\n int getInstallReason(int)\n void setInstallReason(int,int)\n int getUninstallReason(int)\n void setUninstallReason(int,int)\n boolean setOverlayPaths(android.content.pm.overlay.OverlayPaths,int)\n @android.annotation.NonNull android.content.pm.overlay.OverlayPaths getOverlayPaths(int)\n boolean setOverlayPathsForLibrary(java.lang.String,android.content.pm.overlay.OverlayPaths,int)\n @android.annotation.NonNull java.util.Map getOverlayPathsForLibrary(int)\n boolean isAnyInstalled(int[])\n int[] queryInstalledUsers(int[],boolean)\n long getCeDataInode(int)\n void setCeDataInode(long,int)\n boolean getStopped(int)\n void setStopped(boolean,int)\n boolean getNotLaunched(int)\n void setNotLaunched(boolean,int)\n boolean getHidden(int)\n void setHidden(boolean,int)\n int getDistractionFlags(int)\n void setDistractionFlags(int,int)\npublic boolean getInstantApp(int)\n void setInstantApp(boolean,int)\n boolean getVirtualPreload(int)\n void setVirtualPreload(boolean,int)\n void setUserState(int,long,int,boolean,boolean,boolean,boolean,int,android.util.ArrayMap,boolean,boolean,java.lang.String,android.util.ArraySet,android.util.ArraySet,int,int,java.lang.String,java.lang.String)\n void setUserState(int,com.android.server.pm.pkg.PackageUserStateInternal)\n android.util.ArraySet getEnabledComponents(int)\n android.util.ArraySet getDisabledComponents(int)\n void setEnabledComponents(android.util.ArraySet,int)\n void setDisabledComponents(android.util.ArraySet,int)\n void setEnabledComponentsCopy(android.util.ArraySet,int)\n void setDisabledComponentsCopy(android.util.ArraySet,int)\n com.android.server.pm.pkg.PackageUserStateImpl modifyUserStateComponents(int,boolean,boolean)\n void addDisabledComponent(java.lang.String,int)\n void addEnabledComponent(java.lang.String,int)\n boolean enableComponentLPw(java.lang.String,int)\n boolean disableComponentLPw(java.lang.String,int)\n boolean restoreComponentLPw(java.lang.String,int)\n int getCurrentEnabledStateLPr(java.lang.String,int)\n void removeUser(int)\npublic int[] getNotInstalledUserIds()\n void writePackageUserPermissionsProto(android.util.proto.ProtoOutputStream,long,java.util.List,com.android.server.pm.permission.LegacyPermissionDataProvider)\nprotected void writeUsersInfoToProto(android.util.proto.ProtoOutputStream,long)\n void setHarmfulAppWarning(int,java.lang.String)\n java.lang.String getHarmfulAppWarning(int)\n com.android.server.pm.PackageSetting setPath(java.io.File)\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideNonLocalizedLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer,int)\npublic void resetOverrideComponentLabelIcon(int)\npublic void setSplashScreenTheme(int,java.lang.String)\npublic @android.annotation.Nullable java.lang.String getSplashScreenTheme(int)\npublic boolean isLoading()\npublic com.android.server.pm.PackageSetting setLoadingProgress(float)\npublic @android.annotation.NonNull @java.lang.Override long getVersionCode()\npublic @android.annotation.Nullable @java.lang.Override java.util.Map> getMimeGroups()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String getPackageName()\npublic @android.annotation.Nullable @java.lang.Override com.android.server.pm.pkg.AndroidPackageApi getAndroidPackage()\npublic @android.annotation.Nullable @java.lang.Override java.lang.Integer getSharedUserId()\npublic @android.annotation.NonNull android.content.pm.SigningInfo getSigningInfo()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesStaticLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesStaticLibrariesVersions()\npublic @android.annotation.NonNull @java.lang.Override java.util.List getUsesLibraryInfos()\npublic @android.annotation.NonNull @java.lang.Override java.util.List getUsesLibraryFiles()\npublic @java.lang.Override boolean isHiddenUntilInstalled()\npublic @android.annotation.NonNull @java.lang.Override long[] getLastPackageUsageTime()\npublic @java.lang.Override boolean isUpdatedSystemApp()\npublic com.android.server.pm.PackageSetting setDomainSetId(java.util.UUID)\npublic com.android.server.pm.PackageSetting setSharedUser(com.android.server.pm.SharedUserSetting)\npublic com.android.server.pm.PackageSetting setCategoryOverride(int)\npublic com.android.server.pm.PackageSetting setLegacyNativeLibraryPath(java.lang.String)\npublic com.android.server.pm.PackageSetting setMimeGroups(java.util.Map>)\npublic com.android.server.pm.PackageSetting setOldCodePaths(java.util.Set)\npublic com.android.server.pm.PackageSetting setUsesStaticLibraries(java.lang.String[])\npublic com.android.server.pm.PackageSetting setUsesStaticLibrariesVersions(long[])\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageStateUnserialized getTransientState()\npublic @android.annotation.NonNull android.util.SparseArray getUserStates()\nclass PackageSetting extends com.android.server.pm.SettingBase implements [com.android.server.pm.pkg.PackageStateInternal]\n@com.android.internal.util.DataClass(genGetters=true, genConstructor=false, genSetters=false, genBuilder=false)") @Deprecated private void __metadata() {} diff --git a/services/core/java/com/android/server/pm/SettingBase.java b/services/core/java/com/android/server/pm/SettingBase.java index ed85ff9fa2918..4345d5136fb9e 100644 --- a/services/core/java/com/android/server/pm/SettingBase.java +++ b/services/core/java/com/android/server/pm/SettingBase.java @@ -22,6 +22,7 @@ import android.content.pm.ApplicationInfo; import com.android.internal.annotations.VisibleForTesting; import com.android.server.pm.permission.LegacyPermissionState; +import com.android.server.pm.pkg.mutate.PackageStateMutator; import com.android.server.utils.Snappable; import com.android.server.utils.Watchable; import com.android.server.utils.WatchableImpl; @@ -88,6 +89,7 @@ public abstract class SettingBase implements Watchable, Snappable { * Notify listeners that this object has changed. */ protected void onChanged() { + PackageStateMutator.onPackageStateChanged(); dispatchChange(this); } @@ -122,7 +124,7 @@ public abstract class SettingBase implements Watchable, Snappable { return mLegacyPermissionsState; } - SettingBase setFlags(int pkgFlags) { + public SettingBase setFlags(int pkgFlags) { this.mPkgFlags = pkgFlags & (ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_EXTERNAL_STORAGE @@ -131,7 +133,7 @@ public abstract class SettingBase implements Watchable, Snappable { return this; } - SettingBase setPrivateFlags(int pkgPrivateFlags) { + public SettingBase setPrivateFlags(int pkgPrivateFlags) { this.mPkgPrivateFlags = pkgPrivateFlags & (ApplicationInfo.PRIVATE_FLAG_PRIVILEGED | ApplicationInfo.PRIVATE_FLAG_OEM diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index b1ce6a2a53668..6c47eb09cf07f 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -114,6 +114,7 @@ import com.android.server.pm.permission.LegacyPermissionDataProvider; import com.android.server.pm.permission.LegacyPermissionSettings; import com.android.server.pm.permission.LegacyPermissionState; import com.android.server.pm.permission.LegacyPermissionState.PermissionState; +import com.android.server.pm.pkg.PackageStateInternal; import com.android.server.pm.pkg.PackageUserState; import com.android.server.pm.pkg.PackageUserStateInternal; import com.android.server.pm.pkg.SuspendParams; @@ -162,6 +163,7 @@ import java.util.Map.Entry; import java.util.Objects; import java.util.Set; import java.util.UUID; +import java.util.function.Consumer; /** * Holds information about dynamic settings. @@ -257,7 +259,7 @@ public final class Settings implements Watchable, Snappable { public static final int SIGNATURE_MALFORMED_RECOVER = 3; } - private static final boolean DEBUG_STOPPED = false; + static final boolean DEBUG_STOPPED = false; private static final boolean DEBUG_MU = false; private static final boolean DEBUG_KERNEL = false; private static final boolean DEBUG_PARSER = false; @@ -625,7 +627,15 @@ public final class Settings implements Watchable, Snappable { mOtherAppIds = new WatchedSparseArray<>(); mPermissions = new LegacyPermissionSettings(lock); mRuntimePermissionsPersistence = new RuntimePermissionPersistence( - runtimePermissionsPersistence); + runtimePermissionsPersistence, new Consumer() { + @Override + public void accept(Integer userId) { + synchronized (mLock) { + mRuntimePermissionsPersistence.writeStateForUserSync(userId, + mPermissionDataProvider, mPackages, mSharedUsers); + } + } + }); mPermissionDataProvider = permissionDataProvider; mSystemDir = new File(dataDir, "system"); @@ -989,7 +999,6 @@ public final class Settings implements Watchable, Snappable { true /*notLaunched*/, false /*hidden*/, 0 /*distractionFlags*/, - false /*suspended*/, null /*suspendParams*/, instantApp, virtualPreload, @@ -1423,7 +1432,7 @@ public final class Settings implements Watchable, Snappable { void writeAllRuntimePermissionsLPr() { for (int userId : UserManagerService.getInstance().getUserIds()) { - mRuntimePermissionsPersistence.writeStateForUserAsyncLPr(userId); + mRuntimePermissionsPersistence.writeStateForUserAsync(userId); } } @@ -1432,15 +1441,15 @@ public final class Settings implements Watchable, Snappable { } void updateRuntimePermissionsFingerprintLPr(@UserIdInt int userId) { - mRuntimePermissionsPersistence.updateRuntimePermissionsFingerprintLPr(userId); + mRuntimePermissionsPersistence.updateRuntimePermissionsFingerprint(userId); } int getDefaultRuntimePermissionsVersionLPr(int userId) { - return mRuntimePermissionsPersistence.getVersionLPr(userId); + return mRuntimePermissionsPersistence.getVersion(userId); } void setDefaultRuntimePermissionsVersionLPr(int version, int userId) { - mRuntimePermissionsPersistence.setVersionLPr(version, userId); + mRuntimePermissionsPersistence.setVersion(version, userId); } void setPermissionControllerVersion(long version) { @@ -1646,7 +1655,6 @@ public final class Settings implements Watchable, Snappable { false /*notLaunched*/, false /*hidden*/, 0 /*distractionFlags*/, - false /*suspended*/, null /*suspendParams*/, false /*instantApp*/, false /*virtualPreload*/, @@ -1816,10 +1824,9 @@ public final class Settings implements Watchable, Snappable { setBlockUninstallLPw(userId, name, true); } ps.setUserState(userId, ceDataInode, enabled, installed, stopped, notLaunched, - hidden, distractionFlags, suspended, suspendParamsMap, - instantApp, virtualPreload, enabledCaller, enabledComponents, - disabledComponents, installReason, uninstallReason, harmfulAppWarning, - splashScreenTheme); + hidden, distractionFlags, suspendParamsMap, instantApp, virtualPreload, + enabledCaller, enabledComponents, disabledComponents, installReason, + uninstallReason, harmfulAppWarning, splashScreenTheme); mDomainVerificationManager.setLegacyUserState(name, userId, verifState); } else if (tagName.equals("preferred-activities")) { @@ -3100,7 +3107,8 @@ public final class Settings implements Watchable, Snappable { } for (UserInfo user : users) { - mRuntimePermissionsPersistence.readStateForUserSyncLPr(user.id); + mRuntimePermissionsPersistence.readStateForUserSync(user.id, getInternalVersion(), + mPackages, mSharedUsers, getUserRuntimePermissionsFile(user.id)); } /* @@ -3124,7 +3132,8 @@ public final class Settings implements Watchable, Snappable { } void readPermissionStateForUserSyncLPr(@UserIdInt int userId) { - mRuntimePermissionsPersistence.readStateForUserSyncLPr(userId); + mRuntimePermissionsPersistence.readStateForUserSync(userId, getInternalVersion(), + mPackages, mSharedUsers, getUserRuntimePermissionsFile(userId)); } void applyDefaultPreferredAppsLPw(int userId) { @@ -4120,7 +4129,7 @@ public final class Settings implements Watchable, Snappable { file.delete(); removeCrossProfileIntentFiltersLPw(userId); - mRuntimePermissionsPersistence.onUserRemovedLPw(userId); + mRuntimePermissionsPersistence.onUserRemoved(userId); mDomainVerificationManager.clearUser(userId); writePackageListLPr(); @@ -4485,24 +4494,25 @@ public final class Settings implements Watchable, Snappable { } } for (UserInfo user : users) { + final PackageUserStateInternal userState = ps.getUserStateOrDefault(user.id); pw.print(checkinTag); pw.print("-"); pw.print("usr"); pw.print(","); pw.print(user.id); pw.print(","); - pw.print(ps.getInstalled(user.id) ? "I" : "i"); - pw.print(ps.getHidden(user.id) ? "B" : "b"); - pw.print(ps.getSuspended(user.id) ? "SU" : "su"); - pw.print(ps.getStopped(user.id) ? "S" : "s"); - pw.print(ps.getNotLaunched(user.id) ? "l" : "L"); - pw.print(ps.getInstantApp(user.id) ? "IA" : "ia"); - pw.print(ps.getVirtualPreload(user.id) ? "VPI" : "vpi"); - String harmfulAppWarning = ps.getHarmfulAppWarning(user.id); + pw.print(userState.isInstalled() ? "I" : "i"); + pw.print(userState.isHidden() ? "B" : "b"); + pw.print(userState.isSuspended() ? "SU" : "su"); + pw.print(userState.isStopped() ? "S" : "s"); + pw.print(userState.isNotLaunched() ? "l" : "L"); + pw.print(userState.isInstantApp() ? "IA" : "ia"); + pw.print(userState.isVirtualPreload() ? "VPI" : "vpi"); + String harmfulAppWarning = userState.getHarmfulAppWarning(); pw.print(harmfulAppWarning != null ? "HA" : "ha"); pw.print(","); - pw.print(ps.getEnabled(user.id)); - String lastDisabledAppCaller = ps.getLastDisabledAppCaller(user.id); + pw.print(userState.getEnabledState()); + String lastDisabledAppCaller = userState.getLastDisableAppCaller(); pw.print(","); pw.print(lastDisabledAppCaller != null ? lastDisabledAppCaller : "?"); pw.print(","); @@ -4819,48 +4829,48 @@ public final class Settings implements Watchable, Snappable { } for (UserInfo user : users) { + final PackageUserStateInternal userState = ps.getUserStateOrDefault(user.id); pw.print(prefix); pw.print(" User "); pw.print(user.id); pw.print(": "); pw.print("ceDataInode="); - pw.print(ps.getCeDataInode(user.id)); + pw.print(userState.getCeDataInode()); pw.print(" installed="); - pw.print(ps.getInstalled(user.id)); + pw.print(userState.isInstalled()); pw.print(" hidden="); - pw.print(ps.getHidden(user.id)); + pw.print(userState.isHidden()); pw.print(" suspended="); - pw.print(ps.getSuspended(user.id)); + pw.print(userState.isSuspended()); pw.print(" distractionFlags="); - pw.print(ps.getDistractionFlags(user.id)); + pw.print(userState.getDistractionFlags()); pw.print(" stopped="); - pw.print(ps.getStopped(user.id)); + pw.print(userState.isStopped()); pw.print(" notLaunched="); - pw.print(ps.getNotLaunched(user.id)); + pw.print(userState.isNotLaunched()); pw.print(" enabled="); - pw.print(ps.getEnabled(user.id)); + pw.print(userState.getEnabledState()); pw.print(" instant="); - pw.print(ps.getInstantApp(user.id)); + pw.print(userState.isInstantApp()); pw.print(" virtual="); - pw.print(ps.getVirtualPreload(user.id)); + pw.println(userState.isVirtualPreload()); pw.print(" installReason="); - pw.println(ps.getInstallReason(user.id)); + pw.println(userState.getInstallReason()); - if (ps.getSuspended(user.id)) { + if (userState.isSuspended()) { pw.print(prefix); pw.println(" Suspend params:"); - final PackageUserStateInternal pus = ps.readUserState(user.id); - for (int i = 0; i < pus.getSuspendParams().size(); i++) { + for (int i = 0; i < userState.getSuspendParams().size(); i++) { pw.print(prefix); pw.print(" suspendingPackage="); - pw.print(pus.getSuspendParams().keyAt(i)); - final SuspendParams params = pus.getSuspendParams().valueAt(i); + pw.print(userState.getSuspendParams().keyAt(i)); + final SuspendParams params = userState.getSuspendParams().valueAt(i); if (params != null) { pw.print(" dialogInfo="); - pw.print(params.dialogInfo); + pw.print(params.getDialogInfo()); } pw.println(); } } - final OverlayPaths overlayPaths = ps.getOverlayPaths(user.id); + final OverlayPaths overlayPaths = userState.getOverlayPaths(); if (overlayPaths != null) { if (!overlayPaths.getOverlayPaths().isEmpty()) { pw.print(prefix); @@ -4883,7 +4893,7 @@ public final class Settings implements Watchable, Snappable { } final Map sharedLibraryOverlayPaths = - ps.getOverlayPathsForLibrary(user.id); + userState.getSharedLibraryOverlayPaths(); if (sharedLibraryOverlayPaths != null) { for (Map.Entry libOverlayPaths : sharedLibraryOverlayPaths.entrySet()) { @@ -4916,7 +4926,7 @@ public final class Settings implements Watchable, Snappable { } } - String lastDisabledAppCaller = ps.getLastDisabledAppCaller(user.id); + String lastDisabledAppCaller = userState.getLastDisableAppCaller(); if (lastDisabledAppCaller != null) { pw.print(prefix); pw.print(" lastDisabledCaller: "); pw.println(lastDisabledAppCaller); @@ -4929,21 +4939,21 @@ public final class Settings implements Watchable, Snappable { .getPermissionStates(user.id), dumpAll); } - String harmfulAppWarning = ps.getHarmfulAppWarning(user.id); + String harmfulAppWarning = userState.getHarmfulAppWarning(); if (harmfulAppWarning != null) { pw.print(prefix); pw.print(" harmfulAppWarning: "); pw.println(harmfulAppWarning); } if (permissionNames == null) { - ArraySet cmp = ps.getDisabledComponents(user.id); + Set cmp = userState.getDisabledComponents(); if (cmp != null && cmp.size() > 0) { pw.print(prefix); pw.println(" disabledComponents:"); for (String s : cmp) { pw.print(prefix); pw.print(" "); pw.println(s); } } - cmp = ps.getEnabledComponents(user.id); + cmp = userState.getEnabledComponents(); if (cmp != null && cmp.size() > 0) { pw.print(prefix); pw.println(" enabledComponents:"); for (String s : cmp) { @@ -5291,9 +5301,10 @@ public final class Settings implements Watchable, Snappable { public void writePermissionStateForUserLPr(int userId, boolean sync) { if (sync) { - mRuntimePermissionsPersistence.writeStateForUserSyncLPr(userId); + mRuntimePermissionsPersistence.writeStateForUserSync(userId, mPermissionDataProvider, + mPackages, mSharedUsers); } else { - mRuntimePermissionsPersistence.writeStateForUserAsyncLPr(userId); + mRuntimePermissionsPersistence.writeStateForUserAsync(userId); } } @@ -5368,7 +5379,7 @@ public final class Settings implements Watchable, Snappable { } } - private final class RuntimePermissionPersistence { + private static final class RuntimePermissionPersistence { private static final long WRITE_PERMISSIONS_DELAY_MILLIS = 200; private static final long MAX_WRITE_PERMISSIONS_DELAY_MILLIS = 2000; @@ -5381,6 +5392,8 @@ public final class Settings implements Watchable, Snappable { private final Handler mHandler = new MyHandler(); + private final Object mLock = new Object(); + @GuardedBy("mLock") private final SparseBooleanArray mWriteScheduled = new SparseBooleanArray(); @@ -5400,45 +5413,58 @@ public final class Settings implements Watchable, Snappable { // The mapping keys are user ids. private final SparseBooleanArray mPermissionUpgradeNeeded = new SparseBooleanArray(); - public RuntimePermissionPersistence(RuntimePermissionsPersistence persistence) { + // This is a hack to allow this class to invoke a write using Settings's data structures, + // to facilitate moving to a finer scoped lock without a significant refactor. + private final Consumer mInvokeWriteUserStateAsyncCallback; + + public RuntimePermissionPersistence(RuntimePermissionsPersistence persistence, + Consumer invokeWriteUserStateAsyncCallback) { mPersistence = persistence; + mInvokeWriteUserStateAsyncCallback = invokeWriteUserStateAsyncCallback; } - @GuardedBy("Settings.this.mLock") - int getVersionLPr(int userId) { - return mVersions.get(userId, INITIAL_VERSION); - } - - @GuardedBy("Settings.this.mLock") - void setVersionLPr(int version, int userId) { - mVersions.put(userId, version); - writeStateForUserAsyncLPr(userId); - } - - @GuardedBy("Settings.this.mLock") - public boolean isPermissionUpgradeNeeded(int userId) { - return mPermissionUpgradeNeeded.get(userId, true); - } - - @GuardedBy("Settings.this.mLock") - public void updateRuntimePermissionsFingerprintLPr(@UserIdInt int userId) { - if (mExtendedFingerprint == null) { - throw new RuntimeException("The version of the permission controller hasn't been " - + "set before trying to update the fingerprint."); + int getVersion(int userId) { + synchronized (mLock) { + return mVersions.get(userId, INITIAL_VERSION); + } + } + + void setVersion(int version, int userId) { + synchronized (mLock) { + mVersions.put(userId, version); + writeStateForUserAsync(userId); + } + } + + public boolean isPermissionUpgradeNeeded(int userId) { + synchronized (mLock) { + return mPermissionUpgradeNeeded.get(userId, true); + } + } + + public void updateRuntimePermissionsFingerprint(@UserIdInt int userId) { + synchronized (mLock) { + if (mExtendedFingerprint == null) { + throw new RuntimeException( + "The version of the permission controller hasn't been " + + "set before trying to update the fingerprint."); + } + mFingerprints.put(userId, mExtendedFingerprint); + writeStateForUserAsync(userId); } - mFingerprints.put(userId, mExtendedFingerprint); - writeStateForUserAsyncLPr(userId); } public void setPermissionControllerVersion(long version) { - int numUser = mFingerprints.size(); - mExtendedFingerprint = getExtendedFingerprint(version); + synchronized (mLock) { + int numUser = mFingerprints.size(); + mExtendedFingerprint = getExtendedFingerprint(version); - for (int i = 0; i < numUser; i++) { - int userId = mFingerprints.keyAt(i); - String fingerprint = mFingerprints.valueAt(i); - mPermissionUpgradeNeeded.put(userId, - !TextUtils.equals(mExtendedFingerprint, fingerprint)); + for (int i = 0; i < numUser; i++) { + int userId = mFingerprints.keyAt(i); + String fingerprint = mFingerprints.valueAt(i); + mPermissionUpgradeNeeded.put(userId, + !TextUtils.equals(mExtendedFingerprint, fingerprint)); + } } } @@ -5446,84 +5472,92 @@ public final class Settings implements Watchable, Snappable { return PackagePartitions.FINGERPRINT + "?pc_version=" + version; } - public void writeStateForUserAsyncLPr(int userId) { - final long currentTimeMillis = SystemClock.uptimeMillis(); + public void writeStateForUserAsync(int userId) { + synchronized (mLock) { + final long currentTimeMillis = SystemClock.uptimeMillis(); - if (mWriteScheduled.get(userId)) { - mHandler.removeMessages(userId); + if (mWriteScheduled.get(userId)) { + mHandler.removeMessages(userId); - // If enough time passed, write without holding off anymore. - final long lastNotWrittenMutationTimeMillis = mLastNotWrittenMutationTimesMillis - .get(userId); - final long timeSinceLastNotWrittenMutationMillis = currentTimeMillis - - lastNotWrittenMutationTimeMillis; - if (timeSinceLastNotWrittenMutationMillis >= MAX_WRITE_PERMISSIONS_DELAY_MILLIS) { - mHandler.obtainMessage(userId).sendToTarget(); - return; + // If enough time passed, write without holding off anymore. + final long lastNotWrittenMutationTimeMillis = mLastNotWrittenMutationTimesMillis + .get(userId); + final long timeSinceLastNotWrittenMutationMillis = currentTimeMillis + - lastNotWrittenMutationTimeMillis; + if (timeSinceLastNotWrittenMutationMillis + >= MAX_WRITE_PERMISSIONS_DELAY_MILLIS) { + mHandler.obtainMessage(userId).sendToTarget(); + return; + } + + // Hold off a bit more as settings are frequently changing. + final long maxDelayMillis = Math.max(lastNotWrittenMutationTimeMillis + + MAX_WRITE_PERMISSIONS_DELAY_MILLIS - currentTimeMillis, 0); + final long writeDelayMillis = Math.min(WRITE_PERMISSIONS_DELAY_MILLIS, + maxDelayMillis); + + Message message = mHandler.obtainMessage(userId); + mHandler.sendMessageDelayed(message, writeDelayMillis); + } else { + mLastNotWrittenMutationTimesMillis.put(userId, currentTimeMillis); + Message message = mHandler.obtainMessage(userId); + mHandler.sendMessageDelayed(message, WRITE_PERMISSIONS_DELAY_MILLIS); + mWriteScheduled.put(userId, true); } - - // Hold off a bit more as settings are frequently changing. - final long maxDelayMillis = Math.max(lastNotWrittenMutationTimeMillis - + MAX_WRITE_PERMISSIONS_DELAY_MILLIS - currentTimeMillis, 0); - final long writeDelayMillis = Math.min(WRITE_PERMISSIONS_DELAY_MILLIS, - maxDelayMillis); - - Message message = mHandler.obtainMessage(userId); - mHandler.sendMessageDelayed(message, writeDelayMillis); - } else { - mLastNotWrittenMutationTimesMillis.put(userId, currentTimeMillis); - Message message = mHandler.obtainMessage(userId); - mHandler.sendMessageDelayed(message, WRITE_PERMISSIONS_DELAY_MILLIS); - mWriteScheduled.put(userId, true); } } - public void writeStateForUserSyncLPr(int userId) { - mHandler.removeMessages(userId); - mWriteScheduled.delete(userId); + public void writeStateForUserSync(int userId, @NonNull LegacyPermissionDataProvider + legacyPermissionDataProvider, + @NonNull WatchedArrayMap packageStates, + @NonNull WatchedArrayMap sharedUsers) { + synchronized (mLock) { + mHandler.removeMessages(userId); + mWriteScheduled.delete(userId); - mPermissionDataProvider.writeLegacyPermissionStateTEMP(); + legacyPermissionDataProvider.writeLegacyPermissionStateTEMP(); - 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.getSharedUser() == null) { + Map> packagePermissions = + new ArrayMap<>(); + int packagesSize = packageStates.size(); + for (int i = 0; i < packagesSize; i++) { + String packageName = packageStates.keyAt(i); + PackageStateInternal packageState = packageStates.valueAt(i); + if (packageState.getSharedUser() == null) { + List permissions = + getPermissionsFromPermissionsState( + packageState.getLegacyPermissionState(), userId); + if (permissions.isEmpty() && !packageState.isInstallPermissionsFixed()) { + // Storing an empty state means the package is known to the system and + // its install permissions have been granted and fixed. If this is not + // the case, we should not store anything. + continue; + } + packagePermissions.put(packageName, permissions); + } + } + + Map> sharedUserPermissions = + new ArrayMap<>(); + final int sharedUsersSize = sharedUsers.size(); + for (int i = 0; i < sharedUsersSize; i++) { + String sharedUserName = sharedUsers.keyAt(i); + SharedUserSetting sharedUserSetting = sharedUsers.valueAt(i); List permissions = getPermissionsFromPermissionsState( - packageSetting.getLegacyPermissionState(), userId); - if (permissions.isEmpty() && !packageSetting.isInstallPermissionsFixed()) { - // Storing an empty state means the package is known to the system and its - // install permissions have been granted and fixed. If this is not the case, - // we should not store anything. - continue; - } - packagePermissions.put(packageName, permissions); + sharedUserSetting.getLegacyPermissionState(), userId); + sharedUserPermissions.put(sharedUserName, permissions); } + + RuntimePermissionsState runtimePermissions = new RuntimePermissionsState(version, + fingerprint, packagePermissions, sharedUserPermissions); + + mPersistence.writeForUser(runtimePermissions, UserHandle.of(userId)); } - - 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.getLegacyPermissionState(), userId); - sharedUserPermissions.put(sharedUserName, permissions); - } - - RuntimePermissionsState runtimePermissions = new RuntimePermissionsState(version, - fingerprint, packagePermissions, sharedUserPermissions); - - mPersistence.writeForUser(runtimePermissions, UserHandle.of(userId)); } @NonNull @@ -5541,82 +5575,91 @@ public final class Settings implements Watchable, Snappable { return permissions; } - @GuardedBy("Settings.this.mLock") - private void onUserRemovedLPw(int userId) { - // Make sure we do not - mHandler.removeMessages(userId); + private void onUserRemoved(int userId) { + synchronized (mLock) { + // Make sure we do not + mHandler.removeMessages(userId); - mPermissionUpgradeNeeded.delete(userId); - mVersions.delete(userId); - mFingerprints.remove(userId); + mPermissionUpgradeNeeded.delete(userId); + mVersions.delete(userId); + mFingerprints.remove(userId); + } } public void deleteUserRuntimePermissionsFile(int userId) { - mPersistence.deleteForUser(UserHandle.of(userId)); + synchronized (mLock) { + mPersistence.deleteForUser(UserHandle.of(userId)); + } } - @GuardedBy("Settings.this.mLock") - public void readStateForUserSyncLPr(int userId) { - RuntimePermissionsState runtimePermissions = mPersistence.readForUser(UserHandle.of( - userId)); - if (runtimePermissions == null) { - readLegacyStateForUserSyncLPr(userId); - writeStateForUserAsyncLPr(userId); - return; - } - - // If the runtime permissions file exists but the version is not set this is - // an upgrade from P->Q. Hence mark it with the special UPGRADE_VERSION. - int version = runtimePermissions.getVersion(); - if (version == RuntimePermissionsState.NO_VERSION) { - version = UPGRADE_VERSION; - } - mVersions.put(userId, version); - - String fingerprint = runtimePermissions.getFingerprint(); - mFingerprints.put(userId, fingerprint); - - boolean isUpgradeToR = getInternalVersion().sdkVersion < Build.VERSION_CODES.R; - - Map> packagePermissions = - runtimePermissions.getPackagePermissions(); - int packagesSize = mPackages.size(); - for (int i = 0; i < packagesSize; i++) { - String packageName = mPackages.keyAt(i); - PackageSetting packageSetting = mPackages.valueAt(i); - - List permissions = - packagePermissions.get(packageName); - if (permissions != null) { - readPermissionsStateLpr(permissions, packageSetting.getLegacyPermissionState(), - userId); - packageSetting.setInstallPermissionsFixed(true); - } else if (packageSetting.getSharedUser() == null && !isUpgradeToR) { - Slog.w(TAG, "Missing permission state for package: " + packageName); - packageSetting.getLegacyPermissionState().setMissing(true, userId); + public void readStateForUserSync(int userId, @NonNull VersionInfo internalVersion, + @NonNull WatchedArrayMap packageSettings, + @NonNull WatchedArrayMap sharedUsers, + @NonNull File userRuntimePermissionsFile) { + synchronized (mLock) { + RuntimePermissionsState runtimePermissions = mPersistence.readForUser(UserHandle.of( + userId)); + if (runtimePermissions == null) { + readLegacyStateForUserSync(userId, userRuntimePermissionsFile, packageSettings, + sharedUsers); + writeStateForUserAsync(userId); + return; } - } - Map> sharedUserPermissions = - runtimePermissions.getSharedUserPermissions(); - int sharedUsersSize = mSharedUsers.size(); - for (int i = 0; i < sharedUsersSize; i++) { - String sharedUserName = mSharedUsers.keyAt(i); - SharedUserSetting sharedUserSetting = mSharedUsers.valueAt(i); + // If the runtime permissions file exists but the version is not set this is + // an upgrade from P->Q. Hence mark it with the special UPGRADE_VERSION. + int version = runtimePermissions.getVersion(); + if (version == RuntimePermissionsState.NO_VERSION) { + version = UPGRADE_VERSION; + } + mVersions.put(userId, version); - List permissions = - sharedUserPermissions.get(sharedUserName); - if (permissions != null) { - readPermissionsStateLpr(permissions, - sharedUserSetting.getLegacyPermissionState(), userId); - } else if (!isUpgradeToR) { - Slog.w(TAG, "Missing permission state for shared user: " + sharedUserName); - sharedUserSetting.getLegacyPermissionState().setMissing(true, userId); + String fingerprint = runtimePermissions.getFingerprint(); + mFingerprints.put(userId, fingerprint); + + boolean isUpgradeToR = internalVersion.sdkVersion < Build.VERSION_CODES.R; + + Map> packagePermissions = + runtimePermissions.getPackagePermissions(); + int packagesSize = packageSettings.size(); + for (int i = 0; i < packagesSize; i++) { + String packageName = packageSettings.keyAt(i); + PackageSetting packageSetting = packageSettings.valueAt(i); + + List permissions = + packagePermissions.get(packageName); + if (permissions != null) { + readPermissionsState(permissions, + packageSetting.getLegacyPermissionState(), + userId); + packageSetting.setInstallPermissionsFixed(true); + } else if (packageSetting.getSharedUser() == null && !isUpgradeToR) { + Slog.w(TAG, "Missing permission state for package: " + packageName); + packageSetting.getLegacyPermissionState().setMissing(true, userId); + } + } + + Map> sharedUserPermissions = + runtimePermissions.getSharedUserPermissions(); + int sharedUsersSize = sharedUsers.size(); + for (int i = 0; i < sharedUsersSize; i++) { + String sharedUserName = sharedUsers.keyAt(i); + SharedUserSetting sharedUserSetting = sharedUsers.valueAt(i); + + List permissions = + sharedUserPermissions.get(sharedUserName); + if (permissions != null) { + readPermissionsState(permissions, + sharedUserSetting.getLegacyPermissionState(), userId); + } else if (!isUpgradeToR) { + Slog.w(TAG, "Missing permission state for shared user: " + sharedUserName); + sharedUserSetting.getLegacyPermissionState().setMissing(true, userId); + } } } } - private void readPermissionsStateLpr( + private void readPermissionsState( @NonNull List permissions, @NonNull LegacyPermissionState permissionsState, @UserIdInt int userId) { int permissionsSize = permissions.size(); @@ -5630,77 +5673,86 @@ public final class Settings implements Watchable, Snappable { } } - @GuardedBy("Settings.this.mLock") - private void readLegacyStateForUserSyncLPr(int userId) { - File permissionsFile = getUserRuntimePermissionsFile(userId); - if (!permissionsFile.exists()) { - return; - } + private void readLegacyStateForUserSync(int userId, @NonNull File permissionsFile, + @NonNull WatchedArrayMap packageStates, + @NonNull WatchedArrayMap sharedUsers) { + synchronized (mLock) { + if (!permissionsFile.exists()) { + return; + } - FileInputStream in; - try { - in = new AtomicFile(permissionsFile).openRead(); - } catch (FileNotFoundException fnfe) { - Slog.i(PackageManagerService.TAG, "No permissions state"); - return; - } + FileInputStream in; + try { + in = new AtomicFile(permissionsFile).openRead(); + } catch (FileNotFoundException fnfe) { + Slog.i(PackageManagerService.TAG, "No permissions state"); + return; + } - try { - final TypedXmlPullParser parser = Xml.resolvePullParser(in); - parseLegacyRuntimePermissionsLPr(parser, userId); + try { + final TypedXmlPullParser parser = Xml.resolvePullParser(in); + parseLegacyRuntimePermissions(parser, userId, packageStates, sharedUsers); - } catch (XmlPullParserException | IOException e) { - throw new IllegalStateException("Failed parsing permissions file: " - + permissionsFile, e); - } finally { - IoUtils.closeQuietly(in); + } catch (XmlPullParserException | IOException e) { + throw new IllegalStateException("Failed parsing permissions file: " + + permissionsFile, e); + } finally { + IoUtils.closeQuietly(in); + } } } - // Private internals - - @GuardedBy("Settings.this.mLock") - private void parseLegacyRuntimePermissionsLPr(TypedXmlPullParser parser, int userId) + private void parseLegacyRuntimePermissions(TypedXmlPullParser parser, int userId, + @NonNull WatchedArrayMap packageStates, + @NonNull WatchedArrayMap sharedUsers) throws IOException, XmlPullParserException { - final int outerDepth = parser.getDepth(); - int type; - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { - if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { - continue; - } + synchronized (mLock) { + final int outerDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } - switch (parser.getName()) { - case TAG_RUNTIME_PERMISSIONS: { - // If the permisions settings file exists but the version is not set this is - // an upgrade from P->Q. Hence mark it with the special UPGRADE_VERSION - int version = parser.getAttributeInt(null, ATTR_VERSION, UPGRADE_VERSION); - mVersions.put(userId, version); - String fingerprint = parser.getAttributeValue(null, ATTR_FINGERPRINT); - mFingerprints.put(userId, fingerprint); - } break; - - case TAG_PACKAGE: { - String name = parser.getAttributeValue(null, ATTR_NAME); - PackageSetting ps = mPackages.get(name); - if (ps == null) { - Slog.w(PackageManagerService.TAG, "Unknown package:" + name); - XmlUtils.skipCurrentTag(parser); - continue; + switch (parser.getName()) { + case TAG_RUNTIME_PERMISSIONS: { + // If the permisions settings file exists but the version is not set this is + // an upgrade from P->Q. Hence mark it with the special UPGRADE_VERSION + int version = parser.getAttributeInt(null, ATTR_VERSION, + UPGRADE_VERSION); + mVersions.put(userId, version); + String fingerprint = parser.getAttributeValue(null, ATTR_FINGERPRINT); + mFingerprints.put(userId, fingerprint); } - parseLegacyPermissionsLPr(parser, ps.getLegacyPermissionState(), userId); - } break; + break; - case TAG_SHARED_USER: { - String name = parser.getAttributeValue(null, ATTR_NAME); - SharedUserSetting sus = mSharedUsers.get(name); - if (sus == null) { - Slog.w(PackageManagerService.TAG, "Unknown shared user:" + name); - XmlUtils.skipCurrentTag(parser); - continue; + case TAG_PACKAGE: { + String name = parser.getAttributeValue(null, ATTR_NAME); + PackageStateInternal ps = packageStates.get(name); + if (ps == null) { + Slog.w(PackageManagerService.TAG, "Unknown package:" + name); + XmlUtils.skipCurrentTag(parser); + continue; + } + parseLegacyPermissionsLPr(parser, ps.getLegacyPermissionState(), + userId); } - parseLegacyPermissionsLPr(parser, sus.getLegacyPermissionState(), userId); - } break; + break; + + case TAG_SHARED_USER: { + String name = parser.getAttributeValue(null, ATTR_NAME); + SharedUserSetting sus = sharedUsers.get(name); + if (sus == null) { + Slog.w(PackageManagerService.TAG, "Unknown shared user:" + name); + XmlUtils.skipCurrentTag(parser); + continue; + } + parseLegacyPermissionsLPr(parser, sus.getLegacyPermissionState(), + userId); + } + break; + } } } } @@ -5708,25 +5760,27 @@ public final class Settings implements Watchable, Snappable { private void parseLegacyPermissionsLPr(TypedXmlPullParser parser, LegacyPermissionState permissionsState, int userId) throws IOException, XmlPullParserException { - final int outerDepth = parser.getDepth(); - int type; - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { - if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { - continue; - } - - switch (parser.getName()) { - case TAG_ITEM: { - String name = parser.getAttributeValue(null, ATTR_NAME); - final boolean granted = - parser.getAttributeBoolean(null, ATTR_GRANTED, true); - final int flags = - parser.getAttributeIntHex(null, ATTR_FLAGS, 0); - permissionsState.putPermissionState(new PermissionState(name, true, - granted, flags), userId); + synchronized (mLock) { + final int outerDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + switch (parser.getName()) { + case TAG_ITEM: { + String name = parser.getAttributeValue(null, ATTR_NAME); + final boolean granted = + parser.getAttributeBoolean(null, ATTR_GRANTED, true); + final int flags = + parser.getAttributeIntHex(null, ATTR_FLAGS, 0); + permissionsState.putPermissionState(new PermissionState(name, true, + granted, flags), userId); + } + break; } - break; } } } @@ -5740,9 +5794,7 @@ public final class Settings implements Watchable, Snappable { public void handleMessage(Message message) { final int userId = message.what; Runnable callback = (Runnable) message.obj; - synchronized (mLock) { - writeStateForUserSyncLPr(userId); - } + mInvokeWriteUserStateAsyncCallback.accept(userId); if (callback != null) { callback.run(); } diff --git a/services/core/java/com/android/server/pm/pkg/PackageStateInternal.java b/services/core/java/com/android/server/pm/pkg/PackageStateInternal.java index 5460afa665e6a..56f62ab87933c 100644 --- a/services/core/java/com/android/server/pm/pkg/PackageStateInternal.java +++ b/services/core/java/com/android/server/pm/pkg/PackageStateInternal.java @@ -23,6 +23,7 @@ import android.content.pm.SigningDetails; import android.util.SparseArray; import com.android.server.pm.InstallSource; +import com.android.server.pm.PackageKeySetData; import com.android.server.pm.SharedUserSetting; import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.pm.permission.LegacyPermissionState; @@ -82,4 +83,7 @@ public interface PackageStateInternal extends PackageState { String getPathString(); float getLoadingProgress(); + + @NonNull + PackageKeySetData getKeySetData(); } diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java b/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java index 32a9cf1bdb3d3..6fafb242201a1 100644 --- a/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java +++ b/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java @@ -28,6 +28,7 @@ import android.util.Pair; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; +import com.android.internal.util.CollectionUtils; import com.android.internal.util.DataClass; import java.util.Objects; @@ -49,7 +50,6 @@ public class PackageUserStateImpl implements PackageUserStateInternal { private boolean mNotLaunched; private boolean mHidden; // Is the app restricted by owner / admin private int mDistractionFlags; - private boolean mSuspended; private boolean mInstantApp; private boolean mVirtualPreload; private int mEnabledState = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; @@ -101,7 +101,6 @@ public class PackageUserStateImpl implements PackageUserStateInternal { mNotLaunched = other.mNotLaunched; mHidden = other.mHidden; mDistractionFlags = other.mDistractionFlags; - mSuspended = other.mSuspended; mInstantApp = other.mInstantApp; mVirtualPreload = other.mVirtualPreload; mEnabledState = other.mEnabledState; @@ -256,6 +255,28 @@ public class PackageUserStateImpl implements PackageUserStateInternal { return mComponentLabelIconOverrideMap.get(componentName); } + @Override + public boolean isSuspended() { + return !CollectionUtils.isEmpty(mSuspendParams); + } + + public PackageUserStateImpl putSuspendParams(@NonNull String suspendingPackage, + @NonNull SuspendParams suspendParams) { + if (mSuspendParams == null) { + mSuspendParams = new ArrayMap<>(); + } + mSuspendParams.put(suspendingPackage, suspendParams); + return this; + } + + public PackageUserStateImpl removeSuspension(@NonNull String suspendingPackage) { + if (mSuspendParams != null) { + mSuspendParams.remove(suspendingPackage); + } + return this; + } + + // Code below generated by codegen v1.0.23. @@ -311,11 +332,6 @@ public class PackageUserStateImpl implements PackageUserStateInternal { return mDistractionFlags; } - @DataClass.Generated.Member - public boolean isSuspended() { - return mSuspended; - } - @DataClass.Generated.Member public boolean isInstantApp() { return mInstantApp; @@ -432,12 +448,6 @@ public class PackageUserStateImpl implements PackageUserStateInternal { return this; } - @DataClass.Generated.Member - public @NonNull PackageUserStateImpl setSuspended( boolean value) { - mSuspended = value; - return this; - } - @DataClass.Generated.Member public @NonNull PackageUserStateImpl setInstantApp( boolean value) { mInstantApp = value; @@ -532,7 +542,6 @@ public class PackageUserStateImpl implements PackageUserStateInternal { && mNotLaunched == that.mNotLaunched && mHidden == that.mHidden && mDistractionFlags == that.mDistractionFlags - && mSuspended == that.mSuspended && mInstantApp == that.mInstantApp && mVirtualPreload == that.mVirtualPreload && mEnabledState == that.mEnabledState @@ -563,7 +572,6 @@ public class PackageUserStateImpl implements PackageUserStateInternal { _hash = 31 * _hash + Boolean.hashCode(mNotLaunched); _hash = 31 * _hash + Boolean.hashCode(mHidden); _hash = 31 * _hash + mDistractionFlags; - _hash = 31 * _hash + Boolean.hashCode(mSuspended); _hash = 31 * _hash + Boolean.hashCode(mInstantApp); _hash = 31 * _hash + Boolean.hashCode(mVirtualPreload); _hash = 31 * _hash + mEnabledState; @@ -581,10 +589,10 @@ public class PackageUserStateImpl implements PackageUserStateInternal { } @DataClass.Generated( - time = 1633983318771L, + time = 1636145886996L, codegenVersion = "1.0.23", sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java", - inputSignatures = "protected @android.annotation.Nullable android.util.ArraySet mDisabledComponents\nprotected @android.annotation.Nullable android.util.ArraySet mEnabledComponents\nprivate long mCeDataInode\nprivate boolean mInstalled\nprivate boolean mStopped\nprivate boolean mNotLaunched\nprivate boolean mHidden\nprivate int mDistractionFlags\nprivate boolean mSuspended\nprivate boolean mInstantApp\nprivate boolean mVirtualPreload\nprivate int mEnabledState\nprivate @android.content.pm.PackageManager.InstallReason int mInstallReason\nprivate @android.content.pm.PackageManager.UninstallReason int mUninstallReason\nprivate @android.annotation.Nullable java.lang.String mHarmfulAppWarning\nprivate @android.annotation.Nullable java.lang.String mLastDisableAppCaller\nprotected @android.annotation.Nullable android.content.pm.overlay.OverlayPaths mOverlayPaths\nprotected @android.annotation.Nullable android.util.ArrayMap mSharedLibraryOverlayPaths\nprivate @android.annotation.Nullable java.lang.String mSplashScreenTheme\nprivate @android.annotation.Nullable android.util.ArrayMap mSuspendParams\nprivate @android.annotation.Nullable android.content.pm.overlay.OverlayPaths mCachedOverlayPaths\nprivate @android.annotation.Nullable android.util.ArrayMap> mComponentLabelIconOverrideMap\npublic @android.annotation.Nullable boolean setOverlayPaths(android.content.pm.overlay.OverlayPaths)\npublic boolean setSharedLibraryOverlayPaths(java.lang.String,android.content.pm.overlay.OverlayPaths)\npublic @android.annotation.Nullable @java.lang.Override android.util.ArraySet getDisabledComponentsNoCopy()\npublic @android.annotation.Nullable @java.lang.Override android.util.ArraySet getEnabledComponentsNoCopy()\npublic @java.lang.Override boolean isComponentEnabled(java.lang.String)\npublic @java.lang.Override boolean isComponentDisabled(java.lang.String)\npublic @java.lang.Override android.content.pm.overlay.OverlayPaths getAllOverlayPaths()\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer)\npublic void resetOverrideComponentLabelIcon()\npublic @android.annotation.Nullable android.util.Pair getOverrideLabelIconForComponent(android.content.ComponentName)\nclass PackageUserStateImpl extends java.lang.Object implements [com.android.server.pm.pkg.PackageUserStateInternal]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false, genEqualsHashCode=true)") + inputSignatures = "protected @android.annotation.Nullable android.util.ArraySet mDisabledComponents\nprotected @android.annotation.Nullable android.util.ArraySet mEnabledComponents\nprivate long mCeDataInode\nprivate boolean mInstalled\nprivate boolean mStopped\nprivate boolean mNotLaunched\nprivate boolean mHidden\nprivate int mDistractionFlags\nprivate boolean mInstantApp\nprivate boolean mVirtualPreload\nprivate int mEnabledState\nprivate @android.content.pm.PackageManager.InstallReason int mInstallReason\nprivate @android.content.pm.PackageManager.UninstallReason int mUninstallReason\nprivate @android.annotation.Nullable java.lang.String mHarmfulAppWarning\nprivate @android.annotation.Nullable java.lang.String mLastDisableAppCaller\nprotected @android.annotation.Nullable android.content.pm.overlay.OverlayPaths mOverlayPaths\nprotected @android.annotation.Nullable android.util.ArrayMap mSharedLibraryOverlayPaths\nprivate @android.annotation.Nullable java.lang.String mSplashScreenTheme\nprivate @android.annotation.Nullable android.util.ArrayMap mSuspendParams\nprivate @android.annotation.Nullable android.content.pm.overlay.OverlayPaths mCachedOverlayPaths\nprivate @android.annotation.Nullable android.util.ArrayMap> mComponentLabelIconOverrideMap\npublic @android.annotation.Nullable boolean setOverlayPaths(android.content.pm.overlay.OverlayPaths)\npublic boolean setSharedLibraryOverlayPaths(java.lang.String,android.content.pm.overlay.OverlayPaths)\npublic @android.annotation.Nullable @java.lang.Override android.util.ArraySet getDisabledComponentsNoCopy()\npublic @android.annotation.Nullable @java.lang.Override android.util.ArraySet getEnabledComponentsNoCopy()\npublic @java.lang.Override boolean isComponentEnabled(java.lang.String)\npublic @java.lang.Override boolean isComponentDisabled(java.lang.String)\npublic @java.lang.Override android.content.pm.overlay.OverlayPaths getAllOverlayPaths()\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer)\npublic void resetOverrideComponentLabelIcon()\npublic @android.annotation.Nullable android.util.Pair getOverrideLabelIconForComponent(android.content.ComponentName)\npublic @java.lang.Override boolean isSuspended()\npublic com.android.server.pm.pkg.PackageUserStateImpl putSuspendParams(java.lang.String,com.android.server.pm.pkg.SuspendParams)\npublic com.android.server.pm.pkg.PackageUserStateImpl removeSuspension(java.lang.String)\nclass PackageUserStateImpl extends java.lang.Object implements [com.android.server.pm.pkg.PackageUserStateInternal]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false, genEqualsHashCode=true)") @Deprecated private void __metadata() {} diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserStateInternal.java b/services/core/java/com/android/server/pm/pkg/PackageUserStateInternal.java index 6f3331223bff9..bd8b3ab611402 100644 --- a/services/core/java/com/android/server/pm/pkg/PackageUserStateInternal.java +++ b/services/core/java/com/android/server/pm/pkg/PackageUserStateInternal.java @@ -32,6 +32,7 @@ public interface PackageUserStateInternal extends PackageUserState { PackageUserStateInternal DEFAULT = new PackageUserStateDefault(); + // TODO: Make non-null with emptyMap() @Nullable ArrayMap getSuspendParams(); diff --git a/services/core/java/com/android/server/pm/pkg/SuspendParams.java b/services/core/java/com/android/server/pm/pkg/SuspendParams.java index 71512dc840880..d24ce96bb4b63 100644 --- a/services/core/java/com/android/server/pm/pkg/SuspendParams.java +++ b/services/core/java/com/android/server/pm/pkg/SuspendParams.java @@ -42,11 +42,15 @@ public final class SuspendParams { private static final String TAG_APP_EXTRAS = "app-extras"; private static final String TAG_LAUNCHER_EXTRAS = "launcher-extras"; - public SuspendDialogInfo dialogInfo; - public PersistableBundle appExtras; - public PersistableBundle launcherExtras; + private final SuspendDialogInfo dialogInfo; + private final PersistableBundle appExtras; + private final PersistableBundle launcherExtras; - private SuspendParams() { + private SuspendParams(SuspendDialogInfo dialogInfo, PersistableBundle appExtras, + PersistableBundle launcherExtras) { + this.dialogInfo = dialogInfo; + this.appExtras = appExtras; + this.launcherExtras = launcherExtras; } /** @@ -60,11 +64,7 @@ public final class SuspendParams { if (dialogInfo == null && appExtras == null && launcherExtras == null) { return null; } - final SuspendParams instance = new SuspendParams(); - instance.dialogInfo = dialogInfo; - instance.appExtras = appExtras; - instance.launcherExtras = launcherExtras; - return instance; + return new SuspendParams(dialogInfo, appExtras, launcherExtras); } @Override @@ -172,4 +172,16 @@ public final class SuspendParams { } return getInstanceOrNull(readDialogInfo, readAppExtras, readLauncherExtras); } + + public SuspendDialogInfo getDialogInfo() { + return dialogInfo; + } + + public PersistableBundle getAppExtras() { + return appExtras; + } + + public PersistableBundle getLauncherExtras() { + return launcherExtras; + } } diff --git a/services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java b/services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java new file mode 100644 index 0000000000000..35d4d9e82fbe1 --- /dev/null +++ b/services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java @@ -0,0 +1,333 @@ +/* + * Copyright (C) 2021 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.pkg.mutate; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.pm.overlay.OverlayPaths; +import android.util.ArraySet; + +import com.android.server.pm.PackageSetting; +import com.android.server.pm.pkg.PackageUserStateImpl; +import com.android.server.pm.pkg.SuspendParams; + +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Function; + +public class PackageStateMutator { + + private static final AtomicLong sStateChangeSequence = new AtomicLong(); + + private final StateWriteWrapper mStateWrite = new StateWriteWrapper(); + + private final Function mActiveStateFunction; + private final Function mDisabledStateFunction; + + public PackageStateMutator(@NonNull Function activeStateFunction, + @NonNull Function disabledStateFunction) { + mActiveStateFunction = activeStateFunction; + mDisabledStateFunction = disabledStateFunction; + } + + public static void onPackageStateChanged() { + sStateChangeSequence.incrementAndGet(); + } + + @NonNull + public PackageStateWrite forPackage(@NonNull String packageName) { + return mStateWrite.setState(mActiveStateFunction.apply(packageName)); + } + + @Nullable + public PackageStateWrite forPackageNullable(@NonNull String packageName) { + final PackageSetting packageState = mActiveStateFunction.apply(packageName); + mStateWrite.setState(packageState); + if (packageState == null) { + return null; + } + + return mStateWrite.setState(packageState); + } + + @NonNull + public PackageStateWrite forDisabledSystemPackage(@NonNull String packageName) { + return mStateWrite.setState(mDisabledStateFunction.apply(packageName)); + } + + @Nullable + public PackageStateWrite forDisabledSystemPackageNullable(@NonNull String packageName) { + final PackageSetting packageState = mDisabledStateFunction.apply(packageName); + if (packageState == null) { + return null; + } + + return mStateWrite.setState(packageState); + } + + @NonNull + public InitialState initialState(int changedPackagesSequenceNumber) { + return new InitialState(changedPackagesSequenceNumber, sStateChangeSequence.get()); + } + + /** + * @return null if initial state is null or if nothing has changed, otherwise return result + * with what changed + */ + @Nullable + public Result generateResult(@Nullable InitialState state, int changedPackagesSequenceNumber) { + if (state == null) { + return Result.SUCCESS; + } + + boolean packagesChanged = changedPackagesSequenceNumber != state.mPackageSequence; + boolean stateChanged = sStateChangeSequence.get() != state.mStateSequence; + if (packagesChanged && stateChanged) { + return Result.PACKAGES_AND_STATE_CHANGED; + } else if (packagesChanged) { + return Result.PACKAGES_CHANGED; + } else if (stateChanged) { + return Result.STATE_CHANGED; + } else { + return Result.SUCCESS; + } + } + + public static class InitialState { + + private final int mPackageSequence; + private final long mStateSequence; + + public InitialState(int packageSequence, long stateSequence) { + mPackageSequence = packageSequence; + mStateSequence = stateSequence; + } + } + + public static class Result { + + public static final Result SUCCESS = new Result(true, false, false, false); + public static final Result PACKAGES_CHANGED = new Result(false, true, false, false); + public static final Result STATE_CHANGED = new Result(false, false, true, false); + public static final Result PACKAGES_AND_STATE_CHANGED = new Result(false, true, true, false); + public static final Result SPECIFIC_PACKAGE_NULL = new Result(false, false, true, true); + + private final boolean mCommitted; + private final boolean mPackagesChanged; + private final boolean mStateChanged; + private final boolean mSpecificPackageNull; + + public Result(boolean committed, boolean packagesChanged, boolean stateChanged, + boolean specificPackageNull) { + mCommitted = committed; + mPackagesChanged = packagesChanged; + mStateChanged = stateChanged; + mSpecificPackageNull = specificPackageNull; + } + + public boolean isCommitted() { + return mCommitted; + } + + public boolean isPackagesChanged() { + return mPackagesChanged; + } + + public boolean isStateChanged() { + return mStateChanged; + } + + public boolean isSpecificPackageNull() { + return mSpecificPackageNull; + } + } + + private static class StateWriteWrapper implements PackageStateWrite { + + private final UserStateWriteWrapper mUserStateWrite = new UserStateWriteWrapper(); + + @NonNull + private PackageSetting mState; + + public StateWriteWrapper setState(PackageSetting state) { + this.mState = state; + return this; + } + + @NonNull + @Override + public PackageUserStateWrite userState(int userId) { + return mUserStateWrite.setStates( + mState == null ? null : mState.getOrCreateUserState(userId)); + } + + @Override + public PackageStateWrite setLastPackageUsageTime(int reason, long timeInMillis) { + if (mState != null) { + mState.getTransientState().setLastPackageUsageTimeInMills(reason, timeInMillis); + } + return this; + } + + @Override + public PackageStateWrite setHiddenUntilInstalled(boolean value) { + if (mState != null) { + mState.getTransientState().setHiddenUntilInstalled(value); + } + return this; + } + + @NonNull + @Override + public PackageStateWrite setRequiredForSystemUser(boolean requiredForSystemUser) { + if (mState != null) { + if (requiredForSystemUser) { + mState.setPrivateFlags(mState.getPrivateFlags() + | ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER); + } else { + mState.setPrivateFlags(mState.getPrivateFlags() + & ~ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER); + } + } + return this; + } + + @NonNull + @Override + public PackageStateWrite setMimeGroup(@NonNull String mimeGroup, + @NonNull ArraySet mimeTypes) { + if (mState != null) { + mState.setMimeGroup(mimeGroup, mimeTypes); + } + return this; + } + + private static class UserStateWriteWrapper implements PackageUserStateWrite { + + @Nullable + private PackageUserStateImpl mUserState; + + public UserStateWriteWrapper setStates(@Nullable PackageUserStateImpl userState) { + mUserState = userState; + return this; + } + + @NonNull + @Override + public PackageUserStateWrite setInstalled(boolean installed) { + if (mUserState != null) { + mUserState.setInstalled(installed); + } + return this; + } + + @NonNull + @Override + public PackageUserStateWrite setUninstallReason(int reason) { + if (mUserState != null) { + mUserState.setUninstallReason(reason); + } + return this; + } + + @NonNull + @Override + public PackageUserStateWrite setDistractionFlags( + @PackageManager.DistractionRestriction int restrictionFlags) { + if (mUserState != null) { + mUserState.setDistractionFlags(restrictionFlags); + } + return this; + } + + @NonNull + @Override + public PackageUserStateWrite putSuspendParams(@NonNull String suspendingPackage, + @Nullable SuspendParams suspendParams) { + if (mUserState != null) { + mUserState.putSuspendParams(suspendingPackage, suspendParams); + } + return this; + } + + @NonNull + @Override + public PackageUserStateWrite removeSuspension(@NonNull String suspendingPackage) { + if (mUserState != null) { + mUserState.removeSuspension(suspendingPackage); + } + return this; + } + + @NonNull + @Override + public PackageUserStateWrite setHidden(boolean hidden) { + if (mUserState != null) { + mUserState.setHidden(hidden); + } + return this; + } + + @NonNull + @Override + public PackageUserStateWrite setStopped(boolean stopped) { + if (mUserState != null) { + mUserState.setStopped(stopped); + } + return this; + } + + @NonNull + @Override + public PackageUserStateWrite setNotLaunched(boolean notLaunched) { + if (mUserState != null) { + mUserState.setNotLaunched(notLaunched); + } + return this; + } + + @NonNull + @Override + public PackageUserStateWrite setOverlayPaths(@NonNull OverlayPaths overlayPaths) { + if (mUserState != null) { + mUserState.setOverlayPaths(overlayPaths); + } + return this; + } + + @NonNull + @Override + public PackageUserStateWrite setOverlayPathsForLibrary(@NonNull String libraryName, + @Nullable OverlayPaths overlayPaths) { + if (mUserState != null) { + mUserState.setSharedLibraryOverlayPaths(libraryName, overlayPaths); + } + return this; + } + + @NonNull + @Override + public PackageUserStateWrite setHarmfulAppWarning(@Nullable String warning) { + if (mUserState != null) { + mUserState.setHarmfulAppWarning(warning); + } + return this; + } + } + } +} diff --git a/services/core/java/com/android/server/pm/pkg/mutate/PackageStateWrite.java b/services/core/java/com/android/server/pm/pkg/mutate/PackageStateWrite.java new file mode 100644 index 0000000000000..585becee55c0f --- /dev/null +++ b/services/core/java/com/android/server/pm/pkg/mutate/PackageStateWrite.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 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.pkg.mutate; + +import android.annotation.NonNull; +import android.annotation.UserIdInt; +import android.content.pm.PackageManager; +import android.util.ArraySet; + +public interface PackageStateWrite { + + @NonNull + PackageUserStateWrite userState(@UserIdInt int userId); + + @NonNull + PackageStateWrite setLastPackageUsageTime(@PackageManager.NotifyReason int reason, + long timeInMillis); + + @NonNull + PackageStateWrite setHiddenUntilInstalled(boolean hiddenUntilInstalled); + + @NonNull + PackageStateWrite setRequiredForSystemUser(boolean requiredForSystemUser); + + @NonNull + PackageStateWrite setMimeGroup(@NonNull String mimeGroup, @NonNull ArraySet mimeTypes); +} diff --git a/services/core/java/com/android/server/pm/pkg/mutate/PackageUserStateWrite.java b/services/core/java/com/android/server/pm/pkg/mutate/PackageUserStateWrite.java new file mode 100644 index 0000000000000..e23a1b604a490 --- /dev/null +++ b/services/core/java/com/android/server/pm/pkg/mutate/PackageUserStateWrite.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2021 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.pkg.mutate; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.pm.PackageManager; +import android.content.pm.overlay.OverlayPaths; + +import com.android.server.pm.pkg.SuspendParams; + +public interface PackageUserStateWrite { + + @NonNull + PackageUserStateWrite setInstalled(boolean installed); + + @NonNull + PackageUserStateWrite setUninstallReason(@PackageManager.UninstallReason int reason); + + @NonNull + PackageUserStateWrite setDistractionFlags( + @PackageManager.DistractionRestriction int restrictionFlags); + + @NonNull + PackageUserStateWrite putSuspendParams(@NonNull String suspendingPackage, + @Nullable SuspendParams suspendParams); + + @NonNull + PackageUserStateWrite removeSuspension(@NonNull String suspendingPackage); + + @NonNull + PackageUserStateWrite setHidden(boolean hidden); + + @NonNull + PackageUserStateWrite setStopped(boolean stopped); + + @NonNull + PackageUserStateWrite setNotLaunched(boolean notLaunched); + + @NonNull + PackageUserStateWrite setOverlayPaths(@Nullable OverlayPaths overlayPaths); + + @NonNull + PackageUserStateWrite setOverlayPathsForLibrary(@NonNull String libraryName, + @Nullable OverlayPaths overlayPaths); + + @NonNull + PackageUserStateWrite setHarmfulAppWarning(@Nullable String warning); +} 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 6c9f8fee25b02..1b898fac2f065 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java @@ -264,17 +264,17 @@ public class PackageManagerSettingsTests { final SuspendParams params = packageUserState1.getSuspendParams().valueAt(0); watcher.verifyNoChangeReported("fetch user state"); assertThat(params, is(notNullValue())); - assertThat(params.appExtras.size(), is(1)); - assertThat(params.appExtras.getString("app_extra_string"), is("value")); - assertThat(params.launcherExtras.size(), is(1)); - assertThat(params.launcherExtras.getLong("launcher_extra_long"), is(4L)); - assertThat(params.dialogInfo, is(notNullValue())); - assertThat(params.dialogInfo.getDialogMessage(), is("Dialog Message")); - assertThat(params.dialogInfo.getTitleResId(), is(ID_NULL)); - assertThat(params.dialogInfo.getIconResId(), is(TEST_RESOURCE_ID)); - assertThat(params.dialogInfo.getNeutralButtonTextResId(), is(ID_NULL)); - assertThat(params.dialogInfo.getNeutralButtonAction(), is(BUTTON_ACTION_MORE_DETAILS)); - assertThat(params.dialogInfo.getDialogMessageResId(), is(ID_NULL)); + assertThat(params.getAppExtras().size(), is(1)); + assertThat(params.getAppExtras().getString("app_extra_string"), is("value")); + assertThat(params.getLauncherExtras().size(), is(1)); + assertThat(params.getLauncherExtras().getLong("launcher_extra_long"), is(4L)); + assertThat(params.getDialogInfo(), is(notNullValue())); + assertThat(params.getDialogInfo().getDialogMessage(), is("Dialog Message")); + assertThat(params.getDialogInfo().getTitleResId(), is(ID_NULL)); + assertThat(params.getDialogInfo().getIconResId(), is(TEST_RESOURCE_ID)); + assertThat(params.getDialogInfo().getNeutralButtonTextResId(), is(ID_NULL)); + assertThat(params.getDialogInfo().getNeutralButtonAction(), is(BUTTON_ACTION_MORE_DETAILS)); + assertThat(params.getDialogInfo().getDialogMessageResId(), is(ID_NULL)); } @Test @@ -351,18 +351,18 @@ public class PackageManagerSettingsTests { final SuspendParams params11 = readPus1.getSuspendParams().valueAt(0); watcher.verifyNoChangeReported("read package param"); assertThat(params11, is(notNullValue())); - assertThat(params11.dialogInfo, is(dialogInfo1)); - assertThat(BaseBundle.kindofEquals(params11.appExtras, appExtras1), is(true)); - assertThat(BaseBundle.kindofEquals(params11.launcherExtras, launcherExtras1), + assertThat(params11.getDialogInfo(), is(dialogInfo1)); + assertThat(BaseBundle.kindofEquals(params11.getAppExtras(), appExtras1), is(true)); + assertThat(BaseBundle.kindofEquals(params11.getLauncherExtras(), launcherExtras1), is(true)); watcher.verifyNoChangeReported("read package param"); assertThat(readPus1.getSuspendParams().keyAt(1), is("suspendingPackage2")); final SuspendParams params12 = readPus1.getSuspendParams().valueAt(1); assertThat(params12, is(notNullValue())); - assertThat(params12.dialogInfo, is(dialogInfo2)); - assertThat(BaseBundle.kindofEquals(params12.appExtras, appExtras2), is(true)); - assertThat(BaseBundle.kindofEquals(params12.launcherExtras, launcherExtras2), + assertThat(params12.getDialogInfo(), is(dialogInfo2)); + assertThat(BaseBundle.kindofEquals(params12.getAppExtras(), appExtras2), is(true)); + assertThat(BaseBundle.kindofEquals(params12.getLauncherExtras(), launcherExtras2), is(true)); watcher.verifyNoChangeReported("read package param"); @@ -373,9 +373,9 @@ public class PackageManagerSettingsTests { assertThat(readPus2.getSuspendParams().keyAt(0), is("suspendingPackage3")); final SuspendParams params21 = readPus2.getSuspendParams().valueAt(0); assertThat(params21, is(notNullValue())); - assertThat(params21.dialogInfo, is(nullValue())); - assertThat(BaseBundle.kindofEquals(params21.appExtras, appExtras1), is(true)); - assertThat(params21.launcherExtras, is(nullValue())); + assertThat(params21.getDialogInfo(), is(nullValue())); + assertThat(BaseBundle.kindofEquals(params21.getAppExtras(), appExtras1), is(true)); + assertThat(params21.getLauncherExtras(), is(nullValue())); watcher.verifyNoChangeReported("read package param"); final PackageUserStateInternal readPus3 = settingsUnderTest.mPackages.get(PACKAGE_NAME_3) @@ -388,7 +388,7 @@ public class PackageManagerSettingsTests { @Test public void testPackageRestrictionsSuspendedDefault() { final PackageSetting defaultSetting = createPackageSetting(PACKAGE_NAME_1); - assertThat(defaultSetting.getSuspended(0), is(false)); + assertThat(defaultSetting.getUserStateOrDefault(0).isSuspended(), is(false)); } @Test diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java index 828d419c02fff..1e4134ec25d89 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java @@ -82,7 +82,8 @@ public class PackageUserStateTest { assertThat(testUserState.equals(oldUserState), is(false)); oldUserState = new PackageUserStateImpl(); - oldUserState.setSuspended(true); + oldUserState.putSuspendParams("suspendingPackage", + SuspendParams.getInstanceOrNull(null, new PersistableBundle(), null)); assertThat(testUserState.equals(oldUserState), is(false)); oldUserState = new PackageUserStateImpl(); @@ -231,7 +232,6 @@ public class PackageUserStateTest { final PackageUserStateImpl testUserState1 = new PackageUserStateImpl(); - testUserState1.setSuspended(true); testUserState1.setSuspendParams(paramsMap1); PackageUserStateImpl testUserState2 =