Telephony MT SMS/MMS FLOW

本篇文章将简单介绍 Android Mashmallow MT(Mobile Terminated) SMS/MMS 的基本流程

一、短信的接收流程

1. RILJ 收到主动上报的消息 UNSOL_RESPONSE_NEW_SMS

在RIL的处理主动上报的消息的方法processUnsolicited,会通过Registrant的方式发送通知给监听者。

mGsmSmsRegistrant.notifyRegistrant(new AsyncResult(null, sms, null));

通过搜代码可以看到GsmInboundSmsHandler在构造方法里注册监听了这条消息,phone.mCi.setOnNewGsmSms(getHandler(), EVENT_NEW_SMS, null);

来看一下GsmInboundSmsHandler这个类的注释

/**
 * This class broadcasts incoming SMS messages to interested apps after storing them in
 * the SmsProvider "raw" table and ACKing them to the SMSC. After each message has been broadcast
 */

大概意思是这个类是用来,在把接收到的短信存到raw表中之后,会发广播给感兴趣的app。并且,在短信广播之后会给短信中心SMSC发送确信消息。

额,介绍就这么多~,还是要具体看看都干啥了。咦

public class GsmInboundSmsHandler extends InboundSmsHandler

public abstract class InboundSmsHandler extends StateMachine

GsmInboundSmsHandler 是状态机的子类,对状态机不熟的可以简单参考另一篇文章哟~http://blog.csdn.net/djialin0418/article/details/51030331 

InboundSmsHandler 对这个类的介绍的注释比较多啊,一起看一下。

/**
 * This class broadcasts incoming SMS messages to interested apps after storing them in
 * the SmsProvider "raw" table and ACKing them to the SMSC. After each message has been
 * broadcast, its parts are removed from the raw table. If the device crashes after ACKing
 * but before the broadcast completes, the pending messages will be rebroadcast on the next boot.
 *
 *

The state machine starts in {@link IdleState} state. When the {@link SMSDispatcher} receives a
 * new SMS from the radio, it calls {@link #dispatchNormalMessage},
 * which sends a message to the state machine, causing the wakelock to be acquired in
 * {@link #haltedProcessMessage}, which transitions to {@link DeliveringState} state, where the message
 * is saved to the raw table, then acknowledged via the {@link SMSDispatcher} which called us.
 *
 *

After saving the SMS, if the message is complete (either single-part or the final segment
 * of a multi-part SMS), we broadcast the completed PDUs as an ordered broadcast, then transition to
 * {@link WaitingState} state to wait for the broadcast to complete. When the local
 * {@link BroadcastReceiver} is called with the result, it sends {@link #EVENT_BROADCAST_COMPLETE}
 * to the state machine, causing us to either broadcast the next pending message (if one has
 * arrived while waiting for the broadcast to complete), or to transition back to the halted state
 * after all messages are processed. Then the wakelock is released and we wait for the next SMS.
 */

主要说了啥?1.状态机的起始状态是IdleState  2. SMS会在DeliveringState存到raw表中?  3.保存完信息之后会检查信息是否完整(如果是长信息,看看各个部分是否完整?)然后把完整的PDU嵌到有序广播中发送出去。4.然后状态机会进如WaitingState等广播完成,当本地的BroadcastReceiver发送EVENT_BROADCAST_COMPLETE给状态机后,会使 广播一条短信(如果这个时候是有一条短信已经接受但是在等当前的这个广播结束),或者处理所有消息后,状态机回到会haltedState。然后wakelock会被释放,并等待下一条短信。

注释文档介绍的还是挺清晰的,下面还是看代码吧~

1. 把短信写到数据库

GsmInboundSmsHandler 处理消息 EVENT_NEW_SMS

IdleState - processMessage - 

case EVENT_NEW_SMS:

deferMessage(msg);

transitionTo(mDeliveringState);

状态机要在DeliveringState 处理这条消息 class DeliveringState extends State

    /**
     * In the delivering state, the inbound SMS is processed and stored in the raw table.
     * The message is acknowledged before we exit this state. If there is a message to broadcast,
     * transition to {@link WaitingState} state to send the ordered broadcast and wait for the
     * results. When all messages have been processed, the halting state will release the wakelock.
     */

                case EVENT_NEW_SMS:
                    handleNewSms((AsyncResult) msg.obj);
                    sendMessage(EVENT_RETURN_TO_IDLE);

