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
This commit is contained in:
Jackal Guo
2022-03-21 16:40:42 +08:00
parent 127afbda61
commit 0f3307a775
5 changed files with 227 additions and 113 deletions

View File

@@ -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,

View File

@@ -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 */));
}
}

View File

@@ -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

View File

@@ -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
@@ -6119,6 +6038,12 @@ public class PackageManagerService implements PackageSender, TestUtilityService
return mSuspendPackageHelper;
}
@NonNull
@Override
protected DistractingPackageHelper getDistractingPackageHelper() {
return mDistractingPackageHelper;
}
@NonNull
@Override
protected ProtectedPackages getProtectedPackages() {

View File

@@ -116,4 +116,5 @@ public final class PackageManagerServiceTestParams {
public DexOptHelper dexOptHelper;
public SuspendPackageHelper suspendPackageHelper;
public StorageEventHelper storageEventHelper;
public DistractingPackageHelper distractingPackageHelper;
}