当前位置:   article > 正文

Android RIL框架结构及RILJ运行机制

rilj

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关键属性如下表:

这里写图片描述![](https://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运行机制如下:

 

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

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

         RILRequest类:

  • 关键属性:

 

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

         定义为static,所有RILRequest共享;

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

  • 方法:

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

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

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

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

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

  1. RILRequest rr = RILRequest.obtain(XXX, result); // 创建RILRequest对象
  2. rr.mp.writeXXX(); // 依次入Parcel对象数据
  3. 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的处理逻辑详情如下:

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

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

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

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

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

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

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

  • Socket连接的维护过程;
  • 阻塞Socket输入流,接收并处理RILC Response
  1. class RILReceiver implements Runnable {
  2. public void run() {
  3. int retryCount = 0; // 连接Socket重试次数计数器
  4. try {for(;;) { // 涉及输入输出,需要捕获异常,并且开始循环
  5. LocalSocket s = null;
  6. LocalSocketAddress l;
  7. try {
  8. s = new LocalSocket(); // 创建LocalSocket对象
  9. // 创建Socket连接参数对象,重点关注使用的参数
  10. l = new LocalSocketAddress(SOCKET_NAME_RIL, LocalSocketAddress.Namespace.RESERVER);
  11. s.connect(l); // 连接Socket
  12. } catch (IOException ex) {
  13. ......
  14. try {
  15. // 休眠4秒钟后,继续循环建立Socket连接
  16. Thread.sleep(SOCKET_OPEN_RETRY_MILLIS);
  17. } catch (InterruptedException er) {
  18. }
  19. retryCount ++; // 记录重试次数
  20. continue; // 继续开始连接Socket
  21. }
  22. retryCount = 0; // 建立Socket无异常,说明建立连接成功,清空重试次数
  23. mSocket = s; // 将建立的Socket连接对象赋值给RILJ对象属性
  24. // 监听Socket处理逻辑,正常情况下会一直执行for中的处理逻辑
  25. try {
  26. InputStream is = mSocket.getInputStream(); // 通过Socket连接获取输入流
  27. for (;;) { // 如果没有异常会一直执行下去
  28. Parcel p;
  29. // 使用Socket输入流读取byte字节,保存到buffer数组中,并返回数据长度
  30. length = readRilMessage(is, buffer);
  31. if (length < 0) {
  32. break; // 读取的数据长度<0即有异常发生,退出第二个for循环
  33. }
  34. p = Parcel.obtain(); // 创建Parcel对象,用于保存数据
  35. p.unmarshall(buffer, 0, length);
  36. p.setDataPosition(0);
  37. /*非常关键,处理Socket读取的数据Parcel数据对象,不用区分Solicited Response和UnSolicited Response消息*/
  38. processResponse(p);
  39. p.recycle(); // 回收Parcel数据对象
  40. }
  41. }catch(java.io.IOException ex) { // IO异常处理,记录异常日志
  42. }catch(Throwable tr) {
  43. }
  44. /*接收Socket输入流程数据,处理一场,会进入下面的处理逻辑,更新Radio状态的不可用,并且进入下一个循环,重新建立Socket连接*/
  45. SetRadioState(RadioState.RADIO_UNAVAILABLE);
  46. try { // 关闭数据连接
  47. mSocket.close();
  48. } catch (IOException ex) {
  49. }
  50. mSocket = null;
  51. RILRequest.resetSerial(); // 重置RILRequest消息序列号
  52. // 清空RILRequest对象列表
  53. clearRequestsList(RADIO_NOT_AVAILABLE, false);
  54. }} catch (Throwable tr) {
  55. }
  56. // 连接Socket异常,发出消息通知
  57. notifyRegistrantsConnectionChanged(-1);
  58. }
  59. }

【上面的代码中使用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消息通知。

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/386578
推荐阅读
相关标签
  

闽ICP备14008679号