在这个handleNewSms方法中会处理sms,并且处理后会调用RIL的接口来给SMSC短信中心发送确认消息

result = dispatchMessage(sms.mWrappedSmsMessage); //处理短信

notifyAndAcknowledgeLastIncomingSms(handled, result, null); //向SMSC短信中心发送确认消息

主要看一下短信是怎么被处理的

dispatchMessage -> dispatchMessageRadioSpecific(smsb) -> dispatchNormalMessage(smsb)//这里之后便是处理的重点了

InboundSmsTracker tracker;

tracker = new InboundSmsTracker(sms.getPdu(), sms.getTimestampMillis(), destPort,
                    is3gpp2(), false);

参数里面的3gpp2,3gpp是针对GSM手机的,3gpp2是针对CDMA手机的。

-> addTrackerToRawTableAndSendMessage(tracker) -> addTrackerToRawTable(tracker) //重点之一

看下注释

    /**
     * Insert a message PDU into the raw table so we can acknowledge it immediately.
     * If the device crashes before the broadcast to listeners completes, it will be delivered
     * from the raw table on the next device boot. For single-part messages, the deleteWhere
     * and deleteWhereArgs fields of the tracker will be set to delete the correct row after
     * the ordered broadcast completes.
     *
     * @param tracker the tracker to add to the raw table
     * @return true on success; false on failure to write to database
     */

ContentValues values = tracker.getContentValues();
        Uri newUri = mResolver.insert(sRawUri, values);//主要就是做了这么个事情~

这里还是要看一下getContentValues() 这个方法,看起来有利于debug

InboundSmsTracker

    ContentValues getContentValues() {
        ContentValues values = new ContentValues();
        values.put("pdu", HexDump.toHexString(mPdu));
        values.put("date", mTimestamp);
        // Always set the destination port, since it now contains message format flags.
        // Port is a 16-bit value, or -1, so clear the upper bits before setting flags.
        int destPort;
        if (mDestPort == -1) {
            destPort = DEST_PORT_FLAG_NO_PORT;
        } else {
            destPort = mDestPort & DEST_PORT_MASK;
        }
        if (mIs3gpp2) {
            destPort |= DEST_PORT_FLAG_3GPP2;
        } else {
            destPort |= DEST_PORT_FLAG_3GPP;
        }
        if (mIs3gpp2WapPdu) {
            destPort |= DEST_PORT_FLAG_3GPP2_WAP_PDU;
        }
        values.put("destination_port", destPort);
        if (mAddress != null) {
            values.put("address", mAddress);
            values.put("reference_number", mReferenceNumber);
            values.put("sequence", mSequenceNumber);
            values.put("count", mMessageCount);
        }
        return values;
    }

pdu是怎样解析的啊,3gpp还是3gpp2啊,address电话号码啊什么的。


2.写完数据库那么该发广播了吧?

短信存好后return 个RESULT_SMS_HANDLED (= 1),然后发送个消息给状态机sendMessage(EVENT_BROADCAST_SMS, tracker),之后addTrackerToRawTableAndSendMessage返回Intents.RESULT_SMS_HANDLED,那一旦返回这个,岂不是要向SMSC发送确认了,好像也没有在发送短信广播之后啊?

注释貌似在这个地方说反了哟,是先向SMSC发送确认,后发送广播。

看一下在DeliveringState中的处理
                case EVENT_BROADCAST_SMS:
                    // if any broadcasts were sent, transition to waiting state
                    InboundSmsTracker inboundSmsTracker = (InboundSmsTracker) msg.obj;
                    if (processMessagePart(inboundSmsTracker)) {
                        transitionTo(mWaitingState);
                    } else {
                        // if event is sent from SmsBroadcastUndelivered.broadcastSms(), and
                        // processMessagePart() returns false, the state machine will be stuck in
                        // DeliveringState until next message is received. Send message to
                        // transition to idle to avoid that so that wakelock can be released
                        log("No broadcast sent on processing EVENT_BROADCAST_SMS in Delivering " +
                                "state. Return to Idle state");
                        sendMessage(EVENT_RETURN_TO_IDLE);
                    }
                    return HANDLED;
