短信的接收

短信的接收, 请先看一个 Demo

    private void initReceiverSms() {
        tv_content = (TextView) findViewById(R.id.tv_content);

        receiveFilter = new IntentFilter();
        receiveFilter.addAction("android.provider.Telephony.SMS_RECEIVED");
        messageReceiver = new MessageReceiver();
        registerReceiver(messageReceiver, receiveFilter);

    }
    
    private class MessageReceiver extends BroadcastReceiver{
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")) {
                Bundle bundle = intent.getExtras();
                //使用pdu秘钥来提取一个pdus数组
                Object[] pdus = (Object[]) bundle.get("pdus");
                SmsMessage[] messages = new SmsMessage[pdus.length];

                for (int i = 0; i < messages.length; i++) {
                    messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
                }

                //获取发送方号码
                String address = messages[0].getOriginatingAddress();

                //获取短信内容
                String fullMessage = "";
                for (SmsMessage message : messages) {
                    fullMessage += message.getMessageBody();
                }

                tv_content.setText(fullMessage);
            }
        }
    }


短信接收, 需要注册 BroadcastReceiver 来接收接收到的短信信息, 该信息在 Intent 中被传递解析出来, 并进行获取. 

因为 数据时经由 modem 层向上数据传输. 应该需要经由 RIL.java. 

