Android短信接收流程---框架层(Frameworks)
Ps.基于4.1的源码进行分析。。。。
涉及的文件com.android.internal.telephony/Ril.java
com.android.internal.telephony/SMSDispatcher
com.android.internal.telephony/CommandsInterface
com.android.internal.telephony/GsmSMSDispatcher
hardware/ril/libril/ril.cpp
从底层ril.cpp中收到短信处理完成后,通过socket通信到---->>Ril.java,框架层的短信接收流程就开始了!!!
com.android.internal.telephony/Ril.java
com.android.internal.telephony/SMSDispatcher
com.android.internal.telephony/CommandsInterface
com.android.internal.telephony/GsmSMSDispatcher
hardware/ril/libril/ril.cpp
1:Ril.java
Ril.java中有内部类:RILReceiver,RILReceiver的run方法中不断的监听: InputStream is = mSocket.getInputStream();然后 readRilMessage(is, buffer);把消息存入buffer中,然后p.unmarshall(buffer, 0, length);打包成一个Parcel p;然后run方法到最后调用了processResponse(p);进行下一步处理。
class RILReceiver implements Runnable {
byte[] buffer;
RILReceiver() {
buffer = new byte[RIL_MAX_COMMAND_BYTES];
}
public void
run() {
int retryCount = 0;
try {for (;;) {
LocalSocket s = null;
LocalSocketAddress l;
try {
s = new LocalSocket();
l = new LocalSocketAddress(SOCKET_NAME_RIL,
LocalSocketAddress.Namespace.RESERVED);
s.connect(l);
} catch (IOException ex){
try {
if (s != null) {
s.close();
}
} catch (IOException ex2) {
//ignore failure to close after failure to connect
}
// don't print an error message after the the first time
// or after the 8th time
if (retryCount == 8) {
Log.e (LOG_TAG,
"Couldn't find '" + SOCKET_NAME_RIL
+ "' socket after " + retryCount
+ " times, continuing to retry silently");
} else if (retryCount > 0 && retryCount < 8) {
Log.i (LOG_TAG,
"Couldn't find '" + SOCKET_NAME_RIL
+ "' socket; retrying after timeout");
}
try {
Thread.sleep(SOCKET_OPEN_RETRY_MILLIS);
} catch (InterruptedException er) {
}
retryCount++;
continue;
}
retryCount = 0;
mSocket = s;
Log.i(LOG_TAG, "Connected to '" + SOCKET_NAME_RIL + "' socket");
int length = 0;
try {
InputStream is = mSocket.getInputStream();
for (;;) {
Parcel p;
length = readRilMessage(is, buffer);
if (length < 0) {
// End-of-stream reached
break;
}
p = Parcel.obtain();
p.unmarshall(buffer, 0, length);
p.setDataPosition(0);
//Log.v(LOG_TAG, "Read packet: " + length + " bytes");
processResponse(p);
p.recycle();
}
} catch (java.io.IOException ex) {
Log.i(LOG_TAG, "'" + SOCKET_NAME_RIL + "' socket closed",
ex);
} catch (Throwable tr) {
Log.e(LOG_TAG, "Uncaught exception read length=" + length +
"Exception:" + tr.toString());
}
Log.i(LOG_TAG, "Disconnected from '" + SOCKET_NAME_RIL
+ "' socket");
setRadioState (RadioState.RADIO_UNAVAILABLE);
try {
mSocket.close();
} catch (IOException ex) {
}
mSocket = null;
RILRequest.resetSerial();
// Clear request list on close
clearRequestsList(RADIO_NOT_AVAILABLE, false);
}} catch (Throwable tr) {
Log.e(LOG_TAG,"Uncaught exception", tr);
}
/* We're disconnected so we don't know the ril version */
notifyRegistrantsRilConnectionChanged(-1);
}
}
processResponse(p)会根据类型选择调用 processUnsolicited (p)(无需请求直接上报);或是processSolicited (p)(需要先请求才可以);在短信接收过程中调用的是processUnsolicited (p);
processUnsolicited (p)方法会在switch语句中根据p中的类型进行不同的操作,接收短信 会在这个分支中操作case RIL_UNSOL_RESPONSE_NEW_SMS:
case RIL_UNSOL_RESPONSE_NEW_SMS: {
if (RILJ_LOGD) unsljLog(response);
// FIXME this should move up a layer
String a[] = new String[2];
a[1] = (String)ret;
SmsMessage sms;
sms = SmsMessage.newFromCMT(a);
if (mGsmSmsRegistrant != null) {
mGsmSmsRegistrant
.notifyRegistrant(new AsyncResult(null, sms, null));
}
break;
把短消息进一步封装处理成一个SmsMessage类型的消息,然后mGsmSmsRegistrant这个是什么呢O O这是一个Registrant类型(消息注册机制:一个对象中开辟一个空间用于存放Message,当调用regist方法时将Message存放进去,当其调用notify方法时将所有Message取出并发送到MessageQueue中等待处理)暂时不太明白,我简单的理解就是把message发送给handler让handler去处理。
1:那么这个handler在哪里实现的呢??
答:在GsmSMSDispatcher.java(父类:SMSDispather.java)的handleMessage方法中实现。
2:这个handler是在哪里设置到呢。。。
答:在GsmSMSDispatcher.java的构造函数中调用了mCm.setOnNewGsmSms(this, EVENT_NEW_SMS, null);而mCm是在手机开机时调用的PhoneFactory调用makeDefaultPhone()方法创建的RIL实例的一个引用,RIL的父类BaseCommands.java(BaseCommands类实现CommandsInterface的部分接口,通知手机内部状态变化)中实现了
public void setOnNewGsmSms(Handler h, int what, Object obj) {
mGsmSmsRegistrant = new Registrant (h, what, obj);
//由此可知在GsmSMSDispatcher.java把handler设置成了自己
}
然后短消息就从RIL.java中通过SmsMessage的形式提交到了GsmSMSDispatcher.java与他的父类SMSDispather.java这两个进行短信进一步分发的类中的handleMessage方法中进行处理。
2:SMSDispatcher.java(父类)GsmSMSDispatcher.java(子类)
最开始的handleMessage处理是在SMSDispatcher.java中,直接上SMSDispatcher.java中handleMessage方法的代码:
/**
* Handles events coming from the phone stack. Overridden from handler.
*
* @param msg the message to handle
*
*/
@Override
public void handleMessage(Message msg) {
AsyncResult ar;
switch (msg.what) {
case EVENT_NEW_SMS:
// A new SMS has been received by the device
if (false) {
Log.d(TAG, "New SMS Message Received");
}
SmsMessage sms;
ar = (AsyncResult) msg.obj;
if (ar.exception != null) {
Log.e(TAG, "Exception processing incoming SMS. Exception:" + ar.exception);
return;
}
sms = (SmsMessage) ar.result;
try {
int result = dispatchMessage(sms.mWrappedSmsMessage);
if (result != Activity.RESULT_OK) {
// RESULT_OK means that message was broadcast for app(s) to handle.
// Any other result, we should ack here.
boolean handled = (result == Intents.RESULT_SMS_HANDLED);
notifyAndAcknowledgeLastIncomingSms(handled, result, null);
}
} catch (RuntimeException ex) {
Log.e(TAG, "Exception dispatching message", ex);
notifyAndAcknowledgeLastIncomingSms(false, Intents.RESULT_SMS_GENERIC_ERROR, null);
}
break;
case EVENT_SEND_SMS_COMPLETE:
// An outbound SMS has been successfully transferred, or failed.
handleSendComplete((AsyncResult) msg.obj);
break;
case EVENT_SEND_RETRY:
sendSms((SmsTracker) msg.obj);
break;
case EVENT_SEND_LIMIT_REACHED_CONFIRMATION:
handleReachSentLimit((SmsTracker)(msg.obj));
break;
case EVENT_SEND_CONFIRMED_SMS:
{
SmsTracker tracker = (SmsTracker) msg.obj;
if (tracker.isMultipart()) {
sendMultipartSms(tracker);
} else {
sendSms(tracker);
}
mPendingTrackerCount--;
break;
}
case EVENT_STOP_SENDING:
{
SmsTracker tracker = (SmsTracker) msg.obj;
if (tracker.mSentIntent != null) {
try {
tracker.mSentIntent.send(RESULT_ERROR_LIMIT_EXCEEDED);
} catch (CanceledException ex) {
Log.e(TAG, "failed to send RESULT_ERROR_LIMIT_EXCEEDED");
}
}
mPendingTrackerCount--;
break;
}
}
}
在case EVENT_NEW_SMS:分支语句中:调用下一步函数dispatchMessage(……)这个方法我们在SMSDispatcher.java中是一个抽象方法,我们很快就能发现真正的实现是在子类GsmSMSDispatcher.java中,接着上代码:
/** {@inheritDoc} */
@Override
public int dispatchMessage(SmsMessageBase smsb) {
// If sms is null, means there was a parsing error.
if (smsb == null) {
Log.e(TAG, "dispatchMessage: message is null");
return Intents.RESULT_SMS_GENERIC_ERROR;
}
SmsMessage sms = (SmsMessage) smsb;
if (sms.isTypeZero()) {
// As per 3GPP TS 23.040 9.2.3.9, Type Zero messages should not be
// Displayed/Stored/Notified. They should only be acknowledged.
Log.d(TAG, "Received short message type 0, Don't display or store it. Send Ack");
return Intents.RESULT_SMS_HANDLED;
}
// Send SMS-PP data download messages to UICC. See 3GPP TS 31.111 section 7.1.1.
if (sms.isUsimDataDownload()) {
UsimServiceTable ust = mPhone.getUsimServiceTable();
// If we receive an SMS-PP message before the UsimServiceTable has been loaded,
// assume that the data download service is not present. This is very unlikely to
// happen because the IMS connection will not be established until after the ISIM
// records have been loaded, after the USIM service table has been loaded.
if (ust != null && ust.isAvailable(
UsimServiceTable.UsimService.DATA_DL_VIA_SMS_PP)) {
Log.d(TAG, "Received SMS-PP data download, sending to UICC.");
return mDataDownloadHandler.startDataDownload(sms);
} else {
Log.d(TAG, "DATA_DL_VIA_SMS_PP service not available, storing message to UICC.");
String smsc = IccUtils.bytesToHexString(
PhoneNumberUtils.networkPortionToCalledPartyBCDWithLength(
sms.getServiceCenterAddress()));
mCm.writeSmsToSim(SmsManager.STATUS_ON_ICC_UNREAD, smsc,
IccUtils.bytesToHexString(sms.getPdu()),
obtainMessage(EVENT_WRITE_SMS_COMPLETE));
return Activity.RESULT_OK; // acknowledge after response from write to USIM
}
}
if (mSmsReceiveDisabled) {
// Device doesn't support SMS service,
Log.d(TAG, "Received short message on device which doesn't support "
+ "SMS service. Ignored.");
return Intents.RESULT_SMS_HANDLED;
}
// Special case the message waiting indicator messages
boolean handled = false;
if (sms.isMWISetMessage()) {
mPhone.setVoiceMessageWaiting(1, -1); // line 1: unknown number of msgs waiting
handled = sms.isMwiDontStore();
if (false) {
Log.d(TAG, "Received voice mail indicator set SMS shouldStore=" + !handled);
}
} else if (sms.isMWIClearMessage()) {
mPhone.setVoiceMessageWaiting(1, 0); // line 1: no msgs waiting
handled = sms.isMwiDontStore();
if (false) {
Log.d(TAG, "Received voice mail indicator clear SMS shouldStore=" + !handled);
}
}
if (handled) {
return Intents.RESULT_SMS_HANDLED;
}
if (!mStorageMonitor.isStorageAvailable() &&
sms.getMessageClass() != MessageClass.CLASS_0) {
// It's a storable message and there's no storage available. Bail.
// (See TS 23.038 for a description of class 0 messages.)
return Intents.RESULT_SMS_OUT_OF_MEMORY;
}
return dispatchNormalMessage(smsb);
}
没有管他到底干了什么事情。大概就是判断是不是一条普普通通的短信而不是什么特别的短信。
总之最后又重新回到父类SMSDispatcher.java中调用了父类方法dispatchNormalMessage(smsb);上代码:
/**
* Dispatch a normal incoming SMS. This is called from the format-specific
* {@link #dispatchMessage(SmsMessageBase)} if no format-specific handling is required.
*
* @param sms
* @return
*/
protected int dispatchNormalMessage(SmsMessageBase sms) {
SmsHeader smsHeader = sms.getUserDataHeader();
// See if message is partial or port addressed.
if ((smsHeader == null) || (smsHeader.concatRef == null)) {
// Message is not partial (not part of concatenated sequence).
byte[][] pdus = new byte[1][];
pdus[0] = sms.getPdu();
if (smsHeader != null && smsHeader.portAddrs != null) {
if (smsHeader.portAddrs.destPort == SmsHeader.PORT_WAP_PUSH) {
// GSM-style WAP indication
return mWapPush.dispatchWapPdu(sms.getUserData());
} else {
// The message was sent to a port, so concoct a URI for it.
dispatchPortAddressedPdus(pdus, smsHeader.portAddrs.destPort);
}
} else {
// Normal short and non-port-addressed message, dispatch it.
dispatchPdus(pdus);
}
return Activity.RESULT_OK;
} else {
// Process the message part.
SmsHeader.ConcatRef concatRef = smsHeader.concatRef;
SmsHeader.PortAddrs portAddrs = smsHeader.portAddrs;
return processMessagePart(sms.getPdu(), sms.getOriginatingAddress(),
concatRef.refNumber, concatRef.seqNumber, concatRef.msgCount,
sms.getTimestampMillis(), (portAddrs != null ? portAddrs.destPort : -1), false);
}
}
先是提取了短信的头部,判断是不是通过端口发送的短信?可能是通过网络端口发送的奇怪短信把 不管他,,,
然后提取了sms中的pdu部分,协议数据单元么??大概就是短信都是根据一定的协议规定而成的一个byte[],比如前几个byte代表什么什么的。。。maybe是这样子。。
总之接着调用dispatchPdus(pdus); // Normal short and non-port-addressed message, dispatch it。
分发这个pdu(就是短信)接着上dispatchPdus方法的代码(也在父类SMSDispatcher.java中)
protected void dispatchPdus(byte[][] pdus) {
Intent intent = new Intent(Intents.SMS_RECEIVED_ACTION);
intent.putExtra("pdus", pdus);
intent.putExtra("format", getFormat());
dispatch(intent, RECEIVE_SMS_PERMISSION);
}
接着上dispatch(intent, RECEIVE_SMS_PERMISSION)方法的代码(也在父类SMSDispatcher.java中)
public void dispatch(Intent intent, String permission) {
// Hold a wake lock for WAKE_LOCK_TIMEOUT seconds, enough to give any
// receivers time to take their own wake locks.
mWakeLock.acquire(WAKE_LOCK_TIMEOUT);
mContext.sendOrderedBroadcast(intent, permission, mResultReceiver,
this, Activity.RESULT_OK, null, null);
}
简单的说就是把pdu和短信格式放到intent中去,然后发送一个有序广播把短信来了这个广播发送出去。至此,框架层的短信接收就完成了。下面就交付给应用层来处理了。
Ps. 4.4之后的版本这里的广播有所区别,好像变成无序广播了。。总之,4.4以前短信广播可以被高优先级的应用截断,然而4.4以后短信广播是不能截断的了。。。而且4.4以后除了默认短信应用都无法享受短信数据库的更新,删除,插入操作。