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

Commit 8e5b703c authored by Nikita Ioffe's avatar Nikita Ioffe
Browse files

Properly fail commit of a new staged session if another one is in progress

Previous implementation did not really work because:
* PackageInstallerSession.commit marks session as committed and then
  sends MSG_COMMIT message;
* handleCommit calls StagingManager#commitSession;

This means that by the time StagingManager#commitSession(session) is called:
* mStagedSessions already contain session;
* this session is already marked as committed;

As a result, implementation in the ag/6638240 was failing a second committed
session only if it's id is greater than id of the first one.

Why manual testing in the previous CL worked?
I guess, I got lucky and in my case the second session had a greater id.

Bug: 127296534
Test: atest CtsStagedInstallHostTestCases (run 10 times)
Test: adb install --staged foo.apk (10 times with reboots in between)
Change-Id: I78f22d5537a7d074fc69f146dafccee6a6e5e896
parent 93fc5bb4
Loading
Loading
Loading
Loading
+14 −7
Original line number Diff line number Diff line
@@ -993,6 +993,19 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {

        mSealed = true;

        if (params.isStaged) {
            final PackageInstallerSession activeSession = mStagingManager.getActiveSession();
            final boolean anotherSessionAlreadyInProgress =
                    activeSession != null && sessionId != activeSession.sessionId
                            && mParentSessionId != activeSession.sessionId;
            if (anotherSessionAlreadyInProgress) {
                throw new PackageManagerException(
                        PackageManager.INSTALL_FAILED_OTHER_STAGED_SESSION_IN_PROGRESS,
                        "There is already in-progress committed staged session "
                                + activeSession.sessionId, null);
            }
        }

        // Read transfers from the original owner stay open, but as the session's data
        // cannot be modified anymore, there is no leak of information. For staged sessions,
        // further validation is performed by the staging manager.
@@ -1073,13 +1086,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {

    private void handleCommit() {
        if (params.isStaged) {
            try {
            mStagingManager.commitSession(this);
            } catch (StagingManager.AlreadyInProgressStagedSessionException e) {
                dispatchSessionFinished(
                        PackageManager.INSTALL_FAILED_OTHER_STAGED_SESSION_IN_PROGRESS,
                        e.getMessage(), null);
            }
            destroyInternal();
            dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "Session staged", null);
            return;
+2 −20
Original line number Diff line number Diff line
@@ -477,23 +477,13 @@ public class StagingManager {
        return true;
    }

    void commitSession(@NonNull PackageInstallerSession session)
            throws AlreadyInProgressStagedSessionException {
        PackageInstallerSession activeSession = getActiveSession();
        boolean anotherSessionAlreadyInProgress =
                activeSession != null && session.sessionId != activeSession.sessionId;
    void commitSession(@NonNull PackageInstallerSession session) {
        updateStoredSession(session);
        if (anotherSessionAlreadyInProgress) {
            session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
                    "There is already in-progress committed staged session "
                            + activeSession.sessionId);
            throw new AlreadyInProgressStagedSessionException(activeSession.sessionId);
        }
        mBgHandler.post(() -> preRebootVerification(session));
    }

    @Nullable
    private PackageInstallerSession getActiveSession() {
    PackageInstallerSession getActiveSession() {
        synchronized (mStagedSessions) {
            for (int i = 0; i < mStagedSessions.size(); i++) {
                final PackageInstallerSession session = mStagedSessions.valueAt(i);
@@ -651,12 +641,4 @@ public class StagingManager {
            }
        }
    }

    static final class AlreadyInProgressStagedSessionException extends Exception {

        AlreadyInProgressStagedSessionException(int sessionId) {
            super("There is already in-progress committed staged session "
                    + sessionId);
        }
    }
}