【SMS】android 短信接收流程分析——-拦截短信示例代码

观察360的短信拦截和QQ管家的短信拦截,发现先安装的就能先拦截到的短信,然后中断广播,之后谁都不能获取到短信。从这里可以推出系统大概有一个广播表,同等级的按安装先后顺序排放。目前的方法是在应用层调用framework API进行控制的。
  
  为了能更好的了解android接收短信的流程,我进行了更深入的分析,从RIL的通信架构来分析当接收到短信的整个流程。从frameword里的RIL.java
  
  文件可以看出发送短信和接收短信是通过Receiver和Sender架构,发送短信主要通过Sender框架,主要如下(图是从网上窃滴~):

【SMS】android 短信接收流程分析——-拦截短信示例代码_第1张图片
  上层函数调用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

你可能感兴趣的:(android,短信)