Android短信接收流程---框架层(Frameworks)


Ps.基于4.1的源码进行分析。。。。

涉及的文件
com.android.internal.telephony/Ril.java  com.android.internal.telephony/SMSDispatcher  com.android.internal.telephony/CommandsInterface  com.android.internal.telephony/GsmSMSDispatcher     hardware/ril/libril/ril.cpp  

从底层ril.cpp中收到短信处理完成后,通过socket通信到---->>Ril.java,框架层的短信接收流程就开始了!!!


1:Ril.java

Ril.java中有内部类:RILReceiverRILReceiverrun方法中不断的监听: InputStream is = mSocket.getInputStream();然后readRilMessage(is, buffer);把消息存入buffer中,然后p.unmarshall(buffer, 0, length);打包成一个Parcel p;然后run方法到最后调用了processResponse(p);进行下一步处理。

    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                clearRequestsList(RADIO_NOT_AVAILABLE, false);            }} catch (Throwable tr) {                Log.e(LOG_TAG,"Uncaught exception", tr);            }            /* We're disconnected so we don't know the ril version */            notifyRegistrantsRilConnectionChanged(-1);        }    }

processResponse(p)会根据类型选择调用 processUnsolicited (p)(无需请求直接上报);或是processSolicited (p)(需要先请求才可以);在短信接收过程中调用的是processUnsolicited (p);

