diff options
5 files changed, 227 insertions, 113 deletions
diff --git a/services/core/java/com/android/server/pm/BroadcastHelper.java b/services/core/java/com/android/server/pm/BroadcastHelper.java index f1394d403bf7..bf1196d6b969 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 @@ public final class BroadcastHelper { 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 000000000000..7dc45b58a773 --- /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 2b733754685e..2fe7913342a2 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 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal { @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 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal { @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 6cf63d10f1f1..bf80a466e034 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.ArraySet; 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 @@ public class PackageManagerService implements PackageSender, TestUtilityService 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 @@ public class PackageManagerService implements PackageSender, TestUtilityService mResolveIntentHelper = testParams.resolveIntentHelper; mDexOptHelper = testParams.dexOptHelper; mSuspendPackageHelper = testParams.suspendPackageHelper; + mDistractingPackageHelper = testParams.distractingPackageHelper; mSharedLibraries.setDeletePackageHelper(mDeletePackageHelper); @@ -1842,6 +1843,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService 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 @@ public class PackageManagerService implements PackageSender, TestUtilityService 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 @@ public class PackageManagerService implements PackageSender, TestUtilityService @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 @@ public class PackageManagerService implements PackageSender, TestUtilityService @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 144231c95f75..16829e0e8f6c 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 final class PackageManagerServiceTestParams { public DexOptHelper dexOptHelper; public SuspendPackageHelper suspendPackageHelper; public StorageEventHelper storageEventHelper; + public DistractingPackageHelper distractingPackageHelper; } |