# RIL

 class RILReceiver implements Runnable {
        byte[] buffer;

        RILReceiver() {
            buffer = new byte[RIL_MAX_COMMAND_BYTES];
        }

        @Override
        public void
        run() {
            int retryCount = 0;
            String rilSocket = "rild";

            try {for (;;) {
                LocalSocket s = null;
                LocalSocketAddress l;
               ...
               
                riljLog("rilSocket[" + mInstanceId + "] = " + rilSocket);
                try {
                    s = new LocalSocket();
                    l = new LocalSocketAddress(rilSocket,
                            LocalSocketAddress.Namespace.RESERVED);
                    s.connect(l);
                }
                ...

                retryCount = 0;

                mSocket = s;
                Rlog.i(RILJ_LOG_TAG, "(" + mInstanceId + ") Connected to '"
                        + rilSocket + "' socket");

                ...

                int length = 0;
                try {
                    InputStream is = mSocket.getInputStream();

                    for (;;) {
                        Parcel p;

                        length = readRilMessage(is, buffer);

                        if (length < 0) {
                            // End-of-stream reached
                            break;
                        }

                        p = Parcel.obtain();
                        p.unmarshall(buffer, 0, length);
                        p.setDataPosition(0);

                        //Rlog.v(RILJ_LOG_TAG, "Read packet: " + length + " bytes");

                        processResponse(p);
                        p.recycle();
                    }
                } 
                ...

                setRadioState (RadioState.RADIO_UNAVAILABLE);

                try {
                    mSocket.close();
                } catch (IOException ex) {
                }

                mSocket = null;
                RILRequest.resetSerial();

                // Clear request list on close
                clearRequestList(RADIO_NOT_AVAILABLE, false);
            } 
            ...
            /* We're disconnected so we don't know the ril version */
            notifyRegistrantsRilConnectionChanged(-1);
        }
    }

因为 SMS 通过发送者将信息送至 modem 层, 手机上层主要是读取 modem 层的数据, 这里它们使用了 socket 来跨进程读取 modem 处的数据, 使用 Parcel 获取数据, 然后再 processResponse(p) 处理.

# RIL 
    processResponse (Parcel p) {
        int type;

        type = p.readInt();

        if (type == RESPONSE_UNSOLICITED || type == RESPONSE_UNSOLICITED_ACK_EXP) {
            processUnsolicited (p, type); //here
        } else if (type == RESPONSE_SOLICITED || type == RESPONSE_SOLICITED_ACK_EXP) {
            RILRequest rr = processSolicited (p, type);
            if (rr != null) {
                if (type == RESPONSE_SOLICITED) {
                    decrementWakeLock(rr);
                }
                rr.release();
                return;
            }
        } else if (type == RESPONSE_SOLICITED_ACK) {
            int serial;
            serial = p.readInt();

            RILRequest rr;
            synchronized (mRequestList) {
                rr = mRequestList.get(serial);
            }
            if (rr == null) {
                Rlog.w(RILJ_LOG_TAG, "Unexpected solicited ack response! sn: " + serial);
            } else {
                decrementWakeLock(rr);
                if (RILJ_LOGD) {
                    riljLog(rr.serialString() + " Ack < " + requestToString(rr.mRequest));
                }
            }
        }
    }

从这里看, 这里会对类型进行判断而区分进行下一步操作. 对于短信, 其是一种广播形式. 这里先分析  processUnsolicited (p, type);

# RIL
    private void
    processUnsolicited (Parcel p, int type) {
        int response;
        Object ret;

        response = p.readInt();
        case RIL_UNSOL_RESPONSE_NEW_SMS: ret =  responseString(p); break;
        
        switch(response) {
            case RIL_UNSOL_RESPONSE_NEW_SMS: {
                if (RILJ_LOGD) unsljLog(response);

                mEventLog.writeRilNewSms(response);

                // FIXME this should move up a layer
                String a[] = new String[2];

                a[1] = (String)ret;

                SmsMessage sms;

                sms = SmsMessage.newFromCMT(a);
                if (mGsmSmsRegistrant != null) {
                    mGsmSmsRegistrant
                        .notifyRegistrant(new AsyncResult(null, sms, null));
                }
            break;
            }
           
        }
    }

可以看出,
```

 case RIL_UNSOL_RESPONSE_NEW_SMS: ret =  responseString(p); break;

```
获取了短信接收的消息., 最后被封装到了 SmsMessage 中. 然后再上传到 Registrant. 

# Registrant

    /*package*/ void
    internalNotifyRegistrant (Object result, Throwable exception)
    {
        Handler h = getHandler();

        if (h == null) {
            clear();
            /// M: Registrant Debug Log Enhancement
            Log.d("Registrant", "internalNotifyRegistrant(): Warning! Handler is null, it could be already GCed. ( what=" + what + ", userObj=" + userObj + ", result=" + result + ", exception=" + exception + " )");
        } else {
            Message msg = Message.obtain();

            msg.what = what;
            
            msg.obj = new AsyncResult(userObj, result, exception);
            
            h.sendMessage(msg);
        }
    }

这里就很明确了, 消息需要 Handler 进行处理, 同时 msg.what = "EVENT_NEW_SMS", 所以实际的处理在 GsmInboundSmsHandler, 其继承于 InboundSmsHandler, 基类为 StateMachine. 其中 Handler h = getHandler()的 Handler 是 StateMachine 的成员变量. 事件分发 handlemessage().

# StateMachine

    public final void handleMessage(Message msg) {
                 ...

                /** Save the current message */
                mMsg = msg;

                /** State that processed the message */
                State msgProcessedState = null;
                if (mIsConstructionCompleted) {
                    /** Normal path */
                    msgProcessedState = processMsg(msg); //here
                } 
                ...
            }
        }
    }
    
    rivate final State processMsg(Message msg) {
            StateInfo curStateInfo = mStateStack[mStateStackTopIndex];
            if (mDbg) {
                mSm.log("processMsg: " + curStateInfo.state.getName());
            }

            if (isQuit(msg)) {
                transitionTo(mQuittingState);
            } else {
                //com.android.internal.util.State implements IState 
                while (!curStateInfo.state.processMessage(msg)) {

                    curStateInfo = curStateInfo.parentStateInfo;
                    if (curStateInfo == null) {
                        /**
                         * No parents left so it's not handled
                         */
                        mSm.unhandledMessage(msg);
                        break;
                    }
                    if (mDbg) {
                        mSm.log("processMsg: " + curStateInfo.state.getName());
                    }
                }
            }
            return (curStateInfo != null) ? curStateInfo.state : null;
        }

State 拥有多个子类: DefaultState, StartupState, IdleState, DeliveringState, WaitingState, 这里就看 DeliveringState 的实现

# InboundSmsHandler

private class DeliveringState extends State {
        @Override
        public void enter() {
            if (DBG) log("entering Delivering state");
        }

        @Override
        public void exit() {
            if (DBG) log("leaving Delivering state");
        }

