4

I would like to intercept incomming MMS to enable mobile data. For that, I need to intercept them before any other app.

I have setup my intent filter to receive WAP_PUSH_RECEIVED_ACTION broadcasts with the highest possible priority.

But, in the Android documentation (https://developer.android.com/reference/android/provider/Telephony.Sms.Intents.html), there are the two following broadcasts:

  • WAP_PUSH_DELIVER_ACTION (Only sent to default sms app)
  • WAP_PUSH_RECEIVED_ACTION (Sent to all apps)

Please, can you tell me which of these broadcasts is sent first (WAP_PUSH_DELIVER_ACTION or WAP_PUSH_RECEIVED_ACTION) and where did you find this information ?

From where are them send in Android source code ?

Does listening for WAP_PUSH_RECEIVED_ACTION with the highest possible priority let me be the first to receive WAP PUSH broadcasts ?

Thanks

Sigma Pic
  • 91
  • 1
  • 7

1 Answers1

4

This topic seems to be not so popular! I tried to answer the question myself and I found something interesting.

Analysis

SMS and MMS reception are mainly managed in the file InboundSmsHandler.java. This file starts with a comment block that explains the SMS/MMS receiving state machine.

Here is an extract of this comment with explanations:

  1. The state machine starts in InboundSmsHandler.IdleState state.
  2. When the SMSDispatcher receives a new SMS from the radio, it calls dispatchNormalMessage(com.android.internal.telephony.SmsMessageBase), which transitions to InboundSmsHandler.DeliveringState state.
  3. From the InboundSmsHandler.DeliveringState state, processMessagePart(InboundSmsTracker tracker) is called. Within this method, if the destination port number of the SMS is SmsHeader.PORT_WAP_PUSH (in other words if the SMS is an MMS), the WapPushOverSms.dispatchWapPdu(byte[] pdu, BroadcastReceiver receiver, InboundSmsHandler handler) method is called.
  4. Inside the dispatchWapPdu method, they call InboundSmsHandler.dispatchIntent(Intent intent, String permission, int appOp, BroadcastReceiver resultReceiver, UserHandle user). They check if there is a default MMS app and if it's the case, configure the intent to only be delivered to this app.

Code:

// Direct the intent to only the default MMS app. If we can't find a default MMS app
// then sent it to all broadcast receivers.
ComponentName componentName = SmsApplication.getDefaultMmsApplication(mContext, true);
if (componentName != null) {
    // Deliver MMS message only to this receiver
    intent.setComponent(componentName);
    if (DBG) Rlog.v(TAG, "Delivering MMS to: " + componentName.getPackageName() +
            " " + componentName.getClassName());
}

handler.dispatchIntent(intent, permission, appOp, receiver, UserHandle.OWNER);
  1. Inside the dispatchIntent we have what we are looking for, the call to Context.sendOrderedBroadcastAsUser(...). So, it is this method that sends the WAP_PUSH_DELIVER_ACTION broadcast as an ordered broadcast.
  2. This broadcast is also handled (default app and SmsBroadcastReceiver) by the SmsBroadcastReceiver.onReceive(Context context, Intent intent) handler located in InboundSmsHandler.java. Inside this handler, the WAP_PUSH_DELIVER_ACTION case is processed. The intent is changed to WAP_PUSH_RECEIVED_ACTION and broadcasted again through the InboundSmsHandler.dispatchIntent(Intent intent, String permission, int appOp, BroadcastReceiver resultReceiver, UserHandle user) method. This time, not only the default app is concerned, but all interested apps.

Code:

@Override
public void onReceive(Context context, Intent intent) {
    String action = intent.getAction();
    if (action.equals(Intents.SMS_FILTER_ACTION)) {
        // ...
    } else if (action.equals(Intents.SMS_DELIVER_ACTION)) {
        // ...
    } else if (action.equals(Intents.WAP_PUSH_DELIVER_ACTION)) {
        // Now dispatch the notification only intent
        intent.setAction(Intents.WAP_PUSH_RECEIVED_ACTION);
        intent.setComponent(null);
        // Only the primary user will receive notification of incoming mms.
        // That app will do the actual downloading of the mms.
        dispatchIntent(intent, android.Manifest.permission.RECEIVE_SMS,
                AppOpsManager.OP_RECEIVE_SMS, this, UserHandle.OWNER);
    } else {
        // ...
    }
}

Conclusion (Quick answer to the original question)

When an MMS is received, WAP_PUSH_DELIVER_ACTION is broadcasted first to the default app followed by the WAP_PUSH_RECEIVED_ACTION.

Both broadcasts are ordered broadcasts that means that priorities can be used.

Well, it's a bad news for me because it also means that I cannot be the first to be notified for an incoming MMS and turn on the modile data before the MMS app is notified.

Ahh Google, with Lollipop, you make the things harder for us : Android Issue 78084 - setMobileDataEnabled removed

So, I have to look for another way in order to do that.

Sigma Pic
  • 91
  • 1
  • 7