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

Commit cd4e3b6b authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Revert "Revert "[pm] remove old stage dirs on low storage""" into sc-qpr1-dev

parents 778d92c7 50db8a56
Loading
Loading
Loading
Loading
+44 −9
Original line number Original line Diff line number Diff line
@@ -135,6 +135,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
    private static final long MAX_ACTIVE_SESSIONS_NO_PERMISSION = 50;
    private static final long MAX_ACTIVE_SESSIONS_NO_PERMISSION = 50;
    /** Upper bound on number of historical sessions for a UID */
    /** Upper bound on number of historical sessions for a UID */
    private static final long MAX_HISTORICAL_SESSIONS = 1048576;
    private static final long MAX_HISTORICAL_SESSIONS = 1048576;
    /** Destroy sessions older than this on storage free request */
    private static final long MAX_SESSION_AGE_ON_LOW_STORAGE_MILLIS = 8 * DateUtils.HOUR_IN_MILLIS;


    /**
    /**
     * Allow verification-skipping if it's a development app installed through ADB with
     * Allow verification-skipping if it's a development app installed through ADB with
@@ -334,22 +336,28 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements


    @GuardedBy("mSessions")
    @GuardedBy("mSessions")
    private void reconcileStagesLocked(String volumeUuid) {
    private void reconcileStagesLocked(String volumeUuid) {
        final File stagingDir = getTmpSessionDir(volumeUuid);
        final ArraySet<File> unclaimedStages = getStagingDirsOnVolume(volumeUuid);
        final ArraySet<File> unclaimedStages = newArraySet(
                stagingDir.listFiles(sStageFilter));

        // We also need to clean up orphaned staging directory for staged sessions
        final File stagedSessionStagingDir = Environment.getDataStagingDirectory(volumeUuid);
        unclaimedStages.addAll(newArraySet(stagedSessionStagingDir.listFiles()));

        // Ignore stages claimed by active sessions
        // Ignore stages claimed by active sessions
        for (int i = 0; i < mSessions.size(); i++) {
        for (int i = 0; i < mSessions.size(); i++) {
            final PackageInstallerSession session = mSessions.valueAt(i);
            final PackageInstallerSession session = mSessions.valueAt(i);
            unclaimedStages.remove(session.stageDir);
            unclaimedStages.remove(session.stageDir);
        }
        }
        removeStagingDirs(unclaimedStages);
    }


    private ArraySet<File> getStagingDirsOnVolume(String volumeUuid) {
        final File stagingDir = getTmpSessionDir(volumeUuid);
        final ArraySet<File> stagingDirs = newArraySet(stagingDir.listFiles(sStageFilter));

        // We also need to clean up orphaned staging directory for staged sessions
        final File stagedSessionStagingDir = Environment.getDataStagingDirectory(volumeUuid);
        stagingDirs.addAll(newArraySet(stagedSessionStagingDir.listFiles()));
        return stagingDirs;
    }

    private void removeStagingDirs(ArraySet<File> stagingDirsToRemove) {
        // Clean up orphaned staging directories
        // Clean up orphaned staging directories
        for (File stage : unclaimedStages) {
        for (File stage : stagingDirsToRemove) {
            Slog.w(TAG, "Deleting orphan stage " + stage);
            Slog.w(TAG, "Deleting orphan stage " + stage);
            synchronized (mPm.mInstallLock) {
            synchronized (mPm.mInstallLock) {
                mPm.removeCodePathLI(stage);
                mPm.removeCodePathLI(stage);
@@ -363,6 +371,33 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
        }
        }
    }
    }


    /**
     * Called to free up some storage space from obsolete installation files
     */
    public void freeStageDirs(String volumeUuid) {
        final ArraySet<File> unclaimedStagingDirsOnVolume = getStagingDirsOnVolume(volumeUuid);
        final long currentTimeMillis = System.currentTimeMillis();
        synchronized (mSessions) {
            for (int i = 0; i < mSessions.size(); i++) {
                final PackageInstallerSession session = mSessions.valueAt(i);
                if (!unclaimedStagingDirsOnVolume.contains(session.stageDir)) {
                    // Only handles sessions stored on the target volume
                    continue;
                }
                final long age = currentTimeMillis - session.createdMillis;
                if (age >= MAX_SESSION_AGE_ON_LOW_STORAGE_MILLIS) {
                    // Aggressively close old sessions because we are running low on storage
                    // Their staging dirs will be removed too
                    session.abandon();
                } else {
                    // Session is new enough, so it deserves to be kept even on low storage
                    unclaimedStagingDirsOnVolume.remove(session.stageDir);
                }
            }
        }
        removeStagingDirs(unclaimedStagingDirsOnVolume);
    }

    public static boolean isStageName(String name) {
    public static boolean isStageName(String name) {
        final boolean isFile = name.startsWith("vmdl") && name.endsWith(".tmp");
        final boolean isFile = name.startsWith("vmdl") && name.endsWith(".tmp");
        final boolean isContainer = name.startsWith("smdl") && name.endsWith(".tmp");
        final boolean isContainer = name.startsWith("smdl") && name.endsWith(".tmp");
+2 −2
Original line number Original line Diff line number Diff line
@@ -673,7 +673,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
            final Runnable r;
            final Runnable r;
            synchronized (mLock) {
            synchronized (mLock) {
                assertNotChildLocked("StagedSession#abandon");
                assertNotChildLocked("StagedSession#abandon");
                assertCallerIsOwnerOrRoot();
                assertCallerIsOwnerOrRootOrSystem();
                if (isInTerminalState()) {
                if (isInTerminalState()) {
                    // We keep the session in the database if it's in a finalized state. It will be
                    // We keep the session in the database if it's in a finalized state. It will be
                    // removed by PackageInstallerService when the last update time is old enough.
                    // removed by PackageInstallerService when the last update time is old enough.
@@ -3704,7 +3704,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
    private void abandonNonStaged() {
    private void abandonNonStaged() {
        synchronized (mLock) {
        synchronized (mLock) {
            assertNotChildLocked("abandonNonStaged");
            assertNotChildLocked("abandonNonStaged");
            assertCallerIsOwnerOrRoot();
            assertCallerIsOwnerOrRootOrSystem();
            if (mRelinquished) {
            if (mRelinquished) {
                if (LOGD) Slog.d(TAG, "Ignoring abandon after commit relinquished control");
                if (LOGD) Slog.d(TAG, "Ignoring abandon after commit relinquished control");
                return;
                return;
+4 −0
Original line number Original line Diff line number Diff line
@@ -9296,6 +9296,10 @@ public class PackageManagerService extends IPackageManager.Stub
            if (freeBytesRequired > 0) {
            if (freeBytesRequired > 0) {
                smInternal.freeCache(volumeUuid, freeBytesRequired);
                smInternal.freeCache(volumeUuid, freeBytesRequired);
            }
            }
            // 12. Clear temp install session files
            mInstallerService.freeStageDirs(volumeUuid);
            if (file.getUsableSpace() >= bytes) return;
            if (file.getUsableSpace() >= bytes) return;
        } else {
        } else {
            try {
            try {