        @Override
        public boolean processMessage(Message msg) {
            log("DeliveringState.processMessage:" + msg.what);
            switch (msg.what) { 
                case EVENT_NEW_SMS:  //here
                    // handle new SMS from RIL
                    handleNewSms((AsyncResult) msg.obj);
                    sendMessage(EVENT_RETURN_TO_IDLE);
                    return HANDLED;

                case EVENT_INJECT_SMS:
                    // handle new injected SMS
                    handleInjectSms((AsyncResult) msg.obj);
                    sendMessage(EVENT_RETURN_TO_IDLE);
                    return HANDLED;

                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;

                case EVENT_RETURN_TO_IDLE:
                    // return to idle after processing all other messages
                    transitionTo(mIdleState);
                    return HANDLED;

                case EVENT_RELEASE_WAKELOCK:
                    mWakeLock.release();    // decrement wakelock from previous entry to Idle
                    if (!mWakeLock.isHeld()) {
                        // wakelock should still be held until 3 seconds after we enter Idle
                        loge("mWakeLock released while delivering/broadcasting!");
                    }
                    return HANDLED;

                // we shouldn't get this message type in this state, log error and halt.
                case EVENT_BROADCAST_COMPLETE:
                case EVENT_START_ACCEPTING_SMS:
                default:
                    // let DefaultState handle these unexpected message types
                    return NOT_HANDLED;
            }
        }
    }

首先使用 handleNewSms, 然后再通知 Sms 系统空闲.主要看 handleNewSms().

# InboundSmsHandler

    private void handleNewSms(AsyncResult ar) {

        int result;
        try {
            SmsMessage sms = (SmsMessage) ar.result;
            result = dispatchMessage(sms.mWrappedSmsMessage);
        } catch (RuntimeException ex) {
            loge("Exception dispatching message", ex);
            result = Intents.RESULT_SMS_GENERIC_ERROR;
        }

        // RESULT_OK means that the SMS will be acknowledged by special handling,
        // e.g. for SMS-PP data download. Any other result, we should ack here.
        if (result != Activity.RESULT_OK) {
            boolean handled = (result == Intents.RESULT_SMS_HANDLED);
            notifyAndAcknowledgeLastIncomingSms(handled, result, null);
        }
    }

其首先将 SmsMessage 数据从 AsyncResult 解析出来, 接着再 dispatchMessage 分派处理.

# InboundSmsHandler

    private int dispatchMessage(SmsMessageBase smsb) {
        // If sms is null, there was a parsing error.
        if (smsb == null) {
            loge("dispatchSmsMessage: message is null");
            return Intents.RESULT_SMS_GENERIC_ERROR;
        }

        if (mSmsReceiveDisabled) {
            // Device doesn't support receiving SMS,
            log("Received short message on device which doesn't support "
                    + "receiving SMS. Ignored.");
            return Intents.RESULT_SMS_HANDLED;
        }

        // onlyCore indicates if the device is in cryptkeeper
        boolean onlyCore = false;
        try {
            onlyCore = IPackageManager.Stub.asInterface(ServiceManager.getService("package")).
                    isOnlyCoreApps();
        } catch (RemoteException e) {
        }
        if (onlyCore) {
            // Device is unable to receive SMS in encrypted state
            log("Received a short message in encrypted state. Rejecting.");
            return Intents.RESULT_SMS_GENERIC_ERROR;
        }

        return dispatchMessageRadioSpecific(smsb);
    }


 
接着针对 GSM 和 CDMA 分别在 InboundSmsHandler 的子类中进行 dispatchMessageRadioSpecific(smsb), 这里 smsb 是 sms 接收的信息.

# GsmInboundSmsHandler

protected int dispatchMessageRadioSpecific(SmsMessageBase smsb) {
        SmsMessage sms = (SmsMessage) smsb;

        if (sms.isTypeZero()) {
            // As per 3GPP TS 23.040 9.2.3.9, Type Zero messages should not be
            // Displayed/Stored/Notified. They should only be acknowledged.
            log("Received short message type 0, Don't display or store it. Send Ack");
            return Intents.RESULT_SMS_HANDLED;
        }

        // Send SMS-PP data download messages to UICC. See 3GPP TS 31.111 section 7.1.1.
        if (sms.isUsimDataDownload()) {
            UsimServiceTable ust = mPhone.getUsimServiceTable();
            return mDataDownloadHandler.handleUsimDataDownload(ust, sms);
        }

        boolean handled = false;
        if (sms.isMWISetMessage()) {
            updateMessageWaitingIndicator(sms.getNumOfVoicemails());
            handled = sms.isMwiDontStore();
            if (DBG) log("Received voice mail indicator set SMS shouldStore=" + !handled);
        } else if (sms.isMWIClearMessage()) {
            updateMessageWaitingIndicator(0);
            handled = sms.isMwiDontStore();
            if (DBG) log("Received voice mail indicator clear SMS shouldStore=" + !handled);
        }
        if (handled) {
            return Intents.RESULT_SMS_HANDLED;
        }

        if (!mStorageMonitor.isStorageAvailable() &&
                sms.getMessageClass() != SmsConstants.MessageClass.CLASS_0) {
            // It's a storable message and there's no storage available.  Bail.
            // (See TS 23.038 for a description of class 0 messages.)
            return Intents.RESULT_SMS_OUT_OF_MEMORY;
        }

        return dispatchNormalMessage(smsb);
    }


