转(Android 4.4 Kitkat Phone工作流程浅析(四)__RILJ工作流程简析)

来源:互联网 发布:蘑菇超强助手钓鱼软件 编辑:程序博客网 时间:2024/05/15 11:10
本文来自http://blog.csdn.net/yihongyuelan 


       本文代码以MTK平台Android 4.4为分析对象,与Google原生AOSP有些许差异,请读者知悉。
前置文章:
《Android 4.4 Kitkat Phone工作流程浅析(一)__概要和学习计划》

《Android 4.4 Kitkat Phone工作流程浅析(二)__UI结构分析》

《Android 4.4 Kitkat Phone工作流程浅析(三)__MO(去电)流程分析》

       通过上一篇文章《Android 4.4 Kitkat Phone工作流程浅析(三)__MO(去电)流程分析》,我们知道在 Android 4.4 中,拨打电话最终调用到了RIL.java中,并使用send()方法继续向下传递。本文主要目的是简单介绍RILJ工作流程,为后续MT流程分析打下基础。

RIL概述

       RIL 即 Ridio Interface Layer缩写,无线通信接口层,Android 中的实现分为RILJ和RILC两部分。RILJ属于Framework层中的Java部分( 后文使用RILJ指代RIL.java ),RILC属于HAL层中的C/C++部分(也就是rild)。RIL负责将AP层用户的通话控制信息传递给BP层Modem端,同时Modem端也会将相关处理结果返回给AP层。另外Modem状态有改变时也会主动上报给RIL层,再逐步向上传递并最终通过界面显示出来。本文仅简单介绍RILJ部分,详细分析请参看其他大神的分析。

RILJ与RILC以及Modem之间关系如图1:


图1

MO/MT在RILJ中执行流程:

1. MO在RILJ中流程:

       当用户执行MO(去电)时,通过层层判断之后,系统会将相关信息传递到RILJ中,封装好后使用AT指令的方式发送到Modem端,最终由Modem端发起通话请求。在通话接通后Modem端会返回相关AT指令信息给RIL层,RIL层再向上反馈。

整个MO(去电)流程可以简单的归结为两个步骤

(1). ( Request ,  Response) ,即向RILC发起Request,再由RILC向Modem发送相关AT指令,等待Modem处理并反馈结果,如DIAL操作;

(2). (Response),即在对方接通之后,Modem会将状态信息反馈到RILJ中;

2. MT在RILJ中流程:

       当Modem端收到来电信息时,会将相关来电信息通过AT指令发送给RILC,再通过RILC使用socket发送给RILJ,逐层向上传递,最终显示来电响铃界面。

MT(来电)与MO(去电)的第二步相同,通过( Response ),即Modem端主动上报状态改变信息;

我们先来看一下RILJ 的基本组成以及主要功能,图2为RILJ核心类图:


图2

通过上图我们可以看到,RILJ继承自BaseCommands实现了CommandsInterface接口,RILJ包含了三个内部类:RILRequest、RILReceiver、RILSender,分别对应mRequestsList、mSender、mReceiver三个对象。

RILJ中涉及通话控制和消息处理的关键方法:

通话控制类:

dial(),负责创建拨号RILRequest对象;

acceptCall(),负责创建接听RILRequest对象;

rejectCall(),负责创建拒接RILRequest对象;

以上方法最终会通过RILSender并使用socket方式向RILC发起相关请求。

消息处理类:

processUnsolicited(),负责处理UnSolicited反馈信息;

processSolicited(),负责处理Solicited反馈信息;

       这些消息来自RILC的socket反馈,在上一篇MO(去电)流程分析中,dial最终会调用到RIL.java中的RILSender对象的相关方法,向RILC继续传递拨号信息,而MT(来电)时Modem会将相关信息发送到RILC,RILC再将信息通过socket反馈给RILJ,在RILJ中通过RILReceiver接收并开始处理。RILSender负责通过socket向RILC发送RILRequest信息,RILReceiver负责以socket方式从RILC接收Response信息。当RILJ从RILC接收到相关信息时,会逐步向上反馈,这些信息分为两类:

