阅读深入解析Android RIL笔记1 —Android RIL框架结构及RILJ运行机制

来源:互联网 发布:数据分析部门职责 编辑:程序博客网 时间:2024/05/11 22:02

RIL在Android中的实现源代码可分为两大部分:

  • Frameworks框架层中的Java相关程序,简称RILJ。
  • HAL层中的C/C++程序,建成RILC。      

framework层三个关键的Tracker对象:CallTracker,ServiceStateTracker和DataConnectionTracker,这三个Tracker对象负责与RILJ进行交互,这些交互在RIL层中的处理是与Modem基于串口连接的AT命令的发送和执行。

一、Android RIL框架结构:      

        先介绍下Android RIL框架结构,如下图所示:

这里写图片描述

         该图完整体现出RIL层中的数据流向。RILJ与RILC之间通过rild端口的Socket连接【不懂】进行RIL消息的交互与处理;RILC与Modem之间通过qemud端口的Socket连接【不懂】完成AT命令的发送和执行,完成Modem的操作控制和查询请求以及Modem主动上报的消息处理。
       Socket网络连接的方式,按照其处理方式可分为两大类:【可在RILConstants.java中找到Solicited与UnSolicited定义详情】

  • Solicited类型消息处理流程

        一些主动请求的操作,如拨号,接听等。Solicited请求类的RIL消息,根据其动作行为,可再细分为Solicited Request和Solicited Response两个子类消息,正常情况下,这两个子类消息成对出现,请求和应答是一一对应的。

  • UnSolicited类型消息处理流程

        GSM/GPRS Modem硬件模块主动上报的例如来电,接通电话等消息归纳为UnSolicited消息。UnSolicited非请求类得RIL消息,此消息没有请求过程,仅有底层Modem主动上报,因此只有Response。

二、认识RILJ:

        RIL类为核心,继承了BaseCommands抽象类,并实现CommandsInterface接口。

        RILJ关键属性如下表:

这里写图片描述![](http://img.blog.csdn.net/20170208110623730?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaGFueXIxMjA4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)


         RILJ关键方法,包括控制请求(接听拒绝电话,建立断开数据连接等)、查询请求(获取Call状态,获取IMSI、IMEI)、Socket消息发送和接收、RIL消息处理四种。RIL消息处理中,processResponse处理RILC上报消息,根据消息类型,分别调用processUnsolicited和processSolicited处理不同的RIL消息。

         RILJ运行机制如下:

 

这里写图片描述![](http://img.blog.csdn.net/20170208110623730?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaGFueXIxMjA4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)![](http://img.blog.csdn.net/20170208143229363?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaGFueXIxMjA4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)![](http://img.blog.csdn.net/20170208145226360?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaGFueXIxMjA4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)

         Tracker从通话、SIM卡注册的网络服务、手机上网数据连接管理等领域与RILJ交互。

         RILRequest类:

  • 关键属性:

 

static int sNextSerial = 0; // 下一个RILRequest对象的编号static Object sSerialMonitor = new Object(); // 同步访问,加锁对象private static Object sPoolSync = new Object(); // 同步访问,加锁对象private staitc RILRequest sPoolSize = 0;private static final int MAX_POOL_SIZE = 4; // 最大支持4个RILRequest对象int mSerial; // 当前RIL请求编号int mRequest; // RIL请求类型Message mRequest; // 保存RIL请求的Message对象Parcel mp;RILRequest mNext; // 下一个RILRequest处理对象

         定义为static,所有RILRequest共享;

         普通成员变量,当前对象共享;

  • 方法:

         两个非常关键的方法:obtain和onError。

         obtain方法:该公共静态方法用来创建RILRequest对象,其中的处理逻辑可分为两部分:RILRequest缓存对象和当前对象的处理。

         onError方法:可完成RIL请求返回异常或失败的处理。

、解析RILJ发出RIL请求流程:

         RILJ对象提供了非常多的查询、控制Modem的方法,这些方法的处理逻辑相似,如下:

RILRequest rr = RILRequest.obtain(XXX, result); // 创建RILRequest对象rr.mp.writeXXX(); // 依次入Parcel对象数据send(rr); // 发送RILRequest

         RILJ中所有Solicited请求消息的发送过程,可分为三个步骤:

  1. 调用RILRequest类得静态方法obtain,创建RILRequest对象。(上面已了解)
  2. 调用send方法创建RILSender EVENT_SEND类型的Message消息并发出消息通知。send方法调用了accquireWakeLock方法用作电源管理。
  3. RILSender对象的handleMessage方法接收和响应EVENT_SEND类型的Message消息,通过Socket向RILC发送RIL请求。

              handleMessage中EVENT_SEND的处理逻辑详情如下:

    try {        localSocket s;        s = mSocket;        if (s == null) {            ...... // Socket连接异常处理,直接返回        }         // 保存请求的RILRequest对象到mRequestsList列表中        byte[] data; // 定义Socket发送的byte数组        data = rr.mp.marshall(); // Parcel数据处理,获取其byte数组数据        synchronized(mRequestsList) {            mRequestsList.append(rr.mSerial, rr); //增加rr对象            rr.mp.recycle(); // Parcel数据回收            rr.mp = null; // 清空Parcel数据        }        ...... // 省略数据大小限制的逻辑判断以及dataLength数据的创建        // 将byte数组中的数据写入通过LocalSocket连接对象获取输出流        s.getOutputStream().write(dataLength); // Socket写入数据头        s.getOutPutStream().write(data); // Socket写入数据    } catch {        ...... // 省略异常处理,调用rr.onError和rr.release完成异常处理    }

带着几个疑问看下面的内容

LocalSocket什么情况下完成了Socket连接?

连接服务端的地址和端口号是什么?

保存RILRequest对象rr到mRequestsList列表究竟是做什么用的?

、解析RILJ接收Response消息处理流程:

RILReceiver负责监听Socket消息接收并处理RILC上报消息,其处理逻辑可分为两大部分:

  • Socket连接的维护过程;
  • 阻塞Socket输入流,接收并处理RILC Response
class RILReceiver implements Runnable {    public void run() {        int retryCount = 0; // 连接Socket重试次数计数器        try {for(;;) { // 涉及输入输出,需要捕获异常,并且开始循环            LocalSocket s = null;            LocalSocketAddress l;            try {                s = new LocalSocket(); // 创建LocalSocket对象                // 创建Socket连接参数对象,重点关注使用的参数                l = new LocalSocketAddress(SOCKET_NAME_RIL, LocalSocketAddress.Namespace.RESERVER);                s.connect(l); // 连接Socket            } catch (IOException ex) {                ......                try {                    // 休眠4秒钟后,继续循环建立Socket连接                    Thread.sleep(SOCKET_OPEN_RETRY_MILLIS);                } catch (InterruptedException er) {                }                retryCount ++; // 记录重试次数                continue; // 继续开始连接Socket            }            retryCount = 0; // 建立Socket无异常,说明建立连接成功,清空重试次数            mSocket = s; // 将建立的Socket连接对象赋值给RILJ对象属性            // 监听Socket处理逻辑,正常情况下会一直执行for中的处理逻辑            try {                InputStream is = mSocket.getInputStream(); // 通过Socket连接获取输入流                for (;;) { // 如果没有异常会一直执行下去                    Parcel p;                    // 使用Socket输入流读取byte字节,保存到buffer数组中,并返回数据长度                    length = readRilMessage(is, buffer);                    if (length < 0) {                        break; // 读取的数据长度<0即有异常发生,退出第二个for循环                    }                    p = Parcel.obtain(); // 创建Parcel对象,用于保存数据                    p.unmarshall(buffer, 0, length);                    p.setDataPosition(0);                    /*非常关键,处理Socket读取的数据Parcel数据对象,不用区分Solicited Response和UnSolicited Response消息*/                    processResponse(p);                    p.recycle(); // 回收Parcel数据对象                }            }catch(java.io.IOException ex) { // IO异常处理,记录异常日志            }catch(Throwable tr) {            }            /*接收Socket输入流程数据,处理一场,会进入下面的处理逻辑,更新Radio状态的不可用,并且进入下一个循环,重新建立Socket连接*/            SetRadioState(RadioState.RADIO_UNAVAILABLE);            try { // 关闭数据连接                mSocket.close();            } catch (IOException ex) {            }            mSocket = null;            RILRequest.resetSerial(); // 重置RILRequest消息序列号            // 清空RILRequest对象列表            clearRequestsList(RADIO_NOT_AVAILABLE, false);        }} catch (Throwable tr) {        }        // 连接Socket异常,发出消息通知        notifyRegistrantsConnectionChanged(-1);    } }

【上面的代码中使用LocalSocket类进行Socket连接。跟踪其代码,发现它会经过JNJ的调用,最后调用基于Linux Socket编程相关接口,最终实现Socket连接和数据的交互】

        processResponse方法中,首先通过Parcel数据对象获取前4位int数据,它标识Response消息的类型,根据此标识类型调用不同的处理方法。

  • Socilited Response消息处理方法processSolicited。分3步:

        步骤1:读取Solicited请求消息序列号,根据消息序列号调用findAndRemoveRequestFromList方法获取RILRequest对象。获取RILRequest对象后,会将此对象从mRequestsList移除。

        步骤2:通过RILRequest对象的request类型,使用responseXXX方法分别处理Parcel对象中的数据信息,组装成Object返回对象ret。

        步骤3:设置ret对象到RILRequest对象的回调Message消息数据,并发出Message消息通知。

  • UnSolicited Response消息处理方法processUnSolicited。分2步

        步骤1:获取Unsolicited Response消息类型,调用responseXXX方法获取不同的ret对象。

        步骤2:发出Registrant或RegistrantList消息通知。

 

 

 

0 0
原创粉丝点击