进过一系列的判断处理后, 在 dispatchNormalMessage 中进行处理

# InboundSmsHandler
   protected int dispatchNormalMessage(SmsMessageBase sms) {
        SmsHeader smsHeader = sms.getUserDataHeader();
        InboundSmsTracker tracker;

        if ((smsHeader == null) || (smsHeader.concatRef == null)) {
            // Message is not concatenated.
            int destPort = -1;
            if (smsHeader != null && smsHeader.portAddrs != null) {
                // The message was sent to a port.
                destPort = smsHeader.portAddrs.destPort;
                if (DBG) log("destination port: " + destPort);
            }

            // MTK-START
            tracker = TelephonyComponentFactory.getInstance().makeInboundSmsTracker(
                    mPhone.getSubId(), sms.getPdu(), sms.getTimestampMillis(), destPort, is3gpp2(),
                    false, sms.getDisplayOriginatingAddress(), sms.getMessageBody());
            // MTK-END
        } else {
            // Create a tracker for this message segment.
            SmsHeader.ConcatRef concatRef = smsHeader.concatRef;
            SmsHeader.PortAddrs portAddrs = smsHeader.portAddrs;
            int destPort = (portAddrs != null ? portAddrs.destPort : -1);

            // MTK-START
            tracker = TelephonyComponentFactory.getInstance().makeInboundSmsTracker(
                    mPhone.getSubId(), sms.getPdu(), sms.getTimestampMillis(), destPort, is3gpp2(),
                    sms.getDisplayOriginatingAddress(), concatRef.refNumber, concatRef.seqNumber,
                    concatRef.msgCount, false, sms.getMessageBody());
            // MTK-END
        }

        if (VDBG) log("created tracker: " + tracker);

        // de-duping is done only for text messages
        // destPort = -1 indicates text messages, otherwise it's a data sms
        return addTrackerToRawTableAndSendMessage(tracker,
                tracker.getDestPort() == -1 /* de-dup if text message */);
    }

这里将 SMSMessage 数据封装到了 InboundSmsTracker 中. 然后调用 addTrackerToRawTableAndSendMessage().

# InboundSmsHandler

 protected int addTrackerToRawTableAndSendMessage(InboundSmsTracker tracker, boolean deDup) {
        switch(addTrackerToRawTable(tracker, deDup)) {
        case Intents.RESULT_SMS_HANDLED:
            sendMessage(EVENT_BROADCAST_SMS, tracker);
            return Intents.RESULT_SMS_HANDLED;

        case Intents.RESULT_SMS_DUPLICATED:
            return Intents.RESULT_SMS_HANDLED;

        case Intents.RESULT_SMS_GENERIC_ERROR:
        default:
            return Intents.RESULT_SMS_GENERIC_ERROR;
        }
    }

这里接受短信息, 执行了

```
case Intents.RESULT_SMS_HANDLED:
            sendMessage(EVENT_BROADCAST_SMS, tracker);
            return Intents.RESULT_SMS_HANDLED;
```

针对接收短信, 其再一次进入了 DeliveringState 中, 并进行其分派行为:

# InboundSmsHandler

    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");
            endMessage(EVENT_RETURN_TO_IDLE);
        }
        return HANDLED;

这里执行 processMessagePart(), 具体实现

