Introduce DistractingPackageHelper
Move the implementaion of handling distracting packages out of the
PackageManagerService.
Fix: 225784320
Test: atest CtsSuspendAppsTestCases:DistractingPackageTest
Test: atest CtsSuspendAppsPermissionTestCases:NegativePermissionsTest
Test: atest CtsAppEnumerationTestCases:AppEnumerationTests
Test: atest FrameworksServicesTests:PackageManagerSettingsTests
Test: atest FrameworksServicesTests:PackageUserStateTest
Change-Id: I4e44c1f039318bf02d00ff6a6b8b973244108008
Merged-In: I4e44c1f039318bf02d00ff6a6b8b973244108008
diff --git a/services/core/java/com/android/server/pm/BroadcastHelper.java b/services/core/java/com/android/server/pm/BroadcastHelper.java
index f1394d4..bf1196d 100644
--- a/services/core/java/com/android/server/pm/BroadcastHelper.java
+++ b/services/core/java/com/android/server/pm/BroadcastHelper.java
@@ -320,17 +320,6 @@
broadcastAllowlist, null);
}
- public void sendDistractingPackagesChanged(String[] pkgList, int[] uidList, int userId,
- int distractionFlags) {
- final Bundle extras = new Bundle(3);
- extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgList);
- extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidList);
- extras.putInt(Intent.EXTRA_DISTRACTION_RESTRICTIONS, distractionFlags);
- sendPackageBroadcast(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED, null, extras,
- Intent.FLAG_RECEIVER_REGISTERED_ONLY, null, null, new int[]{userId}, null, null,
- null);
- }
-
public void sendFirstLaunchBroadcast(String pkgName, String installerPkg,
int[] userIds, int[] instantUserIds) {
sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH, pkgName, null, 0,
diff --git a/services/core/java/com/android/server/pm/DistractingPackageHelper.java b/services/core/java/com/android/server/pm/DistractingPackageHelper.java
new file mode 100644
index 0000000..7dc45b5
--- /dev/null
+++ b/services/core/java/com/android/server/pm/DistractingPackageHelper.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2022 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;
+
+import static android.content.pm.PackageManager.RESTRICTION_NONE;
+
+import android.annotation.NonNull;
+import android.content.Intent;
+import android.content.pm.PackageManager.DistractionRestriction;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.util.ArraySet;
+import android.util.IntArray;
+import android.util.Slog;
+
+import com.android.internal.util.ArrayUtils;
+import com.android.server.pm.pkg.PackageStateInternal;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Mark, unmark, or remove any {@link DistractionRestriction restrictions} set on given packages.
+ */
+public final class DistractingPackageHelper {
+
+ // TODO(b/198166813): remove PMS dependency
+ private final PackageManagerService mPm;
+ private final PackageManagerServiceInjector mInjector;
+ private final BroadcastHelper mBroadcastHelper;
+ private final SuspendPackageHelper mSuspendPackageHelper;
+
+ /**
+ * Constructor for {@link PackageManagerService}.
+ */
+ DistractingPackageHelper(PackageManagerService pm, PackageManagerServiceInjector injector,
+ BroadcastHelper broadcastHelper, SuspendPackageHelper suspendPackageHelper) {
+ mPm = pm;
+ mInjector = injector;
+ mBroadcastHelper = broadcastHelper;
+ mSuspendPackageHelper = suspendPackageHelper;
+ }
+
+ /**
+ * Mark or unmark the given packages as distracting to the given user.
+ *
+ * @param packageNames Packages to mark as distracting.
+ * @param restrictionFlags Any combination of restrictions to impose on the given packages.
+ * {@link DistractionRestriction#RESTRICTION_NONE} can be used to
+ * clear any existing restrictions.
+ * @param userId the user for which changes are taking place.
+ * @param callingUid The caller's uid.
+ *
+ * @return A list of packages that could not have the {@code restrictionFlags} set. The system
+ * may prevent restricting critical packages to preserve normal device function.
+ */
+ String[] setDistractingPackageRestrictionsAsUser(@NonNull Computer snapshot,
+ String[] packageNames, int restrictionFlags, int userId, int callingUid) {
+ if (ArrayUtils.isEmpty(packageNames)) {
+ return packageNames;
+ }
+ if (restrictionFlags != RESTRICTION_NONE
+ && !mSuspendPackageHelper.isSuspendAllowedForUser(snapshot, userId, callingUid)) {
+ Slog.w(PackageManagerService.TAG,
+ "Cannot restrict packages due to restrictions on user " + userId);
+ return packageNames;
+ }
+
+ final List<String> changedPackagesList = new ArrayList<>(packageNames.length);
+ final IntArray changedUids = new IntArray(packageNames.length);
+ final List<String> unactionedPackages = new ArrayList<>(packageNames.length);
+
+ final ArraySet<String> changesToCommit = new ArraySet<>();
+ final boolean[] canRestrict = (restrictionFlags != RESTRICTION_NONE)
+ ? mSuspendPackageHelper.canSuspendPackageForUser(snapshot, packageNames, userId,
+ callingUid) : null;
+ for (int i = 0; i < packageNames.length; i++) {
+ final String packageName = packageNames[i];
+ final PackageStateInternal packageState =
+ snapshot.getPackageStateInternal(packageName);
+ if (packageState == null
+ || snapshot.shouldFilterApplication(packageState, callingUid, userId)) {
+ Slog.w(PackageManagerService.TAG,
+ "Could not find package setting for package: " + packageName
+ + ". Skipping...");
+ unactionedPackages.add(packageName);
+ continue;
+ }
+ if (canRestrict != null && !canRestrict[i]) {
+ unactionedPackages.add(packageName);
+ continue;
+ }
+ final int oldDistractionFlags = packageState.getUserStateOrDefault(userId)
+ .getDistractionFlags();
+ if (restrictionFlags != oldDistractionFlags) {
+ changedPackagesList.add(packageName);
+ changedUids.add(UserHandle.getUid(userId, packageState.getAppId()));
+ changesToCommit.add(packageName);
+ }
+ }
+
+ mPm.commitPackageStateMutation(null /* initialState */, mutator -> {
+ final int size = changesToCommit.size();
+ for (int index = 0; index < size; index++) {
+ mutator.forPackage(changesToCommit.valueAt(index))
+ .userState(userId)
+ .setDistractionFlags(restrictionFlags);
+ }
+ });
+
+ if (!changedPackagesList.isEmpty()) {
+ final String[] changedPackages = changedPackagesList.toArray(
+ new String[changedPackagesList.size()]);
+ sendDistractingPackagesChanged(changedPackages, changedUids.toArray(), userId,
+ restrictionFlags);
+ mPm.scheduleWritePackageRestrictions(userId);
+ }
+ return unactionedPackages.toArray(new String[0]);
+ }
+
+ /**
+ * Removes any {@link DistractionRestriction restrictions} set on given packages.
+ *
+ * <p> Caller must flush package restrictions if it cares about immediate data consistency.
+ *
+ * @param packagesToChange The packages on which restrictions are to be removed.
+ * @param userId the user for which changes are taking place.
+ */
+ void removeDistractingPackageRestrictions(@NonNull Computer snapshot,
+ String[] packagesToChange, int userId) {
+ if (ArrayUtils.isEmpty(packagesToChange)) {
+ return;
+ }
+ final List<String> changedPackages = new ArrayList<>(packagesToChange.length);
+ final IntArray changedUids = new IntArray(packagesToChange.length);
+ for (int i = 0; i < packagesToChange.length; i++) {
+ final String packageName = packagesToChange[i];
+ final PackageStateInternal ps = snapshot.getPackageStateInternal(packageName);
+ if (ps != null && ps.getUserStateOrDefault(userId).getDistractionFlags()
+ != RESTRICTION_NONE) {
+ changedPackages.add(ps.getPackageName());
+ changedUids.add(UserHandle.getUid(userId, ps.getAppId()));
+ }
+ }
+ mPm.commitPackageStateMutation(null /* initialState */, mutator -> {
+ for (int index = 0; index < changedPackages.size(); index++) {
+ mutator.forPackage(changedPackages.get(index))
+ .userState(userId)
+ .setDistractionFlags(RESTRICTION_NONE);
+ }
+ });
+
+ if (!changedPackages.isEmpty()) {
+ final String[] packageArray = changedPackages.toArray(
+ new String[changedPackages.size()]);
+ sendDistractingPackagesChanged(packageArray, changedUids.toArray(), userId,
+ RESTRICTION_NONE);
+ mPm.scheduleWritePackageRestrictions(userId);
+ }
+ }
+
+ /**
+ * Send broadcast intents for packages distracting changes.
+ *
+ * @param pkgList The names of packages which have suspension changes.
+ * @param uidList The uids of packages which have suspension changes.
+ * @param userId The user where packages reside.
+ */
+ void sendDistractingPackagesChanged(@NonNull String[] pkgList,
+ int[] uidList, int userId, int distractionFlags) {
+ final Bundle extras = new Bundle(3);
+ extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgList);
+ extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidList);
+ extras.putInt(Intent.EXTRA_DISTRACTION_RESTRICTIONS, distractionFlags);
+
+ final Handler handler = mInjector.getHandler();
+ handler.post(() -> mBroadcastHelper.sendPackageBroadcast(
+ Intent.ACTION_DISTRACTING_PACKAGES_CHANGED, null /* pkg */, extras,
+ Intent.FLAG_RECEIVER_REGISTERED_ONLY, null /* targetPkg */,
+ null /* finishedReceiver */, new int[]{userId}, null /* instantUserIds */,
+ null /* allowList */, null /* bOptions */));
+ }
+}
diff --git a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
index 2b73375..2fe7913 100644
--- a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
+++ b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
@@ -83,6 +83,7 @@
@NonNull protected abstract PackageObserverHelper getPackageObserverHelper();
@NonNull protected abstract ResolveIntentHelper getResolveIntentHelper();
@NonNull protected abstract SuspendPackageHelper getSuspendPackageHelper();
+ @NonNull protected abstract DistractingPackageHelper getDistractingPackageHelper();
@NonNull protected abstract ProtectedPackages getProtectedPackages();
@NonNull protected abstract UserNeedsBadgingCache getUserNeedsBadging();
@NonNull protected abstract InstantAppRegistry getInstantAppRegistry();
@@ -248,8 +249,8 @@
@Override
@Deprecated
public final void removeDistractingPackageRestrictions(String packageName, int userId) {
- mService.removeDistractingPackageRestrictions(snapshot(), new String[]{packageName},
- userId);
+ getDistractingPackageHelper().removeDistractingPackageRestrictions(snapshot(),
+ new String[]{packageName}, userId);
}
@Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 6cf63d1..bf80a46 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -159,7 +159,6 @@
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.ExceptionUtils;
-import android.util.IntArray;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
@@ -939,6 +938,7 @@
private final ResolveIntentHelper mResolveIntentHelper;
private final DexOptHelper mDexOptHelper;
private final SuspendPackageHelper mSuspendPackageHelper;
+ private final DistractingPackageHelper mDistractingPackageHelper;
private final IntentResolverInterceptor mIntentResolverInterceptor;
private final StorageEventHelper mStorageEventHelper;
@@ -1683,6 +1683,7 @@
mResolveIntentHelper = testParams.resolveIntentHelper;
mDexOptHelper = testParams.dexOptHelper;
mSuspendPackageHelper = testParams.suspendPackageHelper;
+ mDistractingPackageHelper = testParams.distractingPackageHelper;
mSharedLibraries.setDeletePackageHelper(mDeletePackageHelper);
@@ -1842,6 +1843,8 @@
mProtectedPackages);
mStorageEventHelper = new StorageEventHelper(this, mDeletePackageHelper,
mRemovePackageHelper);
+ mDistractingPackageHelper = new DistractingPackageHelper(this, mInjector, mBroadcastHelper,
+ mSuspendPackageHelper);
synchronized (mLock) {
// Create the computer as soon as the state objects have been installed. The
@@ -3065,43 +3068,19 @@
void removeAllDistractingPackageRestrictions(@NonNull Computer snapshot, int userId) {
final String[] allPackages = snapshot.getAllAvailablePackageNames();
- removeDistractingPackageRestrictions(snapshot, allPackages, userId);
+ mDistractingPackageHelper.removeDistractingPackageRestrictions(snapshot, allPackages,
+ userId);
}
- /**
- * Removes any {@link android.content.pm.PackageManager.DistractionRestriction restrictions}
- * set on given packages.
- *
- * <p> Caller must flush package restrictions if it cares about immediate data consistency.
- *
- * @param packagesToChange The packages on which restrictions are to be removed.
- * @param userId the user for which changes are taking place.
- */
- void removeDistractingPackageRestrictions(@NonNull Computer snapshot,
- String[] packagesToChange, int userId) {
- final List<String> changedPackages = new ArrayList<>();
- final IntArray changedUids = new IntArray();
- for (String packageName : packagesToChange) {
- final PackageStateInternal ps = snapshot.getPackageStateInternal(packageName);
- if (ps != null && ps.getUserStateOrDefault(userId).getDistractionFlags() != 0) {
- changedPackages.add(ps.getPackageName());
- changedUids.add(UserHandle.getUid(userId, ps.getAppId()));
- }
- }
- commitPackageStateMutation(null, mutator -> {
- for (int index = 0; index < changedPackages.size(); index++) {
- mutator.forPackage(changedPackages.get(index))
- .userState(userId)
- .setDistractionFlags(0);
- }
- });
+ private void enforceCanSetDistractingPackageRestrictionsAsUser(@NonNull Computer snapshot,
+ int callingUid, int userId, String callingMethod) {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS,
+ callingMethod);
- if (!changedPackages.isEmpty()) {
- final String[] packageArray = changedPackages.toArray(
- new String[changedPackages.size()]);
- mHandler.post(() -> mBroadcastHelper.sendDistractingPackagesChanged(
- packageArray, changedUids.toArray(), userId, 0));
- scheduleWritePackageRestrictions(userId);
+ if (callingUid != Process.ROOT_UID && callingUid != Process.SYSTEM_UID
+ && UserHandle.getUserId(callingUid) != userId) {
+ throw new SecurityException("Calling uid " + callingUid + " cannot call for user "
+ + userId);
}
}
@@ -5591,73 +5570,13 @@
@Override
public String[] setDistractingPackageRestrictionsAsUser(String[] packageNames,
int restrictionFlags, int userId) {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS,
- "setDistractingPackageRestrictionsAsUser");
-
final int callingUid = Binder.getCallingUid();
- if (callingUid != Process.ROOT_UID && callingUid != Process.SYSTEM_UID
- && UserHandle.getUserId(callingUid) != userId) {
- throw new SecurityException("Calling uid " + callingUid + " cannot call for user "
- + userId);
- }
- Objects.requireNonNull(packageNames, "packageNames cannot be null");
final Computer snapshot = snapshotComputer();
- if (restrictionFlags != 0
- && !mSuspendPackageHelper.isSuspendAllowedForUser(snapshot, userId,
- callingUid)) {
- Slog.w(PackageManagerService.TAG, "Cannot restrict packages due to restrictions on user " + userId);
- return packageNames;
- }
-
- final List<String> changedPackagesList = new ArrayList<>(packageNames.length);
- final IntArray changedUids = new IntArray(packageNames.length);
- final List<String> unactionedPackages = new ArrayList<>(packageNames.length);
-
- ArraySet<String> changesToCommit = new ArraySet<>();
- final boolean[] canRestrict = (restrictionFlags != 0)
- ? mSuspendPackageHelper.canSuspendPackageForUser(snapshot, packageNames, userId,
- callingUid) : null;
- for (int i = 0; i < packageNames.length; i++) {
- final String packageName = packageNames[i];
- final PackageStateInternal packageState =
- snapshot.getPackageStateInternal(packageName);
- if (packageState == null
- || snapshot.shouldFilterApplication(packageState, callingUid, userId)) {
- Slog.w(PackageManagerService.TAG, "Could not find package setting for package: " + packageName
- + ". Skipping...");
- unactionedPackages.add(packageName);
- continue;
- }
- if (canRestrict != null && !canRestrict[i]) {
- unactionedPackages.add(packageName);
- continue;
- }
- final int oldDistractionFlags = packageState.getUserStateOrDefault(userId)
- .getDistractionFlags();
- if (restrictionFlags != oldDistractionFlags) {
- changedPackagesList.add(packageName);
- changedUids.add(UserHandle.getUid(userId, packageState.getAppId()));
- changesToCommit.add(packageName);
- }
- }
-
- commitPackageStateMutation(null, mutator -> {
- final int size = changesToCommit.size();
- for (int index = 0; index < size; index++) {
- mutator.forPackage(changesToCommit.valueAt(index))
- .userState(userId)
- .setDistractionFlags(restrictionFlags);
- }
- });
-
- if (!changedPackagesList.isEmpty()) {
- final String[] changedPackages = changedPackagesList.toArray(
- new String[changedPackagesList.size()]);
- mHandler.post(() -> mBroadcastHelper.sendDistractingPackagesChanged(
- changedPackages, changedUids.toArray(), userId, restrictionFlags));
- scheduleWritePackageRestrictions(userId);
- }
- return unactionedPackages.toArray(new String[0]);
+ enforceCanSetDistractingPackageRestrictionsAsUser(snapshot, callingUid, userId,
+ "setDistractingPackageRestrictionsAsUser");
+ Objects.requireNonNull(packageNames, "packageNames cannot be null");
+ return mDistractingPackageHelper.setDistractingPackageRestrictionsAsUser(snapshot,
+ packageNames, restrictionFlags, userId, callingUid);
}
@Override
@@ -6121,6 +6040,12 @@
@NonNull
@Override
+ protected DistractingPackageHelper getDistractingPackageHelper() {
+ return mDistractingPackageHelper;
+ }
+
+ @NonNull
+ @Override
protected ProtectedPackages getProtectedPackages() {
return mProtectedPackages;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
index 144231c..16829e0e8 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
@@ -116,4 +116,5 @@
public DexOptHelper dexOptHelper;
public SuspendPackageHelper suspendPackageHelper;
public StorageEventHelper storageEventHelper;
+ public DistractingPackageHelper distractingPackageHelper;
}