分享

短息接收

 android之情殇 2012-12-29

2012-07-07 13:13 

目录(?)[+]

短彩信的接收流程

涉及的文件

  1. com.android.internal.telephony/Ril.java  

  2. com.android.internal.telephony/SMSDispatcher  

  3. com.android.internal.telephony/CommandsInterface  

  4. com.android.internal.telephony/GsmSMSDispatcher  

  5. com.android.internal.telephony/CdmanSMSDispatcher  

  6. com.android.internal.telephony/ImsSMSDispatcher  

  7. hardware/ril/libril/ril.cpp  

  8. com.android.mms.transaction/PrivilegedSmsReceiver  

流程分析

时序图

 

android ril java层接收短息的流程

1)监听底层上报的数据

在Ril.java中定义了一个receive的框架:当接收到短信时,底层首先通过rild将接收到的短信通过 socket传送给Ril.java,那大家都知道这个短信接收是一个不定时的,所以就必须有一个监听器一直监视这个socket一旦有短信就触发其相应 的操作。那Ril.java是否有定义这样的一个监听器或者类似的功能了?(补充:这涉及一个Modem端与rild的通信,rild是一个守护进程,是 整个android ril层的入口点,这部分笔者不是很清楚,推荐网页http://blog.163.com/yan_zhennan@126/blog/static/10934475020122275412446/

通过查看代码我们可以发现RILReceiver的内部类:

  1. class RILReceiver implements Runnable {  

  2.         byte[] buffer;  

  3.         RILReceiver() {  

  4.             buffer = new byte[RIL_MAX_COMMAND_BYTES];  

  5.         }  

  6.         public void  

  7.         run() {  

  8.             int retryCount = 0;  

  9.             String rilSocket = "rild";  

  10.             try {for (;;) {  

  11.                 LocalSocket s = null;  

  12.                 LocalSocketAddress l;  

  13.                 boolean multiRild = SystemProperties.getBoolean("ro.multi.rild", false);  

  14.                 if (mInstanceId == 0 || multiRild == false) {  

  15.                     rilSocket = SOCKET_NAME_RIL;  

  16.                 } else {  

  17.                     rilSocket = SOCKET_NAME_RIL1;  

  18.                 }  

  19.                 try {  

  20.                     s = new LocalSocket();  

  21.                     l = new LocalSocketAddress(rilSocket,  

  22.                             LocalSocketAddress.Namespace.RESERVED);  

  23.                     s.connect(l);  

  24.                 }   

  25.                    if (retryCount == 8) {  

  26.                         Log.e (LOG_TAG,  

  27.                             "Couldn't find '" + rilSocket  

  28.                             + "' socket after " + retryCount  

  29.                             + " times, continuing to retry silently");  

  30.                     } else if (retryCount > 0 && retryCount < 8) {  

  31.                         Log.i (LOG_TAG,  

  32.                             "Couldn't find '" + rilSocket  

  33.                             + "' socket; retrying after timeout");  

  34.                     }  

  35.                     try {  

  36.                         Thread.sleep(SOCKET_OPEN_RETRY_MILLIS);  

  37.                     } catch (InterruptedException er) {  

  38.                     }  

  39.                     retryCount++;  

  40.                     continue;  

  41.                 }  

  42.                 retryCount = 0;  

  43.                 mSocket = s;  

  44.                 Log.i(LOG_TAG, "Connected to '" + rilSocket + "' socket");  

  45.                 int length = 0;  

  46.                 try {  

  47.                     InputStream is = mSocket.getInputStream();  

  48.                     for (;;) {  

  49.                         Parcel p;  

  50.                         length = readRilMessage(is, buffer);  

  51.                         if (length < 0) {  

  52.                             // End-of-stream reached  

  53.                             break;  

  54.                         }  

  55.                         p = Parcel.obtain();  

  56.                         p.unmarshall(buffer, 0, length);  

  57.                         p.setDataPosition(0);  

  58. processResponse(p);  

  59.               p.recycle(); }  

2)对底层上报的数据进行处理从上面的代码看出这个线程一直和守护进程rild进行sorcket通信,并获取守护进程上报的数据。可以看出做了很多的工作但是最重要的是processResponse()方法向上汇报数据,下面是其处理代码:

  1. <p>  

  2.      private void  

  3.     processResponse (Parcel p) {  

  4.         int type;  

  5.         type = p.readInt();  

  6.         if (type == RESPONSE_UNSOLICITED) {  

  7.             processUnsolicited (p);  

  8.         } else if (type == RESPONSE_SOLICITED) {  

  9.             processSolicited (p);  

  10.         }  

  11.         releaseWakeLockIfDone();  

  12.     }</p>  

可 以看出在上报数据进行了分类处理,RESPONSE_UNSOLICITED表示接收到数据就直接上报的类型,主动上报,如网络状态和短信、来电等等。 RESPONSE_SOLICITED是必须先请求然后才响应的类型。当然这里是短信接收肯定会走前者。processUnsolicited该方法会根 据当前的请求的类型,如果是短信则是RIL_UNSOL_RESPONSE_NEW_SMS,以下是其调用的代码;
  1. case RIL_UNSOL_RESPONSE_NEW_SMS: {  

  2.                if (RILJ_LOGD) unsljLog(response);  

  3.                // FIXME this should move up a layer  

  4.                String a[] = new String[2];  

  5.                a[1] = (String)ret;  

  6.                SmsMessage sms;  

  7.                sms = SmsMessage.newFromCMT(a);  

  8.                if (mSMSRegistrant != null) {  

  9.                    mSMSRegistrant  

  10.                        .notifyRegistrant(new AsyncResult(null, sms, null));  

  11.                }  

  12.            break;  

  13.            }  


3)追溯该方法,mSMSRegistrant对象的创建过程mSMSRegistrant是BaseCommands的成员变量,且在调用 setOnNewSMS()方法来赋值的,BaseCommands是干什么的有的童鞋会问,我们看一下Ril.java的继承关系就知道 了,Ril.java是它的子类。了解了这些童鞋肯定会问那谁又调用了setOnNewSMS方法?以下是该流程的时序图。

 最后发现该方法设置handler的源头是在GsmSMSDispatcher类里,但最后会调用SmsDispatcher的 handMessage方法。原因是GsmSMSDispatcher是SmsDispatcher的子类而且GsmSMSDispatcher没有复写 handMessage方法,所以接收到消息后肯定由父类的handMessage方法来处理。

到此为止android的ril java层走完了,剩余的就交给中间层慢慢去做。

注意:

1)这是2.3的代码,对比一下4.0的代码可以发现GsmSMSDispatcher复写了handMessage的方法,自己会去处理,但是仅 限于EVENT_NEW_SMS_STATUS_REPORT、EVENT_NEW_BROADCAST_SMS、 EVENT_WRITE_SMS_COMPLETE其余的事件仍由父类SmsDispatcher来完成。

2)4.0中没有setOnNewSMS该方法,替换成了setOnNewGsmSms、setOnNewCdmaSms方法,对应于不同类型的phone做自己的注册。

framework SMSDispatcher接收短信后的处理流程

中间层SMSDispatcher处理流程:

1)该类做了一件重要的事:

