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

Commit 50b5cb18 authored by Songchun Fan's avatar Songchun Fan
Browse files

[pm] send replaced broadcasts for reinstall after DELETE_KEEP_DATA

Such reinstallation should be considered as an app update with
"replace", not a "new install". This makes sure that other services
won't clean the data related to the existing package.

BUG: 288142708
BUG: 300314921

Test: atest
android.content.pm.cts.PackageManagerTest#testReinstallBroadcastsAfterDeleteKeepData
Test: will add more tests

Change-Id: I14341dc64640a0b2f4d434cef6936518f0be5f65
parent b4dabb09
Loading
Loading
Loading
Loading
+51 −85
Original line number Diff line number Diff line
@@ -56,7 +56,6 @@ import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING
import static com.android.server.pm.PackageManagerService.DEBUG_REMOVE;
import static com.android.server.pm.PackageManagerService.DEBUG_UPGRADE;
import static com.android.server.pm.PackageManagerService.DEBUG_VERIFY;
import static com.android.server.pm.PackageManagerService.EMPTY_INT_ARRAY;
import static com.android.server.pm.PackageManagerService.MIN_INSTALLABLE_TARGET_SDK;
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
import static com.android.server.pm.PackageManagerService.POST_INSTALL;
@@ -180,7 +179,6 @@ import com.android.server.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.permission.Permission;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageState;
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.SharedLibraryWrapper;
import com.android.server.pm.pkg.component.ComponentMutateUtils;
@@ -1245,6 +1243,7 @@ final class InstallPackageHelper {
        boolean systemApp = false;
        boolean replace = false;
        synchronized (mPm.mLock) {
            final PackageSetting ps = mPm.mSettings.getPackageLPr(pkgName);
            // Check if installing already existing package
            if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
                String oldName = mPm.mSettings.getRenamedPackageLPr(pkgName);
@@ -1261,16 +1260,15 @@ final class InstallPackageHelper {
                        Slog.d(TAG, "Replacing existing renamed package: oldName="
                                + oldName + " pkgName=" + pkgName);
                    }
                } else if (mPm.mPackages.containsKey(pkgName)) {
                } else if (ps != null) {
                    // This package, under its official name, already exists
                    // on the device; we should replace it.
                    replace = true;
                    if (DEBUG_INSTALL) Slog.d(TAG, "Replace existing package: " + pkgName);
                }

                if (replace) {
                final AndroidPackage oldPackage = mPm.mPackages.get(pkgName);
                if (replace && oldPackage != null) {
                    // Prevent apps opting out from runtime permissions
                    AndroidPackage oldPackage = mPm.mPackages.get(pkgName);
                    final int oldTargetSdk = oldPackage.getTargetSdkVersion();
                    final int newTargetSdk = parsedPackage.getTargetSdkVersion();
                    if (oldTargetSdk > Build.VERSION_CODES.LOLLIPOP_MR1
@@ -1292,7 +1290,6 @@ final class InstallPackageHelper {
                }
            }

            PackageSetting ps = mPm.mSettings.getPackageLPr(pkgName);
            PackageSetting signatureCheckPs = ps;

            // SDK libs can have other major versions with different package names.
@@ -1368,8 +1365,8 @@ final class InstallPackageHelper {
                if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps);

                systemApp = ps.isSystem();
                request.setOriginUsers(
                        ps.queryInstalledUsers(mPm.mUserManager.getUserIds(), true));
                request.setOriginUsers(ps.queryUsersInstalledOrHasData(
                        mPm.mUserManager.getUserIds()));
            }

            final int numGroups = ArrayUtils.size(parsedPackage.getPermissionGroups());
@@ -1595,7 +1592,7 @@ final class InstallPackageHelper {

        boolean shouldCloseFreezerBeforeReturn = true;
        try {
            final PackageState oldPackageState;
            final PackageSetting oldPackageState;
            final AndroidPackage oldPackage;
            String renamedPackage;
            boolean sysPkg = false;
@@ -1648,7 +1645,7 @@ final class InstallPackageHelper {
                        }
                    } else {
                        SigningDetails parsedPkgSigningDetails = parsedPackage.getSigningDetails();
                        SigningDetails oldPkgSigningDetails = oldPackage.getSigningDetails();
                        SigningDetails oldPkgSigningDetails = oldPackageState.getSigningDetails();
                        // default to original signature matching
                        if (!parsedPkgSigningDetails.checkCapability(oldPkgSigningDetails,
                                SigningDetails.CertCapabilities.INSTALLED_DATA)
@@ -1668,7 +1665,8 @@ final class InstallPackageHelper {
                    }

                    // don't allow a system upgrade unless the upgrade hash matches
                    if (oldPackage.getRestrictUpdateHash() != null && oldPackageState.isSystem()) {
                    if (oldPackage != null && oldPackage.getRestrictUpdateHash() != null
                            && oldPackageState.isSystem()) {
                        final byte[] digestBytes;
                        try {
                            final MessageDigest digest = MessageDigest.getInstance("SHA-512");
@@ -1691,6 +1689,7 @@ final class InstallPackageHelper {
                        parsedPackage.setRestrictUpdateHash(oldPackage.getRestrictUpdateHash());
                    }

                    if (oldPackage != null) {
                        // APK should not change its sharedUserId declarations
                        final var oldSharedUid = oldPackage.getSharedUserId() != null
                                ? oldPackage.getSharedUserId() : "<nothing>";
@@ -1704,11 +1703,13 @@ final class InstallPackageHelper {
                        }

                        // APK should not re-join shared UID
                    if (oldPackage.isLeavingSharedUser() && !parsedPackage.isLeavingSharedUser()) {
                        if (oldPackage.isLeavingSharedUser()
                                && !parsedPackage.isLeavingSharedUser()) {
                            throw new PrepareFailure(INSTALL_FAILED_UID_CHANGED,
                                    "Package " + parsedPackage.getPackageName()
                                            + " attempting to rejoin " + newSharedUid);
                        }
                    }

                    // In case of rollback, remember per-user/profile install state
                    allUsers = mPm.mUserManager.getUserIds();
@@ -1740,8 +1741,8 @@ final class InstallPackageHelper {

                // Update what is removed
                PackageRemovedInfo removedInfo = new PackageRemovedInfo(mPm);
                removedInfo.mUid = oldPackage.getUid();
                removedInfo.mRemovedPackage = oldPackage.getPackageName();
                removedInfo.mUid = ps.getAppId();
                removedInfo.mRemovedPackage = ps.getPackageName();
                removedInfo.mInstallerPackageName =
                        ps.getInstallSource().mInstallerPackageName;
                removedInfo.mIsStaticSharedLib =
@@ -1760,8 +1761,8 @@ final class InstallPackageHelper {
                    removedInfo.mUninstallReasons.put(userId,
                            ps.getUninstallReason(userId));
                }
                removedInfo.mIsExternal = oldPackage.isExternalStorage();
                removedInfo.mRemovedPackageVersionCode = oldPackage.getLongVersionCode();
                removedInfo.mIsExternal = oldPackageState.isExternalStorage();
                removedInfo.mRemovedPackageVersionCode = oldPackageState.getVersionCode();
                request.setRemovedInfo(removedInfo);

                sysPkg = oldPackageState.isSystem();
@@ -1801,7 +1802,7 @@ final class InstallPackageHelper {
            } else { // new package install
                ps = null;
                disabledPs = null;
                oldPackage = null;
                oldPackageState = null;
                // Remember this for later, in case we need to rollback this install
                String pkgName1 = parsedPackage.getPackageName();

@@ -1832,8 +1833,8 @@ final class InstallPackageHelper {
            shouldCloseFreezerBeforeReturn = false;

            request.setPrepareResult(replace, targetScanFlags, targetParseFlags,
                    oldPackage, parsedPackage, replace /* clearCodeCache */, sysPkg,
                    ps, disabledPs);
                    oldPackageState, parsedPackage,
                    replace /* clearCodeCache */, sysPkg, ps, disabledPs);
        } finally {
            request.setFreezer(freezer);
            if (shouldCloseFreezerBeforeReturn) {
@@ -2077,7 +2078,7 @@ final class InstallPackageHelper {

                // Set the update and install times
                PackageStateInternal deletedPkgSetting = mPm.snapshotComputer()
                        .getPackageStateInternal(oldPackage.getPackageName());
                        .getPackageStateInternal(packageName);
                // TODO(b/225756739): For rebootless APEX, consider using lastUpdateMillis provided
                //  by apexd to be more accurate.
                installRequest.setScannedPackageSettingFirstInstallTimeFromReplaced(
@@ -2126,8 +2127,10 @@ final class InstallPackageHelper {
                        if (oldCodePaths == null) {
                            oldCodePaths = new ArraySet<>();
                        }
                        if (oldPackage != null) {
                            Collections.addAll(oldCodePaths, oldPackage.getBaseApkPath());
                            Collections.addAll(oldCodePaths, oldPackage.getSplitCodePaths());
                        }
                        ps1.setOldCodePaths(oldCodePaths);
                    } else {
                        ps1.setOldCodePaths(null);
@@ -2852,46 +2855,11 @@ final class InstallPackageHelper {
            mPm.notifyInstantAppPackageInstalled(request.getPkg().getPackageName(),
                    request.getNewUsers());

            // Determine the set of users who are adding this package for
            // the first time vs. those who are seeing an update.
            int[] firstUserIds = EMPTY_INT_ARRAY;
            int[] firstInstantUserIds = EMPTY_INT_ARRAY;
            int[] updateUserIds = EMPTY_INT_ARRAY;
            int[] instantUserIds = EMPTY_INT_ARRAY;
            final boolean allNewUsers = request.getOriginUsers() == null
                    || request.getOriginUsers().length == 0;
            for (int newUser : request.getNewUsers()) {
                final boolean isInstantApp = pkgSetting.getUserStateOrDefault(newUser)
                        .isInstantApp();
                if (allNewUsers) {
                    if (isInstantApp) {
                        firstInstantUserIds = ArrayUtils.appendInt(firstInstantUserIds, newUser);
                    } else {
                        firstUserIds = ArrayUtils.appendInt(firstUserIds, newUser);
                    }
                    continue;
                }
                boolean isNew = true;
                for (int origUser : request.getOriginUsers()) {
                    if (origUser == newUser) {
                        isNew = false;
                        break;
                    }
                }
                if (isNew) {
                    if (isInstantApp) {
                        firstInstantUserIds = ArrayUtils.appendInt(firstInstantUserIds, newUser);
                    } else {
                        firstUserIds = ArrayUtils.appendInt(firstUserIds, newUser);
                    }
                } else {
                    if (isInstantApp) {
                        instantUserIds = ArrayUtils.appendInt(instantUserIds, newUser);
                    } else {
                        updateUserIds = ArrayUtils.appendInt(updateUserIds, newUser);
                    }
                }
            }
            request.populateBroadcastUsers();
            final int[] firstUserIds = request.getFirstTimeBroadcastUserIds();
            final int[] firstInstantUserIds = request.getFirstTimeBroadcastInstantUserIds();
            final int[] updateUserIds = request.getUpdateBroadcastUserIds();
            final int[] instantUserIds = request.getUpdateBroadcastInstantUserIds();

            Bundle extras = new Bundle();
            extras.putInt(Intent.EXTRA_UID, request.getAppId());
@@ -2969,12 +2937,10 @@ final class InstallPackageHelper {
                }
                // If package installer is defined, notify package installer about new
                // app installed
                if (mPm.mRequiredInstallerPackage != null) {
                mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
                        extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND /*flags*/,
                        mPm.mRequiredInstallerPackage, null /*finishedReceiver*/,
                        firstUserIds, instantUserIds, null /* broadcastAllowList */, null);
                }

                // Send replaced for users that don't see the package for the first time
                if (update) {
@@ -3070,7 +3036,7 @@ final class InstallPackageHelper {
                }
            }

            if (allNewUsers && !update) {
            if (request.isAllNewUsers() && !update) {
                mPm.notifyPackageAdded(packageName, request.getAppId());
            } else {
                mPm.notifyPackageChanged(packageName, request.getAppId());
+89 −13
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static android.content.pm.PackageManager.INSTALL_REASON_UNKNOWN;
import static android.content.pm.PackageManager.INSTALL_SCENARIO_DEFAULT;
import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
import static android.os.Process.INVALID_UID;
import static com.android.server.pm.PackageManagerService.EMPTY_INT_ARRAY;
import static com.android.server.pm.PackageManagerService.SCAN_AS_INSTANT_APP;
import static com.android.server.pm.PackageManagerService.TAG;

@@ -43,6 +44,7 @@ import android.util.ArrayMap;
import android.util.ExceptionUtils;
import android.util.Slog;

import com.android.internal.util.ArrayUtils;
import com.android.server.art.model.DexoptResult;
import com.android.server.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.pkg.AndroidPackage;
@@ -52,6 +54,7 @@ import com.android.server.pm.pkg.parsing.ParsingPackageUtils;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

final class InstallRequest {
@@ -69,8 +72,8 @@ final class InstallRequest {
    private int mParseFlags;
    private boolean mReplace;

    @Nullable /* The original Package if it is being replaced, otherwise {@code null} */
    private AndroidPackage mExistingPackage;
    @Nullable /* The original package's name if it is being replaced, otherwise {@code null} */
    private String mExistingPackageName;
    /** parsed package to be scanned */
    @Nullable
    private ParsedPackage mParsedPackage;
@@ -132,6 +135,15 @@ final class InstallRequest {

    private int mDexoptStatus;

    @NonNull
    private int[] mFirstTimeBroadcastUserIds = EMPTY_INT_ARRAY;
    @NonNull
    private int[] mFirstTimeBroadcastInstantUserIds = EMPTY_INT_ARRAY;
    @NonNull
    private int[] mUpdateBroadcastUserIds = EMPTY_INT_ARRAY;
    @NonNull
    private int[] mUpdateBroadcastInstantUserIds = EMPTY_INT_ARRAY;

    // New install
    InstallRequest(InstallingSession params) {
        mUserId = params.getUser().getIdentifier();
@@ -412,11 +424,6 @@ final class InstallRequest {
        return mLibraryConsumers;
    }

    @Nullable
    public AndroidPackage getExistingPackage() {
        return mExistingPackage;
    }

    @Nullable
    public List<String> getAllowlistedRestrictedPermissions() {
        return mInstallArgs == null ? null : mInstallArgs.mAllowlistedRestrictedPermissions;
@@ -453,10 +460,7 @@ final class InstallRequest {

    @Nullable
    public String getExistingPackageName() {
        if (mExistingPackage != null) {
            return mExistingPackage.getPackageName();
        }
        return null;
        return mExistingPackageName;
    }

    @Nullable
@@ -627,6 +631,25 @@ final class InstallRequest {
        return mDexoptStatus;
    }

    public boolean isAllNewUsers() {
        return mOrigUsers == null || mOrigUsers.length == 0;
    }
    public int[] getFirstTimeBroadcastUserIds() {
        return mFirstTimeBroadcastUserIds;
    }

    public int[] getFirstTimeBroadcastInstantUserIds() {
        return mFirstTimeBroadcastInstantUserIds;
    }

    public int[] getUpdateBroadcastUserIds() {
        return mUpdateBroadcastUserIds;
    }

    public int[] getUpdateBroadcastInstantUserIds() {
        return mUpdateBroadcastInstantUserIds;
    }

    public void setScanFlags(int scanFlags) {
        mScanFlags = scanFlags;
    }
@@ -729,13 +752,14 @@ final class InstallRequest {
    }

    public void setPrepareResult(boolean replace, int scanFlags,
            int parseFlags, AndroidPackage existingPackage,
            int parseFlags, PackageState existingPackageState,
            ParsedPackage packageToScan, boolean clearCodeCache, boolean system,
            PackageSetting originalPs, PackageSetting disabledPs) {
        mReplace = replace;
        mScanFlags = scanFlags;
        mParseFlags = parseFlags;
        mExistingPackage = existingPackage;
        mExistingPackageName =
                existingPackageState != null ? existingPackageState.getPackageName() : null;
        mParsedPackage = packageToScan;
        mClearCodeCache = clearCodeCache;
        mSystem = system;
@@ -769,6 +793,58 @@ final class InstallRequest {
        }
    }

    /**
     *  Determine the set of users who are adding this package for the first time vs. those who are
     *  seeing an update.
     */
    public void populateBroadcastUsers() {
        assertScanResultExists();
        mFirstTimeBroadcastUserIds = EMPTY_INT_ARRAY;
        mFirstTimeBroadcastInstantUserIds = EMPTY_INT_ARRAY;
        mUpdateBroadcastUserIds = EMPTY_INT_ARRAY;
        mUpdateBroadcastInstantUserIds = EMPTY_INT_ARRAY;

        final boolean allNewUsers = isAllNewUsers();
        if (allNewUsers) {
            // App was not currently installed on any user
            for (int newUser : mNewUsers) {
                final boolean isInstantApp =
                        mScanResult.mPkgSetting.getUserStateOrDefault(newUser).isInstantApp();
                if (isInstantApp) {
                    mFirstTimeBroadcastInstantUserIds =
                            ArrayUtils.appendInt(mFirstTimeBroadcastInstantUserIds, newUser);
                } else {
                    mFirstTimeBroadcastUserIds =
                            ArrayUtils.appendInt(mFirstTimeBroadcastUserIds, newUser);
                }
            }
            return;
        }
        // App was already installed on some users, but is new to some other users
        for (int newUser : mNewUsers) {
            boolean isFirstTimeUser = !ArrayUtils.contains(mOrigUsers, newUser);
            final boolean isInstantApp =
                    mScanResult.mPkgSetting.getUserStateOrDefault(newUser).isInstantApp();
            if (isFirstTimeUser) {
                if (isInstantApp) {
                    mFirstTimeBroadcastInstantUserIds =
                            ArrayUtils.appendInt(mFirstTimeBroadcastInstantUserIds, newUser);
                } else {
                    mFirstTimeBroadcastUserIds =
                            ArrayUtils.appendInt(mFirstTimeBroadcastUserIds, newUser);
                }
            } else {
                if (isInstantApp) {
                    mUpdateBroadcastInstantUserIds =
                            ArrayUtils.appendInt(mUpdateBroadcastInstantUserIds, newUser);
                } else {
                    mUpdateBroadcastUserIds =
                            ArrayUtils.appendInt(mUpdateBroadcastUserIds, newUser);
                }
            }
        }
    }

    public void onPrepareStarted() {
        if (mPackageMetrics != null) {
            mPackageMetrics.onStepStarted(PackageMetrics.STEP_PREPARE);
+18 −0
Original line number Diff line number Diff line
@@ -844,6 +844,24 @@ public class PackageSetting extends SettingBase implements PackageStateInternal
        return res;
    }

    int[] queryUsersInstalledOrHasData(int[] users) {
        int num = 0;
        for (int user : users) {
            if (getInstalled(user) || readUserState(user).dataExists()) {
                num++;
            }
        }
        int[] res = new int[num];
        num = 0;
        for (int user : users) {
            if (getInstalled(user) || readUserState(user).dataExists()) {
                res[num] = user;
                num++;
            }
        }
        return res;
    }

    long getCeDataInode(int userId) {
        return readUserState(userId).getCeDataInode();
    }