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

Commit be0d6093 authored by TYM Tsai's avatar TYM Tsai
Browse files

Move dexopt out of the package freezer.

The dexopt takes a long time, move it out of the package freezer to
to unblock installer.

Bug: 321139675
Flag: android.content.pm.improve_install_freeze
Test: atest CtsPackageManagerTestCases
Test: atest CtsInstallHostTestCases
Test: atest CtsCompilationTestCases
Change-Id: Ieffaf141fddda8966e97fe5575951e3190b993ee
parent 9bda1c92
Loading
Loading
Loading
Loading
+8 −1
Original line number Diff line number Diff line
@@ -80,6 +80,7 @@ import com.android.server.art.model.DexoptResult;
import com.android.server.pm.PackageDexOptimizer.DexOptResult;
import com.android.server.pm.dex.DexManager;
import com.android.server.pm.dex.DexoptOptions;
import com.android.server.pm.local.PackageManagerLocalImpl;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageState;
import com.android.server.pm.pkg.PackageStateInternal;
@@ -819,10 +820,16 @@ public final class DexOptHelper {
        final PackageSetting ps = installRequest.getScannedPackageSetting();
        final String packageName = ps.getPackageName();

        PackageSetting uncommittedPs = null;
        if (Flags.improveInstallFreeze()) {
            uncommittedPs = ps;
        }

        PackageManagerLocal packageManagerLocal =
                LocalManagerRegistry.getManager(PackageManagerLocal.class);
        try (PackageManagerLocal.FilteredSnapshot snapshot =
                     packageManagerLocal.withFilteredSnapshot()) {
                     PackageManagerLocalImpl.withFilteredSnapshot(packageManagerLocal,
                uncommittedPs)) {
            boolean ignoreDexoptProfile =
                    (installRequest.getInstallFlags()
                            & PackageManager.INSTALL_IGNORE_DEXOPT_PROFILE)
+88 −12
Original line number Diff line number Diff line
@@ -148,6 +148,7 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.EventLog;
import android.util.ExceptionUtils;
import android.util.IntArray;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
@@ -1014,13 +1015,17 @@ final class InstallPackageHelper {
        final Map<String, Settings.VersionInfo> versionInfos = new ArrayMap<>(requests.size());
        try {
            CriticalEventLog.getInstance().logInstallPackagesStarted();

            if (prepareInstallPackages(requests)
                    && scanInstallPackages(requests, createdAppId, versionInfos)) {
                List<ReconciledPackage> reconciledPackages =
                        reconcileInstallPackages(requests, versionInfos);
                if (reconciledPackages != null
                        && renameAndUpdatePaths(requests)
                if (reconciledPackages == null) {
                    return;
                }
                if (Flags.improveInstallFreeze()) {
                    prepPerformDexoptIfNeeded(reconciledPackages);
                }
                if (renameAndUpdatePaths(requests)
                        && commitInstallPackages(reconciledPackages)) {
                    success = true;
                }
@@ -1031,6 +1036,75 @@ final class InstallPackageHelper {
        }
    }

    private int[] getNewUsers(InstallRequest installRequest, int[] allUsers)
            throws PackageManagerException {
        final int userId = installRequest.getUserId();
        if (userId != UserHandle.USER_ALL && userId != UserHandle.USER_CURRENT
                && !mPm.mUserManager.exists(userId)) {
            throw new PackageManagerException(PackageManagerException.INTERNAL_ERROR_MISSING_USER,
                    "User " + userId + " doesn't exist or has been removed");
        }

        final IntArray newUserIds = new IntArray();
        if (userId != UserHandle.USER_ALL) {
            newUserIds.add(userId);
        } else if (allUsers != null) {
            final int[] installedForUsers = installRequest.getOriginUsers();
            for (int currentUserId : allUsers) {
                final boolean installedForCurrentUser = ArrayUtils.contains(
                        installedForUsers, currentUserId);
                final boolean restrictedByPolicy =
                        mPm.isUserRestricted(currentUserId,
                                UserManager.DISALLOW_INSTALL_APPS)
                                || mPm.isUserRestricted(currentUserId,
                                UserManager.DISALLOW_DEBUGGING_FEATURES);
                if (installedForCurrentUser || !restrictedByPolicy) {
                    newUserIds.add(currentUserId);
                }
            }
        }

        if (newUserIds.size() == 0) {
            throw new PackageManagerException(PackageManagerException.INTERNAL_ERROR_MISSING_USER,
                    "User " + userId + " doesn't exist or has been removed");
        } else {
            return newUserIds.toArray();
        }
    }

    private void prepPerformDexoptIfNeeded(List<ReconciledPackage> reconciledPackages) {
        for (ReconciledPackage reconciledPkg : reconciledPackages) {
            final InstallRequest request = reconciledPkg.mInstallRequest;
            // prepare profiles
            final PackageSetting ps = request.getScannedPackageSetting();
            final PackageSetting oldPkgSetting = request.getScanRequestOldPackageSetting();
            final int[] allUsers = mPm.mUserManager.getUserIds();
            if (reconciledPkg.mCollectedSharedLibraryInfos != null
                    || (oldPkgSetting != null
                    && !oldPkgSetting.getSharedLibraryDependencies().isEmpty())) {
                // Reconcile if the new package or the old package uses shared libraries.
                // It is possible that the old package uses shared libraries but the new
                // one doesn't.
                mSharedLibraries.executeSharedLibrariesUpdate(request.getParsedPackage(), ps,
                        null, null, reconciledPkg.mCollectedSharedLibraryInfos, allUsers);
            }
            try (PackageManagerTracedLock installLock = mPm.mInstallLock.acquireLock()) {
                final int[] newUsers = getNewUsers(request, allUsers);
                // Hardcode previousAppId to 0 to disable any data migration (http://b/221088088)
                mAppDataHelper.prepareAppDataPostCommitLIF(ps, 0, newUsers);
                if (request.isClearCodeCache()) {
                    mAppDataHelper.clearAppDataLIF(ps.getPkg(), UserHandle.USER_ALL,
                            FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL
                                    | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
                }
            } catch (PackageManagerException e) {
                request.setError(e.error, e.getMessage());
                return;
            }
            DexOptHelper.performDexoptIfNeeded(request, mDexManager, mContext, null);
        }
    }

    private boolean renameAndUpdatePaths(List<InstallRequest> requests) {
        try (PackageManagerTracedLock installLock = mPm.mInstallLock.acquireLock()) {
            for (InstallRequest request : requests) {
@@ -2655,6 +2729,11 @@ final class InstallPackageHelper {
                incrementalStorages.add(storage);
            }

            if (installRequest.isInstallReplace() && pkg != null) {
                mDexManager.notifyPackageUpdated(packageName,
                        pkg.getBaseApkPath(), pkg.getSplitCodePaths());
            }
            if (!Flags.improveInstallFreeze()) {
                // Hardcode previousAppId to 0 to disable any data migration (http://b/221088088)
                mAppDataHelper.prepareAppDataPostCommitLIF(ps, 0, installRequest.getNewUsers());
                if (installRequest.isClearCodeCache()) {
@@ -2662,14 +2741,11 @@ final class InstallPackageHelper {
                            FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL
                                    | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
                }
            if (installRequest.isInstallReplace() && pkg != null) {
                mDexManager.notifyPackageUpdated(packageName,
                        pkg.getBaseApkPath(), pkg.getSplitCodePaths());
            }

                DexOptHelper.performDexoptIfNeeded(installRequest, mDexManager, mContext,
                        mPm.mInstallLock.getRawLock());
            }
        }
        PackageManagerServiceUtils.waitForNativeBinariesExtractionForIncremental(
                incrementalStorages);
    }
+37 −3
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import com.android.server.pm.Computer;
import com.android.server.pm.PackageManagerLocal;
import com.android.server.pm.PackageManagerService;
import com.android.server.pm.pkg.PackageState;
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.SharedUserApi;
import com.android.server.pm.snapshot.PackageDataSnapshot;

@@ -71,8 +72,26 @@ public class PackageManagerLocalImpl implements PackageManagerLocal {
    @NonNull
    @Override
    public FilteredSnapshotImpl withFilteredSnapshot(int callingUid, @NonNull UserHandle user) {
        return withFilteredSnapshot(callingUid, user, /* uncommittedPs= */ null);
    }

    /**
     * Creates a {@link FilteredSnapshot} with a uncommitted {@link PackageState} that is used for
     * dexopt in the art service to get the correct package state before the package is committed.
     */
    @NonNull
    public static FilteredSnapshotImpl withFilteredSnapshot(PackageManagerLocal pm,
            @NonNull PackageState uncommittedPs) {
        return ((PackageManagerLocalImpl) pm).withFilteredSnapshot(Binder.getCallingUid(),
                Binder.getCallingUserHandle(), uncommittedPs);
    }

    @NonNull
    private FilteredSnapshotImpl withFilteredSnapshot(int callingUid, @NonNull UserHandle user,
            @Nullable PackageState uncommittedPs) {
        return new FilteredSnapshotImpl(callingUid, user,
                mService.snapshotComputer(false /*allowLiveComputer*/), null);
                mService.snapshotComputer(/* allowLiveComputer= */ false),
                /* parentSnapshot= */ null, uncommittedPs);
    }

    @Override
@@ -145,7 +164,8 @@ public class PackageManagerLocalImpl implements PackageManagerLocal {

        @Override
        public FilteredSnapshot filtered(int callingUid, @NonNull UserHandle user) {
            return new FilteredSnapshotImpl(callingUid, user, mSnapshot, this);
            return new FilteredSnapshotImpl(callingUid, user, mSnapshot, this,
                    /* uncommittedPs= */ null);
        }

        @SuppressWarnings("RedundantSuppression")
@@ -209,13 +229,18 @@ public class PackageManagerLocalImpl implements PackageManagerLocal {
        @Nullable
        private final UnfilteredSnapshotImpl mParentSnapshot;

        @Nullable
        private final PackageState mUncommitPackageState;

        private FilteredSnapshotImpl(int callingUid, @NonNull UserHandle user,
                @NonNull PackageDataSnapshot snapshot,
                @Nullable UnfilteredSnapshotImpl parentSnapshot) {
                @Nullable UnfilteredSnapshotImpl parentSnapshot,
                @Nullable PackageState uncommittedPs) {
            super(snapshot);
            mCallingUid = callingUid;
            mUserId = user.getIdentifier();
            mParentSnapshot = parentSnapshot;
            mUncommitPackageState = uncommittedPs;
        }

        @Override
@@ -237,6 +262,10 @@ public class PackageManagerLocalImpl implements PackageManagerLocal {
        @Override
        public PackageState getPackageState(@NonNull String packageName) {
            checkClosed();
            if (mUncommitPackageState != null
                    && packageName.equals(mUncommitPackageState.getPackageName())) {
                return mUncommitPackageState;
            }
            return mSnapshot.getPackageStateFiltered(packageName, mCallingUid, mUserId);
        }

@@ -250,6 +279,11 @@ public class PackageManagerLocalImpl implements PackageManagerLocal {
                var filteredPackageStates = new ArrayMap<String, PackageState>();
                for (int index = 0, size = packageStates.size(); index < size; index++) {
                    var packageState = packageStates.valueAt(index);
                    if (mUncommitPackageState != null
                            && packageState.getPackageName().equals(
                            mUncommitPackageState.getPackageName())) {
                        packageState = (PackageStateInternal) mUncommitPackageState;
                    }
                    if (!mSnapshot.shouldFilterApplication(packageState, mCallingUid, mUserId)) {
                        filteredPackageStates.put(packageStates.keyAt(index), packageState);
                    }