Loading src/java/com/android/internal/telephony/InboundSmsHandler.java +96 −20 Original line number Diff line number Diff line Loading @@ -186,6 +186,9 @@ public abstract class InboundSmsHandler extends StateMachine { /** Update the sms tracker */ public static final int EVENT_UPDATE_TRACKER = 8; /** BroadcastReceiver timed out waiting for an intent */ public static final int EVENT_RECEIVER_TIMEOUT = 9; /** Wakelock release delay when returning to idle state. */ private static final int WAKELOCK_TIMEOUT = 3000; Loading Loading @@ -378,6 +381,9 @@ public abstract class InboundSmsHandler extends StateMachine { case EVENT_UPDATE_TRACKER: whatString = "EVENT_UPDATE_TRACKER"; break; case EVENT_RECEIVER_TIMEOUT: whatString = "EVENT_RECEIVER_TIMEOUT"; break; default: whatString = "UNKNOWN EVENT " + what; } Loading Loading @@ -631,6 +637,15 @@ public abstract class InboundSmsHandler extends StateMachine { deferMessage(msg); return HANDLED; case EVENT_RECEIVER_TIMEOUT: logeWithLocalLog("WaitingState.processMessage: received " + "EVENT_RECEIVER_TIMEOUT"); if (mLastDeliveredSmsTracker != null) { mLastDeliveredSmsTracker.getSmsBroadcastReceiver(InboundSmsHandler.this) .fakeNextAction(); } return HANDLED; case EVENT_BROADCAST_COMPLETE: mLastDeliveredSmsTracker = null; // return to idle after handling all deferred messages Loading Loading @@ -1039,7 +1054,7 @@ public abstract class InboundSmsHandler extends StateMachine { } } SmsBroadcastReceiver resultReceiver = new SmsBroadcastReceiver(tracker); SmsBroadcastReceiver resultReceiver = tracker.getSmsBroadcastReceiver(this); if (!mUserManager.isUserUnlocked()) { log("processMessagePart: !isUserUnlocked; calling processMessagePartWithUserLocked. " Loading Loading @@ -1288,7 +1303,7 @@ public abstract class InboundSmsHandler extends StateMachine { */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public void dispatchIntent(Intent intent, String permission, String appOp, Bundle opts, BroadcastReceiver resultReceiver, UserHandle user, int subId) { Bundle opts, SmsBroadcastReceiver resultReceiver, UserHandle user, int subId) { intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT); final String action = intent.getAction(); if (Intents.SMS_DELIVER_ACTION.equals(action) Loading Loading @@ -1319,6 +1334,11 @@ public abstract class InboundSmsHandler extends StateMachine { for (UserHandle handle : userHandles) { if (mUserManager.isUserRunning(handle)) { runningUserHandles.add(handle); } else { if (handle.equals(UserHandle.SYSTEM)) { logeWithLocalLog("dispatchIntent: SYSTEM user is not running", resultReceiver.mInboundSmsTracker.getMessageId()); } } } if (runningUserHandles.isEmpty()) { Loading @@ -1345,6 +1365,9 @@ public abstract class InboundSmsHandler extends StateMachine { } // Only pass in the resultReceiver when the user SYSTEM is processed. try { if (users[i] == UserHandle.SYSTEM.getIdentifier()) { resultReceiver.setWaitingForIntent(intent); } mContext.createPackageContextAsUser(mContext.getPackageName(), 0, targetUser) .sendOrderedBroadcast(intent, Activity.RESULT_OK, permission, appOp, users[i] == UserHandle.SYSTEM.getIdentifier() Loading @@ -1355,6 +1378,7 @@ public abstract class InboundSmsHandler extends StateMachine { } } else { try { resultReceiver.setWaitingForIntent(intent); mContext.createPackageContextAsUser(mContext.getPackageName(), 0, user) .sendOrderedBroadcast(intent, Activity.RESULT_OK, permission, appOp, resultReceiver, getHandler(), null /* initialData */, Loading Loading @@ -1629,27 +1653,80 @@ public abstract class InboundSmsHandler extends StateMachine { return (PHONE_TYPE_CDMA == activePhone); } @VisibleForTesting public static int sTimeoutDurationMillis = 10 * 60 * 1000; // 10 minutes /** * Handler for an {@link InboundSmsTracker} broadcast. Deletes PDUs from the raw table and * logs the broadcast duration (as an error if the other receivers were especially slow). */ @VisibleForTesting public final class SmsBroadcastReceiver extends BroadcastReceiver { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private final String mDeleteWhere; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private final String[] mDeleteWhereArgs; private long mBroadcastTimeNano; private long mBroadcastTimeMillis; public Intent mWaitingForIntent; private final InboundSmsTracker mInboundSmsTracker; SmsBroadcastReceiver(InboundSmsTracker tracker) { /** * This method must be called anytime an ordered broadcast is sent that is expected to be * received by this receiver. */ public synchronized void setWaitingForIntent(Intent intent) { mWaitingForIntent = intent; mBroadcastTimeMillis = System.currentTimeMillis(); removeMessages(EVENT_RECEIVER_TIMEOUT); sendMessageDelayed(EVENT_RECEIVER_TIMEOUT, sTimeoutDurationMillis); } public SmsBroadcastReceiver(InboundSmsTracker tracker) { mDeleteWhere = tracker.getDeleteWhere(); mDeleteWhereArgs = tracker.getDeleteWhereArgs(); mBroadcastTimeNano = System.nanoTime(); mInboundSmsTracker = tracker; } /** * This method is called if the expected intent (mWaitingForIntent) is not received and * the timer for it expires. It fakes the receipt of the intent to unblock the state * machine. */ public void fakeNextAction() { if (mWaitingForIntent != null) { logeWithLocalLog("fakeNextAction: " + mWaitingForIntent.getAction(), mInboundSmsTracker.getMessageId()); handleAction(mWaitingForIntent, false); } else { logeWithLocalLog("fakeNextAction: mWaitingForIntent is null", mInboundSmsTracker.getMessageId()); } } @Override public void onReceive(Context context, Intent intent) { handleAction(intent, true); } private synchronized void handleAction(Intent intent, boolean onReceive) { String action = intent.getAction(); if (mWaitingForIntent == null || !mWaitingForIntent.getAction().equals(action)) { logeWithLocalLog("handleAction: Received " + action + " when expecting " + mWaitingForIntent == null ? "none" : mWaitingForIntent.getAction(), mInboundSmsTracker.getMessageId()); return; } if (onReceive) { int durationMillis = (int) (System.currentTimeMillis() - mBroadcastTimeMillis); if (durationMillis >= 5000) { loge("Slow ordered broadcast completion time for " + action + ": " + durationMillis + " ms"); } else if (DBG) { log("Ordered broadcast completed for " + action + " in: " + durationMillis + " ms"); } } int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, SubscriptionManager.INVALID_SUBSCRIPTION_ID); if (action.equals(Intents.SMS_DELIVER_ACTION)) { Loading @@ -1661,6 +1738,7 @@ public abstract class InboundSmsHandler extends StateMachine { // All running users will be notified of the received sms. Bundle options = handleSmsWhitelisting(null, false /* bgActivityStartAllowed */); setWaitingForIntent(intent); dispatchIntent(intent, android.Manifest.permission.RECEIVE_SMS, AppOpsManager.OPSTR_RECEIVE_SMS, options, this, UserHandle.ALL, subId); Loading @@ -1683,6 +1761,8 @@ public abstract class InboundSmsHandler extends StateMachine { Bundle options = bopts.toBundle(); String mimeType = intent.getType(); setWaitingForIntent(intent); dispatchIntent(intent, WapPushOverSms.getPermissionForType(mimeType), WapPushOverSms.getAppOpsStringPermissionForIntent(mimeType), options, this, UserHandle.SYSTEM, subId); Loading @@ -1690,11 +1770,11 @@ public abstract class InboundSmsHandler extends StateMachine { // Now that the intents have been deleted we can clean up the PDU data. if (!Intents.DATA_SMS_RECEIVED_ACTION.equals(action) && !Intents.SMS_RECEIVED_ACTION.equals(action) && !Intents.DATA_SMS_RECEIVED_ACTION.equals(action) && !Intents.WAP_PUSH_RECEIVED_ACTION.equals(action)) { loge("unexpected BroadcastReceiver action: " + action); } if (onReceive) { int rc = getResultCode(); if ((rc != Activity.RESULT_OK) && (rc != Intents.RESULT_SMS_HANDLED)) { loge("a broadcast receiver set the result code to " + rc Loading @@ -1702,16 +1782,12 @@ public abstract class InboundSmsHandler extends StateMachine { } else if (DBG) { log("successful broadcast, deleting from raw table."); } } deleteFromRawTable(mDeleteWhere, mDeleteWhereArgs, MARK_DELETED); mWaitingForIntent = null; removeMessages(EVENT_RECEIVER_TIMEOUT); sendMessage(EVENT_BROADCAST_COMPLETE); int durationMillis = (int) ((System.nanoTime() - mBroadcastTimeNano) / 1000000); if (durationMillis >= 5000) { loge("Slow ordered broadcast completion time: " + durationMillis + " ms"); } else if (DBG) { log("ordered broadcast completed in: " + durationMillis + " ms"); } } } } Loading src/java/com/android/internal/telephony/InboundSmsTracker.java +14 −0 Original line number Diff line number Diff line Loading @@ -68,6 +68,8 @@ public class InboundSmsTracker { private String mDeleteWhere; private String[] mDeleteWhereArgs; // BroadcastReceiver associated with this tracker private InboundSmsHandler.SmsBroadcastReceiver mSmsBroadcastReceiver; /** * Copied from SmsMessageBase#getDisplayOriginatingAddress used for blocking messages. * DisplayAddress could be email address if this message was from an email gateway, otherwise Loading Loading @@ -509,4 +511,16 @@ public class InboundSmsTracker { public @InboundSmsHandler.SmsSource int getSource() { return mSmsSource; } /** * Get/create the SmsBroadcastReceiver corresponding to the current tracker. */ public InboundSmsHandler.SmsBroadcastReceiver getSmsBroadcastReceiver( InboundSmsHandler handler) { // lazy initialization if (mSmsBroadcastReceiver == null) { mSmsBroadcastReceiver = handler.new SmsBroadcastReceiver(this); } return mSmsBroadcastReceiver; } } src/java/com/android/internal/telephony/WapPushOverSms.java +2 −3 Original line number Diff line number Diff line Loading @@ -27,7 +27,6 @@ import android.app.Activity; import android.app.AppOpsManager; import android.app.BroadcastOptions; import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; Loading Loading @@ -317,8 +316,8 @@ public class WapPushOverSms implements ServiceConnection { * {@link Activity#RESULT_OK} if the message has been broadcast * to applications */ public int dispatchWapPdu(byte[] pdu, BroadcastReceiver receiver, InboundSmsHandler handler, String address, int subId, long messageId) { public int dispatchWapPdu(byte[] pdu, InboundSmsHandler.SmsBroadcastReceiver receiver, InboundSmsHandler handler, String address, int subId, long messageId) { DecodedResult result = decodeWapPdu(pdu, handler); if (result.statusCode != Activity.RESULT_OK) { return result.statusCode; Loading tests/telephonytests/src/com/android/internal/telephony/WapPushOverSmsTest.java +2 −3 Original line number Diff line number Diff line Loading @@ -29,7 +29,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.AppOpsManager; import android.content.BroadcastReceiver; import android.content.Intent; import android.os.Bundle; import android.os.UserHandle; Loading Loading @@ -92,7 +91,7 @@ public class WapPushOverSmsTest extends TelephonyTest { eq(android.Manifest.permission.RECEIVE_WAP_PUSH), eq(AppOpsManager.OPSTR_RECEIVE_WAP_PUSH), nullable(Bundle.class), isNull(BroadcastReceiver.class), isNull(InboundSmsHandler.SmsBroadcastReceiver.class), eq(UserHandle.SYSTEM), anyInt()); Intent intent = intentArgumentCaptor.getValue(); Loading Loading @@ -147,7 +146,7 @@ public class WapPushOverSmsTest extends TelephonyTest { any(String.class), any(String.class), any(Bundle.class), any(BroadcastReceiver.class), any(InboundSmsHandler.SmsBroadcastReceiver.class), any(UserHandle.class), anyInt()); } Loading tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java +97 −76 Original line number Diff line number Diff line Loading @@ -20,7 +20,6 @@ import static com.android.internal.telephony.TelephonyTestUtils.waitForMs; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Matchers.any; Loading Loading @@ -64,12 +63,10 @@ import com.android.internal.telephony.InboundSmsHandler; import com.android.internal.telephony.InboundSmsTracker; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.SmsBroadcastUndelivered; import com.android.internal.telephony.SmsConstants; import com.android.internal.telephony.SmsHeader; import com.android.internal.telephony.SmsStorageMonitor; import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.cdma.CdmaInboundSmsHandler; import com.android.internal.util.HexDump; import com.android.internal.util.IState; import com.android.internal.util.StateMachine; Loading Loading @@ -100,15 +97,10 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { @Mock private SmsHeader mSmsHeader; private InboundSmsTracker mInboundSmsTracker; private InboundSmsTracker mInboundSmsTrackerSub1; private InboundSmsTracker mInboundSmsTrackerPart1; private InboundSmsTracker mInboundSmsTrackerPart2; @Mock private InboundSmsTracker mMockInboundSmsTracker; private ContentValues mInboundSmsTrackerCV; @Mock private InboundSmsTracker mMockInboundSmsTrackerSub1; private ContentValues mInboundSmsTrackerCVSub1; @Mock private CdmaInboundSmsHandler mCdmaInboundSmsHandler; @Mock private InboundSmsHandler.SmsFilter mSmsFilter; Loading Loading @@ -143,63 +135,25 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { } /** * This is used only for InboundSmsTracker constructed through Cursor. For other cases * real objects should be used. This should be used only for tests related to * SmsBroadcastUndelivered. * This is used only for InboundSmsTracker constructed through Cursor. This should be used only * for tests related to SmsBroadcastUndelivered. Also, this adds a second tracker for multisim. */ private void createMockInboundSmsTracker() { mInboundSmsTrackerCV = new ContentValues(); mInboundSmsTrackerCV.put("destination_port", InboundSmsTracker.DEST_PORT_FLAG_NO_PORT); mInboundSmsTrackerCV.put("pdu", HexDump.toHexString(mSmsPdu)); mInboundSmsTrackerCV.put("address", "1234567890"); mInboundSmsTrackerCV.put("reference_number", 1); mInboundSmsTrackerCV.put("sequence", 1); mInboundSmsTrackerCV.put("count", 1); mInboundSmsTrackerCV.put("date", System.currentTimeMillis()); mInboundSmsTrackerCV.put("message_body", mMessageBody); mInboundSmsTrackerCV.put("display_originating_addr", "1234567890"); mInboundSmsTrackerCV.put("sub_id", mSubId0); doReturn(1).when(mMockInboundSmsTracker).getMessageCount(); doReturn(1).when(mMockInboundSmsTracker).getReferenceNumber(); doReturn("1234567890").when(mMockInboundSmsTracker).getAddress(); doReturn(1).when(mMockInboundSmsTracker).getSequenceNumber(); doReturn(1).when(mMockInboundSmsTracker).getIndexOffset(); doReturn(-1).when(mMockInboundSmsTracker).getDestPort(); doReturn(mMessageBody).when(mMockInboundSmsTracker).getMessageBody(); doReturn(mSmsPdu).when(mMockInboundSmsTracker).getPdu(); doReturn(mInboundSmsTrackerCV.get("date")).when(mMockInboundSmsTracker).getTimestamp(); doReturn(SmsConstants.FORMAT_3GPP).when(mMockInboundSmsTracker).getFormat(); doReturn(mInboundSmsTrackerCV).when(mMockInboundSmsTracker).getContentValues(); doReturn(mSubId0).when(mMockInboundSmsTracker).getSubId(); mInboundSmsTrackerCVSub1 = new ContentValues(); mInboundSmsTrackerCVSub1.put("destination_port", InboundSmsTracker.DEST_PORT_FLAG_NO_PORT); mInboundSmsTrackerCVSub1.put("pdu", HexDump.toHexString(mSmsPdu)); mInboundSmsTrackerCVSub1.put("address", "1234567890"); mInboundSmsTrackerCVSub1.put("reference_number", 1); mInboundSmsTrackerCVSub1.put("sequence", 1); mInboundSmsTrackerCVSub1.put("count", 1); mInboundSmsTrackerCVSub1.put("date", System.currentTimeMillis()); mInboundSmsTrackerCVSub1.put("message_body", mMessageBody); mInboundSmsTrackerCVSub1.put("display_originating_addr", "1234567890"); mInboundSmsTrackerCVSub1.put("sub_id", mSubId1); doReturn(1).when(mMockInboundSmsTrackerSub1).getMessageCount(); doReturn(1).when(mMockInboundSmsTrackerSub1).getReferenceNumber(); doReturn("1234567890").when(mMockInboundSmsTrackerSub1).getAddress(); doReturn(1).when(mMockInboundSmsTrackerSub1).getSequenceNumber(); doReturn(1).when(mMockInboundSmsTrackerSub1).getIndexOffset(); doReturn(-1).when(mMockInboundSmsTrackerSub1).getDestPort(); doReturn(mMessageBody).when(mMockInboundSmsTrackerSub1).getMessageBody(); doReturn(mSmsPdu).when(mMockInboundSmsTrackerSub1).getPdu(); doReturn(mInboundSmsTrackerCVSub1.get("date")).when(mMockInboundSmsTrackerSub1) .getTimestamp(); doReturn(SmsConstants.FORMAT_3GPP).when(mMockInboundSmsTrackerSub1).getFormat(); doReturn(mInboundSmsTrackerCVSub1).when(mMockInboundSmsTrackerSub1).getContentValues(); doReturn(mSubId1).when(mMockInboundSmsTrackerSub1).getSubId(); doReturn(mMockInboundSmsTracker).doReturn(mMockInboundSmsTrackerSub1) private void createInboundSmsTrackerMultiSim() { mInboundSmsTrackerSub1 = new InboundSmsTracker( mContext, mSmsPdu, /* pdu */ System.currentTimeMillis(), /* timestamp */ -1, /* destPort */ false, /* is3gpp2 */ false, /* is3gpp2WapPdu */ "1234567890", /* address */ "1234567890", /* displayAddress */ mMessageBody, /* messageBody */ false, /* isClass0 */ mSubId1, InboundSmsHandler.SOURCE_NOT_INJECTED); doReturn(mInboundSmsTracker).doReturn(mInboundSmsTrackerSub1) .when(mTelephonyComponentFactory) .makeInboundSmsTracker(any(Context.class), nullable(Cursor.class), anyBoolean()); Loading Loading @@ -241,7 +195,7 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { anyBoolean(), nullable(String.class), nullable(String.class), nullable(String.class), anyBoolean(), anyInt(), anyInt()); createMockInboundSmsTracker(); createInboundSmsTrackerMultiSim(); mContentProvider = new FakeSmsContentProvider(); ((MockContentResolver)mContext.getContentResolver()).addProvider( Loading @@ -259,6 +213,7 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { doReturn(mCdmaInboundSmsHandler).when(mPhone).getInboundSmsHandler(true); processAllMessages(); logd("setUp: complete"); } @After Loading Loading @@ -509,9 +464,10 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { intentArgumentCaptor.capture()); assertEquals(Telephony.Sms.Intents.DATA_SMS_RECEIVED_ACTION, intentArgumentCaptor.getAllValues().get(numPastBroadcasts).getAction()); assertNotEquals(0L, // TODO mock messageId correctly in InboundSmsTracker /* assertNotEquals(0L, intentArgumentCaptor.getAllValues().get(numPastBroadcasts) .getLongExtra("messageId", 0L)); .getLongExtra("messageId", 0L)); */ assertEquals("WaitingState", getCurrentState().getName()); mContextFixture.sendBroadcastToOrderedBroadcastReceivers(); Loading Loading @@ -1069,11 +1025,28 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { @MediumTest public void testBroadcastUndeliveredUserLocked() throws Exception { replaceInstance(SmsBroadcastUndelivered.class, "instance", null, null); doReturn(0).when(mMockInboundSmsTracker).getDestPort(); doReturn(2131L).when(mMockInboundSmsTracker).getMessageId(); mInboundSmsTracker = new InboundSmsTracker( mContext, mSmsPdu, /* pdu */ System.currentTimeMillis(), /* timestamp */ 0, /* destPort */ false, /* is3gpp2 */ false, /* is3gpp2WapPdu */ "1234567890", /* address */ "1234567890", /* displayAddress */ mMessageBody, /* messageBody */ false, /* isClass0 */ mSubId0, InboundSmsHandler.SOURCE_NOT_INJECTED); doReturn(mInboundSmsTracker) .when(mTelephonyComponentFactory) .makeInboundSmsTracker(any(Context.class), nullable(Cursor.class), anyBoolean()); // add a fake entry to db mContentProvider.insert(sRawUri, mMockInboundSmsTracker.getContentValues()); mContentProvider.insert(sRawUri, mInboundSmsTracker.getContentValues()); // user locked UserManager userManager = (UserManager)mContext.getSystemService(Context.USER_SERVICE); Loading Loading @@ -1110,11 +1083,27 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { @MediumTest public void testBroadcastUndeliveredUserUnlocked() throws Exception { replaceInstance(SmsBroadcastUndelivered.class, "instance", null, null); doReturn(0).when(mMockInboundSmsTracker).getDestPort(); doReturn(2131L).when(mMockInboundSmsTracker).getMessageId(); mInboundSmsTracker = new InboundSmsTracker( mContext, mSmsPdu, /* pdu */ System.currentTimeMillis(), /* timestamp */ 0, /* destPort */ false, /* is3gpp2 */ false, /* is3gpp2WapPdu */ "1234567890", /* address */ "1234567890", /* displayAddress */ mMessageBody, /* messageBody */ false, /* isClass0 */ mSubId0, InboundSmsHandler.SOURCE_NOT_INJECTED); doReturn(mInboundSmsTracker) .when(mTelephonyComponentFactory) .makeInboundSmsTracker(any(Context.class), nullable(Cursor.class), anyBoolean()); // add a fake entry to db mContentProvider.insert(sRawUri, mMockInboundSmsTracker.getContentValues()); mContentProvider.insert(sRawUri, mInboundSmsTracker.getContentValues()); SmsBroadcastUndelivered.initialize(mContext, mGsmInboundSmsHandler, mCdmaInboundSmsHandler); Loading Loading @@ -1202,8 +1191,8 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { replaceInstance(SmsBroadcastUndelivered.class, "instance", null, null); // add SMSs from different subs to db mContentProvider.insert(sRawUri, mMockInboundSmsTracker.getContentValues()); mContentProvider.insert(sRawUri, mMockInboundSmsTrackerSub1.getContentValues()); mContentProvider.insert(sRawUri, mInboundSmsTracker.getContentValues()); mContentProvider.insert(sRawUri, mInboundSmsTrackerSub1.getContentValues()); SmsBroadcastUndelivered.initialize(mContext, mGsmInboundSmsHandler, mCdmaInboundSmsHandler); // wait for ScanRawTableThread Loading @@ -1223,4 +1212,36 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { any(InboundSmsTracker.class), any(InboundSmsHandler.SmsBroadcastReceiver.class), anyBoolean(), anyBoolean(), Mockito.<List<InboundSmsHandler.SmsFilter>>any()); } @Test @MediumTest public void testBroadcastTimeout() { InboundSmsHandler.sTimeoutDurationMillis = 100; transitionFromStartupToIdle(); // send new SMS to state machine and verify that triggers SMS_DELIVER_ACTION sendNewSms(); ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class); verify(mContext).sendBroadcast(intentArgumentCaptor.capture()); Intent intent = intentArgumentCaptor.getAllValues().get(0); assertEquals(Telephony.Sms.Intents.SMS_DELIVER_ACTION, intent.getAction()); assertEquals("WaitingState", getCurrentState().getName()); // don't send broadcast back to InboundSmsHandler, instead wait for timeout waitForMs(300); processAllMessages(); intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class); verify(mContext, times(2)).sendBroadcast(intentArgumentCaptor.capture()); intent = intentArgumentCaptor.getAllValues().get(1); assertEquals(Telephony.Sms.Intents.SMS_RECEIVED_ACTION, intent.getAction()); // don't send broadcast back to InboundSmsHandler, instead wait for timeout waitForMs(300); processAllMessages(); assertEquals("IdleState", getCurrentState().getName()); } } Loading
src/java/com/android/internal/telephony/InboundSmsHandler.java +96 −20 Original line number Diff line number Diff line Loading @@ -186,6 +186,9 @@ public abstract class InboundSmsHandler extends StateMachine { /** Update the sms tracker */ public static final int EVENT_UPDATE_TRACKER = 8; /** BroadcastReceiver timed out waiting for an intent */ public static final int EVENT_RECEIVER_TIMEOUT = 9; /** Wakelock release delay when returning to idle state. */ private static final int WAKELOCK_TIMEOUT = 3000; Loading Loading @@ -378,6 +381,9 @@ public abstract class InboundSmsHandler extends StateMachine { case EVENT_UPDATE_TRACKER: whatString = "EVENT_UPDATE_TRACKER"; break; case EVENT_RECEIVER_TIMEOUT: whatString = "EVENT_RECEIVER_TIMEOUT"; break; default: whatString = "UNKNOWN EVENT " + what; } Loading Loading @@ -631,6 +637,15 @@ public abstract class InboundSmsHandler extends StateMachine { deferMessage(msg); return HANDLED; case EVENT_RECEIVER_TIMEOUT: logeWithLocalLog("WaitingState.processMessage: received " + "EVENT_RECEIVER_TIMEOUT"); if (mLastDeliveredSmsTracker != null) { mLastDeliveredSmsTracker.getSmsBroadcastReceiver(InboundSmsHandler.this) .fakeNextAction(); } return HANDLED; case EVENT_BROADCAST_COMPLETE: mLastDeliveredSmsTracker = null; // return to idle after handling all deferred messages Loading Loading @@ -1039,7 +1054,7 @@ public abstract class InboundSmsHandler extends StateMachine { } } SmsBroadcastReceiver resultReceiver = new SmsBroadcastReceiver(tracker); SmsBroadcastReceiver resultReceiver = tracker.getSmsBroadcastReceiver(this); if (!mUserManager.isUserUnlocked()) { log("processMessagePart: !isUserUnlocked; calling processMessagePartWithUserLocked. " Loading Loading @@ -1288,7 +1303,7 @@ public abstract class InboundSmsHandler extends StateMachine { */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public void dispatchIntent(Intent intent, String permission, String appOp, Bundle opts, BroadcastReceiver resultReceiver, UserHandle user, int subId) { Bundle opts, SmsBroadcastReceiver resultReceiver, UserHandle user, int subId) { intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT); final String action = intent.getAction(); if (Intents.SMS_DELIVER_ACTION.equals(action) Loading Loading @@ -1319,6 +1334,11 @@ public abstract class InboundSmsHandler extends StateMachine { for (UserHandle handle : userHandles) { if (mUserManager.isUserRunning(handle)) { runningUserHandles.add(handle); } else { if (handle.equals(UserHandle.SYSTEM)) { logeWithLocalLog("dispatchIntent: SYSTEM user is not running", resultReceiver.mInboundSmsTracker.getMessageId()); } } } if (runningUserHandles.isEmpty()) { Loading @@ -1345,6 +1365,9 @@ public abstract class InboundSmsHandler extends StateMachine { } // Only pass in the resultReceiver when the user SYSTEM is processed. try { if (users[i] == UserHandle.SYSTEM.getIdentifier()) { resultReceiver.setWaitingForIntent(intent); } mContext.createPackageContextAsUser(mContext.getPackageName(), 0, targetUser) .sendOrderedBroadcast(intent, Activity.RESULT_OK, permission, appOp, users[i] == UserHandle.SYSTEM.getIdentifier() Loading @@ -1355,6 +1378,7 @@ public abstract class InboundSmsHandler extends StateMachine { } } else { try { resultReceiver.setWaitingForIntent(intent); mContext.createPackageContextAsUser(mContext.getPackageName(), 0, user) .sendOrderedBroadcast(intent, Activity.RESULT_OK, permission, appOp, resultReceiver, getHandler(), null /* initialData */, Loading Loading @@ -1629,27 +1653,80 @@ public abstract class InboundSmsHandler extends StateMachine { return (PHONE_TYPE_CDMA == activePhone); } @VisibleForTesting public static int sTimeoutDurationMillis = 10 * 60 * 1000; // 10 minutes /** * Handler for an {@link InboundSmsTracker} broadcast. Deletes PDUs from the raw table and * logs the broadcast duration (as an error if the other receivers were especially slow). */ @VisibleForTesting public final class SmsBroadcastReceiver extends BroadcastReceiver { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private final String mDeleteWhere; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private final String[] mDeleteWhereArgs; private long mBroadcastTimeNano; private long mBroadcastTimeMillis; public Intent mWaitingForIntent; private final InboundSmsTracker mInboundSmsTracker; SmsBroadcastReceiver(InboundSmsTracker tracker) { /** * This method must be called anytime an ordered broadcast is sent that is expected to be * received by this receiver. */ public synchronized void setWaitingForIntent(Intent intent) { mWaitingForIntent = intent; mBroadcastTimeMillis = System.currentTimeMillis(); removeMessages(EVENT_RECEIVER_TIMEOUT); sendMessageDelayed(EVENT_RECEIVER_TIMEOUT, sTimeoutDurationMillis); } public SmsBroadcastReceiver(InboundSmsTracker tracker) { mDeleteWhere = tracker.getDeleteWhere(); mDeleteWhereArgs = tracker.getDeleteWhereArgs(); mBroadcastTimeNano = System.nanoTime(); mInboundSmsTracker = tracker; } /** * This method is called if the expected intent (mWaitingForIntent) is not received and * the timer for it expires. It fakes the receipt of the intent to unblock the state * machine. */ public void fakeNextAction() { if (mWaitingForIntent != null) { logeWithLocalLog("fakeNextAction: " + mWaitingForIntent.getAction(), mInboundSmsTracker.getMessageId()); handleAction(mWaitingForIntent, false); } else { logeWithLocalLog("fakeNextAction: mWaitingForIntent is null", mInboundSmsTracker.getMessageId()); } } @Override public void onReceive(Context context, Intent intent) { handleAction(intent, true); } private synchronized void handleAction(Intent intent, boolean onReceive) { String action = intent.getAction(); if (mWaitingForIntent == null || !mWaitingForIntent.getAction().equals(action)) { logeWithLocalLog("handleAction: Received " + action + " when expecting " + mWaitingForIntent == null ? "none" : mWaitingForIntent.getAction(), mInboundSmsTracker.getMessageId()); return; } if (onReceive) { int durationMillis = (int) (System.currentTimeMillis() - mBroadcastTimeMillis); if (durationMillis >= 5000) { loge("Slow ordered broadcast completion time for " + action + ": " + durationMillis + " ms"); } else if (DBG) { log("Ordered broadcast completed for " + action + " in: " + durationMillis + " ms"); } } int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, SubscriptionManager.INVALID_SUBSCRIPTION_ID); if (action.equals(Intents.SMS_DELIVER_ACTION)) { Loading @@ -1661,6 +1738,7 @@ public abstract class InboundSmsHandler extends StateMachine { // All running users will be notified of the received sms. Bundle options = handleSmsWhitelisting(null, false /* bgActivityStartAllowed */); setWaitingForIntent(intent); dispatchIntent(intent, android.Manifest.permission.RECEIVE_SMS, AppOpsManager.OPSTR_RECEIVE_SMS, options, this, UserHandle.ALL, subId); Loading @@ -1683,6 +1761,8 @@ public abstract class InboundSmsHandler extends StateMachine { Bundle options = bopts.toBundle(); String mimeType = intent.getType(); setWaitingForIntent(intent); dispatchIntent(intent, WapPushOverSms.getPermissionForType(mimeType), WapPushOverSms.getAppOpsStringPermissionForIntent(mimeType), options, this, UserHandle.SYSTEM, subId); Loading @@ -1690,11 +1770,11 @@ public abstract class InboundSmsHandler extends StateMachine { // Now that the intents have been deleted we can clean up the PDU data. if (!Intents.DATA_SMS_RECEIVED_ACTION.equals(action) && !Intents.SMS_RECEIVED_ACTION.equals(action) && !Intents.DATA_SMS_RECEIVED_ACTION.equals(action) && !Intents.WAP_PUSH_RECEIVED_ACTION.equals(action)) { loge("unexpected BroadcastReceiver action: " + action); } if (onReceive) { int rc = getResultCode(); if ((rc != Activity.RESULT_OK) && (rc != Intents.RESULT_SMS_HANDLED)) { loge("a broadcast receiver set the result code to " + rc Loading @@ -1702,16 +1782,12 @@ public abstract class InboundSmsHandler extends StateMachine { } else if (DBG) { log("successful broadcast, deleting from raw table."); } } deleteFromRawTable(mDeleteWhere, mDeleteWhereArgs, MARK_DELETED); mWaitingForIntent = null; removeMessages(EVENT_RECEIVER_TIMEOUT); sendMessage(EVENT_BROADCAST_COMPLETE); int durationMillis = (int) ((System.nanoTime() - mBroadcastTimeNano) / 1000000); if (durationMillis >= 5000) { loge("Slow ordered broadcast completion time: " + durationMillis + " ms"); } else if (DBG) { log("ordered broadcast completed in: " + durationMillis + " ms"); } } } } Loading
src/java/com/android/internal/telephony/InboundSmsTracker.java +14 −0 Original line number Diff line number Diff line Loading @@ -68,6 +68,8 @@ public class InboundSmsTracker { private String mDeleteWhere; private String[] mDeleteWhereArgs; // BroadcastReceiver associated with this tracker private InboundSmsHandler.SmsBroadcastReceiver mSmsBroadcastReceiver; /** * Copied from SmsMessageBase#getDisplayOriginatingAddress used for blocking messages. * DisplayAddress could be email address if this message was from an email gateway, otherwise Loading Loading @@ -509,4 +511,16 @@ public class InboundSmsTracker { public @InboundSmsHandler.SmsSource int getSource() { return mSmsSource; } /** * Get/create the SmsBroadcastReceiver corresponding to the current tracker. */ public InboundSmsHandler.SmsBroadcastReceiver getSmsBroadcastReceiver( InboundSmsHandler handler) { // lazy initialization if (mSmsBroadcastReceiver == null) { mSmsBroadcastReceiver = handler.new SmsBroadcastReceiver(this); } return mSmsBroadcastReceiver; } }
src/java/com/android/internal/telephony/WapPushOverSms.java +2 −3 Original line number Diff line number Diff line Loading @@ -27,7 +27,6 @@ import android.app.Activity; import android.app.AppOpsManager; import android.app.BroadcastOptions; import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; Loading Loading @@ -317,8 +316,8 @@ public class WapPushOverSms implements ServiceConnection { * {@link Activity#RESULT_OK} if the message has been broadcast * to applications */ public int dispatchWapPdu(byte[] pdu, BroadcastReceiver receiver, InboundSmsHandler handler, String address, int subId, long messageId) { public int dispatchWapPdu(byte[] pdu, InboundSmsHandler.SmsBroadcastReceiver receiver, InboundSmsHandler handler, String address, int subId, long messageId) { DecodedResult result = decodeWapPdu(pdu, handler); if (result.statusCode != Activity.RESULT_OK) { return result.statusCode; Loading
tests/telephonytests/src/com/android/internal/telephony/WapPushOverSmsTest.java +2 −3 Original line number Diff line number Diff line Loading @@ -29,7 +29,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.AppOpsManager; import android.content.BroadcastReceiver; import android.content.Intent; import android.os.Bundle; import android.os.UserHandle; Loading Loading @@ -92,7 +91,7 @@ public class WapPushOverSmsTest extends TelephonyTest { eq(android.Manifest.permission.RECEIVE_WAP_PUSH), eq(AppOpsManager.OPSTR_RECEIVE_WAP_PUSH), nullable(Bundle.class), isNull(BroadcastReceiver.class), isNull(InboundSmsHandler.SmsBroadcastReceiver.class), eq(UserHandle.SYSTEM), anyInt()); Intent intent = intentArgumentCaptor.getValue(); Loading Loading @@ -147,7 +146,7 @@ public class WapPushOverSmsTest extends TelephonyTest { any(String.class), any(String.class), any(Bundle.class), any(BroadcastReceiver.class), any(InboundSmsHandler.SmsBroadcastReceiver.class), any(UserHandle.class), anyInt()); } Loading
tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java +97 −76 Original line number Diff line number Diff line Loading @@ -20,7 +20,6 @@ import static com.android.internal.telephony.TelephonyTestUtils.waitForMs; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Matchers.any; Loading Loading @@ -64,12 +63,10 @@ import com.android.internal.telephony.InboundSmsHandler; import com.android.internal.telephony.InboundSmsTracker; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.SmsBroadcastUndelivered; import com.android.internal.telephony.SmsConstants; import com.android.internal.telephony.SmsHeader; import com.android.internal.telephony.SmsStorageMonitor; import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.cdma.CdmaInboundSmsHandler; import com.android.internal.util.HexDump; import com.android.internal.util.IState; import com.android.internal.util.StateMachine; Loading Loading @@ -100,15 +97,10 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { @Mock private SmsHeader mSmsHeader; private InboundSmsTracker mInboundSmsTracker; private InboundSmsTracker mInboundSmsTrackerSub1; private InboundSmsTracker mInboundSmsTrackerPart1; private InboundSmsTracker mInboundSmsTrackerPart2; @Mock private InboundSmsTracker mMockInboundSmsTracker; private ContentValues mInboundSmsTrackerCV; @Mock private InboundSmsTracker mMockInboundSmsTrackerSub1; private ContentValues mInboundSmsTrackerCVSub1; @Mock private CdmaInboundSmsHandler mCdmaInboundSmsHandler; @Mock private InboundSmsHandler.SmsFilter mSmsFilter; Loading Loading @@ -143,63 +135,25 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { } /** * This is used only for InboundSmsTracker constructed through Cursor. For other cases * real objects should be used. This should be used only for tests related to * SmsBroadcastUndelivered. * This is used only for InboundSmsTracker constructed through Cursor. This should be used only * for tests related to SmsBroadcastUndelivered. Also, this adds a second tracker for multisim. */ private void createMockInboundSmsTracker() { mInboundSmsTrackerCV = new ContentValues(); mInboundSmsTrackerCV.put("destination_port", InboundSmsTracker.DEST_PORT_FLAG_NO_PORT); mInboundSmsTrackerCV.put("pdu", HexDump.toHexString(mSmsPdu)); mInboundSmsTrackerCV.put("address", "1234567890"); mInboundSmsTrackerCV.put("reference_number", 1); mInboundSmsTrackerCV.put("sequence", 1); mInboundSmsTrackerCV.put("count", 1); mInboundSmsTrackerCV.put("date", System.currentTimeMillis()); mInboundSmsTrackerCV.put("message_body", mMessageBody); mInboundSmsTrackerCV.put("display_originating_addr", "1234567890"); mInboundSmsTrackerCV.put("sub_id", mSubId0); doReturn(1).when(mMockInboundSmsTracker).getMessageCount(); doReturn(1).when(mMockInboundSmsTracker).getReferenceNumber(); doReturn("1234567890").when(mMockInboundSmsTracker).getAddress(); doReturn(1).when(mMockInboundSmsTracker).getSequenceNumber(); doReturn(1).when(mMockInboundSmsTracker).getIndexOffset(); doReturn(-1).when(mMockInboundSmsTracker).getDestPort(); doReturn(mMessageBody).when(mMockInboundSmsTracker).getMessageBody(); doReturn(mSmsPdu).when(mMockInboundSmsTracker).getPdu(); doReturn(mInboundSmsTrackerCV.get("date")).when(mMockInboundSmsTracker).getTimestamp(); doReturn(SmsConstants.FORMAT_3GPP).when(mMockInboundSmsTracker).getFormat(); doReturn(mInboundSmsTrackerCV).when(mMockInboundSmsTracker).getContentValues(); doReturn(mSubId0).when(mMockInboundSmsTracker).getSubId(); mInboundSmsTrackerCVSub1 = new ContentValues(); mInboundSmsTrackerCVSub1.put("destination_port", InboundSmsTracker.DEST_PORT_FLAG_NO_PORT); mInboundSmsTrackerCVSub1.put("pdu", HexDump.toHexString(mSmsPdu)); mInboundSmsTrackerCVSub1.put("address", "1234567890"); mInboundSmsTrackerCVSub1.put("reference_number", 1); mInboundSmsTrackerCVSub1.put("sequence", 1); mInboundSmsTrackerCVSub1.put("count", 1); mInboundSmsTrackerCVSub1.put("date", System.currentTimeMillis()); mInboundSmsTrackerCVSub1.put("message_body", mMessageBody); mInboundSmsTrackerCVSub1.put("display_originating_addr", "1234567890"); mInboundSmsTrackerCVSub1.put("sub_id", mSubId1); doReturn(1).when(mMockInboundSmsTrackerSub1).getMessageCount(); doReturn(1).when(mMockInboundSmsTrackerSub1).getReferenceNumber(); doReturn("1234567890").when(mMockInboundSmsTrackerSub1).getAddress(); doReturn(1).when(mMockInboundSmsTrackerSub1).getSequenceNumber(); doReturn(1).when(mMockInboundSmsTrackerSub1).getIndexOffset(); doReturn(-1).when(mMockInboundSmsTrackerSub1).getDestPort(); doReturn(mMessageBody).when(mMockInboundSmsTrackerSub1).getMessageBody(); doReturn(mSmsPdu).when(mMockInboundSmsTrackerSub1).getPdu(); doReturn(mInboundSmsTrackerCVSub1.get("date")).when(mMockInboundSmsTrackerSub1) .getTimestamp(); doReturn(SmsConstants.FORMAT_3GPP).when(mMockInboundSmsTrackerSub1).getFormat(); doReturn(mInboundSmsTrackerCVSub1).when(mMockInboundSmsTrackerSub1).getContentValues(); doReturn(mSubId1).when(mMockInboundSmsTrackerSub1).getSubId(); doReturn(mMockInboundSmsTracker).doReturn(mMockInboundSmsTrackerSub1) private void createInboundSmsTrackerMultiSim() { mInboundSmsTrackerSub1 = new InboundSmsTracker( mContext, mSmsPdu, /* pdu */ System.currentTimeMillis(), /* timestamp */ -1, /* destPort */ false, /* is3gpp2 */ false, /* is3gpp2WapPdu */ "1234567890", /* address */ "1234567890", /* displayAddress */ mMessageBody, /* messageBody */ false, /* isClass0 */ mSubId1, InboundSmsHandler.SOURCE_NOT_INJECTED); doReturn(mInboundSmsTracker).doReturn(mInboundSmsTrackerSub1) .when(mTelephonyComponentFactory) .makeInboundSmsTracker(any(Context.class), nullable(Cursor.class), anyBoolean()); Loading Loading @@ -241,7 +195,7 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { anyBoolean(), nullable(String.class), nullable(String.class), nullable(String.class), anyBoolean(), anyInt(), anyInt()); createMockInboundSmsTracker(); createInboundSmsTrackerMultiSim(); mContentProvider = new FakeSmsContentProvider(); ((MockContentResolver)mContext.getContentResolver()).addProvider( Loading @@ -259,6 +213,7 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { doReturn(mCdmaInboundSmsHandler).when(mPhone).getInboundSmsHandler(true); processAllMessages(); logd("setUp: complete"); } @After Loading Loading @@ -509,9 +464,10 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { intentArgumentCaptor.capture()); assertEquals(Telephony.Sms.Intents.DATA_SMS_RECEIVED_ACTION, intentArgumentCaptor.getAllValues().get(numPastBroadcasts).getAction()); assertNotEquals(0L, // TODO mock messageId correctly in InboundSmsTracker /* assertNotEquals(0L, intentArgumentCaptor.getAllValues().get(numPastBroadcasts) .getLongExtra("messageId", 0L)); .getLongExtra("messageId", 0L)); */ assertEquals("WaitingState", getCurrentState().getName()); mContextFixture.sendBroadcastToOrderedBroadcastReceivers(); Loading Loading @@ -1069,11 +1025,28 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { @MediumTest public void testBroadcastUndeliveredUserLocked() throws Exception { replaceInstance(SmsBroadcastUndelivered.class, "instance", null, null); doReturn(0).when(mMockInboundSmsTracker).getDestPort(); doReturn(2131L).when(mMockInboundSmsTracker).getMessageId(); mInboundSmsTracker = new InboundSmsTracker( mContext, mSmsPdu, /* pdu */ System.currentTimeMillis(), /* timestamp */ 0, /* destPort */ false, /* is3gpp2 */ false, /* is3gpp2WapPdu */ "1234567890", /* address */ "1234567890", /* displayAddress */ mMessageBody, /* messageBody */ false, /* isClass0 */ mSubId0, InboundSmsHandler.SOURCE_NOT_INJECTED); doReturn(mInboundSmsTracker) .when(mTelephonyComponentFactory) .makeInboundSmsTracker(any(Context.class), nullable(Cursor.class), anyBoolean()); // add a fake entry to db mContentProvider.insert(sRawUri, mMockInboundSmsTracker.getContentValues()); mContentProvider.insert(sRawUri, mInboundSmsTracker.getContentValues()); // user locked UserManager userManager = (UserManager)mContext.getSystemService(Context.USER_SERVICE); Loading Loading @@ -1110,11 +1083,27 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { @MediumTest public void testBroadcastUndeliveredUserUnlocked() throws Exception { replaceInstance(SmsBroadcastUndelivered.class, "instance", null, null); doReturn(0).when(mMockInboundSmsTracker).getDestPort(); doReturn(2131L).when(mMockInboundSmsTracker).getMessageId(); mInboundSmsTracker = new InboundSmsTracker( mContext, mSmsPdu, /* pdu */ System.currentTimeMillis(), /* timestamp */ 0, /* destPort */ false, /* is3gpp2 */ false, /* is3gpp2WapPdu */ "1234567890", /* address */ "1234567890", /* displayAddress */ mMessageBody, /* messageBody */ false, /* isClass0 */ mSubId0, InboundSmsHandler.SOURCE_NOT_INJECTED); doReturn(mInboundSmsTracker) .when(mTelephonyComponentFactory) .makeInboundSmsTracker(any(Context.class), nullable(Cursor.class), anyBoolean()); // add a fake entry to db mContentProvider.insert(sRawUri, mMockInboundSmsTracker.getContentValues()); mContentProvider.insert(sRawUri, mInboundSmsTracker.getContentValues()); SmsBroadcastUndelivered.initialize(mContext, mGsmInboundSmsHandler, mCdmaInboundSmsHandler); Loading Loading @@ -1202,8 +1191,8 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { replaceInstance(SmsBroadcastUndelivered.class, "instance", null, null); // add SMSs from different subs to db mContentProvider.insert(sRawUri, mMockInboundSmsTracker.getContentValues()); mContentProvider.insert(sRawUri, mMockInboundSmsTrackerSub1.getContentValues()); mContentProvider.insert(sRawUri, mInboundSmsTracker.getContentValues()); mContentProvider.insert(sRawUri, mInboundSmsTrackerSub1.getContentValues()); SmsBroadcastUndelivered.initialize(mContext, mGsmInboundSmsHandler, mCdmaInboundSmsHandler); // wait for ScanRawTableThread Loading @@ -1223,4 +1212,36 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { any(InboundSmsTracker.class), any(InboundSmsHandler.SmsBroadcastReceiver.class), anyBoolean(), anyBoolean(), Mockito.<List<InboundSmsHandler.SmsFilter>>any()); } @Test @MediumTest public void testBroadcastTimeout() { InboundSmsHandler.sTimeoutDurationMillis = 100; transitionFromStartupToIdle(); // send new SMS to state machine and verify that triggers SMS_DELIVER_ACTION sendNewSms(); ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class); verify(mContext).sendBroadcast(intentArgumentCaptor.capture()); Intent intent = intentArgumentCaptor.getAllValues().get(0); assertEquals(Telephony.Sms.Intents.SMS_DELIVER_ACTION, intent.getAction()); assertEquals("WaitingState", getCurrentState().getName()); // don't send broadcast back to InboundSmsHandler, instead wait for timeout waitForMs(300); processAllMessages(); intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class); verify(mContext, times(2)).sendBroadcast(intentArgumentCaptor.capture()); intent = intentArgumentCaptor.getAllValues().get(1); assertEquals(Telephony.Sms.Intents.SMS_RECEIVED_ACTION, intent.getAction()); // don't send broadcast back to InboundSmsHandler, instead wait for timeout waitForMs(300); processAllMessages(); assertEquals("IdleState", getCurrentState().getName()); } }