# InboundSmsHandler

    private boolean processMessagePart(InboundSmsTracker tracker) {
        int messageCount = tracker.getMessageCount();
        byte[][] pdus;
        int destPort = tracker.getDestPort();

        if (messageCount == 1) {
            // single-part message
            pdus = new byte[][]{tracker.getPdu()};
        } else {

            // MTK-START
            // To lock the raw table of sms database
            synchronized (mRawLock) {
            // MTK-END
                // multi-part message
                Cursor cursor = null;
                try {
                    // used by several query selection arguments
                    String address = tracker.getAddress();
                    String refNumber = Integer.toString(tracker.getReferenceNumber());
                    String count = Integer.toString(tracker.getMessageCount());
                    // MTK-START
                    String subId = Integer.toString(mPhone.getSubId());
                    // MTK-END

                    // query for all segments and broadcast message if we have all the parts
                    // MTK-START
                    String[] whereArgs = {address, refNumber, count, subId};
                    // MTK-END
                    cursor = mResolver.query(sRawUri, PDU_SEQUENCE_PORT_PROJECTION,
                            SELECT_BY_REFERENCE, whereArgs, null);

                    int cursorCount = cursor.getCount();
                    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.

                        // MTK-START
                        // Refresh the timer if receive another new concatenated segments but not
                        // finish
                        if (!SystemProperties.get("ro.mtk_bsp_package").equals("1")) {
                            if (tracker.getIndexOffset() == 1 && tracker.getDestPort() == -1) {
                                log("ConcatenatedSmsFwkExt: refresh timer, ref = " +
                                        tracker.getReferenceNumber());
                                TimerRecord record =
                                        (TimerRecord)mConcatenatedSmsFwkExt.queryTimerRecord(
                                        tracker.getAddress(), tracker.getReferenceNumber(),
                                        tracker.getMessageCount());
                                if (record == null) {
                                    log("ConcatenatedSmsFwkExt: fail to " +
                                            "get TimerRecord to refresh timer");
                                } else {
                                    mConcatenatedSmsFwkExt.refreshTimer(getHandler(), record);
                                }
                            }
                        }
                        // MTK-END
                        return false;
                    }

                    // MTK-START
                    if (!SystemProperties.get("ro.mtk_bsp_package").equals("1")) {
                        if (tracker.getIndexOffset() == 1 && tracker.getDestPort() == -1) {
                            // cancel the timer, because all segments are in place
                            log("ConcatenatedSmsFwkExt: cancel timer, ref = " +
                                    tracker.getReferenceNumber());
                            TimerRecord record =
                                    (TimerRecord)mConcatenatedSmsFwkExt.queryTimerRecord(
                                    tracker.getAddress(), tracker.getReferenceNumber(),
                                    tracker.getMessageCount());
                            if (record == null) {
                                log("ConcatenatedSmsFwkExt: fail to " +
                                        "get TimerRecord to cancel timer");
                            } else {
                                mConcatenatedSmsFwkExt.cancelTimer(getHandler(), record);
                            }
                        }
                    }
                    // MTK-END

                    // All the parts are in place, deal with them
                    pdus = new byte[messageCount][];
                    while (cursor.moveToNext()) {
                        // subtract offset to convert sequence to 0-based array index
                        int index = cursor.getInt(SEQUENCE_COLUMN) - tracker.getIndexOffset();

                        pdus[index] = HexDump.hexStringToByteArray(cursor.getString(PDU_COLUMN));

                        // Read the destination port from the first segment (needed for
                        // CDMA WAP PDU).
                        // It's not a bad idea to prefer the port from the first segment in other
                        // cases.
                        if (index == 0 && !cursor.isNull(DESTINATION_PORT_COLUMN)) {
                            int port = cursor.getInt(DESTINATION_PORT_COLUMN);
                            // strip format flags and convert to real port number, or -1
                            port = InboundSmsTracker.getRealDestPort(port);
                            if (port != -1) {
                                destPort = port;
                            }
                        }
                    }
                } catch (SQLException e) {
                    loge("Can't access multipart SMS database", e);
                    return false;
                } finally {
                    if (cursor != null) {
                        cursor.close();
                    }
                }
            }
        // MTK-START
        }
        // MTK-END

        // Do not process null pdu(s). Check for that and return false in that case.
        List<byte[]> pduList = Arrays.asList(pdus);
        if (pduList.size() == 0 || pduList.contains(null)) {
            loge("processMessagePart: returning false due to " +
                    (pduList.size() == 0 ? "pduList.size() == 0" : "pduList.contains(null)"));
            return false;
        }

        if (!mUserManager.isUserUnlocked()) {
            return processMessagePartWithUserLocked(tracker, pdus, destPort);
        }

        SmsBroadcastReceiver resultReceiver = new SmsBroadcastReceiver(tracker);

        if (destPort == SmsHeader.PORT_WAP_PUSH) {
            // Build up the data stream
            ByteArrayOutputStream output = new ByteArrayOutputStream();
            for (byte[] pdu : pdus) {
                // 3GPP needs to extract the User Data from the PDU; 3GPP2 has already done this
                if (!tracker.is3gpp2()) {
                    SmsMessage msg = SmsMessage.createFromPdu(pdu, SmsConstants.FORMAT_3GPP);
                    if (msg != null) {
                        pdu = msg.getUserData();
                    } else {
                        loge("processMessagePart: SmsMessage.createFromPdu returned null");
                        return false;
                    }
                }
                output.write(pdu, 0, pdu.length);
            }

            // MTK-START
            int result;
            // Put the extra information on bundle
            if (SmsConstants.isWapPushSupport()) {
                log("dispatch wap push pdu with addr & sc addr");
                Bundle bundle = new Bundle();
                if (!tracker.is3gpp2WapPdu()) {
                    SmsMessage sms = SmsMessage.createFromPdu(pdus[0], tracker.getFormat());
                    if (sms != null) {
                        bundle.putString(Telephony.WapPush.ADDR, sms.getOriginatingAddress());
                        String sca = sms.getServiceCenterAddress();
                        if (sca == null) {
                            /* null for app is not a item, it needs to transfer to empty string */
                            sca = "";
                        }
                        bundle.putString(Telephony.WapPush.SERVICE_ADDR, sca);
                    }
                } else {
                    //for CDMA, all info has been parsed into tracker before
                    bundle.putString(Telephony.WapPush.ADDR, tracker.getAddress());
                    bundle.putString(Telephony.WapPush.SERVICE_ADDR, "");
                }

                result = mWapPush.dispatchWapPdu(output.toByteArray(), resultReceiver, this,
                        bundle);
            } else {
                //int result = mWapPush.dispatchWapPdu(output.toByteArray(), resultReceiver, this);
                log("dispatch wap push pdu");
                result = mWapPush.dispatchWapPdu(output.toByteArray(), resultReceiver, this);
            }
            // MTK-END

            if (DBG) log("dispatchWapPdu() returned " + result);
            // result is Activity.RESULT_OK if an ordered broadcast was sent
            if (result == Activity.RESULT_OK) {
                return true;
            } else {
                deleteFromRawTable(tracker.getDeleteWhere(), tracker.getDeleteWhereArgs(),
                        MARK_DELETED);
                return false;
            }
        }

        if (BlockChecker.isBlocked(mContext, tracker.getAddress())) {
            deleteFromRawTable(tracker.getDeleteWhere(), tracker.getDeleteWhereArgs(),
                    DELETE_PERMANENTLY);
            return false;
        }

        boolean carrierAppInvoked = filterSmsWithCarrierOrSystemApp(
            pdus, destPort, tracker, resultReceiver, true /* userUnlocked */);

        if (!carrierAppInvoked) {
            // MTK-START
            dispatchSmsDeliveryIntent(pdus, tracker.getFormat(), destPort, resultReceiver,
                    IConcatenatedSmsFwkExt.UPLOAD_FLAG_NONE);
            // MTK-END
        }

        return true;
    }

