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

Commit 18d20709 authored by Felka Chang's avatar Felka Chang
Browse files

Fix the orphan child session after abandoning the parent session

In the multipackage staged session set condition, whenever a committed
parent session called abandon(), only calling dispatchSessionFinished()
on the parent session would leave its children session as the orphan
child sessions. The child sessions aren't handled very well and they
would be never handled if the installer applications forget to handle
them.

The solution is to notify the each child session in this multipackage
session after the parent session is abandoned. And, to add the
com.android.tests.atomicinstall.SessionAbandonBehaviorTest to verify the
behavior.

Test: atest StagedInstallInternalTest
Test: atest -p \
    frameworks/base/services/core/java/com/android/server/pm/TEST_MAPPING
Test: atest CtsAtomicInstallTestCases
Test: # monitor the log after atest stagedInstallInternalTest and reboot.
Bug: 164964410
Change-Id: I23dabf7da099baebed63e9f9fc73383984015070
parent 9a095a4e
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -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)}.
         * <p>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.</p>
         */
        public void abandon() {
            try {
@@ -1419,7 +1421,8 @@ public class PackageInstaller {
         * when this session is committed.
         *
         * <p>If the parent is staged or has rollback enabled, all children must have
         * the same properties.
         * the same properties.</p>
         * <p>If the parent is abandoned, all children will also be abandoned.</p>
         *
         * @param sessionId the session ID to add to this multi-package session.
         */
+27 −0
Original line number Diff line number Diff line
@@ -3058,6 +3058,31 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
        }
    }

    /**
     * Cleans up the relevant stored files and information of all child sessions.
     * <p>Cleaning up the stored files and session information is necessary for
     * preventing the orphan children sessions.
     * <ol>
     *     <li>To call {@link #destroyInternal()} cleans up the stored files.</li>
     *     <li>To call {@link #dispatchSessionFinished(int, String, Bundle)} to trigger the
     *     procedure to clean up the information in PackageInstallerService.</li>
     * </ol></p>
     */
    private void maybeCleanUpChildSessions() {
        if (!isMultiPackage()) {
            return;
        }

        final List<PackageInstallerSession> 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.