1. Solicited Response

        请求返回消息,这类消息是上层主动请求Modem再由其返回的消息,这些消息由RILC上报给RILJ。比如当我们执行MO(去电)时,会通过RILSender发送dial类型的Request给RILC,RILC再传递给Modem端,再由Modem端发起通话请求。待对方接通之后Modem将相关信息发送到RILC,RILC将结果消息反馈给RILJ,此时由RILReceiver来接收并处理消息,这种消息就是Solicited消息。

       可以简单的理解为( Request , Response )这样成对出现,此时RILC向RILJ返回的Respone就是Solicited消息。

2. UnSolicited Response

       主动返回消息,这类消息由Modem端主动上报。比如当有MT(来电)时,Modem会接收到信息并向RILC发送来电消息,RILC将来电信息再发送给RILJ,这类没有request但由Modem主动上报信息就是UnSolicited信息。

       可以简单的理解为Modem端主动给RILC,再由RIC上报给RILJ的( Response )消息,这类消息就是UnSolicited消息。

无论是 Solicited 还是UnSolicited Respone 消息,在RILJ中都是有RILReceiver来负责接收并处理,整个RILJ的工作可以简单的用图3来描述:


图3

RILJ包含了RILSender和RILReceiver,其中RILSender负责发送Request给RILC,RILReceiver负责接收Solicited和UnSolicited的Response信息。

RILJ工作流程

RILJ的工作内容主要是负责向RILC发起Request,以及从RILC接收Response。主要涉及三个内部类:RILRequest、RILSender、RILReceiver,主要工作包含以下三大内容:

1. RILRequest的构造;

       RILRequest是RILJ的内部类,我们可以把RILRequest看成一个打包类,将相关信息进行加工处理后打包成一个规范的RILRequest并使用RILSender发送给RILC。在RILRequest类中最重要的方法莫过于obtain了,该方法完成了打包工作。我们在MO(去电)流程分析中有看到调用RILJ中的dial方法,并在dial方法中看到了RILRequest的打包代码,如下:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. RILRequest rr = RILRequest.obtain(RIL_REQUEST_DIAL, result, mySimId);  
这里再去看一下obtain方法的实现:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. static RILRequest obtain(int request, Message result, int simId) {  
  2.     RILRequest rr = null;  
  3.     synchronized(sPoolSync) {  
  4.         if (sPool != null) {  
  5.             rr = sPool;  
  6.             sPool = rr.mNext;  
  7.             rr.mNext = null;  
  8.             sPoolSize--;  
  9.         }  
  10.     }  
  11.     if (rr == null) {  
  12.         rr = new RILRequest();  
  13.     }  
  14.     //这里跟Android原生不同,这里多了一个参数simId用于MTK双卡手机标识哪一张SIM卡  
  15.     //static int[] sNextSerial = {0, 0, 0, 0};这里后面会从log中看到如"[233]"的编号  
  16.     //serial是Request的编号并且是唯一的  
  17.     synchronized(sSerialMonitor) {  
  18.         rr.mSerial = sNextSerial[simId]++;  
  19.     }  
  20.     //请求类型  
  21.     rr.mRequest = request;  
  22.     rr.mResult = result;//请求结果 Message对象  
  23.     rr.mParcel = Parcel.obtain();  
  24.     if (result != null && result.getTarget() == null) {  
  25.         throw new NullPointerException("Message target must not be null");  
  26.     }  
  27.     // first elements in any RIL Parcel  
  28.     rr.mParcel.writeInt(request);  
  29.     rr.mParcel.writeInt(rr.mSerial);  
  30.     return rr;  
  31. }  

2. RILSender发送Request;

       在Request构造完成之后我们在dial方法中看到最终调用了send(rr)方法,这里就用到了RILSender,RILSender也是RILJ中的内部类,通过查看send方法可以知道:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. private void  
  2. send(RILRequest rr) {  
  3.     Message msg;  
  4.     if (mSocket == null) {  
  5.         rr.onError(RADIO_NOT_AVAILABLE, null);  
  6.         rr.release();  
  7.         return;  
  8.     }  
  9.     //RILSender集成Handler因此会跳转到相应的handleMessage方法中  
  10.     msg = mSender.obtainMessage(EVENT_SEND, rr);  
  11.     acquireWakeLock();  
  12.     msg.sendToTarget();  
  13. }  

