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

Commit 1d442cb6 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Close logical channels when EuiccService impl app crashes / is unbound." into main

parents c0a4a335 b3dca5cc
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -749,10 +749,12 @@ public class EuiccConnector extends StateMachine implements ServiceConnection {
        @Override
        @Override
        public boolean processMessage(Message message) {
        public boolean processMessage(Message message) {
            if (message.what == CMD_SERVICE_DISCONNECTED) {
            if (message.what == CMD_SERVICE_DISCONNECTED) {
                EuiccSession.get().endAllSessions();
                mEuiccService = null;
                mEuiccService = null;
                transitionTo(mDisconnectedState);
                transitionTo(mDisconnectedState);
                return HANDLED;
                return HANDLED;
            } else if (message.what == CMD_LINGER_TIMEOUT) {
            } else if (message.what == CMD_LINGER_TIMEOUT) {
                EuiccSession.get().endAllSessions();
                unbind();
                unbind();
                transitionTo(mAvailableState);
                transitionTo(mAvailableState);
                return HANDLED;
                return HANDLED;
+52 −10
Original line number Original line Diff line number Diff line
@@ -15,6 +15,7 @@
 */
 */
package com.android.internal.telephony.euicc;
package com.android.internal.telephony.euicc;


import android.annotation.Nullable;
import android.util.ArraySet;
import android.util.ArraySet;


import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.GuardedBy;
@@ -85,14 +86,18 @@ public class EuiccSession {


    /** Returns {@code true} if there is at least one session ongoing. */
    /** Returns {@code true} if there is at least one session ongoing. */
    public boolean hasSession() {
    public boolean hasSession() {
        boolean hasSession;
        boolean hasSession = hasSessionInternal();
        synchronized(this) {
            hasSession = !mSessions.isEmpty();
        }
        Rlog.i(TAG, "hasSession: " + hasSession);
        Rlog.i(TAG, "hasSession: " + hasSession);
        return hasSession;
        return hasSession;
    }
    }


    // The bare metal implementation of hasSession() without logging.
    private boolean hasSessionInternal() {
        synchronized(this) {
            return !mSessions.isEmpty();
        }
    }

    /**
    /**
     * Notes that a logical channel may be opened by the {@code apduSender}, which will
     * Notes that a logical channel may be opened by the {@code apduSender}, which will
     * be used to close the channel when session ends (see {@link #endSession()}).
     * be used to close the channel when session ends (see {@link #endSession()}).
@@ -104,7 +109,7 @@ public class EuiccSession {
    public void noteChannelOpen(ApduSender apduSender) {
    public void noteChannelOpen(ApduSender apduSender) {
        Rlog.i(TAG, "noteChannelOpen: " + apduSender);
        Rlog.i(TAG, "noteChannelOpen: " + apduSender);
        synchronized(this) {
        synchronized(this) {
            if (hasSession()) {
            if (hasSessionInternal()) {
                mApduSenders.add(apduSender);
                mApduSenders.add(apduSender);
            }
            }
        }
        }
@@ -112,19 +117,41 @@ public class EuiccSession {


    /**
    /**
     * Marks the end of a eUICC transaction session. If this ends the last ongoing session,
     * Marks the end of a eUICC transaction session. If this ends the last ongoing session,
     * try to close the logical channel using the noted {@code apduSender}
     * try to close the logical channel using the noted {@code apduSender}s
     * (see {@link #noteChannelOpen()}).
     * (see {@link #noteChannelOpen()}).
     *
     *
     * @param sessionId The session ID.
     * @param sessionId The session ID.
     */
     */
    public void endSession(String sessionId) {
    public void endSession(String sessionId) {
        Rlog.i(TAG, "endSession: " + sessionId);
        Rlog.i(TAG, "endSession: " + sessionId);
        endSessionInternal(sessionId);
    }

    /**
     * Marks the end of all eUICC transaction sessions and close the logical
     * channels using the noted {@code apduSender}s
     * (see {@link #noteChannelOpen()}).
     *
     * <p>This is useful in global cleanup e.g. when EuiccService
     * implementation app crashes and indivial {@link #endSession()} calls
     * won't happen in {@link EuiccConnector}.
     */
    public void endAllSessions() {
        Rlog.i(TAG, "endAllSessions");
        endSessionInternal(null);
    }

    // The implementation of endSession(sessionId) or endAllSessions() when the sessionId is null,
    // without logging.
    private void endSessionInternal(@Nullable String sessionId) {
        ApduSender[] apduSenders = new ApduSender[0];
        ApduSender[] apduSenders = new ApduSender[0];
        synchronized(this) {
        synchronized(this) {
            boolean sessionRemoved = mSessions.remove(sessionId);
            boolean sessionRemoved = removeOrClear(mSessions, sessionId);
            // sessionRemoved is false if the `sessionId` was never started or there was
            // 1. sessionRemoved is false if the `sessionId` was never started or there was
            // no session at all i.e. `sessions` is empty. Don't bother invoke `apduSender`.
            // no session. Don't bother invoke `apduSender`.
            if (sessionRemoved && mSessions.isEmpty()) {
            // 2. If some session is removed, and as a result there is no more session, we
            // can clsoe channels.
            if (sessionRemoved && !hasSessionInternal()) {
                // copy mApduSenders to a local variable so we don't call closeAnyOpenChannel()
                // copy mApduSenders to a local variable so we don't call closeAnyOpenChannel()
                // which can take time in synchronized block.
                // which can take time in synchronized block.
                apduSenders = mApduSenders.toArray(apduSenders);
                apduSenders = mApduSenders.toArray(apduSenders);
@@ -136,6 +163,21 @@ public class EuiccSession {
        }
        }
    }
    }


    /**
     * Removes the given element from the set. If the element is null, clears the set.
     *
     * @return true if the set changed as a result of the call
     */
    private static boolean removeOrClear(Set<String> collection, @Nullable String element) {
        if (element == null) {
            boolean collectionChanged = !collection.isEmpty();
            collection.clear();
            return collectionChanged;
        } else {
            return collection.remove(element);
        }
    }

    @VisibleForTesting
    @VisibleForTesting
    public EuiccSession() {}
    public EuiccSession() {}
}
}
+37 −1
Original line number Original line Diff line number Diff line
@@ -103,6 +103,7 @@ public class EuiccSessionTest extends TelephonyTest {


    private EuiccSession mEuiccSession;
    private EuiccSession mEuiccSession;
    @Mock private ApduSender mApduSender;
    @Mock private ApduSender mApduSender;
    @Mock private ApduSender mApduSender2;


    @Before
    @Before
    public void setUp() throws Exception {
    public void setUp() throws Exception {
@@ -114,6 +115,7 @@ public class EuiccSessionTest extends TelephonyTest {
    public void startOneSession_featureDisabled_noop() throws Exception {
    public void startOneSession_featureDisabled_noop() throws Exception {
        mEuiccSession.startSession(SESSION_ID_1);
        mEuiccSession.startSession(SESSION_ID_1);
        mEuiccSession.noteChannelOpen(mApduSender);
        mEuiccSession.noteChannelOpen(mApduSender);
        mEuiccSession.noteChannelOpen(mApduSender2);


        assertThat(mEuiccSession.hasSession()).isFalse();
        assertThat(mEuiccSession.hasSession()).isFalse();


@@ -121,6 +123,7 @@ public class EuiccSessionTest extends TelephonyTest {


        assertThat(mEuiccSession.hasSession()).isFalse();
        assertThat(mEuiccSession.hasSession()).isFalse();
        verify(mApduSender, never()).closeAnyOpenChannel();
        verify(mApduSender, never()).closeAnyOpenChannel();
        verify(mApduSender2, never()).closeAnyOpenChannel();
    }
    }


    @Test
    @Test
@@ -128,6 +131,7 @@ public class EuiccSessionTest extends TelephonyTest {
    public void startOneSession_endSession_hasSession() throws Exception {
    public void startOneSession_endSession_hasSession() throws Exception {
        mEuiccSession.startSession(SESSION_ID_1);
        mEuiccSession.startSession(SESSION_ID_1);
        mEuiccSession.noteChannelOpen(mApduSender);
        mEuiccSession.noteChannelOpen(mApduSender);
        mEuiccSession.noteChannelOpen(mApduSender2);


        assertThat(mEuiccSession.hasSession()).isTrue();
        assertThat(mEuiccSession.hasSession()).isTrue();


@@ -140,6 +144,7 @@ public class EuiccSessionTest extends TelephonyTest {


        assertThat(mEuiccSession.hasSession()).isFalse();
        assertThat(mEuiccSession.hasSession()).isFalse();
        verify(mApduSender).closeAnyOpenChannel();
        verify(mApduSender).closeAnyOpenChannel();
        verify(mApduSender2).closeAnyOpenChannel();
    }
    }


    @Test
    @Test
@@ -164,7 +169,24 @@ public class EuiccSessionTest extends TelephonyTest {


    @Test
    @Test
    @EnableFlags(Flags.FLAG_OPTIMIZATION_APDU_SENDER)
    @EnableFlags(Flags.FLAG_OPTIMIZATION_APDU_SENDER)
    public void noteChannelOpen_noSession_noop() throws Exception {
    public void startTwoSessions_endAllSessions_hasSession() throws Exception {
        mEuiccSession.startSession(SESSION_ID_1);
        mEuiccSession.noteChannelOpen(mApduSender);
        mEuiccSession.startSession(SESSION_ID_2);
        mEuiccSession.noteChannelOpen(mApduSender2);

        assertThat(mEuiccSession.hasSession()).isTrue();

        mEuiccSession.endAllSessions();

        assertThat(mEuiccSession.hasSession()).isFalse();
        verify(mApduSender).closeAnyOpenChannel();
        verify(mApduSender2).closeAnyOpenChannel();
    }

    @Test
    @EnableFlags(Flags.FLAG_OPTIMIZATION_APDU_SENDER)
    public void noteChannelOpen_noSession_endSession_noop() throws Exception {
        // noteChannelOpen called without a session started
        // noteChannelOpen called without a session started
        mEuiccSession.noteChannelOpen(mApduSender);
        mEuiccSession.noteChannelOpen(mApduSender);


@@ -175,4 +197,18 @@ public class EuiccSessionTest extends TelephonyTest {
        assertThat(mEuiccSession.hasSession()).isFalse();
        assertThat(mEuiccSession.hasSession()).isFalse();
        verify(mApduSender, never()).closeAnyOpenChannel();
        verify(mApduSender, never()).closeAnyOpenChannel();
    }
    }

    @Test
    @EnableFlags(Flags.FLAG_OPTIMIZATION_APDU_SENDER)
    public void endAllSessions_noSession_endAllSessions_noOp() throws Exception {
        // noteChannelOpen called without a session started
        mEuiccSession.noteChannelOpen(mApduSender);

        assertThat(mEuiccSession.hasSession()).isFalse();

        mEuiccSession.endAllSessions();

        assertThat(mEuiccSession.hasSession()).isFalse();
        verify(mApduSender, never()).closeAnyOpenChannel();
    }
}
}