Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8800a495 authored by Pavel Grafov's avatar Pavel Grafov Committed by Android (Google) Code Review
Browse files

Merge "Allow cross user package suspension" into main

parents cfd29aa8 2cee6416
Loading
Loading
Loading
Loading
+15 −4
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.internal.app;

import static android.app.admin.flags.Flags.crossUserSuspensionEnabled;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
import static android.content.pm.SuspendDialogInfo.BUTTON_ACTION_MORE_DETAILS;
@@ -59,6 +60,7 @@ public class SuspendedAppActivity extends AlertActivity
    public static final String EXTRA_SUSPENDED_PACKAGE = PACKAGE_NAME + ".extra.SUSPENDED_PACKAGE";
    public static final String EXTRA_SUSPENDING_PACKAGE =
            PACKAGE_NAME + ".extra.SUSPENDING_PACKAGE";
    public static final String EXTRA_SUSPENDING_USER = PACKAGE_NAME + ".extra.SUSPENDING_USER";
    public static final String EXTRA_DIALOG_INFO = PACKAGE_NAME + ".extra.DIALOG_INFO";
    public static final String EXTRA_ACTIVITY_OPTIONS = PACKAGE_NAME + ".extra.ACTIVITY_OPTIONS";
    public static final String EXTRA_UNSUSPEND_INTENT = PACKAGE_NAME + ".extra.UNSUSPEND_INTENT";
@@ -67,6 +69,7 @@ public class SuspendedAppActivity extends AlertActivity
    private IntentSender mOnUnsuspend;
    private String mSuspendedPackage;
    private String mSuspendingPackage;
    private int mSuspendingUserId;
    private int mNeutralButtonAction;
    private int mUserId;
    private PackageManager mPm;
@@ -117,7 +120,7 @@ public class SuspendedAppActivity extends AlertActivity
                .setPackage(mSuspendingPackage);
        final String requiredPermission = Manifest.permission.SEND_SHOW_SUSPENDED_APP_DETAILS;
        final ResolveInfo resolvedInfo = mPm.resolveActivityAsUser(moreDetailsIntent,
                MATCH_DIRECT_BOOT_UNAWARE | MATCH_DIRECT_BOOT_AWARE, mUserId);
                MATCH_DIRECT_BOOT_UNAWARE | MATCH_DIRECT_BOOT_AWARE, mSuspendingUserId);
        if (resolvedInfo != null && resolvedInfo.activityInfo != null
                && requiredPermission.equals(resolvedInfo.activityInfo.permission)) {
            moreDetailsIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, mSuspendedPackage)
@@ -231,12 +234,17 @@ public class SuspendedAppActivity extends AlertActivity
        }
        mSuspendedPackage = intent.getStringExtra(EXTRA_SUSPENDED_PACKAGE);
        mSuspendingPackage = intent.getStringExtra(EXTRA_SUSPENDING_PACKAGE);
        if (crossUserSuspensionEnabled()) {
            mSuspendingUserId = intent.getIntExtra(EXTRA_SUSPENDING_USER, mUserId);
        } else {
            mSuspendingUserId = mUserId;
        }
        mSuppliedDialogInfo = intent.getParcelableExtra(EXTRA_DIALOG_INFO, android.content.pm.SuspendDialogInfo.class);
        mOnUnsuspend = intent.getParcelableExtra(EXTRA_UNSUSPEND_INTENT, android.content.IntentSender.class);
        if (mSuppliedDialogInfo != null) {
            try {
                mSuspendingAppResources = createContextAsUser(
                        UserHandle.of(mUserId), /* flags */ 0).getPackageManager()
                        UserHandle.of(mSuspendingUserId), /* flags */ 0).getPackageManager()
                        .getResourcesForApplication(mSuspendingPackage);
            } catch (PackageManager.NameNotFoundException ne) {
                Slog.e(TAG, "Could not find resources for " + mSuspendingPackage, ne);
@@ -299,7 +307,7 @@ public class SuspendedAppActivity extends AlertActivity
                    case BUTTON_ACTION_MORE_DETAILS:
                        if (mMoreDetailsIntent != null) {
                            startActivityAsUser(mMoreDetailsIntent, mOptions,
                                    UserHandle.of(mUserId));
                                    UserHandle.of(mSuspendingUserId));
                        } else {
                            Slog.wtf(TAG, "Neutral button should not have existed!");
                        }