通过前面的核心类图我们可以知道,RILSender集成自Handler,因此这里会跳转到RILSender的handleMessage方法中,并执行case EVENT_SEND,代码如下:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. case EVENT_SEND:  
  2.     boolean alreadySubtracted = false;  
  3.     try {  
  4.     LocalSocket s;  
  5.     //获取LocalSocket,并对socket进行判断是否正常  
  6.     s = mSocket;  
  7.     //... ...省略部分代码  
  8.     //将Request添加到链表中  
  9.     synchronized (mRequestList) {  
  10.             mRequestList.add(rr);  
  11.     }  
  12.     //... ...省略部分代码  
  13.     //定义socket发送需要的byte数组  
  14.     byte[] data;  
  15.     //获取数据  
  16.     data = rr.mParcel.marshall();  
  17.     //... ...省略部分代码  
  18.     //向socket写入数据  
  19.     s.getOutputStream().write(dataLength);  
  20.     s.getOutputStream().write(data);  
  21.     }  
  22.     //... ...省略部分代码  
  23. break;  

这里使用了socket的方式将拨号请求发送给了RILC,最后又RILC向Modem端传递。在完成以上步骤之后dial流程就走到了RILC中,再由RILC向Modem端发出dial的AT指令。

3. RILReceiver接收Response;

       当MO(去电)接听以及MT(来电)时,Modem端会将相关信息通过RILC发送给RILJ,负责接收的正式RILReceiver,RILReceiver也是RILJ的内部类,该类实现了Runnable接口,因此实际启动是以Thread的方式启动的。RILReceiver在PhoneProxy的构造方法中通过调用startRilReceiver启动,这里是MTK改动过,原生是直接在RIL.java的构造方法中启动线程。

RILReceiver主要完成两项工作:

(1). 维护local socket的连接;

(2). 阻塞local socket并处理RILC的Response ( Solicited 和 UnSolicited );

