天天看點

[Android][KK][SMS]Frameworks學習——發送短信流程分析三、發送短信流程分析

二、短信資料結構一、Android SMS架構

三、發送短信流程分析

四、接收短信流程分析

三、發送短信流程分析

1.Application層的短信發送流程

Application層中短信發送的流程,其邏輯的實作代碼在packages/apps/Mms包路徑下,流程如下圖。

[Android][KK][SMS]Frameworks學習——發送短信流程分析三、發送短信流程分析

1.1 Application層短信資料流向跟蹤

a.圖中省略了短信UI界面的相關操作,将WorkingMessage對象的send方法調用作為短信發送流程的開始。在該方法裡做了如下操作:建立Conversation容器儲存短信資料;判斷彩信or短信;建立新線程,并執行preSendSmsWorker調用。

b.在第3步WorkingMessage.sendSmsWorker中,以短信的dests(發送位址,string), msgText(短信内容,string), threadId(線程ID,long)三個資料為參數構造了SmsMessageSender對象,并且調用該對象的sendMessage方法。

c.第6步和第7步是在SmsMessageSender對象的queueMessage方法中同步調用的。第6步調用Telephony Framework層中的Sms類的靜态方法,把即将發送的短信相關資訊儲存到資料庫中。第7步則發起請求發送短信的廣播。

d.第7步SmsReceiver接收請求發送短信的廣播,啟動SmsReceiverService服務(第11步)。

e.第16步,最終該服務中的sendFirstQueueMessage方法(synchronized同步鎖保證線程安全)繼續響應短信發送請求:首先,讀取資料庫中等待發送的短信資料,以短信資料(address, msgText, threadId, status,msgUri)構造SmsSingleRecipientSender對象。然後,通過SmsSingleRecipientSender對象的sendMessage方法,繼續發起短信發送的請求。

1.2 SmsSingleRecipientSender與framework層的互動

SmsSingleRecipientSender類作為app層傳遞短信發送請求到framework層的最後一關,它的功能隻有一個sendMessage()。有必要分析其内部邏輯實作。

SmsSingleRecipientSender對象被調用sendMessage()時, 有如下邏輯處理:

a.調用SmsManager對象divideMessage方法分拆短信内容(若沒有超過長度則不拆)。

b.将儲存的短信轉移至outbox中。

c.建立PendingIntent對象deliveryIntents和sentIntents(個數由分拆的短信數決定),用以回調廣播短信發送狀态報告和短信發送結果報告。

d.這裡出現了分支:判斷是否多sim卡。如果是,則調用MSimSmsManager對象的sendMultipartTextMessage方法。如果不是,調用SmsManager對象的sendMultipartTextMessage方法。前者擷取的是isms_msim服務,後者擷取的是isms服務,其餘的邏輯實作是一緻的。

至此,發送短信的請求被傳遞到framework層。

1.3 SmsManager提供給app層調用的對短信操作的接口

由于SmsManager和MSimSmsManager中提供的接口除了擷取的服務不同,其他的邏輯實作基本一緻,是以隻分析SmsManager的接口。isms服務和isms_msim服務下節學習。

該類提供了短信拆分、短信發送、将短信複制到SIM卡、從SIM卡删除短信和小區廣播等接口,接口中不做處理,直接調用其他類的方法完成。

getDefault():獲得預設的SmsManager對象。

divideMessage():短信拆分。不做處理,直接調用SmsMessage.fragmentText()來完成實機的拆分操作。

sendMultipartTextMessage():短信發送。若傳入的短信内容是分段的,則調用isms服務的sendMultipartText();若傳入的是單短信,則通過sendTextMessage()調用isms服務的 sendText()。

sendDataMessage():發送短信至指定應用端口。不做處理,直接調用isms服務的sendData()。

copyMessageToIcc(): 将短信複制到SIM卡。不做處理,直接調用isms服務的copyMessageToIccEf()。

deleteMessageFromIcc():從SIM卡删除短信。不做處理,直接調用isms服務的updateMessageOnIccEf()。

2.Framework層的短信發送流程

發送短信的請求,從app層通過SmsManager對象的sendMultipartTextMessage方法調用,已經傳遞到了Telephony Framework層中,Telephony Framework層與RIL層互動,最終完成短信的發送請求,轉換成RIL請求,其處理流程詳情如下圖所示。

[Android][KK][SMS]Frameworks學習——發送短信流程分析三、發送短信流程分析

本圖是繼續上節的調用,在SmsManager的sendMultipartTextMessage中出現了分支:若傳入的短信内容是分段的,則調用isms服務的sendMultipartText();若傳入的是單短信,則通過sendTextMessage()調用isms服務的 sendText()。

2.1 Framework層短信資料流向跟蹤