字面上还是比较清晰的,如果在这里processMessagePart(inboundSmsTracker)发出广播了,那这个方法应该会return ture,然后状态机会进入WaitingState,在看一下WaitingState的注释
    /** Broadcasting state. Waits for current broadcast to complete before delivering next. */
    final WaitingState mWaitingState = new WaitingState();
应该是要等待这次广播完成,才能回到DeliveringState,之后才可以处理下一条信息。还是贴一下WaitingState的代码
                case EVENT_BROADCAST_COMPLETE:
                    // return to idle after handling all deferred messages
                    sendMessage(EVENT_RETURN_TO_IDLE);
                    transitionTo(mDeliveringState);
                    return HANDLED;
还是看一下processMessagePart(inboundSmsTracker)这个方法,从注释上看貌似只有这个SmsBroadcastUndelivered.broadcastSms()方法过来的猜会return false,然后状态机会回到
IdleState。那processMessagePart(inboundSmsTracker)到底做了啥事情呢?
    /**
     * Process the inbound SMS segment. If the message is complete, send it as an ordered
     * broadcast to interested receivers and return true. If the message is a segment of an
     * incomplete multi-part SMS, return false.
     * @param tracker the tracker containing the message segment to process
     * @return true if an ordered broadcast was sent; false if waiting for more message segments
     */
    boolean processMessagePart(InboundSmsTracker tracker) {
看来是要发广播,这里主要说了一个长短信的问题吧?就是如果一条长短信有好多部分,必须要等所有的部分都收到才能发广播,如果发了广播就会return true,否则为false。
代码比较长,不全贴了,主要说一下逻辑。首先是获得pdu,如果是短-短信,就是收到只有一条,那么pdu可以直接从tracker里面拿
            // single-part message
            pdus = new byte[][]{tracker.getPdu()};
如果是长-短信,只为先到的部分没有发广播,后到的部分跑到这里时,tracker里又没有携带先到的部分的内容,所以只能去数据库里取,为啥呢,因为刚刚存过了啊(是因为先存的啊)~
                if (cursorCount < messageCount) {
                    // Wait for the other message parts to arrive. It's also possible for the last
                    // segment to arrive before processing the EVENT_BROADCAST_SMS for one of the
                    // earlier segments. In that case, the broadcast will be sent as soon as all
                    // segments are in the table, and any later EVENT_BROADCAST_SMS messages will
                    // get a row count of 0 and return.
                    return false;
                }
上面这几句话没看懂,看懂的可以解释一下~难道可以给一个segment来发广播?说好了等segment都到齐了一起发呢~???但是从代码上是可以看出还是要等一起的。
然后new了个receiver,SmsBroadcastReceiver resultReceiver = new SmsBroadcastReceiver(tracker); 这个是用来接收广播的
在向下就是if (destPort == SmsHeader.PORT_WAP_PUSH),这个应该是处理彩信的。 那么彩信咋处理?
##通过wap push来下载,mWapPush.dispatchWapPdu(output.toByteArray(), resultReceiver, this);先不看这个,先把短信的看完。##
carrierPackages = card.getCarrierPackageNamesForIntent(
                    mContext.getPackageManager(),
                    new Intent(CarrierMessagingService.SERVICE_INTERFACE));
systemPackages =
                getSystemAppForIntent(new Intent(CarrierMessagingService.SERVICE_INTERFACE));
这两个carrierPackages和systemPackages应该是可以处理接收短信的应用路径,
可能分别对应运营商的app(通过uiccCard来获得的)和系统app(好像是可以设置默认sms app的,不清楚是不是和这个是对应的)。
优先级如下,
        if (carrierPackages != null && carrierPackages.size() == 1) {// 运营商的最高,但是数量只能是1
            log("Found carrier package.");
            CarrierSmsFilter smsFilter = new CarrierSmsFilter(pdus, destPort,
                    tracker.getFormat(), resultReceiver);
            CarrierSmsFilterCallback smsFilterCallback = new CarrierSmsFilterCallback(smsFilter);
            smsFilter.filterSms(carrierPackages.get(0), smsFilterCallback);
        } else if (systemPackages != null && systemPackages.size() == 1) {// 系统其次,数量也必须是1
            log("Found system package.");
            CarrierSmsFilter smsFilter = new CarrierSmsFilter(pdus, destPort,
                    tracker.getFormat(), resultReceiver);
            CarrierSmsFilterCallback smsFilterCallback = new CarrierSmsFilterCallback(smsFilter);
            smsFilter.filterSms(systemPackages.get(0), smsFilterCallback);
        } else {//否则就是默认的处理???
            logv("Unable to find carrier package: " + carrierPackages
                    + ", nor systemPackages: " + systemPackages);
            dispatchSmsDeliveryIntent(pdus, tracker.getFormat(), destPort, resultReceiver);
        }
这上面其实就是两种处理方式,一种是找到可用的app来接收sms,另外一种是默认的处理。先简单看一下如果有可用的app的那种。
smsFilter.filterSms(systemPackages.get(0), smsFilterCallback);
-> bindToCarrierMessagingService(mContext, carrierPackageName)
Intent intent = new Intent(CarrierMessagingService.SERVICE_INTERFACE);
-> context.bindService(intent, mCarrierMessagingServiceConnection, Context.BIND_AUTO_CREATE);
-> smsFilter是这个类的实例CarrierSmsFilter
onServiceReady(ICarrierMessagingService.Stub.asInterface(service)); //从这行代码可以看出bind的service是ICarrierMessagingService
        /**
         * Invokes the {@code carrierMessagingService} to filter messages. The filtering result is
         * delivered to {@code smsFilterCallback}.
         */
        @Override
        protected void onServiceReady(ICarrierMessagingService carrierMessagingService) {
            try {
                carrierMessagingService.filterSms(
                        new MessagePdu(Arrays.asList(mPdus)), mSmsFormat, mDestPort,
                        mPhone.getSubId(), mSmsFilterCallback);
            } catch (RemoteException e) {
                loge("Exception filtering the SMS: " + e);
                mSmsFilterCallback.onFilterComplete(true);
            }
        }
    }