首先针对短信的长度, 切割成多段来处理之. 

SmsBroadcastReceiver resultReceiver = new SmsBroadcastReceiver(tracker);  //广播接收者. 

//数据分发, 
dispatchSmsDeliveryIntent(pdus, tracker.getFormat(), destPort, resultReceiver,
                    IConcatenatedSmsFwkExt.UPLOAD_FLAG_NONE);

黑名单处理

    if (BlockChecker.isBlocked(mContext, tracker.getAddress())) {
            deleteFromRawTable(tracker.getDeleteWhere(), tracker.getDeleteWhereArgs(),
                    DELETE_PERMANENTLY);
            return false;
        }

所以实际上, 系统将数据由广播接收者再进行处理

# InboundSmsHandler

 private void dispatchSmsDeliveryIntent(byte[][] pdus, String format, int destPort,
            BroadcastReceiver resultReceiver, int longSmsUploadFlag) {
    // MTK-END
        Intent intent = new Intent();

        intent.putExtra("pdus", pdus);
        intent.putExtra("format", format);

        if (destPort == -1) {
            intent.setAction(Intents.SMS_DELIVER_ACTION);
            // Direct the intent to only the default SMS app. If we can't find a default SMS app
            // then sent it to all broadcast receivers.
            // We are deliberately delivering to the primary user's default SMS App.
            ComponentName componentName = SmsApplication.getDefaultSmsApplication(mContext, true);
            if (componentName != null) {
                // Deliver SMS message only to this receiver.
                intent.setComponent(componentName);
                log("Delivering SMS to: " + componentName.getPackageName() +
                    " " + componentName.getClassName());
            } else {
                intent.setComponent(null);
            }

            // TODO: Validate that this is the right place to store the SMS.
            if (SmsManager.getDefault().getAutoPersisting()) {
                final Uri uri = writeInboxMessage(intent);
                if (uri != null) {
                    // Pass this to SMS apps so that they know where it is stored
                    intent.putExtra("uri", uri.toString());
                }
            }

            // MTK-START
            // To check if needs to add upload flag to app
            if (!SystemProperties.get("ro.mtk_bsp_package").equals("1")) {
                int uploadFlag = longSmsUploadFlag;
                // If someone already decide to use the spcified flag, it should not change it
                if (uploadFlag == IConcatenatedSmsFwkExt.UPLOAD_FLAG_NONE) {
                    // To check if needs to add upload flag to app
                    uploadFlag = IConcatenatedSmsFwkExt.UPLOAD_FLAG_NEW;
                    SmsMessage msg = SmsMessage.createFromPdu(pdus[0], format);
                    if (msg != null) {
                        SmsHeader udh = msg.getUserDataHeader();
                        if (udh != null && udh.concatRef != null) {
                            TimerRecord tr = new TimerRecord(msg.getOriginatingAddress(),
                                    udh.concatRef.refNumber, udh.concatRef.msgCount, null);
                            // MTK-START
                            // To lock the raw table of sms database
                            synchronized (mRawLock) {
                                uploadFlag = mConcatenatedSmsFwkExt.getUploadFlag(tr);
                            }
                            // MTK-END
                        }
                    }
                    log("uploadFlag=" + uploadFlag);
                }

                if (uploadFlag == IConcatenatedSmsFwkExt.UPLOAD_FLAG_UPDATE ||
                        uploadFlag == IConcatenatedSmsFwkExt.UPLOAD_FLAG_NEW) {
                    log("dispatch all pdus with new/upload flag");
                    intent.putExtra(IConcatenatedSmsFwkExt.UPLOAD_FLAG_TAG, uploadFlag);
                }
            }

            // If Phone Privacy Lock feature turns on,
            // change and send mPhonePrivacyLockReceiver to check permission first
            // mPhonePrivacyLockReceiver -> default sms application -> others
            if (SmsConstants.isPrivacyLockSupport()) {
                // Change action as "android.intent.action.MOMS_SMS_RECEIVED" to let
                // Moms check first
                intent.setAction(Intents.PRIVACY_LOCK_SMS_RECEIVED_ACTION);
                intent.setComponent(null);
            }
            // MTK-END
        } else {
            intent.setAction(Intents.DATA_SMS_RECEIVED_ACTION);
            Uri uri = Uri.parse("sms://localhost:" + destPort);
            intent.setData(uri);
            intent.setComponent(null);
        }

        Bundle options = handleSmsWhitelisting(intent.getComponent());
        dispatchIntent(intent, android.Manifest.permission.RECEIVE_SMS,
                AppOpsManager.OP_RECEIVE_SMS, options, resultReceiver, UserHandle.SYSTEM);
    }