给CommandInterface设置handler的处理方法,就是当接收到短信后触发mSMSRegistrant.notifyRegistrant(new AsyncResult(null, sms, null));方法

然后回调调用之前传入的handler,接着在handler里面处理短信消息。

2)handler处理接收到的短信消息:

  1. @Override     

  2.     public void handleMessage(Message msg) {  

  3.         AsyncResult ar;  

  4.         switch (msg.what) {  

  5.         case EVENT_NEW_SMS:  

  6.             // A new SMS has been received by the device  

  7.             if (Config.LOGD) {  

  8.                 Log.d(TAG, "New SMS Message Received");  

  9.             }  

  10.             SmsMessage sms;  

  11.             ar = (AsyncResult) msg.obj;  

  12.             if (ar.exception != null) {  

  13.                 Log.e(TAG, "Exception processing incoming SMS. Exception:"     

  14.                         + ar.exception);  

  15.                 return;  

  16.             }  

  17.             sms = (SmsMessage) ar.result;  

  18.             try {  

  19.                 int result = dispatchMessage(sms.mWrappedSmsMessage);  

  20.                 if (result != Activity.RESULT_OK) {  

  21.                     // RESULT_OK means that message was broadcast for app(s) to     

  22.                     // handle.  

  23.                     // Any other result, we should ack here.  

  24.                     boolean handled = (result == Intents.RESULT_SMS_HANDLED);  

  25.                     notifyAndAcknowledgeLastIncomingSms(handled, result, null);  

  26.                 }  

  27.             } catch (RuntimeException ex) {  

  28.                 Log.e(TAG, "Exception dispatching message", ex);  

  29.                 notifyAndAcknowledgeLastIncomingSms(false,     

  30.                         Intents.RESULT_SMS_GENERIC_ERROR, null);  

  31.             }  

  32.             break;  

  33.         }  

  34.     }  

 说明:

