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,框架層的短信接收流程就開始了!!!
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以後除了默認短信應用都無法享受短信數據庫的更新,刪除,插入操作。