从上面 intent将 pdus 数据进行封装

```
    Intent intent = new Intent();
    intent.putExtra("pdus", pdus);// 这就是为什么我们要从pdus中获取数据.
    intent.putExtra("format", format);
```

短信不需要使用端口号:

if (destPort == -1) {
            intent.setAction(Intents.SMS_DELIVER_ACTION);
            // Direct the intent to only the default SMS app. If we can't find a default SMS app
            // then sent it to all broadcast receivers.
            // We are deliberately delivering to the primary user's default SMS App.
            //获取默认短信应用
            ComponentName componentName = SmsApplication.getDefaultSmsApplication(mContext, true);
            if (componentName != null) {
                // Deliver SMS message only to this receiver.
                intent.setComponent(componentName); //指定默认短信应用包名 
                log("Delivering SMS to: " + componentName.getPackageName() +
                    " " + componentName.getClassName());
            } else {
                intent.setComponent(null);
            }

            // TODO: Validate that this is the right place to store the SMS.
            //持久化处理
            if (SmsManager.getDefault().getAutoPersisting()) {
                final Uri uri = writeInboxMessage(intent);
                if (uri != null) {
                    // Pass this to SMS apps so that they know where it is stored
                    intent.putExtra("uri", uri.toString());
                }
            }
        }
    }

