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

Commit 933072bd authored by JW Wang's avatar JW Wang Committed by Android (Google) Code Review
Browse files

Merge changes from topic "bug162286562"

* changes:
  Fix #removeChildSessionId (4/n)
  Fix #removeChildSessionId (3/n)
  Fix #addChildSessionId (2/n)
  Fix #addChildSessionId (1/n)
  Ensure mutation to multiple objects is done atomically
parents 96650db0 b1d2b9dc
Loading
Loading
Loading
Loading
+70 −17
Original line number Diff line number Diff line
@@ -157,6 +157,7 @@ import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

public class PackageInstallerSession extends IPackageInstallerSession.Stub {
@@ -262,6 +263,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {

    private final Object mLock = new Object();

    /**
     * Used to detect and reject concurrent access to this session object to ensure mutation
     * to multiple objects like {@link #addChildSessionId} are done atomically.
     */
    private final AtomicBoolean mTransactionLock = new AtomicBoolean(false);

    /** Timestamp of the last time this session changed state  */
    @GuardedBy("mLock")
    private long updatedMillis;
@@ -3162,12 +3169,39 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
        }
    }

    private void acquireTransactionLock() {
        if (!mTransactionLock.compareAndSet(false, true)) {
            throw new UnsupportedOperationException("Concurrent access not supported");
        }
    }

    private void releaseTransactionLock() {
        mTransactionLock.compareAndSet(true, false);
    }

    @Override
    public void addChildSessionId(int childSessionId) {
        if (!params.isMultiPackage) {
            throw new IllegalStateException("Single-session " + sessionId + " can't have child.");
        }

        final PackageInstallerSession childSession = mSessionProvider.getSession(childSessionId);
        if (childSession == null || !childSession.canBeAddedAsChild(sessionId)) {
        if (childSession == null) {
            throw new IllegalStateException("Unable to add child session " + childSessionId
                    + " as it does not exist.");
        }
        if (childSession.params.isMultiPackage) {
            throw new IllegalStateException("Multi-session " + childSessionId
                    + " can't be a child.");
        }

        try {
            acquireTransactionLock();
            childSession.acquireTransactionLock();

            if (!childSession.canBeAddedAsChild(sessionId)) {
                throw new IllegalStateException("Unable to add child session " + childSessionId
                            + " as it does not exist or is in an invalid state.");
                        + " as it is in an invalid state.");
            }
            synchronized (mLock) {
                assertCallerIsOwnerOrRootLocked();
@@ -3180,22 +3214,41 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
                childSession.setParentSessionId(this.sessionId);
                addChildSessionIdLocked(childSessionId);
            }
        } finally {
            releaseTransactionLock();
            childSession.releaseTransactionLock();
        }
    }

    @Override
    public void removeChildSessionId(int sessionId) {
        final PackageInstallerSession session = mSessionProvider.getSession(sessionId);
        synchronized (mLock) {
            final int indexOfSession = mChildSessionIds.indexOfKey(sessionId);
        try {
            acquireTransactionLock();
            if (session != null) {
                session.setParentSessionId(SessionInfo.INVALID_ID);
                session.acquireTransactionLock();
            }

            synchronized (mLock) {
                assertCallerIsOwnerOrRootLocked();
                assertPreparedAndNotSealedLocked("removeChildSessionId");

                final int indexOfSession = mChildSessionIds.indexOfKey(sessionId);
                if (indexOfSession < 0) {
                    // not added in the first place; no-op
                    return;
                }
                if (session != null) {
                    session.setParentSessionId(SessionInfo.INVALID_ID);
                }
                mChildSessionIds.removeAt(indexOfSession);
            }
        } finally {
            releaseTransactionLock();
            if (session != null) {
                session.releaseTransactionLock();
            }
        }
    }

    /**