android 簡訊接收流程分析——為更好的攔截簡訊做準備

來源:互聯網
上載者:User

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

 

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

檔案可以看出傳送簡訊和接收簡訊是通過Receiver和Sender架構,傳送簡訊主要通過Sender架構,主要如下(圖是從網上竊滴~):

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

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

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

從右邊那塊(結合代碼)可以看出簡訊接收是從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類裡

該類做了一件重要的事:給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服務類來處理簡訊並儲存簡訊。

 

參考文章:

http://newfaction.net/2011/03/15/android-2-2-ril-java-part-of-the-code-profile.html

http://blog.csdn.net/maxleng/article/details/5593759

http://www.360doc.com/content/10/0625/11/496343_35127382.shtml

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.