diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2020-12-16 00:14:48 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2020-12-16 00:14:48 +0000 |
commit | ca05b4c5f776ec504a707efda2feecf6c816649f (patch) | |
tree | 625503b6cd7dbfe16c1d745aa91be305870d7690 | |
parent | ee0bb78123605aa53a07eee18fef0781be2c2fbf (diff) | |
parent | 69c24da80c37260459e7b09e5b144a02124e25d9 (diff) | |
download | base-android11-qpr1-d-release.tar.gz |
Merge cherrypicks of [13232450, 13232453, 13232296, 13232297, 13232298, 13232944, 13232945, 13232946, 13232947, 13232948, 13232949, 13232950, 13232519, 13232351, 13232398, 13232352, 13232696, 13232697, 13232698] into rvc-qpr1-d-releaseandroid-11.0.0_r31android11-qpr1-d-release
Change-Id: I19488ebc84e5d7a9de13c07415e79e727aa99544
4 files changed, 72 insertions, 0 deletions
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 330f99523507..9f0efa5fad83 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -299,6 +299,10 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements 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 for (int i = 0; i < mSessions.size(); i++) { final PackageInstallerSession session = mSessions.valueAt(i); diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index ea53132ae409..c9f09545c3e6 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -1581,6 +1581,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { destroyInternal(); // Dispatch message to remove session from PackageInstallerService. dispatchSessionFinished(error, detailMessage, null); + // TODO(b/173194203): clean up staged session in destroyInternal() call instead + if (isStaged() && stageDir != null) { + cleanStageDir(); + } } private void onStorageUnhealthy() { diff --git a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java index 02597d548361..e67354982b05 100644 --- a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java +++ b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java @@ -96,6 +96,19 @@ public class StagedInstallInternalTest { assertSessionReady(sessionId); } + @Test + public void testStagedInstallationShouldCleanUpOnValidationFailure() throws Exception { + InstallUtils.commitExpectingFailure(AssertionError.class, "INSTALL_FAILED_INVALID_APK", + Install.single(TestApp.AIncompleteSplit).setStaged()); + } + + @Test + public void testStagedInstallationShouldCleanUpOnValidationFailureMultiPackage() + throws Exception { + InstallUtils.commitExpectingFailure(AssertionError.class, "INSTALL_FAILED_INVALID_APK", + Install.multi(TestApp.AIncompleteSplit, TestApp.B1, TestApp.Apex1).setStaged()); + } + private static void assertSessionReady(int sessionId) { assertSessionState(sessionId, (session) -> assertThat(session.isStagedSessionReady()).isTrue()); diff --git a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java index 9b432f7d0ca5..28a5424199a4 100644 --- a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java +++ b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java @@ -21,6 +21,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertTrue; import com.android.ddmlib.Log; +import com.android.tradefed.device.DeviceNotAvailableException; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; import com.android.tradefed.util.ProcessInfo; @@ -30,6 +31,10 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + @RunWith(DeviceJUnit4ClassRunner.class) public class StagedInstallInternalTest extends BaseHostJUnit4Test { @@ -87,6 +92,52 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test { runPhase("testSystemServerRestartDoesNotAffectStagedSessions_Verify"); } + @Test + public void testStagedInstallationShouldCleanUpOnValidationFailure() throws Exception { + List<String> before = getStagingDirectories(); + runPhase("testStagedInstallationShouldCleanUpOnValidationFailure"); + List<String> after = getStagingDirectories(); + assertThat(after).isEqualTo(before); + } + + @Test + public void testStagedInstallationShouldCleanUpOnValidationFailureMultiPackage() + throws Exception { + List<String> before = getStagingDirectories(); + runPhase("testStagedInstallationShouldCleanUpOnValidationFailureMultiPackage"); + List<String> after = getStagingDirectories(); + assertThat(after).isEqualTo(before); + } + + @Test + public void testOrphanedStagingDirectoryGetsCleanedUpOnReboot() throws Exception { + //create random directories in /data/app-staging folder + getDevice().enableAdbRoot(); + getDevice().executeShellCommand("mkdir /data/app-staging/session_123"); + getDevice().executeShellCommand("mkdir /data/app-staging/random_name"); + getDevice().disableAdbRoot(); + + assertThat(getStagingDirectories()).isNotEmpty(); + getDevice().reboot(); + assertThat(getStagingDirectories()).isEmpty(); + } + + private List<String> getStagingDirectories() throws DeviceNotAvailableException { + String baseDir = "/data/app-staging"; + try { + getDevice().enableAdbRoot(); + return getDevice().getFileEntry(baseDir).getChildren(false) + .stream().filter(entry -> entry.getName().matches("session_\\d+")) + .map(entry -> entry.getName()) + .collect(Collectors.toList()); + } catch (Exception e) { + // Return an empty list if any error + return Collections.EMPTY_LIST; + } finally { + getDevice().disableAdbRoot(); + } + } + private void restartSystemServer() throws Exception { // Restart the system server long oldStartTime = getDevice().getProcessByName("system_server").getStartTime(); |