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中]
[java]
mReceiver = newRILReceiver(); 
mReceiverThread =new Thread(mReceiver, "RILReceiver"); 
mReceiverThread.start(); 

其中的類型
mReceiver: RILReceiver
mReceiverThread: Thread
 
RILReceiver實現瞭Runnable
RILReceiver

 

關註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)。

 SmsMessage

 

mSMSRegistrant是RIL父類的成員。通過setOnNewSMS()/unSetOnNewSMS()設置和取消設置。SMSDispatcher的構造函數中註冊瞭SMS的Registrant

mCm.setOnNewSMS(this, EVENT_NEW_SMS, null);

 Regstrant

 

所以,調用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

發佈留言