[Android][KK][SMS]Frameworks学习——发送短信流程分析

时间:2022-06-19 21:16:23


二、短信数据结构
一、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学习——发送短信流程分析

本图是继续上节的调用,在SmsManagersendMultipartTextMessage中出现了分支:若传入的短信内容是分段的,则调用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.3IccSMSInterfaceManager服务将这5个参数传递到了SMSDispatcher两个子类GsmSMSDispatcher或者CdmaSMSDispatchersendText();该方法将短信数据(收信人电话、短信中心号码、短信内容)构造成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个参数:smscpdu(均从SmsTrack对象track中取出)以及一个带track参数的handler消息reply用以回调。mCmSMSDispatcher构造方法中mCm =phone.mCM获得的RIL对象。

d.7步,在Ril.sendSMS()中,传入的3个参数(smscpduhandler消息)被封装进了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 SMSDispatcherRIL的交互

SMSDispatcher类是通过sendSMS方法与RIL交互的,sendSMS方法又是由子类GSMDispatcher或者CDMADispatcher具体实现的。现在分析一下GSMDispatcher类中该方法的逻辑实现。

a.从入参Smstrack对象中取出smscpdu

b.创建一个EVENT_SEND_SMS_COMPLETE消息,并将Smstrack对象封装进该消息。

c.出现分支:如果是sms over IMS,那么调用RIL.sendImsGsmSms方法;如果不是,那么调用RIL.sendSMS方法,传入的参数为smscpdu以及EVENT_SEND_SMS_COMPLETE消息。

d.RIL.sendSMS方法做的事情就是将传入的EVENT_SEND_SMS_COMPLETE消息和smsc/pdu构造成RIL_REQUEST_SEND_SMSRIL请求。最终将RIL请求通过socket发送给RILC

由此可见, SMSDispatcherRIL的交互的目的是为了把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:保存smscpdu

sentIntent:在小节1.2中有讲到, SmsSingleRecipientSender.sendMessage方法中创建的Intent对象,Action类型为 SmsReceiverService.MESSAGE_SENT_ACTION。使用此对象发出广播时,会进入SmsReceiver类中的onReceive方法接收广播。此外,构造参数还包括Uri

deliveryIntentSmsSingleRecipientSender.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_COMPLETEEVENT_SEND_SMS_COMPLETE类型的消息会在handleSendComplete方法中具体处理,逻辑实现如下:

a.获取SmsTracker对象tracker以及sentIntent

b.如果返回的结果无异常,那么使用sentIntent发出广播,并且如果此短信需要知道是否对方已接收到,将SmsTracker对象tracker保存到deliveryPendingList

c.如果返回的结果有异常,那么构造封装有trackerEVENT_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消息通知,会在GSMSMSDispatcherhandleMessage中接收,并交给handleStatusReport方法处理:

a.deliveryPendingList中取出SmsTracker对象tracker

b.SmsTracker对象tracker中获取 deliveryIntent

c.使用deliveryIntent发出广播


上文中有讲到deliveryIntent是由SmsSingleRecipientSender.sendMessage方法创建的Action类型为 MessageStatusReceiver.MESSAGE_STATUS_RECEIVED_ACTIONIntent对象。

使用此对象发出广播时,MessageStatusReceiver类中的onReceive方法会接收到,并且通过MessageStatusService服务,调用其updateMessageStatus方法更新短信发送状态。