本文主要介紹Android如何接收短信,流程分爲兩個部分,Framework層和App層。數據庫
Framework層:this
短信的接收,Framework部分處理的順序是RIL->SMSDispatcher->GsmSMSDispatcher/CdmaSMSDispatcher->SMSDispatcher。spa
當短信到Framework層以後,會首先啓動RIL中的RILReceiver去接收短信,在RILReceiver中使用LocalSocket去讀短信,而後把讀到的短信放在一個Parcel對象中,而後調用processResponse(Parcel p)去處理,processResponse()中調用processUnsolicited(Parcel p)處理。orm
對於GSM,事件類型爲RIL_UNSOL_RESPONSE_NEW_SMS,先調用responseString(Parcel p)從Parcel中獲取數據,而後再使用newFromCMT()方法獲取SmsMessage對象,此時短信數據已被轉換成短信pdu保存在SmsMessage對象中。而後調用mGsmSmsRegistrant的notifyRegistrant(new AsyncResult(null, sms, null))方法發送消息,轉入 SMSDispatcher的handleMessage()方法進行處理,事件類型爲EVENT_NEW_SMS。對象
對於CDMA,事件類型爲RIL_UNSOL_RESPONSE_CDMA_NEW_SMS,調用responseCdmaSms()從Parcel中獲取數據,消息分發時使用的是CdmaSMSDispatcher,其餘處理大部分都是和GSM是相同的。blog
這裏爲何調用了notifyRegistrant()方法就會轉入SMSDispatcher中進行處理呢?接口
原來在GsmSMSDispatcher初始化時調用了mCi.setOnNewGsmSms(this, EVENT_NEW_SMS, null),mCi在SMSDispatcher中聲明爲CommandsInterface,實際爲一個BaseCommands對象,由於BaseCommands實現了CommandsInterface接口。事件
在SMSDispatcher中處理EVENT_NEW_SMS事件時,首先從message中取出保存短信的SmsMessage對象,而後調用dispatchMessage()進行消息分發。ci
在GsmSMSDispatcher的dispatchMessage()方法中,會對短信作一些特殊類型判斷,這裏的這些類型好像不是正常短信的類型,這些短信類型是什麼我也不太清楚,須要再深刻研究。但這裏還有一個比較重要的處理就是會判斷手機存儲是否是已經滿了,判斷的依據是可用的存儲是否大於1MB,若是小於1MB,則會返回一個RESULT_SMS_OUT_OF_MEMORY的Int值,而後發送一個SMS_REJECTED_ACTION的廣播,App側的SmsRejectedReceiver接收到這個廣播後,就會拒絕接收這條短信,而後作一個memory full的notification。it
在知足前面這些條件以後,則調用dispatchNormalMessage()處理這條普通的短信,這是一個比較重要的方法,它會判斷正常短信的幾種類型:
1.彩信通知(WapPushOverSms.dispatchWapPdu())
2.指定端口的彩信(dispatchPortAddressedPdus())
3.普通短信(dispatchPdus())
4.長短信(processMessagePart())
這裏須要說明兩點:
1.接收彩信其實是由framework層向App層發送一條彩信通知,這條通知裏攜帶有一些彩信的信息,譬如說彩信的大小,過時時間等,App層收到這條彩信通知之後會啓動相應的transaction去彩信中心下載彩信。
2.長短信的處理,由於長短信不能一次接收完,而是分段接收,因此接收到的部分先要存儲起來,使用SmsHeader.ConcatRef的refNumber把多個part標記爲一條長短信,當把所有的part接收完以後,纔會整條顯示給用戶,不然不會通知App層。
對於普通短信來講,這時候framework層的工做就結束了,須要通知App層,因此在dispatchPdus()中發送SMS_RECEIVED_ACTION的廣播,由PrivilegedSmsReceiver接收,而後轉入App層處理。
App層:
PrivilegedSmsReceiver在接收到短信來了的廣播以後,由SmsReceiver啓動SmsReceiverService來作具體的處理。
接收短信的action爲SMS_RECEIVED_ACTION,因此調用handleSmsReceived()處理,使用insertMessage()將短信插入數據庫,這裏首先會判斷短信是否爲CLASS_0短信,若是是則直接顯示,不插入數據庫。若是不是則會進行消息的替換或者插入數據庫,替換使用了SmsMessaged的isReplace()方法判斷,原則是短信協議標識mProtocolIdentifier的判斷。若是既不是CLASS_0短信也不須要替換,則將短信插入數據庫,而後使用MessagingNotification在StatusBar作一個notification,通知用戶短信來了。
接下來就是短信的顯示了,當新接收到的短信插入數據庫之後,由於數據庫改變了,UI會收到onContentChanged事件,而ComposeMessageActivity註冊了MessageListAdapter.OnDataSetChangedListener監聽,因此會觸發onContentChanged()方法,在此方法中調用startMsgListQuery()開始查詢,查詢結束後在BackgroundQueryHandler的onQueryComplete()中changeCursor,從新綁定MessageItem。至此,一條短信的接收處理完成。
做者:殘陽破曉