diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index 596d39b50848a..0fc9fad4d635e 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -1356,7 +1356,9 @@ public class PackageInstaller { * Completely abandon this session, destroying all staged data and * rendering it invalid. Abandoned sessions will be reported to * {@link SessionCallback} listeners as failures. This is equivalent to - * opening the session and calling {@link Session#abandon()}. + * {@link #abandonSession(int)}. + *

If the parent is abandoned, all children will also be abandoned. Any written data + * would be destroyed and the created {@link Session} information will be discarded.

*/ public void abandon() { try { @@ -1419,7 +1421,8 @@ public class PackageInstaller { * when this session is committed. * *

If the parent is staged or has rollback enabled, all children must have - * the same properties. + * the same properties.

+ *

If the parent is abandoned, all children will also be abandoned.

* * @param sessionId the session ID to add to this multi-package session. */ diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 5d2928e1a854b..57b80eab61e6b 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -3058,6 +3058,31 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } + /** + * Cleans up the relevant stored files and information of all child sessions. + *

Cleaning up the stored files and session information is necessary for + * preventing the orphan children sessions. + *

    + *
  1. To call {@link #destroyInternal()} cleans up the stored files.
  2. + *
  3. To call {@link #dispatchSessionFinished(int, String, Bundle)} to trigger the + * procedure to clean up the information in PackageInstallerService.
  4. + *

+ */ + private void maybeCleanUpChildSessions() { + if (!isMultiPackage()) { + return; + } + + final List childSessions = getChildSessions(); + final int size = childSessions.size(); + for (int i = 0; i < size; ++i) { + final PackageInstallerSession session = childSessions.get(i); + session.destroyInternal(); + session.dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned" + + " because the parent session is abandoned", null); + } + } + private void abandonNonStaged() { synchronized (mLock) { assertCallerIsOwnerOrRootLocked(); @@ -3068,6 +3093,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { destroyInternal(); } dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned", null); + maybeCleanUpChildSessions(); } private void abandonStaged() { @@ -3092,6 +3118,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { cleanStageDir(childSessions); destroyInternal(); dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned", null); + maybeCleanUpChildSessions(); }; if (mInPreRebootVerification) { // Pre-reboot verification is ongoing. It is not safe to clean up the session yet.