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

Commit eb403e7d authored by Winson's avatar Winson
Browse files

Isolate IPackageManager implementation

To avoid leaking IPackageManager methods directly into
PackageManagerService, moves the IPM implementation into an inner
class similar to PackageManagerInternal.

This will help enforce snapshot consistency by ensuring that all
non-IPM PMS methods can always take in a Computer instance to re-use.

Bug: 217961172

Test: presubmit

Change-Id: Ibf7bd3d1d90a40786279763ba8d62eb9348bb760
parent 4b2ee74e
Loading
Loading
Loading
Loading
+0 −11
Original line number Diff line number Diff line
@@ -497,20 +497,9 @@ interface IPackageManager {
    void enterSafeMode();
    @UnsupportedAppUsage
    boolean isSafeMode();
    void systemReady();
    @UnsupportedAppUsage
    boolean hasSystemUidErrors();

    /**
     * Ask the package manager to fstrim the disk if needed.
     */
    void performFstrimIfNeeded();

    /**
     * Ask the package manager to update packages if needed.
     */
    void updatePackagesIfNeeded();

    /**
     * Notify the package manager that a package is going to be used and why.
     *
+11 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ import android.util.SparseArray;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.pm.PackageList;
import com.android.server.pm.PackageSetting;
import com.android.server.pm.dex.DynamicCodeLogger;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.pkg.AndroidPackageApi;
import com.android.server.pm.pkg.PackageState;
@@ -68,6 +69,7 @@ import java.util.function.Consumer;
 * @hide Only for use within the system server.
 */
public abstract class PackageManagerInternal {

    @IntDef(prefix = "PACKAGE_", value = {
            PACKAGE_SYSTEM,
            PACKAGE_SETUP_WIZARD,
@@ -902,6 +904,11 @@ public abstract class PackageManagerInternal {
    public abstract void freeStorage(String volumeUuid, long bytes,
            @StorageManager.AllocateFlags int flags) throws IOException;

    /**
     * Blocking call to clear all cached app data above quota.
     */
    public abstract void freeAllAppCacheAboveQuota(@NonNull String volumeUuid) throws IOException;

    /** Returns {@code true} if the specified component is enabled and matches the given flags. */
    public abstract boolean isEnabledAndMatches(@NonNull ParsedMainComponent component,
            @PackageManager.ComponentInfoFlagsBits long flags, int userId);
@@ -1362,4 +1369,8 @@ public abstract class PackageManagerInternal {
     */
    @NonNull
    public abstract PackageDataSnapshot snapshot();

    public abstract void shutdown();

    public abstract DynamicCodeLogger getDynamicCodeLogger();
}
+1 −1
Original line number Diff line number Diff line
@@ -557,7 +557,7 @@ public final class BackgroundDexOptService {

    /** Gets the size of a package. */
    private long getPackageSize(PackageManagerService pm, String pkg) {
        PackageInfo info = pm.getPackageInfo(pkg, 0, UserHandle.USER_SYSTEM);
        PackageInfo info = pm.snapshotComputer().getPackageInfo(pkg, 0, UserHandle.USER_SYSTEM);
        long size = 0;
        if (info != null && info.applicationInfo != null) {
            File path = Paths.get(info.applicationInfo.sourceDir).toFile();
+15 −0
Original line number Diff line number Diff line
@@ -284,6 +284,21 @@ public interface Computer extends PackageDataSnapshot {
    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
    long updateFlagsForResolve(long flags, int userId, int callingUid, boolean wantInstantApps,
            boolean onlyExposedExplicitly, boolean isImplicitImageCaptureIntentAndNotSetByDpc);

    /**
     * Checks if the request is from the system or an app that has the appropriate cross-user
     * permissions defined as follows:
     * <ul>
     * <li>INTERACT_ACROSS_USERS_FULL if {@code requireFullPermission} is true.</li>
     * <li>INTERACT_ACROSS_USERS if the given {@code userId} is in a different profile group
     * to the caller.</li>
     * <li>Otherwise, INTERACT_ACROSS_PROFILES if the given {@code userId} is in the same profile
     * group as the caller.</li>
     * </ul>
     *
     * @param checkShell whether to prevent shell from access if there's a debugging restriction
     * @param message the message to log on security exception
     */
    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
    void enforceCrossUserOrProfilePermission(int callingUid, @UserIdInt int userId,
            boolean requireFullPermission, boolean checkShell, String message);
+20 −15
Original line number Diff line number Diff line
@@ -685,7 +685,8 @@ final class DeletePackageHelper {
            return;
        }

        if (!deleteAllUsers && mPm.getBlockUninstallForUser(internalPackageName, userId)) {
        if (!deleteAllUsers && mPm.mIPackageManager
                .getBlockUninstallForUser(internalPackageName, userId)) {
            mPm.mHandler.post(() -> {
                try {
                    observer.onPackageDeleted(packageName,
@@ -705,11 +706,14 @@ final class DeletePackageHelper {
        // Queue up an async operation since the package deletion may take a little while.
        mPm.mHandler.post(() -> {
            int returnCode;
            final PackageSetting ps = mPm.mSettings.getPackageLPr(internalPackageName);
            final Computer innerSnapshot = mPm.snapshotComputer();
            final PackageStateInternal packageState =
                    innerSnapshot.getPackageStateInternal(internalPackageName);
            boolean doDeletePackage = true;
            if (ps != null) {
            if (packageState != null) {
                final boolean targetIsInstantApp =
                        ps.getInstantApp(UserHandle.getUserId(callingUid));
                        packageState.getUserStateOrDefault(UserHandle.getUserId(callingUid))
                                .isInstantApp();
                doDeletePackage = !targetIsInstantApp
                        || canViewInstantApps;
            }
@@ -718,7 +722,7 @@ final class DeletePackageHelper {
                    returnCode = deletePackageX(internalPackageName, versionCode,
                            userId, deleteFlags, false /*removedBySystem*/);
                } else {
                    int[] blockUninstallUserIds = getBlockUninstallForUsers(
                    int[] blockUninstallUserIds = getBlockUninstallForUsers(innerSnapshot,
                            internalPackageName, users);
                    // If nobody is blocking uninstall, proceed with delete for all users
                    if (ArrayUtils.isEmpty(blockUninstallUserIds)) {
@@ -769,39 +773,40 @@ final class DeletePackageHelper {
        }
        final int callingUserId = UserHandle.getUserId(callingUid);
        // If the caller installed the pkgName, then allow it to silently uninstall.
        if (callingUid == mPm.getPackageUid(
                mPm.getInstallerPackageName(pkgName), 0, callingUserId)) {
        if (callingUid == mPm.mIPackageManager.getPackageUid(
                mPm.mIPackageManager.getInstallerPackageName(pkgName), 0, callingUserId)) {
            return true;
        }

        // Allow package verifier to silently uninstall.
        if (mPm.mRequiredVerifierPackage != null && callingUid == mPm.getPackageUid(
                mPm.mRequiredVerifierPackage, 0, callingUserId)) {
        if (mPm.mRequiredVerifierPackage != null && callingUid == mPm.mIPackageManager
                .getPackageUid(mPm.mRequiredVerifierPackage, 0, callingUserId)) {
            return true;
        }

        // Allow package uninstaller to silently uninstall.
        if (mPm.mRequiredUninstallerPackage != null && callingUid == mPm.getPackageUid(
                mPm.mRequiredUninstallerPackage, 0, callingUserId)) {
        if (mPm.mRequiredUninstallerPackage != null && callingUid == mPm.mIPackageManager
                .getPackageUid(mPm.mRequiredUninstallerPackage, 0, callingUserId)) {
            return true;
        }

        // Allow storage manager to silently uninstall.
        if (mPm.mStorageManagerPackage != null && callingUid == mPm.getPackageUid(
        if (mPm.mStorageManagerPackage != null && callingUid == mPm.mIPackageManager.getPackageUid(
                mPm.mStorageManagerPackage, 0, callingUserId)) {
            return true;
        }

        // Allow caller having MANAGE_PROFILE_AND_DEVICE_OWNERS permission to silently
        // uninstall for device owner provisioning.
        return mPm.checkUidPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS, callingUid)
        return mPm.mIPackageManager.checkUidPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS, callingUid)
                == PERMISSION_GRANTED;
    }

    private int[] getBlockUninstallForUsers(String packageName, int[] userIds) {
    private int[] getBlockUninstallForUsers(@NonNull Computer snapshot, String packageName,
            int[] userIds) {
        int[] result = EMPTY_INT_ARRAY;
        for (int userId : userIds) {
            if (mPm.getBlockUninstallForUser(packageName, userId)) {
            if (snapshot.getBlockUninstallForUser(packageName, userId)) {
                result = ArrayUtils.appendInt(result, userId);
            }
        }
Loading