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

Commit f5af2699 authored by Amit Mahajan's avatar Amit Mahajan
Browse files

Add a timeout in waiting state to unblock the state machine after 30s.

This is so that if the state machine is stuck in waiting state, the
current message can be dropped and other messages can still be
processed.

Test: manual with hacks to make state machine be stuck in waiting
state
runtest --path
frameworks/opt/telephony/tests/telephonytests/src/com/android/
internal/telephony/gsm/GsmInboundSmsHandlerTest.java
--test-method testWaitingStateTimeout
Bug: 65599291
Merged-in: Ib944b28023c1225d6db8945b56eff8996d0a0248
Change-Id: Ib944b28023c1225d6db8945b56eff8996d0a0248
parent eb140d53
Loading
Loading
Loading
Loading
+47 −0
Original line number Diff line number Diff line
@@ -158,6 +158,17 @@ public abstract class InboundSmsHandler extends StateMachine {
    /** New SMS received as an AsyncResult. */
    public static final int EVENT_INJECT_SMS = 8;

    /** Update tracker object; used only in waiting state */
    private static final int EVENT_UPDATE_TRACKER = 9;

    /** Timeout in case state machine is stuck in a state for too long; used only in waiting
     * state */
    private static final int EVENT_STATE_TIMEOUT = 10;

    /** Timeout duration for EVENT_STATE_TIMEOUT */
    @VisibleForTesting
    public static final int STATE_TIMEOUT = 30000;

    /** Wakelock release delay when returning to idle state. */
    private static final int WAKELOCK_TIMEOUT = 3000;

@@ -450,6 +461,7 @@ public abstract class InboundSmsHandler extends StateMachine {
                    // if any broadcasts were sent, transition to waiting state
                    InboundSmsTracker inboundSmsTracker = (InboundSmsTracker) msg.obj;
                    if (processMessagePart(inboundSmsTracker)) {
                        sendMessage(EVENT_UPDATE_TRACKER, inboundSmsTracker);
                        transitionTo(mWaitingState);
                    } else {
                        // if event is sent from SmsBroadcastUndelivered.broadcastSms(), and
@@ -493,18 +505,41 @@ public abstract class InboundSmsHandler extends StateMachine {
     * {@link IdleState} after any deferred {@link #EVENT_BROADCAST_SMS} messages are handled.
     */
    private class WaitingState extends State {
        private InboundSmsTracker mTracker;

        @Override
        public void enter() {
            if (DBG) log("entering Waiting state");
            mTracker = null;
            sendMessageDelayed(EVENT_STATE_TIMEOUT, STATE_TIMEOUT);
        }

        @Override
        public void exit() {
            if (DBG) log("exiting Waiting state");
            // Before moving to idle state, set wakelock timeout to WAKE_LOCK_TIMEOUT milliseconds
            // to give any receivers time to take their own wake locks
            setWakeLockTimeout(WAKELOCK_TIMEOUT);
            if (VDBG) {
                if (hasMessages(EVENT_STATE_TIMEOUT)) {
                    log("exiting Waiting state: removing EVENT_STATE_TIMEOUT from message queue");
                }
                if (hasMessages(EVENT_UPDATE_TRACKER)) {
                    log("exiting Waiting state: removing EVENT_UPDATE_TRACKER from message queue");
                }
            }
            removeMessages(EVENT_STATE_TIMEOUT);
            removeMessages(EVENT_UPDATE_TRACKER);
        }

        @Override
        public boolean processMessage(Message msg) {
            log("WaitingState.processMessage:" + msg.what);
            switch (msg.what) {
                case EVENT_UPDATE_TRACKER:
                    mTracker = (InboundSmsTracker) msg.obj;
                    return HANDLED;

                case EVENT_BROADCAST_SMS:
                    // defer until the current broadcast completes
                    deferMessage(msg);
@@ -520,6 +555,18 @@ public abstract class InboundSmsHandler extends StateMachine {
                    // not ready to return to idle; ignore
                    return HANDLED;

                case EVENT_STATE_TIMEOUT:
                    // stuck in WaitingState for too long; drop the message and exit this state
                    if (mTracker != null) {
                        log("WaitingState.processMessage: EVENT_STATE_TIMEOUT; dropping message");
                        dropSms(new SmsBroadcastReceiver(mTracker));
                    } else {
                        log("WaitingState.processMessage: EVENT_STATE_TIMEOUT; mTracker is null "
                                + "- sending EVENT_BROADCAST_COMPLETE");
                        sendMessage(EVENT_BROADCAST_COMPLETE);
                    }
                    return HANDLED;

                default:
                    // parent state handles the other message types
                    return NOT_HANDLED;
+25 −1
Original line number Diff line number Diff line
@@ -47,8 +47,8 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Telephony;
import android.support.test.filters.FlakyTest;
import android.support.test.filters.MediumTest;
import android.test.mock.MockContentResolver;
import android.test.suitebuilder.annotation.MediumTest;

import com.android.internal.telephony.FakeSmsContentProvider;
import com.android.internal.telephony.InboundSmsHandler;
@@ -777,4 +777,28 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest {

        verifySmsIntentBroadcasts(0);
    }

    @FlakyTest
    @Ignore
    @Test
    @MediumTest
    public void testWaitingStateTimeout() throws Exception {
        transitionFromStartupToIdle();

        // send new SMS to state machine and verify that triggers SMS_DELIVER_ACTION
        mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS,
                new AsyncResult(null, mSmsMessage, null));
        waitForMs(100);

        ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class);
        verify(mContext, times(1)).sendBroadcast(
                intentArgumentCaptor.capture());
        assertEquals(Telephony.Sms.Intents.SMS_DELIVER_ACTION,
                intentArgumentCaptor.getAllValues().get(0).getAction());
        assertEquals("WaitingState", getCurrentState().getName());

        waitForMs(InboundSmsHandler.STATE_TIMEOUT + 300);

        assertEquals("IdleState", getCurrentState().getName());
    }
}