在解析WAPPUSH over SMS時,看了一下Android裡SMS接收的流程,並按照自己需要的流程記錄,其他分支的詳細處理並未講述。PDU資料的encode/decode也並未在本文中進行解析,有興趣的讀者可以到相應的代碼處自己解讀一下。
Android中,RIL用RILReciever接收SMS pdu,並根據不同的資訊類型用相應函數來處理。因手機制式的差異,用GsmSmsDispatcher或CdmaSmsDispatcher來做各自的訊息處理並分發。最後的分發是通過發送相應的Broadcast,所以,對感興趣的訊息處理,可以註冊Receiver來監聽相應的Broadcast,實現自己的SMS/MMS/Wap push,以及其他類型訊息的接收處理。
RIL建構函式中,Receiver的初始化[在檔案RIL.java中]
[java]
mReceiver = newRILReceiver();
mReceiverThread =new Thread(mReceiver, "RILReceiver");
mReceiverThread.start();
其中的類型
mReceiver: RILReceiver
mReceiverThread: Thread
RILReceiver實現了Runnable
關注RILReceiver線程的實現[在RILReceiver::run()中]
[java] public void run() {
int retryCount= 0;
try {for (;;) {
LocalSockets = null;
LocalSocketAddress l;
try {
s = newLocalSocket();
l = newLocalSocketAddress(SOCKET_NAME_RIL,
LocalSocketAddress.Namespace.RESERVED);
s.connect(l);
} catch (IOException ex){
// 。。。
}
retryCount= 0;
mSocket =s;
int length= 0;
try {
InputStreamis = 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);
processResponse(p);
p.recycle();
}
} catch(java.io.IOException ex) {
// …
} catch(Throwable tr) {
// …
}
// …
}} catch(Throwable tr) {
Log.e(LOG_TAG,"Uncaught exception", tr);
}
}
public void run() {
int retryCount= 0;
try {for (;;) {
LocalSockets = null;
LocalSocketAddress l;
try {
s = newLocalSocket();
l = newLocalSocketAddress(SOCKET_NAME_RIL,
LocalSocketAddress.Namespace.RESERVED);
s.connect(l);
} catch (IOException ex){
// 。。。
}
retryCount= 0;
mSocket =s;
int length= 0;
try {
InputStreamis = 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);
processResponse(p);
p.recycle();
}
} catch(java.io.IOException ex) {
// …
} catch(Throwable tr) {
// …
}
// …
}} catch(Throwable tr) {
Log.e(LOG_TAG,"Uncaught exception", tr);
}
}
RILReceiver線程不停的監聽本地Socket,讀到資料之後在processResponse()[Line#37]中處理。
[java] private void processResponse (Parcel p) {
int type;
type = p.readInt();
if(type == RESPONSE_UNSOLICITED) {
processUnsolicited (p);
}else if (type == RESPONSE_SOLICITED) {
processSolicited (p);
}
releaseWakeLockIfDone();
}
private void processResponse (Parcel p) {
int type;
type = p.readInt();
if(type == RESPONSE_UNSOLICITED) {
processUnsolicited (p);
}else if (type == RESPONSE_SOLICITED) {
processSolicited (p);
}
releaseWakeLockIfDone();
}
如果類型屬於Unsolicited訊息,則在processUnsolicited()中處理。收到的簡訊是屬於Unsolicited資訊,看它的實現。
processUnsolicited()中很長的switch… case語句中對收到簡訊的處理在case RIL_UNSOL_RESPONSE_NEW_SMS:
[java] SmsMessage sms;
sms = SmsMessage.newFromCMT(a);
if (mSMSRegistrant != null) {
mSMSRegistrant.notifyRegistrant(new AsyncResult(null, sms, null));
}
SmsMessage sms;
sms = SmsMessage.newFromCMT(a);
if (mSMSRegistrant != null) {
mSMSRegistrant.notifyRegistrant(new AsyncResult(null, sms, null));
}
這裡的SmsMessage是android.telephony.SmsMessage。newFromCMT()中會根據電話類型(GSM/CDMA)選擇具體的SmsMessage進行封裝(因為Rational Rose中,同一工程中,不同包內的類也不允許同名,com.android.internal.telephony.gsm.SmsMessage用gsm.SmsMessage代替;com.android.internal.telephony.cdma.SmsMessage用cdma.SmsMessage代替。實際類型都是SmsMessage)。
mSMSRegistrant是RIL父類的成員。通過setOnNewSMS()/unSetOnNewSMS()設定和取消設定。SMSDispatcher的建構函式中註冊了SMS的Registrant
mCm.setOnNewSMS(this, EVENT_NEW_SMS, null);
所以,調用mSMSRegistrant.notifyRegistrant(newAsyncResult(null, sms, null))之後,執行的是SMSDispatcher中Handler在handleMessage()中對EVENT_NEW_SMS的處理:
[java] 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 thatmessage was broadcast for app(s) to handle.
// Any other result, weshould 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);
}
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 thatmessage was broadcast for app(s) to handle.
// Any other result, weshould 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);
}
SMSDispatcher是一個abstract的類,dispatchMessage()的具體實現在GsmSMSDispatcher或CdmaSMSDispatcher中。
GsmSMSDispatcher::dispatchMessage()中,會對Class 0類型的簡訊,有目標連接埠的簡訊,和長簡訊做處理。
目標連接埠為WAPPUSH的資訊,則調用mWapPush.dispatchWapPdu(sms.getUserData(),pdus)讓WAPPUSH來處理;其它未知的連接埠,則用“sms://localhost:<port>”指定連接埠。
對長簡訊,調用processMessagePart()進行組合處理。
1) 有目標連接埠且目標連接埠是WAP PUSH(SmsHeader.PORT_WAP_PUSH)的資訊,用WapPushOverSms::dispatchWapPdu()來處理:
根據不同的contentType:
-> dispatchWapPdu_PushCO();
-> dispatchWapPdu_MMS();
-> dispatchWapPdu_default()
2) 有目標地址且目標連接埠不是WAP PUSH的資訊,在SMSDispatcher::dispatchPortAddressedPdus()中處理:
Uri uri =Uri.parse("sms://localhost:" + port);
Intent intent= new Intent(Intents.DATA_SMS_RECEIVED_ACTION, uri);
intent.putExtra("pdus", pdus);
dispatch(intent, "android.permission.RECEIVE_SMS");
3) 通常的無目標地址的資訊(普通簡訊),在SMSDispatcher::dispatchPdus()中處理:
Intent intent= new Intent(Intents.SMS_RECEIVED_ACTION);
intent.putExtra("pdus", pdus);
dispatch(intent, "android.permission.RECEIVE_SMS");
摘自 田海立@CSDN