短信的发送流程(framework)
一、主要文件
- /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.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.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方法来实现的。这里没有一一细举。
四、总结
该发送流程只是简述了中间层的发送流程,对于彩信的发送流程会用单独的篇幅来描述。对于应用层一系列复杂操作也尚未分析,如果想要了解应用层是如何做到的,且听下回分解。