最后在进行行为上的分派. 

# InboundSmsHandler

    public void dispatchIntent(Intent intent, String permission, int appOp,
            Bundle opts, BroadcastReceiver resultReceiver, UserHandle user) {
        intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT);//添加标志位, 非终止
        // MTK-START
        intent.putExtra("rTime", System.currentTimeMillis()); //时间戳
        // MTK-END
        final String action = intent.getAction();
        if (Intents.SMS_DELIVER_ACTION.equals(action)
                || Intents.SMS_RECEIVED_ACTION.equals(action)
                || Intents.WAP_PUSH_DELIVER_ACTION.equals(action)
                || Intents.WAP_PUSH_RECEIVED_ACTION.equals(action)) {
            // Some intents need to be delivered with high priority:
            // SMS_DELIVER, SMS_RECEIVED, WAP_PUSH_DELIVER, WAP_PUSH_RECEIVED
            // In some situations, like after boot up or system under load, normal
            // intent delivery could take a long time.
            // This flag should only be set for intents for visible, timely operations
            // which is true for the intents above.
            intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); //提高优先级.
        }
        SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId());
        if (user.equals(UserHandle.ALL)) {//接收到的是 UserHandle.ALL
            // Get a list of currently started users.
            int[] users = null;
            try {
                users = ActivityManagerNative.getDefault().getRunningUserIds();
            } catch (RemoteException re) {
            }
            if (users == null) {
                users = new int[] {user.getIdentifier()};
            }
            // Deliver the broadcast only to those running users that are permitted
            // by user policy.
            for (int i = users.length - 1; i >= 0; i--) {
                UserHandle targetUser = new UserHandle(users[i]);
                if (users[i] != UserHandle.USER_SYSTEM) {
                    // Is the user not allowed to use SMS?
                    if (mUserManager.hasUserRestriction(UserManager.DISALLOW_SMS, targetUser)) {
                        continue;
                    }
                    // Skip unknown users and managed profiles as well
                    UserInfo info = mUserManager.getUserInfo(users[i]);
                    if (info == null || info.isManagedProfile()) {
                        continue;
                    }
                }
                // Only pass in the resultReceiver when the USER_SYSTEM is processed.
                mContext.sendOrderedBroadcastAsUser(intent, targetUser, permission, appOp, opts,
                        users[i] == UserHandle.USER_SYSTEM ? resultReceiver : null,
                        getHandler(), Activity.RESULT_OK, null, null);
            }
        } else {
            mContext.sendOrderedBroadcastAsUser(intent, user, permission, appOp, opts,
                    resultReceiver, getHandler(), Activity.RESULT_OK, null, null);
        }
    }

这里主要针对多用户进行处理, 实际这里是执行体, 

```
mContext.sendOrderedBroadcastAsUser(intent, targetUser, permission, appOp, opts, 
                         users[i] == UserHandle.USER_SYSTEM ? resultReceiver : null,
                        getHandler(), Activity.RESULT_OK, null, null);
```
这里执行的是一个有序广播.
>优点:

1,按优先级的不同,优先Receiver可对数据进行处理,并传给下一个Receiver

2,通过abortBroadcast可终止广播的传播  

看其参数:
intent: SMS_DELIVER_ACTION, SMS_RECEIVED_ACTION, FLAG_RECEIVER_FOREGROUND, FLAG_RECEIVER_NO_ABORT

targetUser: 默认就主用户吧. 不讨论

permission: android.Manifest.permission.RECEIVE_SMS

appOp: AppOpsManager.OP_RECEIVE_SMS, 应用需要该权限. 一般是默认短信应用才具有.

users[i] == UserHandle.USER_SYSTEM ? resultReceiver : null, 默认resultReceiver.

Activity.RESULT_OK: 返回的标志位. 不讨论

这里, 就可以发现, 这个有序广播发送了 SMS_RECEIVED_ACTION 信息. 这里基本上就可以明确 Demo 为什么这样写了.
 

猜你喜欢

转载自blog.csdn.net/dec_sun/article/details/82735276