@@ -324,7 +332,7 @@ public class SuspendedAppActivity extends AlertActivity
                                .putExtra(Intent.EXTRA_PACKAGE_NAME, mSuspendedPackage)
                                .setPackage(mSuspendingPackage)
                                .addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
                        sendBroadcastAsUser(reportUnsuspend, UserHandle.of(mUserId));
                        sendBroadcastAsUser(reportUnsuspend, UserHandle.of(mSuspendingUserId));

                        if (mOnUnsuspend != null) {
                            Bundle activityOptions =
@@ -365,6 +373,9 @@ public class SuspendedAppActivity extends AlertActivity
                .putExtra(Intent.EXTRA_USER_ID, userId)
                .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                        | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
        if (crossUserSuspensionEnabled()) {
            intent.putExtra(EXTRA_SUSPENDING_USER, suspendingPackage.userId);
        }
        return intent;
    }
}
+1 −0
Original line number Diff line number Diff line
@@ -142,6 +142,7 @@ message PackageProto {
        // UTC timestamp of first install for the user
        optional int32 first_install_time_ms = 11;
        optional ArchiveState archive_state = 12;
        repeated int32 suspending_user = 13;
    }

    message InstallSourceProto {
+2 −1
Original line number Diff line number Diff line
@@ -542,7 +542,8 @@ final class DeletePackageHelper {
        final Computer snapshot = mPm.snapshotComputer();
        for (final int affectedUserId : outInfo.mRemovedUsers) {
            if (hadSuspendAppsPermission.get(affectedUserId)) {
                mPm.unsuspendForSuspendingPackage(snapshot, packageName, affectedUserId);
                mPm.unsuspendForSuspendingPackage(snapshot, packageName,
                        affectedUserId /*suspendingUserId*/, true /*inAllUsers*/);
                mPm.removeAllDistractingPackageRestrictions(snapshot, affectedUserId);
            }
        }
+8 −3
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.pm;

import static android.app.admin.flags.Flags.crossUserSuspensionEnabled;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
import static android.content.pm.PackageManager.RESTRICTION_NONE;

@@ -45,6 +46,7 @@ import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Process;
import android.os.UserHandle;
import android.os.storage.StorageManager;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -687,14 +689,17 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal {
    @Override
    @Deprecated
    public final void unsuspendAdminSuspendedPackages(int affectedUser) {
        final int suspendingUserId = affectedUser;
        mService.unsuspendForSuspendingPackage(snapshot(), PLATFORM_PACKAGE_NAME, suspendingUserId);
        final int suspendingUserId =
                crossUserSuspensionEnabled() ? UserHandle.USER_SYSTEM : affectedUser;
        mService.unsuspendForSuspendingPackage(
                snapshot(), PLATFORM_PACKAGE_NAME, suspendingUserId, /* inAllUsers= */ false);
    }

    @Override
    @Deprecated
    public final boolean isAdminSuspendingAnyPackages(int userId) {
        final int suspendingUserId = userId;
        final int suspendingUserId =
                crossUserSuspensionEnabled() ? UserHandle.USER_SYSTEM : userId;
        return snapshot().isSuspendingAnyPackages(PLATFORM_PACKAGE_NAME, suspendingUserId, userId);
    }

+61 −15
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server.pm;
import static android.Manifest.permission.MANAGE_DEVICE_ADMINS;
import static android.Manifest.permission.SET_HARMFUL_APP_WARNINGS;
import static android.app.AppOpsManager.MODE_IGNORED;
import static android.app.admin.flags.Flags.crossUserSuspensionEnabled;
import static android.content.pm.PackageManager.APP_METADATA_SOURCE_APK;
import static android.content.pm.PackageManager.APP_METADATA_SOURCE_UNKNOWN;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
@@ -3181,27 +3182,53 @@ public class PackageManagerService implements PackageSender, TestUtilityService
                    callingMethod);
        }

        final int packageUid = snapshot.getPackageUid(suspender.packageName, 0, targetUserId);
        if (crossUserSuspensionEnabled()) {
            final int suspendingPackageUid =
                    snapshot.getPackageUid(suspender.packageName, 0, suspender.userId);
            if (suspendingPackageUid != callingUid) {
                throw new SecurityException("Suspender package %s doesn't match calling uid %d"
                                .formatted(suspender.packageName, callingUid));
            }
            if (targetUserId != suspender.userId) {
                mContext.enforceCallingOrSelfPermission(
                        Manifest.permission.INTERACT_ACROSS_USERS_FULL, callingMethod);
            }
        } else {
            // Here only SHELL can suspend across users
            final int packageUid =
                    snapshot.getPackageUid(suspender.packageName, 0, targetUserId);
            final boolean allowedPackageUid = packageUid == callingUid;
        // TODO(b/139383163): remove special casing for shell and enforce INTERACT_ACROSS_USERS_FULL
            final boolean allowedShell = callingUid == SHELL_UID
                    && UserHandle.isSameApp(packageUid, callingUid);

            if (!allowedShell && !allowedPackageUid) {
                throw new SecurityException("Suspending package " + suspender.packageName
                    + " in user " + targetUserId + " does not belong to calling uid " + callingUid);
                        + " in user " + targetUserId + " does not belong to calling uid "
                        + callingUid);
            }
        }
    }

    /**
     * @param inAllUsers Whether to unsuspend packages suspended by the given package in other
     *                   users. This flag is only used when cross-user suspension is enabled.
     */
    void unsuspendForSuspendingPackage(@NonNull Computer computer, String suspendingPackage,
            @UserIdInt int suspendingUserId) {
            @UserIdInt int suspendingUserId, boolean inAllUsers) {
        // TODO: This can be replaced by a special parameter to iterate all packages, rather than
        //  this weird pre-collect of all packages.
        final String[] allPackages = computer.getPackageStates().keySet().toArray(new String[0]);
        final Predicate<UserPackage> suspenderPredicate =
                UserPackage.of(suspendingUserId, suspendingPackage)::equals;
        if (!crossUserSuspensionEnabled() || !inAllUsers) {
            mSuspendPackageHelper.removeSuspensionsBySuspendingPackage(computer,
                    allPackages, suspenderPredicate, suspendingUserId);
        } else {
            for (int targetUserId: mUserManager.getUserIds()) {
                mSuspendPackageHelper.removeSuspensionsBySuspendingPackage(
                        computer, allPackages, suspenderPredicate, targetUserId);
            }
        }
    }

    void removeAllDistractingPackageRestrictions(@NonNull Computer snapshot, int userId) {
@@ -4053,7 +4080,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
                // This app should not generally be allowed to get disabled by the UI, but
                // if it ever does, we don't want to end up with some of the user's apps
                // permanently suspended.
                unsuspendForSuspendingPackage(computer, packageName, userId);
                unsuspendForSuspendingPackage(computer, packageName, userId, true /* inAllUsers */);
                removeAllDistractingPackageRestrictions(computer, userId);
            }
            success = true;