processUnsolicited (p)方法会在switch语句中根据p中的类型进行不同的操作,接收短信 会在这个分支中操作case RIL_UNSOL_RESPONSE_NEW_SMS:

    case RIL_UNSOL_RESPONSE_NEW_SMS: {                if (RILJ_LOGD) unsljLog(response);                // FIXME this should move up a layer                String a[] = new String[2];                a[1] = (String)ret;                SmsMessage sms;                sms = SmsMessage.newFromCMT(a);                if (mGsmSmsRegistrant != null) {                  mGsmSmsRegistrant                        .notifyRegistrant(new AsyncResult(null, sms, null));                }            break;
把短消息进一步封装处理成一个SmsMessage类型的消息,然后mGsmSmsRegistrant这个是什么呢O O这是一个Registrant类型(消息注册机制:一个对象中开辟一个空间用于存放Message,当调用regist方法时将Message存放进去,当其调用notify方法时将所有Message取出并发送到MessageQueue中等待处理)暂时不太明白,我简单的理解就是把message发送给handler让handler去处理。

1:那么这个handler在哪里实现的呢??

答:在GsmSMSDispatcher.java(父类:SMSDispather.java)的handleMessage方法中实现。

2:这个handler是在哪里设置到呢。。。

答:在GsmSMSDispatcher.java的构造函数中调用了mCm.setOnNewGsmSms(this, EVENT_NEW_SMS, null);而mCm是在手机开机时调用的PhoneFactory调用makeDefaultPhone()方法创建的RIL实例的一个引用,RIL的父类BaseCommands.java(BaseCommands类实现CommandsInterface的部分接口,通知手机内部状态变化)中实现了

public void setOnNewGsmSms(Handler h, int what, Object obj) {
mGsmSmsRegistrant = new Registrant (h, what, obj);

//由此可知在GsmSMSDispatcher.java把handler设置成了自己
}


然后短消息就从RIL.java中通过SmsMessage的形式提交到了GsmSMSDispatcher.java与他的父类SMSDispather.java这两个进行短信进一步分发的类中的handleMessage方法中进行处理。


2:SMSDispatcher.java(父类)GsmSMSDispatcher.java(子类)

最开始的handleMessage处理是在SMSDispatcher.java中,直接上SMSDispatcher.java中handleMessage方法的代码:

   /**     * Handles events coming from the phone stack. Overridden from handler.     *     * @param msg the message to handle  *  */    @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 (false) {                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;        case EVENT_SEND_SMS_COMPLETE:            // An outbound SMS has been successfully transferred, or failed.            handleSendComplete((AsyncResult) msg.obj);            break;        case EVENT_SEND_RETRY:            sendSms((SmsTracker) msg.obj);            break;        case EVENT_SEND_LIMIT_REACHED_CONFIRMATION:            handleReachSentLimit((SmsTracker)(msg.obj));            break;        case EVENT_SEND_CONFIRMED_SMS:        {            SmsTracker tracker = (SmsTracker) msg.obj;            if (tracker.isMultipart()) {                sendMultipartSms(tracker);            } else {                sendSms(tracker);            }            mPendingTrackerCount--;            break;        }        case EVENT_STOP_SENDING:        {            SmsTracker tracker = (SmsTracker) msg.obj;            if (tracker.mSentIntent != null) {                try {                    tracker.mSentIntent.send(RESULT_ERROR_LIMIT_EXCEEDED);                } catch (CanceledException ex) {                    Log.e(TAG, "failed to send RESULT_ERROR_LIMIT_EXCEEDED");                }            }            mPendingTrackerCount--;            break;        }        }    }

在case EVENT_NEW_SMS:分支语句中:调用下一步函数dispatchMessage(……)这个方法我们在SMSDispatcher.java中是一个抽象方法,我们很快就能发现真正的实现是在子类GsmSMSDispatcher.java中,接着上代码:

  /** {@inheritDoc} */    @Override    public int dispatchMessage(SmsMessageBase smsb) {        // If sms is null, means there was a parsing error.        if (smsb == null) {            Log.e(TAG, "dispatchMessage: message is null");            return Intents.RESULT_SMS_GENERIC_ERROR;        }        SmsMessage sms = (SmsMessage) smsb;        if (sms.isTypeZero()) {            // As per 3GPP TS 23.040 9.2.3.9, Type Zero messages should not be            // Displayed/Stored/Notified. They should only be acknowledged.            Log.d(TAG, "Received short message type 0, Don't display or store it. Send Ack");            return Intents.RESULT_SMS_HANDLED;        }        // Send SMS-PP data download messages to UICC. See 3GPP TS 31.111 section 7.1.1.        if (sms.isUsimDataDownload()) {            UsimServiceTable ust = mPhone.getUsimServiceTable();            // If we receive an SMS-PP message before the UsimServiceTable has been loaded,            // assume that the data download service is not present. This is very unlikely to            // happen because the IMS connection will not be established until after the ISIM            // records have been loaded, after the USIM service table has been loaded.            if (ust != null && ust.isAvailable(                    UsimServiceTable.UsimService.DATA_DL_VIA_SMS_PP)) {                Log.d(TAG, "Received SMS-PP data download, sending to UICC.");                return mDataDownloadHandler.startDataDownload(sms);            } else {                Log.d(TAG, "DATA_DL_VIA_SMS_PP service not available, storing message to UICC.");                String smsc = IccUtils.bytesToHexString(                        PhoneNumberUtils.networkPortionToCalledPartyBCDWithLength(                                sms.getServiceCenterAddress()));                mCm.writeSmsToSim(SmsManager.STATUS_ON_ICC_UNREAD, smsc,                        IccUtils.bytesToHexString(sms.getPdu()),                        obtainMessage(EVENT_WRITE_SMS_COMPLETE));                return Activity.RESULT_OK;  // acknowledge after response from write to USIM            }        }        if (mSmsReceiveDisabled) {            // Device doesn't support SMS service,            Log.d(TAG, "Received short message on device which doesn't support "                    + "SMS service. Ignored.");            return Intents.RESULT_SMS_HANDLED;        }        // Special case the message waiting indicator messages        boolean handled = false;        if (sms.isMWISetMessage()) {            mPhone.setVoiceMessageWaiting(1, -1);  // line 1: unknown number of msgs waiting            handled = sms.isMwiDontStore();            if (false) {                Log.d(TAG, "Received voice mail indicator set SMS shouldStore=" + !handled);            }        } else if (sms.isMWIClearMessage()) {            mPhone.setVoiceMessageWaiting(1, 0);   // line 1: no msgs waiting            handled = sms.isMwiDontStore();            if (false) {                Log.d(TAG, "Received voice mail indicator clear SMS shouldStore=" + !handled);            }        }        if (handled) {            return Intents.RESULT_SMS_HANDLED;        }        if (!mStorageMonitor.isStorageAvailable() &&                sms.getMessageClass() != MessageClass.CLASS_0) {            // It's a storable message and there's no storage available.  Bail.            // (See TS 23.038 for a description of class 0 messages.)            return Intents.RESULT_SMS_OUT_OF_MEMORY;        }       return dispatchNormalMessage(smsb);    }
没有管他到底干了什么事情。大概就是判断是不是一条普普通通的短信而不是什么特别的短信。

总之最后又重新回到父类SMSDispatcher.java中调用了父类方法dispatchNormalMessage(smsb);上代码:

   /**     * Dispatch a normal incoming SMS. This is called from the format-specific     * {@link #dispatchMessage(SmsMessageBase)} if no format-specific handling is required.     *     * @param sms     * @return     */    protected int dispatchNormalMessage(SmsMessageBase sms) {        SmsHeader smsHeader = sms.getUserDataHeader();        // See if message is partial or port addressed.        if ((smsHeader == null) || (smsHeader.concatRef == null)) {            // Message is not partial (not part of concatenated sequence).            byte[][] pdus = new byte[1][];            pdus[0] = sms.getPdu();            if (smsHeader != null && smsHeader.portAddrs != null) {                if (smsHeader.portAddrs.destPort == SmsHeader.PORT_WAP_PUSH) {                    // GSM-style WAP indication                    return mWapPush.dispatchWapPdu(sms.getUserData());                } else {                    // The message was sent to a port, so concoct a URI for it.                    dispatchPortAddressedPdus(pdus, smsHeader.portAddrs.destPort);                }            } else {                // Normal short and non-port-addressed message, dispatch it.               dispatchPdus(pdus);            }            return Activity.RESULT_OK;        } else {            // Process the message part.            SmsHeader.ConcatRef concatRef = smsHeader.concatRef;            SmsHeader.PortAddrs portAddrs = smsHeader.portAddrs;            return processMessagePart(sms.getPdu(), sms.getOriginatingAddress(),                    concatRef.refNumber, concatRef.seqNumber, concatRef.msgCount,                    sms.getTimestampMillis(), (portAddrs != null ? portAddrs.destPort : -1), false);        }    }

先是提取了短信的头部,判断是不是通过端口发送的短信?可能是通过网络端口发送的奇怪短信把 不管他,,,

然后提取了sms中的pdu部分,协议数据单元么??大概就是短信都是根据一定的协议规定而成的一个byte[],比如前几个byte代表什么什么的。。。maybe是这样子。。

总之接着调用dispatchPdus(pdus); // Normal short and non-port-addressed message, dispatch it。

分发这个pdu(就是短信)接着上dispatchPdus方法的代码(也在父类SMSDispatcher.java中)

   protected void dispatchPdus(byte[][] pdus) {        Intent intent = new Intent(Intents.SMS_RECEIVED_ACTION);        intent.putExtra("pdus", pdus);        intent.putExtra("format", getFormat());        dispatch(intent, RECEIVE_SMS_PERMISSION);    }

接着上dispatch(intent, RECEIVE_SMS_PERMISSION)方法的代码(也在父类SMSDispatcher.java中)

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

简单的说就是把pdu和短信格式放到intent中去,然后发送一个有序广播把短信来了这个广播发送出去。至此,框架层的短信接收就完成了。下面就交付给应用层来处理了。

Ps. 4.4之后的版本这里的广播有所区别,好像变成无序广播了。。总之,4.4以前短信广播可以被高优先级的应用截断,然而4.4以后短信广播是不能截断的了。。。而且4.4以后除了默认短信应用都无法享受短信数据库的更新,删除,插入操作。



更多相关文章

  1. Android全屏(包含3种隐藏顶部状态栏及标题栏和一种隐藏Android 4.
  2. Android中短信的收发机制 发送短信 接收短信 拦截短信 监听短信
  3. android 中调用接口发送短信
  4. Android两种播放视频的方法(SurfaceView、MediaPlayer、SeekBar)
  5. Android 解屏代码
  6. android去掉标题的方法
  7. Android 4.0 HttpUrlConnection的getInputStream()方法总是返回
  8. eclipse中安装android ADT插件及无法下载ADT解决方法
  9. 【Android】Android6.0发送短信Demo

随机推荐

  1. Android(安卓)Uri.getQueryParameter使用
  2. android自定义适配屏幕的ImageView
  3. android RadioButton单选按钮的使用
  4. SharePreference之记录应用的使用次数
  5. Android(安卓)OnScrollListener
  6. GPU Accelerated Compositing in Chrome
  7. Android练习之Intent发邮件ACTION_SEND
  8. Android学习之键盘事件
  9. MyBaseAdapter
  10. Android(安卓)Studio默认产生Fragment