跨进程调用了啊,现在要找一下刚刚被bind的那个service的代码了。
代码在 frameworks/base/core/java/android/service/carrier/CarrierMessagingService.java
     public void filterSms(MessagePdu pdu, String format, int destPort,
                           int subId, final ICarrierMessagingCallback callback) {
            onFilterSms(pdu, format, destPort, subId, new ResultCallback() {
                    @Override
                    public void onReceiveResult(final Boolean result) throws RemoteException {
                        callback.onFilterComplete(result);
                    }
                });
        }
-> onFilterSms -> callback.onReceiveResult(true) //那也没干啥啊?bind的这个service之后啥都没干啊~难道是为了验证service有没有bind成功?可以不可以通信?
这个callback是上面的smsFilterCallback,回去看下,CarrierSmsFilterCallback smsFilterCallback = new CarrierSmsFilterCallback(smsFilter);
        /**
         * This method should be called only once.
         */
        @Override
        public void onFilterComplete(boolean keepMessage) {
            mSmsFilter.disposeConnection(mContext);


            logv("onFilterComplete: keepMessage is "+ keepMessage);
            if (keepMessage) {
                dispatchSmsDeliveryIntent(mSmsFilter.mPdus, mSmsFilter.mSmsFormat,
                        mSmsFilter.mDestPort, mSmsFilter.mSmsBroadcastReceiver);
            } else {
                // Drop this SMS.
                final long token = Binder.clearCallingIdentity();
                try {
                    // Needs phone package permissions.
                    deleteFromRawTable(mSmsFilter.mSmsBroadcastReceiver.mDeleteWhere,
                            mSmsFilter.mSmsBroadcastReceiver.mDeleteWhereArgs);
                } finally {
                    Binder.restoreCallingIdentity(token);
                }
                sendMessage(EVENT_BROADCAST_COMPLETE);
            }
        }
这短代码除了有点长,还是很好理解的。bind成功就保留这条msg,没成功就丢掉即删除在raw表中的数据。看一下bind成功的处理,和默认的差不多啊~
1.dispatchSmsDeliveryIntent(mSmsFilter.mPdus, mSmsFilter.mSmsFormat,
                        mSmsFilter.mDestPort, mSmsFilter.mSmsBroadcastReceiver);
