短信的發送流程(framework) java
1、主要文件
- /packages/apps/Mms/com/android/mm/transaction/SmsSingleRecipientSender
- /framework/base/telephony/java/com/android/internal/telephony/ISms.aidl
- /framework/base/telephony/com/android/internal/telephony/IccSmsInterfaceManager
- /telephony/java/com/android/internal/telephony/SMSDispatcher.java
- /telephony/java/com/android/internal/telephony/ImsSMSDispatcher.java
- /telephony/java/com/android/internal/telephony/GsmSMSDispatcher.java
- /telephony/java/com/android/internal/telephony/CdmaSMSDispatcher.java
- /telephony/java/android/telephony/SmsMessage.java
- /base/telephony/java/com/android/internal/telephony/RIL.java
- /framework/base/telephone/java/android/telephone/SmsManager
- /framework/base/telephone/java/android/telephone/MSimIccSmsInterfaceManager
文件簡單說明:
SmsSingleRecipientSender是應用程序Mms發送短信時需調用的類
ISms.aidl:用於和MSimIccSmsInterfaceManager進行通訊
注意:這裏參考的是高通2.3的源碼,在4.0的源碼中已經取消了MSimIccSmsInterfaceManager這個類。
2、流程圖
2.1類圖
2.2 時序圖
1)android2.3 的時序圖:
2)android4.0 的時序圖
因爲在4.0中取消了MSimIccSmsInterfaceManager這個類,也便是4.0使用ISms.aidl直接訪問IccSmsInterfaceManager來進行一些操做,省略掉中間的這個過程。
爲了給你們一個比較清晰的對比,如下爲4.0的時序圖:
對比能夠看出有一些細微的區別,其原理差很少只是在2.3的基礎上將一些過程簡化。
說明:其中GsmSmsDispatcher只是其中一個分支,另外一個分支是CdmaSmsDispatcher,這裏以Gsm爲例子
3、流程解析
3.1 應用層調用入口
發送短信,應用程序Mms經過調用SmsSingleRecipientSender類的sendMessage方法,將短信發出,這是短信發送的入口之一,如下是其核心代碼:
- try {
- smsManager.sendMultipartTextMessage(mDest, mServiceCenter, messages, sentIntents,
- deliveryIntents, mSubscription);
- }
- catch (Exception ex) {
- throw new MmsException("SmsMessageSender.sendMessage: caught " + ex
- + " from SmsManager.sendTextMessage()");
- } if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE))
- {
- log("sendMessage: address=" + mDest + ", threadId=" + mThreadId + ",
- uri=" + mUri + ", msgs.count=" + messageCount);
- }
經過上面代碼能夠看出,經過調用SmsManager類的sendMulipartTextMessage方法,進入中間層,其餘的工做由中間層來完成的。
3.2 中間層調用詳解
3.2.1 SmsManager 到SMSDispatcher.sendRawPdu();
下圖爲代碼的執行流程:
你們能夠看出cdma和gsm都會走到SMSDispatcher的sendRawPdu()方法來發送短信,能夠叫啥來着葉落歸根,或者時分久必合,合久必分。那不一樣之處在於構造SmsTracker對象的時候,其成員變量RadioTechnologyFamily的值不一樣,cdma使用的是RadioTechnologyFamily.RADIO_TECH_3GPP2,而GSM使用的是RadioTechnologyFamily.RADIO_TECH_3GPP。
3.2.2 SMSDispatcher.sendRawPdu()到RIL的流程
爲了更清晰的該方法到Ril的流程,特畫流程圖共你們參考
其中mCm爲CommandInterface,爲一個藉口,RIL.java實現了該藉口,因此調用會調用到RIL.java中去,因爲RIL.java是中間層和rild守護進程通訊的一個入口,從這能夠將對應的操做在rild中去完成。這就將接力棒交到了RIL層去了。
3.2.3 RIL.java發送解析
sendImsGsmSms、sendSms、sendCdmaSms、sendImsCdmaSms這四個方法基本流程是大體相同的,都是先構造RILRequest,再調用send方法發送。區別就在於不一樣的方法在得到RILRequest時傳入的請求類型不一樣,構造出來的pdu結構不一樣,以及兩個Ims方法須要先往RILRequest中寫入一個數字。
以sendImsGsmSms爲例,如下是其核心代碼:
- public void
- sendImsGsmSms (String smscPDU, String pdu, Message result) {
- RILRequest rr = RILRequest.obtain(RIL_REQUEST_IMS_SEND_SMS, result);
-
- rr.mp.writeInt(1); //RadioTechnologyFamily.RADIO_TECH_3GPP;
- constructGsmSendSmsRilRequest(rr, smscPDU, pdu);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- send(rr);
- }
其執行流程以下流程圖所示:
看了RIL的內部調用流程你們會以爲奇怪,RILSender是個什麼東東了?經過查看代碼你會發現,這傢伙是一個內部類,該類繼承了handler,因此你如今明白了吧爲啥能夠給它發送消息。到此爲止RIL.java已經將發送操做傳遞給守護進程rild,那剩下的操做就由守護進程和貓這端來完成了。
3.3 發送後的處理
經過上面的各個步驟已經最終將短信發出,那短信發出去了是否是就結束了?很顯然不是,雖然這不是一個開始但遠遠沒有到結束的時候,哈哈別高興的太早,下面要說的就是發送短信後作的一系列的斷後處理。
斷後處理最主要的有兩個工做:一是釋放資源,其中最重要的就是RILRequest這個對象,我們不能忘恩負義對吧,用了就一腳踢開無論不問了。二是發送報告,若是在短信的設置裏沒有打開發送報告這個選項,但仍是的爲它作一些事情,所謂時刻準備着,若是這個選項打開就能夠直接獲取發送報告了。那下面的重點就是講解這兩個方面的內容。
要執行斷後處理,確定是咱們肯定咱們的發送操做實行完了,怎麼去判斷咱們的操做是否執行完了?還記得上面提到的RIL.java會經過LocalSocket將命令發到rild去,咱中國講究禮尚往來,那這也有這個美德,當發送完成後rild會給RIL一個返回信息,當RIL接收後會去執行相應的動做。
3.3.1 RIL到SMSDispatcher的執行流程
對於發送流程裏你們能否還記得RIL.java中有一個RILSender內部類它是用於向rild發送命令,那還有一個功能與其相反RILReceiver內部類主要用於讀取rild的「答謝」。
這裏涉及到一個發送短信的時候返回的事件是什麼?
前面提到的發送短信的四種方式對應的事件類型爲:
1)sendSMS對應RIL_REQUEST_SEND_SMS
2)sendCdmaSms對應RIL_REQUEST_CDMA_SEND_SMS、
3)sendImsGsmSms&sendImsCdmaSms對應RIL_REQUEST_IMS_SEND_SMS
且在構造message時實際上會將what設置爲SEND_SMS_COMPLETE,到此爲止RIL的工做順利完成,請看最後一步RILRequest對象也釋放掉了,剩餘的工做SMSDispatcher將會繼續完成,看SMSDispatcher如何將這些信息傳遞,請看下節。
3.3.2SMSDispatcher分發信息
SMSDipatcher收到傳遞的信息後調用本身的handMessage方法處理
SEND_SMS_COMPLETE這個消息。且看下圖代碼執行流程:
3.3.3 發送報告
1)
RIL調用到SMSDispatcher說明
對於GSM,在構造方法中,將GsmSMSDispatcher註冊爲RIL接收到發送報告時該事件的接收者,並設置消息類型爲EVENT_NEW_SMS_STATUS_REPORT,相應的Registrant類爲mSmsStatusRegistrant。
對於CDMA,則設置消息類型爲EVENT_NEW_SMS,相應的Registrant類爲mCdmaSMSRegistrant。
當RIL收到底層傳來的發送報告,過程與3.3.1執行流程類似,會產生一個類型RESPONSE_UNSOLICITED,轉入processUnsolicited處理,這裏不重複贅述。
2)GSM 和CDMA 的處理說明
對於GSM,其事件類型爲RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT,會先調用responseString從Parcel中獲取數據,再調用mSmsStatusRegistrant的notifyRegistrant方法設置消息類的what屬性設置爲EVENT_NEW_SMS_STATUS_REPORT,最後轉到SMSDispatcher進行處理。
而CDMA,事件爲RIL_UNSOL_RESPONSE_CDMA_NEW_SMS,處理過程與GSM大體相同,只是從Parcel中獲取數據是調用responseCdmaSms方法獲取SmsMessage對象,而後再調用mCdmaSMSRegistrant的notifyRegistrant方法設置消息類型,其中what屬性爲EVENT_NEW_SMS,最後轉到SMSDispatcher進行處理。
3)SMSDispatcher處理
對於GSM,直接調用handleStatusReport方法處理,從傳入的AsyncResult對象中獲取SmsMessage進而獲取SmsTracker的索引,從deliveryPendingList中取出SmsTracker,發送deliveryIntent併發送消息確認。
對於CDMA,在handleMessage中轉到EVENT_NEW_SMS,調用dispatchMessage進行消息的分發。
對於這個之後的操做流程以下圖所示:
說明dipatcherMessage方法中還有不少的操做以及發送確認消息和上面提到的錯誤信息發送都是經過pendingIntent的send方法來實現的。這裏沒有一一細舉。
4、總結
該發送流程只是簡述了中間層的發送流程,對於彩信的發送流程會用單獨的篇幅來描述。對於應用層一系列複雜操做也還沒有分析,若是想要了解應用層是如何作到的,且聽下回分解。