a.第1步中,SmsManager.sendMultipartTextMessage方法有5個入參:

String destinationAddress //收信人的電話ADDRESS

String scAddress //短信中心号碼SERVICE_CENTER

ArrayList<String> parts //短信内容BODY

ArrayList<PendingIntent> sentIntents //短信發送狀态報告的回調intent

ArrayList<PendingIntent> deliveryIntents //短信發送結果的回調intent

由此可見,由app層調用framework層接口時,傳入了短信資料:收信人電話、短信中心号碼、短信内容,以及兩個狀态回調intent。該方法啟動IccSMSInterfaceManager服務,并以這5個參數為入參調用它的sendMultipartText/sendText方法。

b.第3步IccSMSInterfaceManager服務将這5個參數傳遞到了SMSDispatcher兩個子類GsmSMSDispatcher或者CdmaSMSDispatcher的sendText();該方法将短信資料(收信人電話、短信中心号碼、短信内容)構造成SubmitPdu的對象pdu,然後将pdu和兩個回調intent一起封裝進SmsTrack對象中。

在IccSMSInterfaceManager服務中,建立的是 ImsSMSDispatcher對象(在ImsSMSDispatcher構造函數中會new兩個對象:GsmSMSDispatcher對象和CdmaSMSDispatcher對象),并且調用sendMultipartText/sendText方法。在該方法中會根據GSM/CDMA,來調用GsmSMSDispatcher/CdmaSMSDispatcher對象的sendMultipartText/sendText方法來具體實作。

c.第6步,SmsTrack對象track被傳入SMSDispatcher兩個子類GsmSMSDispatcher或者CdmaSMSDispatcher重寫的sendSms()方法中。該方法中又調用mCm.sendSMS(),并傳入3個參數:smsc,pdu(均從SmsTrack對象track中取出)以及一個帶track參數的handler消息reply用以回調。mCm是SMSDispatcher構造方法中mCm =phone.mCM獲得的RIL對象。

d.第7步,在Ril.sendSMS()中,傳入的3個參數(smsc,pdu,handler消息)被封裝進了RILRequest對象rr中,并且調用Ril.send()。

e.第8步,Ril.send()中又會将RIL請求rr,封裝成一個指定的消息(EVENT_SEND),并把它放到message隊列中,由RILSender對象mSender來執行。

f.第9步,在RILSender.handleMessage()中,處理收到的RILRequest消息,将消息中的rr資料寫入到Socket的輸出流,即通過Socket将短信資料傳遞到RIL層。

至此,短信的發送已經跟蹤到RIL層了。短信發送請求從app層分多個步驟傳遞到Framework層,在Framework層拆分短信、建立PDU對象等操作,然後調用到RIL對象中發送短信的方法,将短信請求轉換為對應的RIL請求調用。

2.2 IccSmsInterfaceManager類分析(Qcomcode)

IccSmsInterfaceManager的構造函數中有将自己注冊成為isms服務,是以在SmsManager.sendMultipartTextMessage/sendText等方法中獲得的isms服務就是它。

ServiceManager.addService("isms", this);

ISms iccISms = Isms.Stub.asInterface(ServiceManager.getService("isms"));

IccSmsInterfaceManager類,實作了ISms.stub接口,它的作用就像類注釋說的那樣:to provide an inter-process communication to access Sms in Icc,為短信接入SIM卡提供内部程序通信。

IccSmsInterfaceManager的構造函數中還構造了一個ImsSMSDispatcher對象,SmsManager的sendMultipartTextMessage/sendText方法,是通過IccSmsInterfaceManager服務調用ImsSMSDispatcher對象的方法。

而SmsManager的copyMessageToIccEf/updateMessageOnIccEf/enableCellBroadcast等方法,也是通過IccSmsInterfaceManager服務,調用RIL對象的方法來完成。

2.3 SMSDispatcher與RIL的互動

SMSDispatcher類是通過sendSMS方法與RIL互動的,sendSMS方法又是由子類GSMDispatcher或者CDMADispatcher具體實作的。現在分析一下GSMDispatcher類中該方法的邏輯實作。

a.從入參Smstrack對象中取出smsc和pdu

b.建立一個EVENT_SEND_SMS_COMPLETE消息,并将Smstrack對象封裝進該消息。

c.出現分支:如果是sms over IMS,那麼調用RIL.sendImsGsmSms方法;如果不是,那麼調用RIL.sendSMS方法,傳入的參數為smsc、pdu以及EVENT_SEND_SMS_COMPLETE消息。

d.RIL.sendSMS方法做的事情就是将傳入的EVENT_SEND_SMS_COMPLETE消息和smsc/pdu構造成RIL_REQUEST_SEND_SMS的RIL請求。最終将RIL請求通過socket發送給RILC。

