本文主要介绍Android如何接收短信,流程分为两个部分,Framework层和App层。
class="p16">Framework层:
短信的接收,Framework部分处理的顺序是RIL->SMSDispatcher->GsmSMSDispatcher/CdmaSMSDispatcher->SMSDispatcher。
当短信到Framework层之后,会首先启动RIL中的RILReceiver去接收短信,在RILReceiver中使用LocalSocket去读短信,然后把读到的短信放在一个Parcel对象中,然后调用processResponse(Parcel p)去处理,processResponse()中调用processUnsolicited(Parcel p)处理。
对于GSM,事件类型为RIL_UNSOL_RESPONSE_NEW_SMS,先调用responseString(Parcel p)从Parcel中获取数据,然后再使用newFromCMT()方法获取SmsMessage对象,此时短信数据已被转换成短信pdu保存在SmsMessage对象中。然后调用mGsmSmsRegistrant的notifyRegistrant(new AsyncResult(null, sms, null))方法发送消息,转入 SMSDispatcher的handleMessage()方法进行处理,事件类型为EVENT_NEW_SMS。
对于CDMA,事件类型为RIL_UNSOL_RESPONSE_CDMA_NEW_SMS,调用responseCdmaSms()从Parcel中获取数据,消息分发时使用的是CdmaSMSDispatcher,其他处理大部分都是和GSM是相同的。
这里为什么调用了notifyRegistrant()方法就会转入SMSDispatcher中进行处理呢?
原来在GsmSMSDispatcher初始化时调用了mCi.setOnNewGsmSms(this, EVENT_NEW_SMS, null),mCi在SMSDispatcher中声明为CommandsInterface,实际为一个BaseCommands对象,因为BaseCommands实现了CommandsInterface接口。
在SMSDispatcher中处理EVENT_NEW_SMS事件时,首先从message中取出保存短信的SmsMessage对象,然后调用dispatchMessage()进行消息分发。
在GsmSMSDispatcher的dispatchMessage()方法中,会对短信做一些特殊类型判断,这里的这些类型好像不是正常短信的类型,这些短信类型是什么我也不太清楚,需要再深入研究。但这里还有一个比较重要的处理就是会判断手机存储是不是已经满了,判断的依据是可用的存储是否大于1MB,如果小于1MB,则会返回一个RESULT_SMS_OUT_OF_MEMORY的Int值,然后发送一个SMS_REJECTED_ACTION的广播,App侧的SmsRejectedReceiver接收到这个广播后,就会拒绝接收这条短信,然后做一个memory full的notification。
在满足前面这些条件之后,则调用dispatchNormalMessage()处理这条普通的短信,这是一个比较重要的方法,它会判断正常短信的几种类型:
1.彩信通知(WapPushOverSms.dispatchWapPdu())
2.指定端口的彩信(dispatchPortAddressedPdus())
3.普通短信(dispatchPdus())
4.长短信(processMessagePart())
这里需要说明两点:
1.接收彩信实际上是由framework层向App层发送一条彩信通知,这条通知里携带有一些彩信的信息,譬如说彩信的大小,过期时间等,App层收到这条彩信通知以后会启动相应的transaction去彩信中心下载彩信。
2.长短信的处理,因为长短信不能一次接收完,而是分段接收,所以接收到的部分先要存储起来,使用SmsHeader.ConcatRef的refNumber把多个part标记为一条长短信,当把全部的part接收完之后,才会整条显示给用户,否则不会通知App层。
对于普通短信来说,这时候framework层的工作就结束了,需要通知App层,所以在dispatchPdus()中发送SMS_RECEIVED_ACTION的广播,由PrivilegedSmsReceiver接收,然后转入App层处理。
App层:
PrivilegedSmsReceiver在接收到短信来了的广播之后,由SmsReceiver启动SmsReceiverService来做具体的处理。
接收短信的action为SMS_RECEIVED_ACTION,所以调用handleSmsReceived()处理,使用insertMessage()将短信插入数据库,这里首先会判断短信是否为CLASS_0短信,如果是则直接显示,不插入数据库。如果不是则会进行消息的替换或者插入数据库,替换使用了SmsMessaged的isReplace()方法判断,原则是短信协议标识mProtocolIdentifier的判断。如果既不是CLASS_0短信也不需要替换,则将短信插入数据库,然后使用MessagingNotification在StatusBar做一个notification,通知用户短信来了。
接下来就是短信的显示了,当新接收到的短信插入数据库以后,因为数据库改变了,UI会收到onContentChanged事件,而ComposeMessageActivity注册了MessageListAdapter.OnDataSetChangedListener监听,所以会触发onContentChanged()方法,在此方法中调用startMsgListQuery()开始查询,查询结束后在BackgroundQueryHandler的onQueryComplete()中changeCursor,重新绑定MessageItem。至此,一条短信的接收处理完成。
作者:残阳破晓