短信的发送流程(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、总结
该发送流程只是简述了中间层的发送流程,对于彩信的发送流程会用单独的篇幅来描述。对于应用层一系列复杂操做也还没有分析,若是想要了解应用层是如何作到的,且听下回分解。