赞
踩
RIL在Android中的实现源代码可分为两大部分:
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请求类的RIL消息,根据其动作行为,可再细分为Solicited Request和Solicited Response两个子类消息,正常情况下,这两个子类消息成对出现,请求和应答是一一对应的。
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请求消息的发送过程,可分为三个步骤:
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上报消息,其处理逻辑可分为两大部分:
- 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消息的类型,根据此标识类型调用不同的处理方法。
步骤1:读取Solicited请求消息序列号,根据消息序列号调用findAndRemoveRequestFromList方法获取RILRequest对象。获取RILRequest对象后,会将此对象从mRequestsList移除。
步骤2:通过RILRequest对象的request类型,使用responseXXX方法分别处理Parcel对象中的数据信息,组装成Object返回对象ret。
步骤3:设置ret对象到RILRequest对象的回调Message消息数据,并发出Message消息通知。
步骤1:获取Unsolicited Response消息类型,调用responseXXX方法获取不同的ret对象。
步骤2:发出Registrant或RegistrantList消息通知。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。