Revert "Revert "[pm] remove old stage dirs on low storage""

This reverts commit b45ebca772.

Reason for revert: adding the fix for system to abandon sessions

BUG: 67862680
Test: manual
Change-Id: I2b735e4860dce6eb6d5d8ddc158e8b3165910dc7
Merged-In: I91170ba399b3a596320b3bd9c8188912e5c4f1be
This commit is contained in:
Songchun Fan
2021-10-14 10:40:25 -07:00
parent 8bcd86e662
commit bd25f70623
3 changed files with 58 additions and 5 deletions

View File

@@ -125,6 +125,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
private static final long MAX_ACTIVE_SESSIONS = 1024;
/** Upper bound on number of historical sessions for a UID */
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;
private final Context mContext;
private final PackageManagerService mPm;
@@ -228,23 +230,58 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
@GuardedBy("mSessions")
private void reconcileStagesLocked(String volumeUuid, boolean isEphemeral) {
final File stagingDir = buildStagingDir(volumeUuid, isEphemeral);
final ArraySet<File> unclaimedStages = newArraySet(
stagingDir.listFiles(sStageFilter));
final ArraySet<File> unclaimedStages = getStagingDirsOnVolume(volumeUuid, isEphemeral);
// Ignore stages claimed by active sessions
for (int i = 0; i < mSessions.size(); i++) {
final PackageInstallerSession session = mSessions.valueAt(i);
unclaimedStages.remove(session.stageDir);
}
removeStagingDirs(unclaimedStages);
}
private ArraySet<File> getStagingDirsOnVolume(String volumeUuid, boolean isEphemeral) {
final File stagingDir = buildStagingDir(volumeUuid, isEphemeral);
final ArraySet<File> stagingDirs = newArraySet(
stagingDir.listFiles(sStageFilter));
return stagingDirs;
}
private void removeStagingDirs(ArraySet<File> stagingDirsToRemove) {
// Clean up orphaned staging directories
for (File stage : unclaimedStages) {
for (File stage : stagingDirsToRemove) {
Slog.w(TAG, "Deleting orphan stage " + stage);
synchronized (mPm.mInstallLock) {
mPm.removeCodePathLI(stage);
}
}
}
/**
* Called to free up some storage space from obsolete installation files
*/
public void freeStageDirs(String volumeUuid, boolean internalVolume) {
final ArraySet<File> unclaimedStagingDirsOnVolume = getStagingDirsOnVolume(volumeUuid, internalVolume);
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) {

View File

@@ -793,6 +793,19 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
}
/**
* Check if the caller is the owner of this session. Otherwise throw a
* {@link SecurityException}.
*/
@GuardedBy("mLock")
private void assertCallerIsOwnerOrRootOrSystemLocked() {
final int callingUid = Binder.getCallingUid();
if (callingUid != Process.ROOT_UID && callingUid != mInstallerUid
&& callingUid != Process.SYSTEM_UID) {
throw new SecurityException("Session does not belong to uid " + callingUid);
}
}
/**
* If anybody is reading or writing data of the session, throw an {@link SecurityException}.
*/
@@ -1564,7 +1577,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
@Override
public void abandon() {
synchronized (mLock) {
assertCallerIsOwnerOrRootLocked();
assertCallerIsOwnerOrRootOrSystemLocked();
if (mRelinquished) {
Slog.d(TAG, "Ignoring abandon after commit relinquished control");

View File

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