int result = dispatchMessage(sms.mWrappedSmsMessage);

 该段会通过子类(GsmSMSDispatcher)的dispatchMessage方法处理。
经一系列的判断处理最后普通短信将交给dispatchPdus(pdus);这个方法处理。

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

  2. Intent intent = new Intent(Intents.SMS_RECEIVED_ACTION);  

  3. intent.putExtra("pdus", pdus);  

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

  5. }  

  6. void dispatch(Intent intent, String permission) {  

  7. // Hold a wake lock for WAKE_LOCK_TIMEOUT seconds, enough to give any  

  8. // receivers time to take their own wake locks.  

  9. mWakeLock.acquire(WAKE_LOCK_TIMEOUT);  

  10. mContext.sendOrderedBroadcast(intent, permission, mResultReceiver,  

  11. this, Activity.RESULT_OK, null, null);  

  12. }  

3)我们可以看出这个方法将短信通过顺序广播播放出去(action是SMS_RECEIVED_ACTION),无论广播是否被中断最后都会调用 mResultReceiver,这里会将已读或未读的状态告诉给对方。如果短信广播中间没有受到終止。然后短信app中 PrivilegedSmsReceiver广播接收器接收到广播后会调用onReceiveWithPrivilege方法,由于 PrivilegedSmsReceiver继承与SmsReceiver,所以会调用父类的该方法。其代码:

  1. protected void onReceiveWithPrivilege(Context context, Intent intent, boolean privileged) {  

  2.         // If 'privileged' is false, it means that the intent was delivered to the base  

  3.         // no-permissions receiver class.  If we get an SMS_RECEIVED message that way, it  

  4.         // means someone has tried to spoof the message by delivering it outside the normal  

  5.         // permission-checked route, so we just ignore it.  

  6.         if (!privileged && (intent.getAction().equals(Intents.SMS_RECEIVED_ACTION)  

  7.                 || intent.getAction().equals(Intents.SMS_CB_RECEIVED_ACTION))) {  

  8.             return;  

  9.         }  

  10.         intent.setClass(context, SmsReceiverService.class);  

  11.         intent.putExtra("result", getResultCode());  

  12.         beginStartingService(context, intent);  

  13.     }  

最后交由SmsReceiverService该service去处理,到此为止已经到应用层Mms。

彩信的接收

  可能有些童鞋看到这明白了短信的接收可能会问到那彩信的接收又会使什么样的了,为了解惑所以在此简单描述彩信接收的过程,由于很多和短信相似。这个过程了 就画一个时序图个大家,注意:这直到应用层,应用层的具体实现会有专门的文章来讲述。在这以GSM为例,以下是其时序图:
            

说明:大家可以看出和短信的接收来他们的区别在于dispatchMessage方法会根据smsHeader.portAddrs来判断当前是彩信还是短信,然后调用对应的方法。

总结

   这里没有去分析rild是怎么和ril.java 建立socket通信,也没有讲rild怎么和moderm端进行通信的,这些我会继续研究,希望尽早分享给大家。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多