Android中SMS的接收處理
在解析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中]
mReceiver = newRILReceiver(); mReceiverThread =new Thread(mReceiver, "RILReceiver"); mReceiverThread.start();
其中的類型
- mReceiver: RILReceiver
- mReceiverThread: Thread
RILReceiver實現了Runnable
關注RILReceiver線程的實現[在RILReceiver::run()中]
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]中處理。
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:
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的處理:
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:
對長短信,調用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");
轉自:http://blog.csdn.net/thl789/article/details/7284383