@@ -4339,6 +4366,19 @@ public class PackageManagerService implements PackageSender, TestUtilityService
        }
        mInstantAppRegistry.onUserRemoved(userId);
        mPackageMonitorCallbackHelper.onUserRemoved(userId);
        if (crossUserSuspensionEnabled()) {
            cleanUpCrossUserSuspension(userId);
        }
    }

    private void cleanUpCrossUserSuspension(int removedUser) {
        final Computer computer = snapshotComputer();
        var allPackages = computer.getAllAvailablePackageNames();
        for (int targetUserId : mUserManager.getUserIds()) {
            if (targetUserId == removedUser) continue;
            mSuspendPackageHelper.removeSuspensionsBySuspendingPackage(computer, allPackages,
                    userPackage -> userPackage.userId == removedUser, targetUserId);
        }
    }

    /**
@@ -4745,7 +4785,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService
                        if (checkPermission(Manifest.permission.SUSPEND_APPS, packageName, userId)
                                == PERMISSION_GRANTED) {
                            final Computer snapshot = snapshotComputer();
                            unsuspendForSuspendingPackage(snapshot, packageName, userId);
                            unsuspendForSuspendingPackage(
                                    snapshot, packageName, userId, true /* inAllUsers */);
                            removeAllDistractingPackageRestrictions(snapshot, userId);
                            synchronized (mLock) {
                                flushPackageRestrictionsAsUserInternalLocked(userId);
@@ -6239,7 +6280,9 @@ public class PackageManagerService implements PackageSender, TestUtilityService
            final boolean quarantined = ((flags & PackageManager.FLAG_SUSPEND_QUARANTINED) != 0)
                    && Flags.quarantinedEnabled();
            final Computer snapshot = snapshotComputer();
            final UserPackage suspender = UserPackage.of(targetUserId, suspendingPackage);
            final UserPackage suspender = crossUserSuspensionEnabled()
                    ? UserPackage.of(suspendingUserId, suspendingPackage)
                    : UserPackage.of(targetUserId, suspendingPackage);
            enforceCanSetPackagesSuspendedAsUser(snapshot, quarantined, suspender, callingUid,
                    targetUserId, "setPackagesSuspendedAsUser");
            return mSuspendPackageHelper.setPackagesSuspended(snapshot, packageNames, suspended,
@@ -6707,7 +6750,10 @@ public class PackageManagerService implements PackageSender, TestUtilityService
        @Override
        public String[] setPackagesSuspendedByAdmin(
                @UserIdInt int userId, @NonNull String[] packageNames, boolean suspended) {
            final int suspendingUserId = userId;
            // Suspension by admin isn't attributed to admin package but to the platform,
            // Using USER_SYSTEM for consistency with other internal suspenders, like shell or root.
            final int suspendingUserId =
                    crossUserSuspensionEnabled() ? UserHandle.USER_SYSTEM : userId;
            final UserPackage suspender = UserPackage.of(
                    suspendingUserId, PackageManagerService.PLATFORM_PACKAGE_NAME);
            return mSuspendPackageHelper.setPackagesSuspended(snapshotComputer(), packageNames,
Loading