android 短信接收流程分析——爲更好的攔截短信做準備

觀察360的短信攔截和QQ管家的短信攔截,發現先安裝的就能先攔截到的短信,然後中斷廣播,之後誰都不能獲取到短信。從這裏可以推出系統大概有一個廣播表,同等級的按安裝先後順序排放。目前的方法是在應用層調用framework API進行控制的。

 

爲了能更好的瞭解android接收短信的流程,我進行了更深入的分析,從RIL的通信架構來分析當接收到短信的整個流程。從frameword裏的RIL.java

clip_image002

文件可以看出發送短信和接收短信是通過Receiver和Sender架構,發送短信主要通過Sender框架,主要如下(圖是從網上竊滴~):

image

上層函數調用Command Interface將請求消息發送到sender架構,由該架構將請求發送到RILD的架構。

目前主要分析接收短信走過的那些渠道,因此發送短信只是略微的說明一下。

接收短信流程如下(從發送消息到接收消息的處理流程)(圖是從網上剽滴~):

clip_image002[6]

從上圖右邊那塊(結合代碼)可以看出短信接收是從ril.cpp文件通過socket與RIL.java的socket交流,當ril.cpp收到短信後處理完成後會通過socket發送字節流給上層的RIL.java,而在RIL.java中有Receiver架構(該架構主要是一條線程)在不斷監聽,

 

Receiver架構代碼:

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

                    synchronized (mRequestsList) {

                        for (int i = 0, sz = mRequestsList.size(); i < sz; i++) {

                            RILRequest rr = mRequestsList.get(i);

                            rr.onError(RADIO_NOT_AVAILABLE, null);

                            rr.release();

                        }

                        mRequestsList.clear();

                    }

                }
            } catch (Throwable tr) {

                Log.e(LOG_TAG, "Uncaught exception", tr);

            }

        }

    }

 

因此從代碼可以看出獲取到短信消息後經過一系列地分析然後提交給processResponse(p); 方法處理,處理過程中會有兩種response,一種是主動上報,比如網絡狀態,短信,來電等都不需要經過請求,用unsolicited詞語專門描述,另一種纔是真正意義上的response,也就是命令的響應用solicited描述。那接收短信就是屬於unsolicited,跳到processUnsolicited (Parcel p)方法,查看該方法可得出會繼續觸發以下方法mSMSRegistrant.notifyRegistrant(new AsyncResult(null, sms, null)); 追溯該方法對象的創建,最後發現該方法設置handler的源頭是在:SMSDispatcher類裏

clip_image004

該類做了一件重要的事:給Command Interface設置handler的處理方法,就是當接收到短信後觸發mSMSRegistrant.notifyRegistrant(new AsyncResult(null, sms, null));方法,然後回調調用之前傳入的handler,接着在handler裏面處理短信消息。

mCm.setOnNewSMS(this, EVENT_NEW_SMS, null);

mCm.setOnSmsStatus(this, EVENT_NEW_SMS_STATUS_REPORT, null);

mCm.setOnIccSmsFull(this, EVENT_ICC_FULL, null);

mCm.registerForOn(this, EVENT_RADIO_ON, null);

 

handler處理接收到的短信消息:

@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 (Config.LOGD) {

                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;

        }

    }

 

int result = dispatchMessage(sms.mWrappedSmsMessage); 該段會通過子類(GsmSMSDispatcher)的dispatchMessage方法處理。經一系列的判斷處理最後普通短信將交給dispatchPdus(pdus);這個方法處理。

 

protected void dispatchPdus(byte[][] pdus) {

Intent intent = new Intent(Intents.SMS_RECEIVED_ACTION);

intent.putExtra("pdus", pdus);

dispatch(intent, "android.permission.RECEIVE_SMS");

}

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);

}

 

最後,我們可以看出這個方法將短信通過順序廣播播放出去(action是SMS_RECEIVED_ACTION),無論廣播是否被中斷最後都會調用mResultReceiver,這裏會將已讀或未讀的狀態告訴給對方。如果短信廣播中間沒有受到終止,那麼接下來的流程是:PrivilegedSmsReceiver類接收到android.provider.Telephony.SMS_RECEIVED的請求然後調用 intent.setClass(context,SmsReceiverService.class); 啓動SmsReceiverService服務類來處理短信並保存短信。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章