短信的接收, 请先看一个 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{@Overridepublic 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.

# RILclass RILReceiver implements Runnable {byte[] buffer;RILReceiver() {buffer = new byte[RIL_MAX_COMMAND_BYTES];}@Overridepublic voidrun() {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 reachedbreak;}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 closeclearRequestList(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);

# RILprivate voidprocessUnsolicited (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 layerString 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*/ voidinternalNotifyRegistrant (Object result, Throwable exception){Handler h = getHandler();if (h == null) {clear();/// M: Registrant Debug Log EnhancementLog.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().

# StateMachinepublic 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 的实现

# InboundSmsHandlerprivate class DeliveringState extends State {@Overridepublic void enter() {if (DBG) log("entering Delivering state");}@Overridepublic void exit() {if (DBG) log("leaving Delivering state");}@Overridepublic boolean processMessage(Message msg) {log("DeliveringState.processMessage:" + msg.what);switch (msg.what) { case EVENT_NEW_SMS:  //here// handle new SMS from RILhandleNewSms((AsyncResult) msg.obj);sendMessage(EVENT_RETURN_TO_IDLE);return HANDLED;case EVENT_INJECT_SMS:// handle new injected SMShandleInjectSms((AsyncResult) msg.obj);sendMessage(EVENT_RETURN_TO_IDLE);return HANDLED;case EVENT_BROADCAST_SMS:// if any broadcasts were sent, transition to waiting stateInboundSmsTracker 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 releasedlog("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 messagestransitionTo(mIdleState);return HANDLED;case EVENT_RELEASE_WAKELOCK:mWakeLock.release();    // decrement wakelock from previous entry to Idleif (!mWakeLock.isHeld()) {// wakelock should still be held until 3 seconds after we enter Idleloge("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 typesreturn NOT_HANDLED;}}}

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

# InboundSmsHandlerprivate 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 分派处理.

# InboundSmsHandlerprivate 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 cryptkeeperboolean onlyCore = false;try {onlyCore = IPackageManager.Stub.asInterface(ServiceManager.getService("package")).isOnlyCoreApps();} catch (RemoteException e) {}if (onlyCore) {// Device is unable to receive SMS in encrypted statelog("Received a short message in encrypted state. Rejecting.");return Intents.RESULT_SMS_GENERIC_ERROR;}return dispatchMessageRadioSpecific(smsb);}

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

# GsmInboundSmsHandlerprotected 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 中进行处理

# InboundSmsHandlerprotected 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-STARTtracker = 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-STARTtracker = 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 smsreturn addTrackerToRawTableAndSendMessage(tracker,tracker.getDestPort() == -1 /* de-dup if text message */);}

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

# InboundSmsHandlerprotected 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 中, 并进行其分派行为:

# InboundSmsHandlercase EVENT_BROADCAST_SMS:// if any broadcasts were sent, transition to waiting stateInboundSmsTracker 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 releasedlog("No broadcast sent on processing EVENT_BROADCAST_SMS in Delivering " +state. Return to Idle state");endMessage(EVENT_RETURN_TO_IDLE);}return HANDLED;

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

# InboundSmsHandlerprivate boolean processMessagePart(InboundSmsTracker tracker) {int messageCount = tracker.getMessageCount();byte[][] pdus;int destPort = tracker.getDestPort();if (messageCount == 1) {// single-part messagepdus = new byte[][]{tracker.getPdu()};} else {// MTK-START// To lock the raw table of sms databasesynchronized (mRawLock) {// MTK-END// multi-part messageCursor cursor = null;try {// used by several query selection argumentsString address = tracker.getAddress();String refNumber = Integer.toString(tracker.getReferenceNumber());String count = Integer.toString(tracker.getMessageCount());// MTK-STARTString subId = Integer.toString(mPhone.getSubId());// MTK-END// query for all segments and broadcast message if we have all the parts// MTK-STARTString[] whereArgs = {address, refNumber, count, subId};// MTK-ENDcursor = 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// finishif (!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-ENDreturn false;}// MTK-STARTif (!SystemProperties.get("ro.mtk_bsp_package").equals("1")) {if (tracker.getIndexOffset() == 1 && tracker.getDestPort() == -1) {// cancel the timer, because all segments are in placelog("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 thempdus = new byte[messageCount][];while (cursor.moveToNext()) {// subtract offset to convert sequence to 0-based array indexint 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 -1port = 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 streamByteArrayOutputStream output = new ByteArrayOutputStream();for (byte[] pdu : pdus) {// 3GPP needs to extract the User Data from the PDU; 3GPP2 has already done thisif (!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-STARTint result;// Put the extra information on bundleif (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 beforebundle.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-ENDif (DBG) log("dispatchWapPdu() returned " + result);// result is Activity.RESULT_OK if an ordered broadcast was sentif (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-STARTdispatchSmsDeliveryIntent(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;}

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

# InboundSmsHandlerprivate void dispatchSmsDeliveryIntent(byte[][] pdus, String format, int destPort,BroadcastReceiver resultReceiver, int longSmsUploadFlag) {// MTK-ENDIntent 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 storedintent.putExtra("uri", uri.toString());}}// MTK-START// To check if needs to add upload flag to appif (!SystemProperties.get("ro.mtk_bsp_package").equals("1")) {int uploadFlag = longSmsUploadFlag;// If someone already decide to use the spcified flag, it should not change itif (uploadFlag == IConcatenatedSmsFwkExt.UPLOAD_FLAG_NONE) {// To check if needs to add upload flag to appuploadFlag = 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 databasesynchronized (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 -> othersif (SmsConstants.isPrivacyLockSupport()) {// Change action as "android.intent.action.MOMS_SMS_RECEIVED" to let// Moms check firstintent.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 storedintent.putExtra("uri", uri.toString());}}}}

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

# InboundSmsHandlerpublic void dispatchIntent(Intent intent, String permission, int appOp,Bundle opts, BroadcastReceiver resultReceiver, UserHandle user) {intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT);//添加标志位, 非终止// MTK-STARTintent.putExtra("rTime", System.currentTimeMillis()); //时间戳// MTK-ENDfinal 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 wellUserInfo 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 为什么这样写了.

Android:短信的接收相关推荐

  1. android短信接收流程

    信息的接收工作是由底层来完成的,当有一个 新的信息时底层完成接收后会以Intent的方式来通知上层应用,信息的相关内容也包含在Intent当中,Android所支持的信息Intent都定义在andro ...

  2. Android之发送短信和接收验证码

    最近项目需求需要发送短信和接收验证码并将验证码显示在输入框中 以下是我的记录 前提---权限 <uses-permission android:name="android.permis ...

  3. Android短信操作(通过内容提供者)

    2019独角兽企业重金招聘Python工程师标准>>> 1.Android短信数据库表结构 URI主要有: content://sms/               所有短信 con ...

  4. Android 短信解析

    URI主要有: content://sms/               所有短信 content://sms/inbox        收件箱 content://sms/sent         ...

  5. android 手机短信恢复,Android短信如何恢复

    Android短信如何恢复?虽然当下微信使用非常普及,但不少重要事项还是会使用短信进行沟通的,比如快递密码箱ID提醒.信用卡还款提醒.验证码等.其目的是确保一定收到,不会因断网.未登陆等消息消失.所以 ...

  6. Android短信拦截机制适配的坑(下)--4.4以上系统,主要是6.0

    前一篇文章,Android短信拦截机制适配的坑(上)--4.4以下系统 介绍了广播接收的顺序,但是我明确说明在4.4以下系统,那么4.4及以上系统会遇到说明问题呢? 首先我们要来了解4.4系统短信的机 ...

  7. Android短信收到,语音播报

    发送短信功能界面 /*** 发送短信Demo* * @description:* @author ldm* @date 2016-4-22 上午9:07:53*/ public class SmsAc ...

  8. android 短信 字符 执行,Android短信中的特殊字符

    我已经观察了这个问题多年,现在不知道它来自哪里.我担心这个bug在2011年的新版Android中仍然可以观察到,并且我希望如果不解决它,我终于可以帮助我完全理解它.Android短信中的特殊字符 让 ...

  9. Android短信的发送和广播接收者实现短信的监听

    Android短信的发送和广播接收者实现短信的监听  要注意Android清单中权限的设置以及广播的注册监听实现 以下就是 Android清单的XML AndroidManifest.xml < ...

最新文章

  1. EcologyEvolution|微生物功能多样性从概念到应用
  2. serv-u 自定义html,Serv-U架设教程_Serv-U使用教程图文版
  3. asp.net mvc请求响应模型原理回顾
  4. 多头注意力机制的理解
  5. layui 渲染select下拉选项 ,日期控件的用法
  6. 考前建议:好好看一下 《网络工程师考试案例动手实验营》附录A
  7. Android搜索手机文件
  8. 微信公众平台如何获得openid
  9. 52 - 算法 - LeetCode 20 数据结构类 stack
  10. Advice只有切面化之后才能显现出AOP的巨大优势
  11. 使用matplotlib绘制高级图表
  12. get/post在线接口
  13. VUE微信开放平台实现网站微信登陆
  14. lisp块改色_关于CAD制图的技巧:篇九,快速修改颜色。
  15. T3677 道生一——dfs
  16. Bomb Game(题目地址链接:https://acs.jxnu.edu.cn/problem/NOIOPJCH02011661)
  17. pytorch Bus error (core dumped)
  18. unreal4 源码引言
  19. 【19/04/18 膜赛】土豪聪要请客(stol)
  20. ps在html中的应用程序,Photoshop在网页设计中的应用与方法

热门文章

  1. 动手深度学习13——计算机视觉:数据增广、图片分类
  2. Probability|Given UVA - 11181
  3. LED屏幕上轮流显示三色条纹、彩虹、四叶草(数组与内存映射的采用)
  4. linux下qt响应全局热键,Qt全局热键(windows篇)(使用RegisterHotKey和句柄进行注册)...
  5. 综合日语第一册第九课
  6. 乐高凯德机器人_乐高机器人体验课
  7. python自动生成ppt_用Python自动化生成倒计时图片
  8. 如何调试Kubernetes集群中的网络延迟问题
  9. VAD实现-读取语音数据、数据预处理、算法计算流程与框架
  10. 测试之全流程质量保证