由此可見, SMSDispatcher與RIL的互動的目的是為了把Framework層發送短信的請求轉換為RIL請求,以便交給RILC進行處理。

2.4 短信發送狀态相關處理機制

短信能否成功發送到對方手機,主要有兩個因素:手機Modem将短信成功發送到短信中心和短信中心成功發送短信到對方手機。

2.4.1如何判斷短信發送至短信中心

Modem作為發送短信的最終執行者,是以當它将短信發送給短信中心時,是知道短信發送到短信中心的結果是成功還是失敗的。Modem會将該結果回報給RIL層。RILReceiver會接收到RIL_REQUEST_SEND_SMS消息,交給processSolicited方法來處理:送出這個消息。

[Android][KK][SMS]Frameworks學習——發送短信流程分析三、發送短信流程分析

2.3節有講到SMSDispatcher.sendSMS中建立了EVENT_SEND_SMS_COMPLETE消息。

Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker);

這是一個回調的消息對象。SmsTracker對象tracker被儲存在該消息對象中,傳遞給了RIL對象。而SmsTracker對象tracker是在上圖第4步被建立的,用于構造它的三個參數分别是:

map:儲存smsc和pdu。

sentIntent:在小節1.2中有講到, SmsSingleRecipientSender.sendMessage方法中建立的Intent對象,Action類型為 SmsReceiverService.MESSAGE_SENT_ACTION。使用此對象發出廣播時,會進入SmsReceiver類中的onReceive方法接收廣播。此外,構造參數還包括Uri。

deliveryIntent:SmsSingleRecipientSender.sendMessage方法中建立的Intent對象,Action類型為 MessageStatusReceiver.MESSAGE_STATUS_RECEIVED_ACTION。使用此對象發出廣播時,會進入MessageStatusReceiver類中的onReceive方法接收廣播。

SMSDispatcher在與RIL對象互動時,将EVENT_SEND_SMS_COMPLETE消息對象reply 作為入參傳遞給RIL。是以當RIL對象收到Modem回報的Response結果後,将使用對應的Handler消息對象發出消息通知進行回調操作。

[Android][KK][SMS]Frameworks學習——發送短信流程分析三、發送短信流程分析

SMSDispatcher接收到RIL發起的Callback消息通知,在handleMessage方法中處理消息類型為EVENT_SEND_SMS_COMPLETE。EVENT_SEND_SMS_COMPLETE類型的消息會在handleSendComplete方法中具體處理,邏輯實作如下:

a.擷取SmsTracker對象tracker以及sentIntent

b.如果傳回的結果無異常,那麼使用sentIntent發出廣播,并且如果此短信需要知道是否對方已接收到,将SmsTracker對象tracker儲存到deliveryPendingList。

c.如果傳回的結果有異常,那麼構造封裝有tracker的EVENT_SEND_RETRY消息,重新發送短信,最多3次。

sentIntent發出廣播後,SmsReceiver類中的onReceive方法會接收到,并且通過SmsReceiverService服務,調用其handleSmsSent方法,根據回報的結果來更新短信發送狀态及相關提示。

2.4.2如何判斷對方以及成功接收到短信

如果開啟短信發送的狀态報告,那麼短信中心将短信成功發給對方時,會将結果發送給短信發送方。Modem接收到短信中心回報的短信成功發送至對方的消息,交給RIL層處理RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT類型的RIL消息。

RIL通過processUnsolicited方法找到RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT的處理方法:通過mSmsStatusRegistrant對象發出短信狀态報告的消息通知。

由2.1.c得知,RIL對象是在SMSDispatcher的構造方法中擷取到的。而在其子類GSMSMSDispatcher的構造方法中對RIL對象做了如下操作:

mCm.setOnSmsStatus(this, EVENT_NEW_SMS_STATUS_REPORT, null);

該方法完成了mSmsStatusRegistrant對象的消息注冊。

是以,RIL通過mSmsStatusRegistrant對象發出的EVENT_NEW_SMS_STATUS_REPORT消息通知,會在GSMSMSDispatcher的handleMessage中接收,并交給handleStatusReport方法處理:

a.從deliveryPendingList中取出SmsTracker對象tracker

b.從SmsTracker對象tracker中擷取 deliveryIntent

c.使用deliveryIntent發出廣播

上文中有講到deliveryIntent是由SmsSingleRecipientSender.sendMessage方法建立的Action類型為 MessageStatusReceiver.MESSAGE_STATUS_RECEIVED_ACTION的Intent對象。

使用此對象發出廣播時,MessageStatusReceiver類中的onReceive方法會接收到,并且通過MessageStatusService服務,調用其updateMessageStatus方法更新短信發送狀态。