Loading src/java/com/android/internal/telephony/InboundSmsHandler.java +47 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading Loading @@ -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); Loading @@ -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; Loading tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java +25 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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()); } } Loading
src/java/com/android/internal/telephony/InboundSmsHandler.java +47 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading Loading @@ -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); Loading @@ -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; Loading
tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java +25 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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()); } }