阅读深入解析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关键属性如下表:
RILJ关键方法,包括控制请求(接听拒绝电话,建立断开数据连接等)、查询请求(获取Call状态,获取IMSI、IMEI)、Socket消息发送和接收、RIL消息处理四种。RIL消息处理中,processResponse处理RILC上报消息,根据消息类型,分别调用processUnsolicited和processSolicited处理不同的RIL消息。
RILJ运行机制如下:
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请求消息的发送过程,可分为三个步骤:
- 调用RILRequest类得静态方法obtain,创建RILRequest对象。(上面已了解)
- 调用send方法创建RILSender EVENT_SEND类型的Message消息并发出消息通知。send方法调用了accquireWakeLock方法用作电源管理。
- 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消息通知。
- 阅读深入解析Android RIL笔记1 —Android RIL框架结构及RILJ运行机制
- RIL框架结构及RILJ的运行机制
- android ril
- Android RIL
- Android RIL
- Android RIL
- Android RIL
- android RILJ运行机制
- Android RIL与 WindowsMobile RIL
- Android RIL源码研究笔记 の ril (一)
- Android RIL源码研究笔记 の ril (二)
- RIL 机制---消息从RILJ到RIL
- RIL 机制---消息从RIL到RILJ
- Android Application-Telephony-RIL 1
- 深入理解Android Telephony 之vendor ril
- Android RIL 结构解析和移植
- Android RIL源码研究笔记1- ril_event机制
- Android RIL源码研究笔记 の ril_event
- Qt5.7设置应用程序图标-基于Windows
- 创建javaScript自定义对象,并给属性赋值
- Android 点击EditText文本框之外任何地方隐藏键盘
- java如何正确停止一个线程
- 【plsql-dev】PL/SQL 报错: A query with LOB's requires OCI8 mode, but OCI7 mode is used
- 阅读深入解析Android RIL笔记1 —Android RIL框架结构及RILJ运行机制
- 简单介绍WebView的使用
- 例题 3.13
- Java 中的枚举 (enum)
- 数字在排序数组中出现的次数
- run-time error '339': component 'COMDLG32.OCX' or one of its dependeencies n的解决方法
- Android 自定义广播和系统广播(电话状态)(基础)
- logstash 字段引用
- Android之Intent全面解析及用法