2.dispatchSmsDeliveryIntent(pdus, tracker.getFormat(), destPort, resultReceiver);
这个方法有很多有用的信息,
    /**
     * Creates and dispatches the intent to the default SMS app or the appropriate port.
     *
     * @param pdus message pdus
     * @param format the message format, typically "3gpp" or "3gpp2"
     * @param destPort the destination port
     * @param resultReceiver the receiver handling the delivery result
     */
a.
destPort == -1代表啥意思还不确定,就假设当做现在没有接收app的意思吧,然后会获取用户设置默认收发短信的app的CompnentName,然后放在intent里
intent.setAction(Intents.SMS_DELIVER_ACTION);
ComponentName componentName = SmsApplication.getDefaultSmsApplication(mContext, true);
intent.setComponent(componentName);//用户没设置default sms app, 那就set null。
然后要做sms 的持久化了,SmsManager.getDefault().getAutoPersisting(),看看它要干啥,看下注释,如果返回true的话,就自动(有条件的)保存
   /**
     * Get the value of the flag to automatically write sent/received SMS/MMS messages into system
     *
     * When this flag is on, all SMS/MMS sent/received are stored by system automatically
     * When this flag is off, only SMS/MMS sent by non-default SMS apps are stored by system
     * automatically
     *
     * @return the current value of the auto persist flag
     * {@hide}
     */
-> IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
return iMms.getAutoPersisting();//又来了,看看这个IMms.Stub在哪,有两个地方有具体实现~~~,原来是一个调用另一个,我去了,绕晕了。
-> 这个iMms应该是MmsServiceBroker的内部类,private final class BinderService extends IMms.Stub
->         public boolean getAutoPersisting() throws RemoteException {
            return getServiceGuarded().getAutoPersisting();
        }
