Android6.0的SMS(短信)源码分析--短信接收
1?????SMS接收流程
Android6.0中對短信的處理比起老版本還是變化有點大的。在分析源代碼之前,我們可以先猜測一下Android中接收短信的大致流程。首先根據之前分析phone應用的經驗,猜測最先接收到短信消息的肯定是Modem,接著上報的RILJ,RILJ在通知到XXXTracker,之后也許會有個SmsManager的東西作統一管理,再之后就是App層。當然,這僅僅是猜測,到底是不是需要看代碼。
1.1???從RILJ開始
RILJ與RILD以及Modem的交互方式在之前的phone應用分析中就已經詳細敘述了,這里直接從RILJ開始。由于接收短信底層主動上報的消息(非URC消息),因此由RILJ. processUnsolicited()處理。我們已經知道processUnsolicited()對消息的處理基本上都是分兩個步驟的:1,解析出消息包;2,將詳細包通知到其Registrant。如下:
| ??? private void ??? processUnsolicited (Parcel p) { ??????? int response; ??????? Object ret; ? ??????? response = p.readInt(); ? ??????? try {switch(response) { ????????????…… ?????????? //這里其實針對的是GSM短信 ????????????case RIL_UNSOL_RESPONSE_NEW_SMS: ret =? responseString(p); break; ??????????? case RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT: ret =? responseString(p); break; ??????????? case RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM: ret =? responseInts(p); break; ????????????…… ??????????? //新來CDMA短信 ????????????case RIL_UNSOL_RESPONSE_CDMA_NEW_SMS:? ret =? responseCdmaSms(p);?break; ? ??????????case RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS:? ret =? responseRaw(p); break; ??????????? case RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL:? ret =? responseVoid(p); break; ????????????…… ??????? }} catch (Throwable tr) { ??????????? Rlog.e(RILJ_LOG_TAG, "Exception processing unsol response: " + response + ??????????????? "Exception:" + tr.toString()); ??????????? return; ??????? } ? ??????? switch(response) { ????????????…… ??????????? //對GSM短信的處理,其實就是通知其注冊者 ????????????case RIL_UNSOL_RESPONSE_NEW_SMS:?{ ??????????????? if (RILJ_LOGD) unsljLog(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_STATUS_REPORT: ??????????????? if (RILJ_LOGD) unsljLogRet(response, ret); ? ??????????????? if (mSmsStatusRegistrant != null) { ??????????????????? mSmsStatusRegistrant.notifyRegistrant( ??????????????????????????? new AsyncResult(null, ret, null)); ??????????????? } ??????????? break; ??????????? case RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM: ??????????????? if (RILJ_LOGD) unsljLogRet(response, ret); ? ??????????????? int[] smsIndex = (int[])ret; ? ??????????????? if(smsIndex.length == 1) { ??????????????????? if (mSmsOnSimRegistrant != null) { ??????????????????????? mSmsOnSimRegistrant. ??????????????????????????????? notifyRegistrant(new AsyncResult(null, smsIndex, null)); ??????????????????? } ??????????????? } else { ??????????????????? if (RILJ_LOGD) riljLog(" NEW_SMS_ON_SIM ERROR with wrong length " ??????????????????????????? + smsIndex.length); ??????????????? } ??????????? break; ????????????…… ? ??????????? case RIL_UNSOL_SIM_SMS_STORAGE_FULL: ??????????????? if (RILJ_LOGD) unsljLog(response); ? ??????????????? if (mIccSmsFullRegistrant != null) { ??????????????????? mIccSmsFullRegistrant.notifyRegistrant(); ??????????????? } ??????????????? break; ? ???????????…… ????????????//對新來CDMA短信的處理,也是通知其注冊者 ??????????? case RIL_UNSOL_RESPONSE_CDMA_NEW_SMS: ??????????????? if (RILJ_LOGD) unsljLog(response); ? ??????????????? SmsMessage sms = (SmsMessage) ret; ? ??????????????? if (mCdmaSmsRegistrant != null) { ???????????????? ???mCdmaSmsRegistrant ????????????????????????.notifyRegistrant(new AsyncResult(null, sms, null)); ??????????????? } ??????????????? break; ? ??????????? case RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS: ??????????????? if (RILJ_LOGD) unsljLogvRet(response, IccUtils.bytesToHexString((byte[])ret)); ? ??????????????? if (mGsmBroadcastSmsRegistrant != null) { ??????????????????? mGsmBroadcastSmsRegistrant ??????????????????????? .notifyRegistrant(new AsyncResult(null, ret, null)); ??????????????? } ??????????????? break; ? ??????????? case RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL: ??????????????? if (RILJ_LOGD) unsljLog(response); ? ??????????????? if (mIccSmsFullRegistrant != null) { ??????????????????? mIccSmsFullRegistrant.notifyRegistrant(); ??????????????? } ??????????? ????break; ????????????…… ??????? } ??? } |
可以看到,對于不同類型的短信是作了區分處理,GSM短信通知給了mGsmSmsRegistrant,而CDMA短信通知給了mCdmaSmsRegistrant。在之前本博客對UICC卡的分析文章中:一張UICC卡是對應一個phone的,一個Phone對應一個RILJ。那這里就有點奇怪了,為什么一個RILJ會同時對GSM和CDMA短信作處理呢?難道一個RILJ有可能管理兩個RILD么?這塊還有待研究。
接著之前的分析,RILJ到底將來短信的消息通知給了誰呢,查找代碼發現并沒有XXXRegistrant.add()的地方,倒是有這樣的一個函數,
| ?? @Override ? ??public void setOnNewCdmaSms(Handler h, int what, Object obj) { ??????? mCdmaSmsRegistrant = new Registrant (h, what, obj); ??? } |
在之前的phone應用分析中其實也遇到過這樣的注冊方式,通過這樣的方式其實就是明確指出了只有一個注冊者會接收此通知消息。在SoureInsight中查找方法的調用者發現CdmaInboundSmsHandler在器構造方法中調用了注冊函數。
| ?? ?private CdmaInboundSmsHandler(Context context, SmsStorageMonitor storageMonitor, ??????????? PhoneBase phone, CdmaSMSDispatcher smsDispatcher) { ??????? super("CdmaInboundSmsHandler", context, storageMonitor, phone, ??????????????? CellBroadcastHandler.makeCellBroadcastHandler(context, phone)); ??????? mSmsDispatcher = smsDispatcher; ??????? mServiceCategoryProgramHandler = CdmaServiceCategoryProgramHandler.makeScpHandler(context, ??????????????? phone.mCi); ???????//設置為RIL_UNSOL_RESPONSE_CDMA_NEW_SMS的監聽者 ????????phone.mCi.setOnNewCdmaSms(getHandler(), EVENT_NEW_SMS, null); ??? } |
當RILJ接收RIL_UNSOL_RESPONSE_CDMA_NEW_SMS,向CdmaInboundSmsHandler發出了一個EVENT_NEW_SMS的廣播。根據phone應用分析的callTacker的分析經驗,這種Event消息是在Handler的HandleMessage()中去處理。查找整個CdmaInboundSmsHandler及其父類InboundSmsHandler發現并沒用重載handleMessage()方法。倒是發現InboundSmsHandler繼承了StateMachine。關于stateMachine在之前的netd中有接觸過,其具體內容將在以后分析。以下是摘自網絡的一點內容:
StateMachine是一個層次狀態機(hierarchical state machine):一個狀態可以有多個子狀態的狀態機。狀態機中的狀態須繼承基類State,并實現成員函數processMessage,從而對收到的 Message進行處理;其它可選實現的成員函數為enter()、exit()和getName()。函數enter和exit相當于面向對象編程里的 “狀態”的構造和析構函數。函數getName用于返回狀態的名稱,多用于調試目的。
狀態機有多少子狀態,可在構建狀態機時,使用addState(State state, State parent)來添加所有的子狀態,構建出一個層次狀態關系。初始狀態可由setInitialState函數指定。 使用者應調用StateMachine的start函數讓狀態機進入工作狀態:初始化狀態堆棧,調用初始狀態(包括其父狀態)的enter函數等。
其實說白了就是狀態機會根據所處的不同狀態調用不同的“HandleMessage()”(這里只是為了更好的說明,其實準確的名字應該是processMessage(),其中的轉換一想就明了了),并且狀態機的各種狀態之間是可以相互轉換的。
這里InboundSmsHandler繼承了StateMachine,并且實現了以下五種狀態。
| /** ???? * This parent state throws an exception (for debug builds) or prints an error for unhandled ???? * message types. ???? */ //這種狀態在運行時基本上不會存在 ??? class DefaultState extends State { ??????? @Override ??????? public boolean processMessage(Message msg) { ??????????? switch (msg.what) { ??????????????? case EVENT_UPDATE_PHONE_OBJECT: { ??????????????????? onUpdatePhoneObject((PhoneBase) msg.obj); ??????????????????? break; ??????????????? } ??????????????? default: { ??????????????????? String errorText = "processMessage: unhandled message type " + msg.what + ??????????????????????? " currState=" + getCurrentState().getName(); ??????????????????? if (Build.IS_DEBUGGABLE) { ??????????????????????? loge("---- Dumping InboundSmsHandler ----"); ??????????????????????? loge("Total records=" + getLogRecCount()); ??????????????????????? for (int i = Math.max(getLogRecSize() - 20, 0); i < getLogRecSize(); i++) { ??????????????????????????? loge("Rec[%d]: %s\n" + i + getLogRec(i).toString()); ??????????????????????? } ??????????????????????? loge("---- Dumped InboundSmsHandler ----"); ? ??????????????????????? throw new RuntimeException(errorText); ??????????????????? } else { ??????????????????????? loge(errorText); ??????????????????? } ??????????????????? break; ??????????????? } ??????????? } ??????????? return HANDLED; ??????? } ??? } |
開啟過程中的狀態
| /** ???? * The Startup state waits for {@link SmsBroadcastUndelivered} to process the raw table and ???? * notify the state machine to broadcast any complete PDUs that might not have been broadcast. ???? */ ??? class StartupState extends State { ??????? @Override ??????? public boolean processMessage(Message msg) { ??????????? log("StartupState.processMessage:" + msg.what); ??????????? switch (msg.what) { ??????????????? case EVENT_NEW_SMS: ??????????????? case EVENT_INJECT_SMS: ??????????????? case EVENT_BROADCAST_SMS: ????????????????????deferMessage(msg);//這里其實就是延遲處理的意思 ??????????????????? return HANDLED; ? ??????????????? case EVENT_START_ACCEPTING_SMS://開始接受短信,便是準備好 ????????????????????transitionTo(mIdleState);//切換到idle狀態,時刻準備著 ??????????????????? return HANDLED; ? ??????????????? case EVENT_BROADCAST_COMPLETE: ??????????????? case EVENT_RETURN_TO_IDLE: ??????????????? case EVENT_RELEASE_WAKELOCK: ??????????????? default: ??????????????????? // let DefaultState handle these unexpected message types ??????????????????? return NOT_HANDLED; ??????????? } ???? ???} ??? } |
接著是Idle狀態,在沒有短信的時候處于這個狀態。
| /** ???? * In the idle state the wakelock is released until a new SM arrives, then we transition ???? * to Delivering mode to handle it, acquiring the wakelock on exit. ???? */ ??? class IdleState extends State { ??????? @Override ??????? public void enter() { ??????????? if (DBG) log("entering Idle state"); ??????????? sendMessageDelayed(EVENT_RELEASE_WAKELOCK, WAKELOCK_TIMEOUT); ??????? } ? ??????? @Override ??????? public void exit() { ??????????? mWakeLock.acquire(); ?????????? ?if (DBG) log("acquired wakelock, leaving Idle state"); ??????? } ? ??????? @Override ????????public boolean processMessage(Message msg)?{ ??????????? log("IdleState.processMessage:" + msg.what); ??????????? if (DBG) log("Idle state processing message type " + msg.what); ??????????? switch (msg.what) { ??????????????? case EVENT_NEW_SMS://新短信來了,注意這里沒有break,意味著什么你懂的 ??????????????? case EVENT_INJECT_SMS: ??????????????? case EVENT_BROADCAST_SMS: ????????????????????deferMessage(msg);//延遲處理 ?????????????????? ?transitionTo(mDeliveringState);//將狀態切換到投遞狀態 ??????????????????? return HANDLED; ? ??????????????? case EVENT_RELEASE_WAKELOCK: ??????????????????? mWakeLock.release(); ??????????????????? if (DBG) { ??????????????????????? if (mWakeLock.isHeld()) { ?????? ?????????????????????// this is okay as long as we call release() for every acquire() ??????????????????????????? log("mWakeLock is still held after release"); ??????????????????????? } else { ??????????????????????????? log("mWakeLock released"); ??????? ????????????????} ??????????????????? } ??????????????????? return HANDLED; ? ??????????????? case EVENT_RETURN_TO_IDLE: ??????????????????? // already in idle state; ignore ??????????????????? return HANDLED; ? ??????????????? case EVENT_BROADCAST_COMPLETE: ??????????????? case EVENT_START_ACCEPTING_SMS: ??????????????? default: ??????????????????? // let DefaultState handle these unexpected message types ??????????????????? return NOT_HANDLED; ??????????? } ??????? } ??? } |
接著是投遞狀態,短信投遞的核心工作都是在此狀態下完成的。
| /** ???? * 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. ???? */ ??? 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://新短信 ????????????????????// handle new SMS from RIL ????????????????????handleNewSms((AsyncResult) msg.obj);//委托此方法做具體處理 ??????????????????? //投遞完畢,返回Idle狀態,注意這里的方式并不是直接調用transitionTo,//因為在handleNewSms()過程中狀態可能已經發生變化 ????????????????????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; ??????????????// handleNewSm()會進入到這里作真正的核心處理 ????????????????case EVENT_BROADCAST_SMS://開始想App發送廣播 ????????????????????// 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; ??????????? } ??????? } ??? } |
WaitingState狀態其實指明已經有短信正在廣播,此時來一條短信,當然需要等到第一條短信廣播完畢才能繼續發送廣播了
| ? /** ???? * The waiting state delegates handling of new SMS to parent {@link DeliveringState}, but ???? * defers handling of the {@link #EVENT_BROADCAST_SMS} phase until after the current ???? * result receiver sends {@link #EVENT_BROADCAST_COMPLETE}. Before transitioning to ???? * {@link DeliveringState}, {@link #EVENT_RETURN_TO_IDLE} is sent to transition to ???? * {@link IdleState} after any deferred {@link #EVENT_BROADCAST_SMS} messages are handled. ???? */ ??? class WaitingState extends State { ??????? @Override ??????? public boolean processMessage(Message msg) { ??????????? log("WaitingState.processMessage:" + msg.what); ??????????? switch (msg.what) { ????????????????case EVENT_BROADCAST_SMS://廣播過程中 ????????????????????// defer until the current broadcast completes ????????????????????deferMessage(msg);//已有短信正在廣播,新短信延遲發送, ??????????????????? return HANDLED; ? ????????????????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; ? ??????????????? default: ??????????????????? // parent state handles the other message types ??????????????????? return NOT_HANDLED; ??????????? } ??? ????} ??? } |
至此,RILJ到StateMachine在廣播給上層App的流程大概如下圖所示:
當然,還有幾個細節需要具體討論:1,短信消息是如何廣播出去的?2,到底是誰接收了這個廣播?
1.2???StateMachine投遞廣播
根據上一節的分析,DeliveringState狀態下調用了handleNewSms((AsyncResult)msg.obj);對新來短信做了處理,這節就從這里展開。首先來看handleNewSms()。
| void handleNewSms(AsyncResult ar) { ??????? if (ar.exception != null) { ??????????? loge("Exception processing incoming SMS: " + ar.exception); ??????????? return; ??????? } ? ??????? int result; ??????? try { ????????????SmsMessage sms = (SmsMessage) ar.result;//解析出短信 ????????????result = dispatchMessage(sms.mWrappedSmsMessage);//dispatch短信 ??????? } 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,然后dispatch
| ??? public 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; ??????? } ? ??????? return?dispatchMessageRadioSpecific(smsb);//這里 ??? } |
dispatchMessageRadioSpecific(smsb)其實是過濾一些特殊的短信,對于一些特殊的短信走的是特殊的處理,非特殊短信則直接放行讓后面的函數處理。dispatchMessageRadioSpecific為抽象方法,在子類中實現。
| ????/** ???? * Process Cell Broadcast, Voicemail Notification, and other 3GPP/3GPP2-specific messages. ???? * @param smsb the SmsMessageBase object from the RIL ???? * @return true if the message was handled here; false to continue processing ???? */ ??? @Override ??? protected int dispatchMessageRadioSpecific(SmsMessageBase smsb) { ??????? if (isInEmergencyCallMode()) { ? ??????????return Activity.RESULT_OK; ??????? } ? ????????SmsMessage sms = (SmsMessage) smsb; ??????? boolean isBroadcastType = (SmsEnvelope.MESSAGE_TYPE_BROADCAST == sms.getMessageType()); ? ????????// Handle CMAS emergency broadcast messages. ??????? if (isBroadcastType) { ??????????? log("Broadcast type message"); ??????????? SmsCbMessage cbMessage = sms.parseBroadcastSms(); ??????????? if (cbMessage != null) { ??????????????? mCellBroadcastHandler.dispatchSmsMessage(cbMessage); ??????????? } else { ?????? ?????????loge("error trying to parse broadcast SMS"); ??????????? } ??????????? return Intents.RESULT_SMS_HANDLED; ??????? } ? ????????// Initialize fingerprint field, and see if we have a network duplicate SMS. ??????? mLastDispatchedSmsFingerprint = sms.getIncomingSmsFingerprint(); ??????? if (mLastAcknowledgedSmsFingerprint != null && ??????????????? Arrays.equals(mLastDispatchedSmsFingerprint, mLastAcknowledgedSmsFingerprint)) { ??????????? return Intents.RESULT_SMS_HANDLED; ??????? } ? ????????// Decode BD stream and set sms variables. ??????? sms.parseSms(); ??????? int teleService = sms.getTeleService(); ? ??????? switch (teleService) { ??????????? case SmsEnvelope.TELESERVICE_VMN: ??????????? case SmsEnvelope.TELESERVICE_MWI: ??????????????? // handle voicemail indication ??????????????? handleVoicemailTeleservice(sms); ??????????????? return Intents.RESULT_SMS_HANDLED; ? ??????????? case SmsEnvelope.TELESERVICE_WMT: ??????????? case SmsEnvelope.TELESERVICE_WEMT: ??????????????? if (sms.isStatusReportMessage()) { ??????????????????? mSmsDispatcher.sendStatusReportMessage(sms); ??????????????????? return Intents.RESULT_SMS_HANDLED; ??????????????? } ??????????????? break; ? ??????????? case SmsEnvelope.TELESERVICE_SCPT: ??????????????? mServiceCategoryProgramHandler.dispatchSmsMessage(sms); ??????????????? return Intents.RESULT_SMS_HANDLED; ? ??????????? case SmsEnvelope.TELESERVICE_WAP: ??????????????? // handled below, after storage check ??????????????? break; ? ??????????? default: ??????????????? loge("unsupported teleservice 0x" + Integer.toHexString(teleService)); ??????????????? return Intents.RESULT_SMS_UNSUPPORTED; ??????? } ? ??????? if (!mStorageMonitor.isStorageAvailable() && ??????????????? sms.getMessageClass() != SmsConstants.MessageClass.CLASS_0) { ??????????? // It's a storable message and there's no storage available.? Bail. ??????????? // (See C.S0015-B v2.0 for a description of "Immediate Display" ??????????? // messages, which we represent as CLASS_0.) ??????????? return Intents.RESULT_SMS_OUT_OF_MEMORY; ??????? } ? ??????? if (SmsEnvelope.TELESERVICE_WAP == teleService) { ??????????? return processCdmaWapPdu(sms.getUserData(), sms.mMessageRef, ??????????????????? sms.getOriginatingAddress(), sms.getTimestampMillis()); ??????? } ? ????????return dispatchNormalMessage(smsb);//非特殊消息,直接放行給normal方法處理 ??? } |
接著是普通短信的處理方法:
| ????/** ???? * Dispatch a normal incoming SMS. This is called from {@link #dispatchMessageRadioSpecific} ???? * if no format-specific handling was required. Saves the PDU to the SMS provider raw table, ???? * creates an {@link InboundSmsTracker}, then sends it to the state machine as an ???? * {@link #EVENT_BROADCAST_SMS}. Returns {@link Intents#RESULT_SMS_HANDLED} or an error value. ???? * ???? * @param sms the message to dispatch ? ???* @return {@link Intents#RESULT_SMS_HANDLED} if the message was accepted, or an error status ???? */ ??? 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); ??????????? } ? ??????????? tracker = new InboundSmsTracker(sms.getPdu(), sms.getTimestampMillis(), destPort, ??????????????????? is3gpp2(), false); ??????? } 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); ?????????????//根據新來短信新建一個InboundSmsTacker ????????????tracker = new InboundSmsTracker(sms.getPdu(), sms.getTimestampMillis(), destPort, ????????????????????is3gpp2(), sms.getOriginatingAddress(), concatRef.refNumber, ????????????????????concatRef.seqNumber, concatRef.msgCount, false); ??????? } ? ??????? if (VDBG) log("created tracker: " + tracker); ??????? return?addTrackerToRawTableAndSendMessage(tracker);//處理tracker ??? } |
接著進入addTrackerToRawTableAndSendMessage(tracker);
| ????/** ???? * Helper to add the tracker to the raw table and then send a message to broadcast it, if ???? * successful. Returns the SMS intent status to return to the SMSC. ???? * @param tracker the tracker to save to the raw table and then deliver ???? * @return {@link Intents#RESULT_SMS_HANDLED} or {@link Intents#RESULT_SMS_GENERIC_ERROR} ???? * or {@link Intents#RESULT_SMS_DUPLICATED} ???? */ ??? protected int addTrackerToRawTableAndSendMessage(InboundSmsTracker tracker) { ??????? switch(addTrackerToRawTable(tracker)) {//別忽略了這個方法① ??????? case Intents.RESULT_SMS_HANDLED: ????????????//這里會回到狀態機的proessMessage ????????????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; ??????? } ??? } |
首先來看①,其實就是向短信息寫入raw表,此表存放所有的短信息
| private int addTrackerToRawTable(InboundSmsTracker tracker) { ??????? if (tracker.getMessageCount() != 1) { ????????????// check for duplicate message segments ??????????? Cursor cursor = null; ??????????? try { ????????????????// sequence numbers are 1-based except for CDMA WAP, which is 0-based ??????????????? int sequence = tracker.getSequenceNumber(); ? ????????????????// convert to strings for query ??????????????? String address = tracker.getAddress(); ??????????????? String refNumber = Integer.toString(tracker.getReferenceNumber()); ??????????????? String count = Integer.toString(tracker.getMessageCount()); ? ??????????????? String seqNumber = Integer.toString(sequence); ? ????????????????// set the delete selection args for multi-part message ??????????????? String[] deleteWhereArgs = {address, refNumber, count}; ??????????????? tracker.setDeleteWhere(SELECT_BY_REFERENCE, deleteWhereArgs); ? ????????????????// Check for duplicate message segments ??????????????? cursor = mResolver.query(sRawUri, PDU_PROJECTION, ??????????????????????? "address=? AND reference_number=? AND count=? AND sequence=?", ??????????????????????? new String[] {address, refNumber, count, seqNumber}, null); ? ????????????????// moveToNext() returns false if no duplicates were found ??????????????? if (cursor.moveToNext()) { ????????????????? ??loge("Discarding duplicate message segment, refNumber=" + refNumber ??????????????????????????? + " seqNumber=" + seqNumber); ??????????????????? String oldPduString = cursor.getString(PDU_COLUMN); ??????????????????? byte[] pdu = tracker.getPdu(); ???? ???????????????byte[] oldPdu = HexDump.hexStringToByteArray(oldPduString); ??????????????????? if (!Arrays.equals(oldPdu, tracker.getPdu())) { ??????????????????????? loge("Warning: dup message segment PDU of length " + pdu.length ???????????????????????? ???????+ " is different from existing PDU of length " + oldPdu.length); ??????????????????? } ??????????????????? return Intents.RESULT_SMS_DUPLICATED;?? // reject message ??????????????? } ??????????????? cursor.close(); ??????????? } catch (SQLException e) { ??????????????? loge("Can't access multipart SMS database", e); ??????????????? return Intents.RESULT_SMS_GENERIC_ERROR;????// reject message ??????????? } finally { ??????????????? if (cursor != null) { ??????????????????? cursor.close(); ?????????? ?????} ??????????? } ??????? } ? ??????? ContentValues values = tracker.getContentValues(); ? ??????? if (VDBG) log("adding content values to raw table: " + values.toString()); ????????Uri newUri = mResolver.insert(sRawUri, values); ??????? if (DBG) log("URI of new row -> " + newUri); ? ??????? try { ??????????? long rowId = ContentUris.parseId(newUri); ??????????? if (tracker.getMessageCount() == 1) { ????????????????// set the delete selection args for single-part message ??????????????? tracker.setDeleteWhere(SELECT_BY_ID, new String[]{Long.toString(rowId)}); ??????????? } ??????????? return Intents.RESULT_SMS_HANDLED; ??????? } catch (Exception e) { ??????????? loge("error parsing URI for new row: " + newUri, e); ??????????? return Intents.RESULT_SMS_GENERIC_ERROR; ??????? } ??? } |
接著分析②,首先需要明確的是此時的狀態還是投遞狀態,因此,執行以下processMessage
| ??????? @Override ??????? public boolean processMessage(Message msg) { ??????????? log("DeliveringState.processMessage:" + msg.what); ??????????? switch (msg.what) { ??????????????? case EVENT_NEW_SMS: ??????????????????? // 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 ????????????????? //首先是解出tracker ????????????????????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; ??????????? } ??????? } |
進入processMessagePart(),此方法是核心的處理方法,主要將短信廣播大到了App層
| ????/** ???? * 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) { ??????? int messageCount = tracker.getMessageCount(); ??????? byte[][] pdus;//需要將短信轉化成pdus ??????? int destPort = tracker.getDestPort(); ? ??????? if (messageCount == 1) { ????????????// single-part message ??????????? pdus = new byte[][]{tracker.getPdu()}; ??????? } else { ????????????// 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()); ? ????????????????// query for all segments and broadcast message if we have all the parts ??????????????? String[] whereArgs = {address, refNumber, count}; ??????????????? 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. ??????????????????? return false; ??????????????? } ? ????????????????// 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(); ??????????????? } ?????? ?????} ??????? } ????????//這里是一個廣播receiver,接收系統廣播,并將短信廣播到第三方App ????????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); ??????????????????? pdu = msg.getUserData(); ??????????????? } ??????????????? output.write(pdu, 0, pdu.length); ??????????? } ??????????? int result = mWapPush.dispatchWapPdu(output.toByteArray(), resultReceiver, this); ??????????? 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()); ??????????????? return false; ??????????? } ??????? } ? ??????? List<String> carrierPackages = null; ??????? UiccCard card = UiccController.getInstance().getUiccCard(mPhone.getPhoneId()); ??????? if (card != null) { ??????????? carrierPackages = card.getCarrierPackageNamesForIntent( ??????????????????? mContext.getPackageManager(), ??????????????????? new Intent(CarrierMessagingService.SERVICE_INTERFACE)); ??????? } else { ??????????? loge("UiccCard not initialized."); ??????? } ? ????????List<String> systemPackages = ????????????????getSystemAppForIntent(new Intent(CarrierMessagingService.SERVICE_INTERFACE)); ? ??????? if (carrierPackages != null && carrierPackages.size() == 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) { ??????????? 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);//這里發送個系統SMSAPP ??????? } ? ??????? return true; ??? } |
來看dispatchSmsDeliveryIntent()
| ??? /** ???? * 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 ???? */ ??? void dispatchSmsDeliveryIntent(byte[][] pdus, String format, int destPort, ??????????? BroadcastReceiver resultReceiver) { ????????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()); ??????????????? } ??????????? } ??????? } 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()); ????????//開始廣播,內部調用了broadcaster方法。 ????????dispatchIntent(intent, android.Manifest.permission.RECEIVE_SMS, ????????????????AppOpsManager.OP_RECEIVE_SMS, options, resultReceiver, UserHandle.OWNER); ??? } |
再來看之前的SmsBroadcastReceiverresultReceiver = new SmsBroadcastReceiver(tracker);
| ????/** ???? * 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();//新建一個action,在之后發送出去 ??????????? if (action.equals(Intents.SMS_DELIVER_ACTION)) {//普通短信這里 ????????????????// Now dispatch the notification only intent ????????????????intent.setAction(Intents.SMS_RECEIVED_ACTION);//設置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); ??????????? } 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); ??????????????? 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"); ??????????????? } ??????????? } ?????? ?} ??? } |
至此,短信廣播被發送給了系統SmsApp和第三方App,第三方App好理解,只要在其應用配置文件中配置監聽此廣播就行了,這里想知道的是系統SMS怎么處理的。
1.3???系統SMSApp
首先需要指出的是本文所說的“系統SmsApp”只是短信接收后觸發通知管理。本人查閱資料貌似說接收短信的有一個默認的App(可設置),這個App會第一時間接收到這個廣播并且有最高的短信權限。而其他app則權限較低。這里的系統SMSApp是在packages\apps\BasicSmsReceiver,其配置文件配置監聽了如下android.provider.Telephony.SMS_RECEIVED
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" ??????? package="com.android.basicsmsreceiver"> ? ??? <original-package android:name="com.android.basicsmsreceiver" /> ? ??? <uses-permission android:name="android.permission.RECEIVE_SMS" /> ? ??? <!-- Needed just for the unit tests --> ??? <uses-permission android:name="android.permission.READ_PHONE_STATE" /> ??? <uses-permission android:name="android.permission.SEND_SMS" /> ? ??? <application android:name="BasicSmsReceiverApp" ??????????? android:label="@string/sms_app_name" ??????????? android:hardwareAccelerated="true"> ? ??????? <activity android:name=".DialogSmsDisplay" ????????????????? android:theme="@android:style/Theme.Material.Light.Dialog" ????????????????? android:launchMode="singleTop" /> ? ??????? <receiver android:name=".SmsMessageReceiver"> ??????????? <intent-filter> ??????????????? <action android:name="android.provider.Telephony.SMS_RECEIVED" /> ??????????? </intent-filter> ??????? </receiver> ? ??? </application> </manifest> |
而在Telephony.java中有如下代碼
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
??????????? public static final StringSMS_RECEIVED_ACTION =
???????????????????"android.provider.Telephony.SMS_RECEIVED";
對比從狀態機中發出的廣播SMS_RECEIVED_ACTION,因此可以確定短信廣播就是被此App接收了,進入到其onReceive中。
| ??? private void addNotification(Context context, String fromAddress, String message) { ????????int notificationId = BasicSmsReceiverApp.getBasicSmsReceiverApp().getNextNotificationId(); ????????//新建一個notification ????????Notification.Builder notification = new Notification.Builder(context) ????????????.setTicker(message) ????????????.setWhen(System.currentTimeMillis()) ????????????.setContentTitle(fromAddress) ????????????.setContentText(message) ????????????.setSmallIcon(R.drawable.stat_notify_sms) ????????????.setContentIntent(createDisplayMessageIntent(context, fromAddress, message, ????????????????????notificationId)); ? ??????? Log.i(LOG_TAG, "addNotification notificationId: " + notificationId); ????????//獲取通知管理器服務 ????????NotificationManager notificationManager = ?(NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE); ????????//開始通知 ??????? notificationManager.notify(notificationId, notification.getNotification()); ??? } |
當然這里可能很多地方會接收到此條通知,但最重要的肯定是UI,這里直接在同一個App文件中的DialogSmsDisplay.java中。
| @Override ??? protected void onNewIntent(Intent intent) { ????????removeDialog(DIALOG_SHOW_MESSAGE); ? ????????parseIntent(intent); ??? } |
進入到parseIntent()。
| ??? private void parseIntent(Intent intent) { ??????? if (intent == null) { ??????????? return; ??????? } ????????Bundle extras = intent.getExtras(); ??????? if (extras == null) { ??????????? return; ??????? } ????????//解析戶短信的具體內容 ????????mFromAddress = extras.getString(SMS_FROM_ADDRESS_EXTRA); ?? ?????mMessage = extras.getString(SMS_MESSAGE_EXTRA); ????????int notificationId = extras.getInt(SMS_NOTIFICATION_ID_EXTRA); ? ??????? Log.i(LOG_TAG, "notificationId: " + notificationId); ? ????????// Dismiss the notification that brought us here. ??????? NotificationManager notificationManager = ??????????? (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE); ??????? notificationManager.cancel(notificationId); ????????//顯示界面,其實解釋顯示短信的有關信息 ????????showDialog(DIALOG_SHOW_MESSAGE); ??? } |
至此系統UI顯示出來了。
原文地址: http://blog.csdn.net/a34140974/article/details/50963617
總結
以上是生活随笔為你收集整理的Android6.0的SMS(短信)源码分析--短信接收的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android6.0的SMS(短信)源码
- 下一篇: Android5.0源码分析—— Zyg