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

This commit is contained in:
TreeHugger Robot
2021-11-03 23:19:52 +00:00
committed by Android (Google) Code Review
3 changed files with 51 additions and 15 deletions

View File

@@ -134,6 +134,9 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
/** 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
* disable verification flag specified. * disable verification flag specified.
@@ -295,22 +298,29 @@ 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 = 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()));
final ArraySet<File> unclaimedStages = getStagingDirsOnVolume(volumeUuid);
// 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);
@@ -318,6 +328,34 @@ 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 void onPrivateVolumeMounted(String volumeUuid) { public void onPrivateVolumeMounted(String volumeUuid) {
synchronized (mSessions) { synchronized (mSessions) {
reconcileStagesLocked(volumeUuid); reconcileStagesLocked(volumeUuid);

View File

@@ -2610,14 +2610,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
List<PackageInstallerSession> childSessions = getChildSessionsNotLocked(); List<PackageInstallerSession> childSessions = getChildSessionsNotLocked();
synchronized (mLock) { synchronized (mLock) {
if (params.isStaged && mDestroyed) {
// If a user abandons staged session in an unsafe state, then system will try to
// abandon the destroyed staged session when it is safe on behalf of the user.
assertCallerIsOwnerOrRootOrSystemLocked();
} else {
assertCallerIsOwnerOrRootLocked();
}
assertCallerIsOwnerOrRootOrSystemLocked();
if (isStagedAndInTerminalState()) { if (isStagedAndInTerminalState()) {
// 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.

View File

@@ -5133,6 +5133,10 @@ public class PackageManagerService extends IPackageManager.Stub
InstantAppRegistry.DEFAULT_UNINSTALLED_INSTANT_APP_MIN_CACHE_PERIOD))) { InstantAppRegistry.DEFAULT_UNINSTALLED_INSTANT_APP_MIN_CACHE_PERIOD))) {
return; return;
} }
// 12. Clear temp install session files
mInstallerService.freeStageDirs(volumeUuid);
} else { } else {
try { try {
mInstaller.freeCache(volumeUuid, bytes, 0, 0); mInstaller.freeCache(volumeUuid, bytes, 0, 0);