getServiceGuarded() 这个方法要返回MmsService instance, 如果没有连接service, 那需要连一下(bindService)。现在代码还跑在Framework
-> 然后到了MmsService, 到了其他进程了, 代码目录 /packages/services/Mms/src/com/android/mms/service/MmsService.java
MmsService extends Service 
private IMms.Stub mStub = new IMms.Stub(
-> getAutoPersisting()
-> getAutoPersistingPref() // 还是写在sharedPreference里的~~~,private static final String PREF_AUTO_PERSISTING = "autopersisting";
   public boolean getAutoPersistingPref() {
        final SharedPreferences preferences = getSharedPreferences(
                SHARED_PREFERENCES_NAME, MODE_PRIVATE);
        return preferences.getBoolean(PREF_AUTO_PERSISTING, false);
    }
好长啊~要回到梦开始的地方了,如果自动持久化为true,那么会call writeInboxMessage(intent); //Store a received SMS into Telephony provider
final SmsMessage[] messages = Telephony.Sms.Intents.getMessagesFromIntent(intent);
mContext.getContentResolver().insert(Telephony.Sms.Inbox.CONTENT_URI, values);
很明显,拿出message,保存到Inbox 这个表里。
谁能帮忙解释一下下面这两句啥意思,干啥用滴?看不懂~
final long identity = Binder.clearCallingIdentity();
Binder.restoreCallingIdentity(identity);


b.
destPort == -1 为false,下面的我没看懂,要之后看看这个Uri有啥用
            intent.setAction(Intents.DATA_SMS_RECEIVED_ACTION);
            Uri uri = Uri.parse("sms://localhost:" + destPort);
            intent.setData(uri);


最后调用dispatchIntent(intent, android.Manifest.permission.RECEIVE_SMS,
                AppOpsManager.OP_RECEIVE_SMS, options, resultReceiver, UserHandle.OWNER);
if (user.equals(UserHandle.ALL)) {
                mContext.sendOrderedBroadcastAsUser(intent, targetUser, permission, appOp, opts,
                        users[i] == UserHandle.USER_OWNER ? resultReceiver : null,
                        getHandler(), Activity.RESULT_OK, null, null)
        } else {
            mContext.sendOrderedBroadcastAsUser(intent, user, permission, appOp, opts,
                    resultReceiver, getHandler(), Activity.RESULT_OK, null, null);
        }
dispatchIntent方法截取了部分代码,从调用时带入的参数UserHandle.OWNER 看,那么一直会走else这部分。好了,到现在广播也发了。下一步该干啥?看看谁收?
这个UserHandle.OWNER 和 UserHandle.ALL 能不能有人来解释一下~不懂~
好像是这个resultReceiver来接收者个广播~。虽然很长,还是全贴了吧,因为我可能说不明白~


    /**
     * 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).
     */
    private final class SmsBroadcastReceiver extends BroadcastReceiver {
        private final String mDeleteWhere;
        private final String[] mDeleteWhereArgs;
        private long mBroadcastTimeNano;


        SmsBroadcastReceiver(InboundSmsTracker tracker) {
            mDeleteWhere = tracker.getDeleteWhere();
            mDeleteWhereArgs = tracker.getDeleteWhereArgs();
            mBroadcastTimeNano = System.nanoTime();
        }


        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (action.equals(Intents.SMS_DELIVER_ACTION)) {//短信
                // Now dispatch the notification only intent
                intent.setAction(Intents.SMS_RECEIVED_ACTION);//变了
                intent.setComponent(null);
                // All running users will be notified of the received sms.
                Bundle options = handleSmsWhitelisting(null);
                dispatchIntent(intent, android.Manifest.permission.RECEIVE_SMS,
                        AppOpsManager.OP_RECEIVE_SMS, options, this, UserHandle.ALL);//变成ALL了哟~
            } 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.
                Bundle options = null;
                try {
                    long duration = mDeviceIdleController.addPowerSaveTempWhitelistAppForMms(
                            mContext.getPackageName(), 0, "mms-broadcast");
                    BroadcastOptions bopts = BroadcastOptions.makeBasic();
                    bopts.setTemporaryAppWhitelistDuration(duration);
                    options = bopts.toBundle();
                } catch (RemoteException e) {
                }
                dispatchIntent(intent, android.Manifest.permission.RECEIVE_SMS,
                        AppOpsManager.OP_RECEIVE_SMS, options, this, UserHandle.OWNER);
            } else {
                // 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);
                }


                int rc = getResultCode();
                if ((rc != Activity.RESULT_OK) && (rc != Intents.RESULT_SMS_HANDLED)) {
                    loge("a broadcast receiver set the result code to " + rc
                            + ", deleting from raw table anyway!");
                } else if (DBG) {
                    log("successful broadcast, deleting from raw table.");
                }


                deleteFromRawTable(mDeleteWhere, mDeleteWhereArgs);// 要把raw表的数据删除
                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");
                }
            }
        }
    }
EVENT_BROADCAST_COMPLETE,现在是啥状态?哦,发了广播要在WaitingState的。
                case EVENT_BROADCAST_COMPLETE:
                    // return to idle after handling all deferred messages
                    sendMessage(EVENT_RETURN_TO_IDLE);
                    transitionTo(mDeliveringState);
                    return HANDLED;


                case EVENT_RETURN_TO_IDLE:
                    // not ready to return to idle; ignore
                    return HANDLED;
额~~~~搞毛线啊~,不管了,那现在貌似没啥事了。
sms app可能收到广播后,弹出个通知,然后用户点进去的时候会查数据库,就是Inbox那个,然后就会显示出来,并且有已读未读的状态显示什么的吧,我猜的。



二、还有彩信~~~代码超长,不贴了。大部分代码看不懂,但是感觉用处不大~
if (destPort == SmsHeader.PORT_WAP_PUSH) 
mWapPush.dispatchWapPdu(output.toByteArray(), resultReceiver, this);
在流程上,关注的应该就是下面这几行了吧~
Intent intent = new Intent(Intents.WAP_PUSH_DELIVER_ACTION);//过滤处理的应用
ComponentName componentName = SmsApplication.getDefaultMmsApplication(mContext, true);//找到默认app来处理, 没有就拉倒,谁处理都行
handler.dispatchIntent(intent, permission, appOp, options, receiver, UserHandle.OWNER);//发广播~

你可能感兴趣的:(Telephony)