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

Commit 9f7005c5 authored by Song Chun Fan's avatar Song Chun Fan Committed by Android (Google) Code Review
Browse files

Merge "[pm] consolidate InstallRequest and InstalledPackageInfo"

parents ce3586ec 828ca4d4
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -271,7 +271,8 @@ final class DeletePackageHelper {
        // other processes clean up before deleting resources.
        synchronized (mPm.mInstallLock) {
            if (info.mArgs != null) {
                mRemovePackageHelper.cleanUpResources(info.mArgs);
                mRemovePackageHelper.cleanUpResources(info.mArgs.mCodeFile,
                        info.mArgs.mInstructionSets);
            }

            boolean reEnableStub = false;
+3 −16
Original line number Diff line number Diff line
@@ -70,10 +70,9 @@ final class InstallArgs {
            UserHandle user, String[] instructionSets,
            String abiOverride, String[] installGrantPermissions,
            List<String> allowlistedRestrictedPermissions,
            int autoRevokePermissionsMode,
            String traceMethod, int traceCookie, SigningDetails signingDetails,
            int installReason, int installScenario, boolean forceQueryableOverride,
            int dataLoaderType, int packageSource) {
            int autoRevokePermissionsMode, String traceMethod, int traceCookie,
            SigningDetails signingDetails, int installReason, int installScenario,
            boolean forceQueryableOverride, int dataLoaderType, int packageSource) {
        mOriginInfo = originInfo;
        mMoveInfo = moveInfo;
        mInstallFlags = installFlags;
@@ -96,18 +95,6 @@ final class InstallArgs {
        mPackageSource = packageSource;
    }

    /** New install */
    InstallArgs(InstallingSession params) {
        this(params.mOriginInfo, params.mMoveInfo, params.mObserver, params.mInstallFlags,
                params.mInstallSource, params.mVolumeUuid,
                params.getUser(), null /*instructionSets*/, params.mPackageAbiOverride,
                params.mGrantedRuntimePermissions, params.mAllowlistedRestrictedPermissions,
                params.mAutoRevokePermissionsMode,
                params.mTraceMethod, params.mTraceCookie, params.mSigningDetails,
                params.mInstallReason, params.mInstallScenario, params.mForceQueryableOverride,
                params.mDataLoaderType, params.mPackageSource);
    }

    /**
     * Create args that describe an existing installed package. Typically used
     * when cleaning up old installs, or used as a move source.
+255 −251

File changed.

Preview size limit exceeded, changes collapsed.

+382 −5
Original line number Diff line number Diff line
@@ -16,12 +16,389 @@

package com.android.server.pm;

import static android.content.pm.PackageManager.INSTALL_REASON_UNKNOWN;
import static android.content.pm.PackageManager.INSTALL_SCENARIO_DEFAULT;

import static com.android.server.pm.PackageManagerService.TAG;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.apex.ApexInfo;
import android.app.AppOpsManager;
import android.content.pm.DataLoaderType;
import android.content.pm.IPackageInstallObserver2;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.SigningDetails;
import android.net.Uri;
import android.os.UserHandle;
import android.util.ExceptionUtils;
import android.util.Slog;

import com.android.server.pm.pkg.AndroidPackage;

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

final class InstallRequest {
    public final InstallArgs mArgs;
    public final PackageInstalledInfo mInstallResult;
    private final int mUserId;
    @Nullable
    private final InstallArgs mInstallArgs;
    @NonNull
    private final PackageInstalledInfo mInstalledInfo;
    @Nullable
    private Runnable mPostInstallRunnable;
    @Nullable
    private PackageRemovedInfo mRemovedInfo;

    // New install
    InstallRequest(InstallingSession params) {
        mUserId = params.getUser().getIdentifier();
        mInstallArgs = new InstallArgs(params.mOriginInfo, params.mMoveInfo, params.mObserver,
                params.mInstallFlags, params.mInstallSource, params.mVolumeUuid,
                params.getUser(), null /*instructionSets*/, params.mPackageAbiOverride,
                params.mGrantedRuntimePermissions, params.mAllowlistedRestrictedPermissions,
                params.mAutoRevokePermissionsMode,
                params.mTraceMethod, params.mTraceCookie, params.mSigningDetails,
                params.mInstallReason, params.mInstallScenario, params.mForceQueryableOverride,
                params.mDataLoaderType, params.mPackageSource);
        mInstalledInfo = new PackageInstalledInfo();
    }

    // Install existing package as user
    InstallRequest(int userId, int returnCode, AndroidPackage pkg, int[] newUsers,
            Runnable runnable) {
        mUserId = userId;
        mInstallArgs = null;
        mInstalledInfo = new PackageInstalledInfo();
        mInstalledInfo.mReturnCode = returnCode;
        mInstalledInfo.mPkg = pkg;
        mInstalledInfo.mNewUsers = newUsers;
        mPostInstallRunnable = runnable;
    }

    private static class PackageInstalledInfo {
        String mName;
        int mUid = -1;
        // The set of users that originally had this package installed.
        int[] mOrigUsers;
        // The set of users that now have this package installed.
        int[] mNewUsers;
        AndroidPackage mPkg;
        int mReturnCode;
        String mReturnMsg;
        String mInstallerPackageName;
        // The set of packages consuming this shared library or null if no consumers exist.
        ArrayList<AndroidPackage> mLibraryConsumers;
        PackageFreezer mFreezer;
        // In some error cases we want to convey more info back to the observer
        String mOrigPackage;
        String mOrigPermission;
        // The ApexInfo returned by ApexManager#installPackage, used by rebootless APEX install
        ApexInfo mApexInfo;
    }

    public String getName() {
        return mInstalledInfo.mName;
    }

    public String getReturnMsg() {
        return mInstalledInfo.mReturnMsg;
    }

    public OriginInfo getOriginInfo() {
        return mInstallArgs == null ? null : mInstallArgs.mOriginInfo;
    }

    public PackageRemovedInfo getRemovedInfo() {
        return mRemovedInfo;
    }

    public String getOrigPackage() {
        return mInstalledInfo.mOrigPackage;
    }

    public String getOrigPermission() {
        return mInstalledInfo.mOrigPermission;
    }

    @Nullable
    public File getCodeFile() {
        return mInstallArgs == null ? null : mInstallArgs.mCodeFile;
    }

    @Nullable
    public String getCodePath() {
        return (mInstallArgs != null && mInstallArgs.mCodeFile != null)
                ? mInstallArgs.mCodeFile.getAbsolutePath() : null;
    }

    @Nullable
    public String getAbiOverride() {
        return mInstallArgs == null ? null : mInstallArgs.mAbiOverride;
    }

    public int getReturnCode() {
        return mInstalledInfo.mReturnCode;
    }

    @Nullable
    public IPackageInstallObserver2 getObserver() {
        return mInstallArgs == null ? null : mInstallArgs.mObserver;
    }

    public boolean isMoveInstall() {
        return mInstallArgs != null && mInstallArgs.mMoveInfo != null;
    }

    @Nullable
    public String getMoveToUuid() {
        return (mInstallArgs != null && mInstallArgs.mMoveInfo != null)
                ? mInstallArgs.mMoveInfo.mToUuid : null;
    }

    @Nullable
    public String getMovePackageName() {
        return  (mInstallArgs != null && mInstallArgs.mMoveInfo != null)
                ? mInstallArgs.mMoveInfo.mPackageName : null;
    }

    @Nullable
    public String getMoveFromCodePath() {
        return  (mInstallArgs != null && mInstallArgs.mMoveInfo != null)
                ? mInstallArgs.mMoveInfo.mFromCodePath : null;
    }

    @Nullable
    public File getOldCodeFile() {
        return (mRemovedInfo != null && mRemovedInfo.mArgs != null)
                ? mRemovedInfo.mArgs.mCodeFile : null;
    }

    @Nullable
    public String[] getOldInstructionSet() {
        return (mRemovedInfo != null && mRemovedInfo.mArgs != null)
                ? mRemovedInfo.mArgs.mInstructionSets : null;
    }

    public UserHandle getUser() {
        return new UserHandle(mUserId);
    }

    public int getUserId() {
        return mUserId;
    }

    public int getInstallFlags() {
        return mInstallArgs == null ? 0 : mInstallArgs.mInstallFlags;
    }

    public int getInstallReason() {
        return mInstallArgs == null ? INSTALL_REASON_UNKNOWN : mInstallArgs.mInstallReason;
    }

    @Nullable
    public String getVolumeUuid() {
        return mInstallArgs == null ? null : mInstallArgs.mVolumeUuid;
    }

    public AndroidPackage getPkg() {
        return mInstalledInfo.mPkg;
    }

    @Nullable
    public String getTraceMethod() {
        return mInstallArgs == null ? null : mInstallArgs.mTraceMethod;
    }

    public int getTraceCookie() {
        return mInstallArgs == null ? 0 : mInstallArgs.mTraceCookie;
    }

    public boolean isUpdate() {
        return mRemovedInfo != null && mRemovedInfo.mRemovedPackage != null;
    }

    @Nullable
    public String getRemovedPackage() {
        return mRemovedInfo != null ? mRemovedInfo.mRemovedPackage : null;
    }

    public boolean isInstallForExistingUser() {
        return mInstallArgs == null;
    }

    @Nullable
    public InstallSource getInstallSource() {
        return mInstallArgs == null ? null : mInstallArgs.mInstallSource;
    }

    @Nullable
    public String getInstallerPackageName() {
        return (mInstallArgs != null && mInstallArgs.mInstallSource != null)
                ? mInstallArgs.mInstallSource.installerPackageName : null;
    }

    public int getDataLoaderType() {
        return mInstallArgs == null ? DataLoaderType.NONE : mInstallArgs.mDataLoaderType;
    }

    public int getSignatureSchemeVersion() {
        return mInstallArgs == null ? SigningDetails.SignatureSchemeVersion.UNKNOWN
                : mInstallArgs.mSigningDetails.getSignatureSchemeVersion();
    }

    @NonNull
    public SigningDetails getSigningDetails() {
        return mInstallArgs == null ? SigningDetails.UNKNOWN : mInstallArgs.mSigningDetails;
    }

    @Nullable
    public Uri getOriginUri() {
        return mInstallArgs == null ?  null : Uri.fromFile(mInstallArgs.mOriginInfo.mResolvedFile);
    }

    public ApexInfo getApexInfo() {
        return mInstalledInfo.mApexInfo;
    }

    public String getSourceInstallerPackageName() {
        return mInstallArgs.mInstallSource.installerPackageName;
    }

    public boolean isRollback() {
        return mInstallArgs != null
                && mInstallArgs.mInstallReason == PackageManager.INSTALL_REASON_ROLLBACK;
    }

    public int[] getNewUsers() {
        return mInstalledInfo.mNewUsers;
    }

    public int[] getOriginUsers() {
        return mInstalledInfo.mOrigUsers;
    }

    public int getUid() {
        return mInstalledInfo.mUid;
    }

    @Nullable
    public String[] getInstallGrantPermissions() {
        return mInstallArgs == null ?  null : mInstallArgs.mInstallGrantPermissions;
    }

    public ArrayList<AndroidPackage> getLibraryConsumers() {
        return mInstalledInfo.mLibraryConsumers;
    }

    @Nullable
    public List<String> getAllowlistedRestrictedPermissions() {
        return mInstallArgs == null ? null : mInstallArgs.mAllowlistedRestrictedPermissions;
    }

    public int getAutoRevokePermissionsMode() {
        return mInstallArgs == null
                ? AppOpsManager.MODE_DEFAULT : mInstallArgs.mAutoRevokePermissionsMode;
    }

    public int getPackageSource() {
        return mInstallArgs == null
                ? PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED : mInstallArgs.mPackageSource;
    }

    public int getInstallScenario() {
        return mInstallArgs == null ? INSTALL_SCENARIO_DEFAULT : mInstallArgs.mInstallScenario;
    }

    public boolean isForceQueryableOverride() {
        return mInstallArgs != null && mInstallArgs.mForceQueryableOverride;
    }

    public void closeFreezer() {
        if (mInstalledInfo.mFreezer != null) {
            mInstalledInfo.mFreezer.close();
        }
    }

    public void runPostInstallRunnable() {
        if (mPostInstallRunnable != null) {
            mPostInstallRunnable.run();
        }
    }

    public void setCodeFile(File codeFile) {
        if (mInstallArgs != null) {
            mInstallArgs.mCodeFile = codeFile;
        }
    }

    public void setError(int code, String msg) {
        setReturnCode(code);
        setReturnMessage(msg);
        Slog.w(TAG, msg);
    }

    public void setError(String msg, PackageManagerException e) {
        mInstalledInfo.mReturnCode = e.error;
        setReturnMessage(ExceptionUtils.getCompleteMessage(msg, e));
        Slog.w(TAG, msg, e);
    }

    public void setReturnCode(int returnCode) {
        mInstalledInfo.mReturnCode = returnCode;
    }

    public void setReturnMessage(String returnMsg) {
        mInstalledInfo.mReturnMsg = returnMsg;
    }

    public void setApexInfo(ApexInfo apexInfo) {
        mInstalledInfo.mApexInfo = apexInfo;
    }

    public void setPkg(AndroidPackage pkg) {
        mInstalledInfo.mPkg = pkg;
    }

    public void setUid(int uid) {
        mInstalledInfo.mUid = uid;
    }

    public void setNewUsers(int[] newUsers) {
        mInstalledInfo.mNewUsers = newUsers;
    }

    public void setOriginPackage(String originPackage) {
        mInstalledInfo.mOrigPackage = originPackage;
    }

    public void setOriginPermission(String originPermission) {
        mInstalledInfo.mOrigPermission = originPermission;
    }

    public void setInstallerPackageName(String installerPackageName) {
        mInstalledInfo.mInstallerPackageName = installerPackageName;
    }

    public void setName(String packageName) {
        mInstalledInfo.mName = packageName;
    }

    public void setOriginUsers(int[] userIds) {
        mInstalledInfo.mOrigUsers = userIds;
    }

    public void setFreezer(PackageFreezer freezer) {
        mInstalledInfo.mFreezer = freezer;
    }

    public void setRemovedInfo(PackageRemovedInfo removedInfo) {
        mRemovedInfo = removedInfo;
    }

    InstallRequest(InstallArgs args, PackageInstalledInfo res) {
        mArgs = args;
        mInstallResult = res;
    public void setLibraryConsumers(ArrayList<AndroidPackage> libraryConsumers) {
        mInstalledInfo.mLibraryConsumers = libraryConsumers;
    }
}
+49 −50
Original line number Diff line number Diff line
@@ -253,68 +253,69 @@ class InstallingSession {
    }

    private void processPendingInstall() {
        InstallArgs args = new InstallArgs(this);
        InstallRequest installRequest = new InstallRequest(this);
        if (mRet == PackageManager.INSTALL_SUCCEEDED) {
            mRet = copyApk(args);
            mRet = copyApk(installRequest);
        }
        if (mRet == PackageManager.INSTALL_SUCCEEDED) {
            F2fsUtils.releaseCompressedBlocks(
                    mPm.mContext.getContentResolver(), new File(args.getCodePath()));
                    mPm.mContext.getContentResolver(), new File(installRequest.getCodePath()));
        }
        installRequest.setReturnCode(mRet);
        if (mParentInstallingSession != null) {
            mParentInstallingSession.tryProcessInstallRequest(args, mRet);
            mParentInstallingSession.tryProcessInstallRequest(installRequest);
        } else {
            PackageInstalledInfo res = new PackageInstalledInfo(mRet);
            // Queue up an async operation since the package installation may take a little while.
            mPm.mHandler.post(() -> processInstallRequests(
                    res.mReturnCode == PackageManager.INSTALL_SUCCEEDED /* success */,
                    Collections.singletonList(new InstallRequest(args, res))));
                    mRet == PackageManager.INSTALL_SUCCEEDED /* success */,
                    Collections.singletonList(installRequest)));
        }
    }

    private int copyApk(InstallArgs args) {
    private int copyApk(InstallRequest request) {
        if (mMoveInfo == null) {
            return copyApkForFileInstall(args);
            return copyApkForFileInstall(request);
        } else {
            return copyApkForMoveInstall(args);
            return copyApkForMoveInstall(request);
        }
    }

    private int copyApkForFileInstall(InstallArgs args) {
    private int copyApkForFileInstall(InstallRequest request) {
        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyApk");
        try {
            if (mOriginInfo.mStaged) {
                if (DEBUG_INSTALL) {
                    Slog.d(TAG, mOriginInfo.mFile + " already staged; skipping copy");
                }
                args.mCodeFile = mOriginInfo.mFile;
                request.setCodeFile(mOriginInfo.mFile);
                return PackageManager.INSTALL_SUCCEEDED;
            }

            try {
                final boolean isEphemeral =
                        (mInstallFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
                args.mCodeFile =
                        mPm.mInstallerService.allocateStageDirLegacy(mVolumeUuid, isEphemeral);
                request.setCodeFile(
                        mPm.mInstallerService.allocateStageDirLegacy(mVolumeUuid, isEphemeral));
            } catch (IOException e) {
                Slog.w(TAG, "Failed to create copy file: " + e);
                return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
            }

            int ret = PackageManagerServiceUtils.copyPackage(
                    mOriginInfo.mFile.getAbsolutePath(), args.mCodeFile);
                    mOriginInfo.mFile.getAbsolutePath(), request.getCodeFile());
            if (ret != PackageManager.INSTALL_SUCCEEDED) {
                Slog.e(TAG, "Failed to copy package");
                return ret;
            }

            final boolean isIncremental = isIncrementalPath(args.mCodeFile.getAbsolutePath());
            final File libraryRoot = new File(args.mCodeFile, LIB_DIR_NAME);
            final boolean isIncremental = isIncrementalPath(
                    request.getCodeFile().getAbsolutePath());
            final File libraryRoot = new File(request.getCodeFile(), LIB_DIR_NAME);
            NativeLibraryHelper.Handle handle = null;
            try {
                handle = NativeLibraryHelper.Handle.create(args.mCodeFile);
                handle = NativeLibraryHelper.Handle.create(request.getCodeFile());
                ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
                        args.mAbiOverride, isIncremental);
                        request.getAbiOverride(), isIncremental);
            } catch (IOException e) {
                Slog.e(TAG, "Copying native libraries failed", e);
                ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
@@ -328,7 +329,7 @@ class InstallingSession {
        }
    }

    private int copyApkForMoveInstall(InstallArgs args) {
    private int copyApkForMoveInstall(InstallRequest request) {
        if (DEBUG_INSTALL) {
            Slog.d(TAG, "Moving " + mMoveInfo.mPackageName + " from "
                    + mMoveInfo.mFromUuid + " to " + mMoveInfo.mToUuid);
@@ -345,8 +346,9 @@ class InstallingSession {
        }

        final String toPathName = new File(mMoveInfo.mFromCodePath).getName();
        args.mCodeFile = new File(Environment.getDataAppDirectory(mMoveInfo.mToUuid), toPathName);
        if (DEBUG_INSTALL) Slog.d(TAG, "codeFile after move is " + args.mCodeFile);
        request.setCodeFile(
                new File(Environment.getDataAppDirectory(mMoveInfo.mToUuid), toPathName));
        if (DEBUG_INSTALL) Slog.d(TAG, "codeFile after move is " + request.getCodeFile());

        return PackageManager.INSTALL_SUCCEEDED;
    }
@@ -460,7 +462,7 @@ class InstallingSession {
        List<InstallRequest> apexInstallRequests = new ArrayList<>();
        List<InstallRequest> apkInstallRequests = new ArrayList<>();
        for (InstallRequest request : installRequests) {
            if ((request.mArgs.mInstallFlags & PackageManager.INSTALL_APEX) != 0) {
            if ((request.getInstallFlags() & PackageManager.INSTALL_APEX) != 0) {
                apexInstallRequests.add(request);
            } else {
                apkInstallRequests.add(request);
@@ -485,7 +487,7 @@ class InstallingSession {
                // processInstallRequestAsync. In that case just notify the observer about the
                // failure.
                InstallRequest request = apexInstallRequests.get(0);
                mPm.notifyInstallObserver(request.mInstallResult, request.mArgs.mObserver);
                mPm.notifyInstallObserver(request);
            }
            return;
        }
@@ -496,28 +498,25 @@ class InstallingSession {
    private void processApkInstallRequests(boolean success, List<InstallRequest> installRequests) {
        if (success) {
            for (InstallRequest request : installRequests) {
                if (request.mInstallResult.mReturnCode != PackageManager.INSTALL_SUCCEEDED) {
                    cleanUpForFailedInstall(request.mArgs);
                if (request.getReturnCode() != PackageManager.INSTALL_SUCCEEDED) {
                    cleanUpForFailedInstall(request);
                }
            }

            mInstallPackageHelper.installPackagesTraced(installRequests);

            for (InstallRequest request : installRequests) {
                doPostInstall(request.mInstallResult.mReturnCode, request.mArgs);
                doPostInstall(request);
            }
        }
        for (InstallRequest request : installRequests) {
            mInstallPackageHelper.restoreAndPostInstall(request.mArgs.mUser.getIdentifier(),
                    request.mInstallResult,
                    new PostInstallData(request.mArgs,
                            request.mInstallResult, null));
            mInstallPackageHelper.restoreAndPostInstall(request);
        }
    }

    private void doPostInstall(int status, InstallArgs args) {
    private void doPostInstall(InstallRequest request) {
        if (mMoveInfo != null) {
            if (status == PackageManager.INSTALL_SUCCEEDED) {
            if (request.getReturnCode() == PackageManager.INSTALL_SUCCEEDED) {
                mRemovePackageHelper.cleanUpForMoveInstall(mMoveInfo.mFromUuid,
                        mMoveInfo.mPackageName, mMoveInfo.mFromCodePath);
            } else {
@@ -525,18 +524,18 @@ class InstallingSession {
                        mMoveInfo.mPackageName, mMoveInfo.mFromCodePath);
            }
        } else {
            if (status != PackageManager.INSTALL_SUCCEEDED) {
                mRemovePackageHelper.removeCodePath(args.mCodeFile);
            if (request.getReturnCode() != PackageManager.INSTALL_SUCCEEDED) {
                mRemovePackageHelper.removeCodePath(request.getCodeFile());
            }
        }
    }

    private void cleanUpForFailedInstall(InstallArgs args) {
        if (args.mMoveInfo != null) {
            mRemovePackageHelper.cleanUpForMoveInstall(args.mMoveInfo.mToUuid,
                    args.mMoveInfo.mPackageName, args.mMoveInfo.mFromCodePath);
    private void cleanUpForFailedInstall(InstallRequest request) {
        if (request.isMoveInstall()) {
            mRemovePackageHelper.cleanUpForMoveInstall(request.getMoveToUuid(),
                    request.getMovePackageName(), request.getMoveFromCodePath());
        } else {
            mRemovePackageHelper.removeCodePath(args.mCodeFile);
            mRemovePackageHelper.removeCodePath(request.getCodeFile());
        }
    }

@@ -560,7 +559,7 @@ class InstallingSession {
        InstallRequest request = requests.get(0);
        try {
            // Should directory scanning logic be moved to ApexManager for better test coverage?
            final File dir = request.mArgs.mOriginInfo.mResolvedFile;
            final File dir = request.getOriginInfo().mResolvedFile;
            final File[] apexes = dir.listFiles();
            if (apexes == null) {
                throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
@@ -580,7 +579,7 @@ class InstallingSession {
                    // The newly installed APEX will not be reverted even if
                    // processApkInstallRequests() fails. Need a way to keep info stored in apexd
                    // and PMS in sync in the face of install failures.
                    request.mInstallResult.mApexInfo = apexInfo;
                    request.setApexInfo(apexInfo);
                    mPm.mHandler.post(() -> processApkInstallRequests(true, requests));
                    return;
                } else {
@@ -588,10 +587,10 @@ class InstallingSession {
                }
            }
        } catch (PackageManagerException e) {
            request.mInstallResult.setError("APEX installation failed", e);
            request.setError("APEX installation failed", e);
        }
        PackageManagerService.invalidatePackageInfoCache();
        mPm.notifyInstallObserver(request.mInstallResult, request.mArgs.mObserver);
        mPm.notifyInstallObserver(request);
    }

    /**
@@ -600,7 +599,7 @@ class InstallingSession {
     */
    private class MultiPackageInstallingSession {
        private final List<InstallingSession> mChildInstallingSessions;
        private final Map<InstallArgs, Integer> mCurrentState;
        private final Map<InstallRequest, Integer> mCurrentState;
        @NonNull
        final PackageManagerService mPm;
        final UserHandle mUser;
@@ -636,8 +635,8 @@ class InstallingSession {
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }

        public void tryProcessInstallRequest(InstallArgs args, int currentStatus) {
            mCurrentState.put(args, currentStatus);
        public void tryProcessInstallRequest(InstallRequest request) {
            mCurrentState.put(request, request.getReturnCode());
            if (mCurrentState.size() != mChildInstallingSessions.size()) {
                return;
            }
@@ -651,9 +650,9 @@ class InstallingSession {
                }
            }
            final List<InstallRequest> installRequests = new ArrayList<>(mCurrentState.size());
            for (Map.Entry<InstallArgs, Integer> entry : mCurrentState.entrySet()) {
                installRequests.add(new InstallRequest(entry.getKey(),
                        new PackageInstalledInfo(completeStatus)));
            for (Map.Entry<InstallRequest, Integer> entry : mCurrentState.entrySet()) {
                entry.getKey().setReturnCode(completeStatus);
                installRequests.add(entry.getKey());
            }
            int finalCompleteStatus = completeStatus;
            mPm.mHandler.post(() -> processInstallRequests(
Loading