Android 4.2短信发送流程。
1. ComposeMessageActivity接收用户输入并且响应用户点击事件。
函数调用顺序confirmSendMessageIfNeeded() ->sendMessage()
sendMessage中会调用到WorkingMessage的send方法。
2. WorkingMessage的send方法会对此时消息做判断,如果包含Email或是MMS则启动彩信发送程序发送SendReq请求向MMSC. 彩信流程将会在以后介绍。
如果send方法判定为短信,则会new新线程。
3. 在新建线程中会调用preSendSmsWorker函式。
preSendSmsWorker其实只做以下几件事:
a. 调用MessageStatusListener的onPreMessageSent方法通知UI线程更新状态。
b. 调用sendSmsWorker函数去发送短信,参数包含了消息体接收人,所属线程id(此为消息所属会话线程ID,并非操作系统中的线程ID,个人感觉名字起的有待商榷)
4. sendSmsWorker函数中会创建SmsMessageSender实例并调用其sendMessage函式。
5. SmsMessageSender的sendMessage其实只是调用了自己的queueMessage。
queueMessage顾名思意将消息入队。其实就是调用Framework中Telephony.java的addMessageToUri将消息插入至SMS数据库(数据库的实现在smsprovider.java)
其中主要填写以下字段:
a. SUB_ID: 用于双卡标识
b. ADDRESS: 发送地址
c. DATE: 发送时间
d. READ: 是否已读
e. SUBJECT: 短信么有
f. BODY:消息体
g. STATUS:分为STATUS_COMPLETE,STATUS_PENDING,STATUS_FAILED,STATUS_NONE,此时会写为STATUS_PENDING。
h. THREAD_ID: 会话线程ID.
值得注意的是STATUS与smsprovider在insert时会加入的TYPE, TYPE 中包含了MESSAGE_TYPE_INBOX, MESSAGE_TYPE_SENT, MESSAGE_TYPE_QUEUED, MESSAGE_TYPE_OUTBOX等等。此时我们是MESSAGE_TYPE_QUEUED类型。
6. 此时我们从Framework中回到app中。继续看queueMessage函式做了啥,在把数据加入队列后会发送广播消息ACTION_SEND_MESSAGE。此消息由SmsReceiver.java去接收.
7. SmsReceiver.java接到消息都干了啥呢?其实他么干啥事,就去startservice.这也是我们编写android程序时常用的方法,在receiver中启动服务。毕竟大家都知道receiver中最好不处理长时间的数据,因为如果时间太长会阻塞UI线程并触发ANR.
8. SmsReceiverService的handleMessage会接收到ACTION_SEND_MESSAGE,此时会调用handleSendMessage,它会判断是否在发送状态,如果不在发送中则会调用sendFirstQueuedMessage去发送队列中的消息。
此队列就是我们之前调用framework的addMessageToUri函式插入的消息的队列。
9. 取到队列中的消息后我们会构造SmsSingleRecipientSender实例,SmsSingleRecipientSender用于单笔消息的发送。SmsSingleRecipientSender的sendMessage函式将被调用。
10. sendMessage()主要做了以下几件事:
a. 如果目的地址为EMail地址,则会调用MmsConfig的getEmailGateway()取得预配置的SMS Email发送网关地址作为发送目的地址。
b. 修改数据库中消息的TYPE,由MESSAGE_TYPE_QUEUED至MESSAGE_TYPE_OUTBOX。
c. 调用SmsManager的sendMultipartTextMessage去发送消息,如果是双卡会调用MSimSmsManager的sendMultipartTextMessage,此代码应该是高通进行修改的(个人看法)。MSimSmsManager主要加入了subscription参数以便区别哪张卡。此时单卡多卡会出现很多区别,使用的isms服务也存在区别。
11. sendMessage()调用MSimSmsManager的sendMultipartTextMessage后将会向ServiceManager取得"isms_msim"服务(单卡时为”isms”).
如果为长短信则会调用MSimIccSmsInterfaceManagerProxy的sendMultipartText函式去根据subscription取得相应的MSimIccSmsInterfaceManager,并调用其sendMultipartText。
如果是普通短信则会最终调用到MSimIccSmsInterfaceManager的sendText。
12. 无论是sendMultipartText或sendText都会调用到ImsSMSDispatcher的相应函式,并且都会判断其发送方式CDMA或GSM. 两者的实例类为CdmaSMSDispatcher和GsmSMSDispatcher。
如果是发送长短信,则会调用到SMSDispatcher基类的sendMultipartText。主要是调用sendNewSubmitPdu函式去逐个发送,此函式被CdmaSMSDispatcher和GsmSMSDispatcher分别实现。
在sendNewSubmitPdu函式中会调用sendRawPdu函式,后会调用CdmaSMSDispatcher或GsmSMSDispatcher的sendSms函式,这里将会调用到Ril的sendSMS.
13. Ril中将组装RILRequest,并发送至ril层。
14. 当RIL发送成功后processSolicited将接收到RIL_REQUEST_SEND_SMS的response.此时会触发消息并由SMSDispatcher的handleMessage接收,消息名为EVENT_SEND_SMS_COMPLETE,此时会调用handleSendComplete函式并把结果传入(AsyncResult)。
以下几件事会被handleSendComplete执行:
a. 如果发现mDeliveryIntent不等于空则表明需要传送报告,所以会将SmsTracker加入deliveryPendingList以等待传送报告回执。
b. 如果返回的exception不存在,则说明发送时未出现异常,所以会发送intent至SmsReceiver。(可能这里会感觉Ril怎么能知道通知谁并用什么action呢?其实都是得益于发送时传入的deliveryIntents与sentIntents,这个可以查看SmsSingleRecipientSender的sendMessage,每当你发送时都会事先构造好回执的intent.)SmsReceiverService收到MESSAGE_SENT_ACTION后会触发下一个队列中消息的发送。