RILReceiver启动之后会建立local socket并阻塞,代码如下:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. @Override  
  2. public void  
  3. run() {  
  4.     //... ...省略部分代码  
  5.     try {  
  6.         for (;;) {  
  7.         //... ...省略部分代码  
  8.         //建立并维护 Local Socket  
  9.         try {  
  10.             s = new LocalSocket();  
  11.             l = new LocalSocketAddress(socketRil,  
  12.                     LocalSocketAddress.Namespace.RESERVED);  
  13.             s.connect(l);  
  14.         } catch (IOException ex){  
  15.         //... ...省略部分代码  
  16.         //当连接失败后休眠4s并继续尝试连接  
  17.         }  
  18.         //... ...省略部分代码  
  19.         try {  
  20.             InputStream is = mSocket.getInputStream();  
  21.             for (;;) {//阻塞  
  22.                 Parcel p;  
  23.                 length = readRilMessage(is, buffer);  
  24.                 if (length < 0) {  
  25.                     // End-of-stream reached  
  26.                     break;  
  27.                 }  
  28.                 p = Parcel.obtain();  
  29.                 p.unmarshall(buffer, 0, length);  
  30.                 p.setDataPosition(0);  
  31.                 //处理Respone消息(Solicited和UnSolicited)  
  32.                 processResponse(p);  
  33.                 p.recycle();  
  34.             }  
  35.         }  
  36.         //... ...省略部分代码  
  37. }  

那么通过以上分析我们可以简单的将RILJ的工作流程总结为:打包,发送,接收三个步骤。在RILReceiver中接收到RILC的socket信息之后,使用processResponse进行处理,进而分为processUnsolicited()和processSolicited()方法。

processSolicited()方法主要完成以下三件事:

(1). 根据Response中的request serial编号找到RequestList中的对象并移除;

       因为Solicited的Request是一一对应的,当处理完本次Response之后不再需要改Request对象,因此这里会移除,使用方法findAndRemoveRequestFromList()。

(2). 根据request的类型使用responseXXX方法处获取从RILC中返回的信息;

       这里会有很多request类型,对应的responseXXX方法也有很多,比如responseInts()、responseVoid()、responseString()、responseOperator()等等,通过这些方法取出Parcel对象中的内容,该对象中包含了Request需要查询的信息。

(3). 将第2步获取到的信息存储到Message中并触发回调;

执行代码如下:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. if (rr.mResult != null) {  
  2.     AsyncResult.forMessage(rr.mResult, ret, null);  
  3.     rr.mResult.sendToTarget();  
  4. }  
我们知道RILRequest类中有定义mResult为Message类型,在obtain方法执行的时候已经对mResult进行了赋值,这里的Message就是从GSMCallTracker中传递过来的,有兴趣的童鞋自己追踪一下吧,注意看清楚dial中的参与即可。也就是说通过分析我们知道processSolicited()处理完成会携带相关信息跳转到GSMCallTracker中继续执行。

processUnsolicited()方法主要以下两件事:

(1). 根据response消息的类型使用responseXXX方法处获取从RILC中返回的信息;

这一步和processSolicited()方法的第2步类似,并将从Parcel对象中获取到的数据保存到局部变量Object类型的对象ret中。

(2). 使用notifyRegistrants()方法将相关信息通知到订阅者( Subscribe );

因为这里使用的是观察者模式( Publisher-Subscribe ),相关订阅者会根据获取到不同的信息作出与之对应的反应。

       对于MO(去电)而言,整个过程既包含了processSolicited()也包含了processUnsolicited()。为什么这么说呢?当我们执行dial操作后,会将相关信息发送到Modem端,此时执行的步骤是DIAL,Modem端发起DIAL成功后返回给RILJ,这个步骤就是( Request , Respone )。之后如果对方接通了那么Modem会将相关信息反馈给RILJ,这个步骤即( Respone ),通过Radio Log可以看到:

(a). 拨号Request和Respone

D/RILJ    (  966):  RIL(1) :[0253]> DIAL
D/RILJ    (  966):  RIL(1) :[0253]< DIAL 

(b). 返回MO接通的Respone

V/RILJ    (  966):  RIL(1) :[UNSL RIL]< UNSOL_CALL_PROGRESS_INFO {1, 6, 0, 1, 0, 0, 13800138000, 145, }

至于MO接通后返回信息里面的参数这里不详细解释,主要是AT指令中携带的信息,不同硬件平台会有一些自己的定制。对于Request和Respone并不一定是连续出现在Log中的,我们只需要查看其唯一的serial编号即可找到Request对应的Respone。另外,在RILJ的Log中我们可以根据大于(>)符号和小于(<)符号来判断是Request还是Response,即:

(I). 大于符号(>)对应Request,表示RILJ向RILC发送请求;

(II). 小于符号(<)对应Response,表示RILC向RILJ反馈信息;

       前面我们说过Solicited信息是成对出现的,通过log也能证明这一点,平时查看Log可以根据request的serial编号来找到对应的response。在完成以上拨号操作之后Solicited信息就执行完毕了,接下来是等待对方接通,若对方接通则Modem会收到相应的指令并向RILC传递接通信息。该信息由Modem主动上报,因此属于UnSolicited信息,由processUnsolicited()方法来处理。

总结

       RILJ的主要作用是将通话控制信息使用socket传递给RILC,RILC再使用AT指令传递给Modem端;RILC通过socket返回的Modem处理结果给RILJ并通知上层应用;可以说RILJ在Android Telephony结构中有着承上启下的作用。

RILJ的主要工作内容可以概括为以下三点:

1. 构造打包RILRequest;

2. RILSender通过socket向RILC发起request;

3. RILReceiver通过socket结构RILC反馈response;

RILReceiver接收到的消息分为两类:

1. Solicited Response,与之对应的处理方法是processSolicited();

2. UnSolicited Response,与之对应的处理方法是processUnsolicited();

0 0
原创粉丝点击