Android GSM驱动模块(rild)详细分析(二)request流程

熊猫哥哥 发表于IT168和Opendroid 转载请注明

1. 多路复用I/O机制的运转

上文说到request是接收,是通过ril_event_loop中的多路复用I/O,也对初始化做了分析.现在我们来仔细看看这个机制如何运转.

ril_event_set负责配置一个event,主要有两种event:

ril_event_add添加使用多路I/O的event,它负责将其挂到队列,同时将event的通道句柄fd加入到watch_table,然后通过select等待.

ril_timer_add添加timer event,它将其挂在队列,同时重新计算最短超时时间.

无论哪种add,最后都会调用triggerEvLoop来刷新队列,更新超时值或等待对象.

刷新之后, ril_event_loop从阻塞的位置,select返回,只有两种可能,一是超时,二是等待到了某I/O操作.

超时的处理在processTimeouts中,摘下超时的event,加入pending_list.

检查有I/O操作的通道的处理在processReadReadies中,将超时的event加入pending_list.

最后在firePending中,检索pending_list的event并依次执行event->func.

这些操作完之后,计算新超时时间,并重新select阻塞于多路I/O.

前面的初始化流程已分析得知,初始化完成以后,队列上挂了3个event对象,分别是:

s_listen_event: 名为rild的socket,主要requeset & response通道

s_debug_event: 名为rild-debug的socket,调试用requeset & response通道(流程与s_listen_event基本相同,后面仅分析s_listen_event)

s_wakeupfd_event: 无名管道,用于队列主动唤醒(前面提到的队列刷新,就用它来实现,请参考使用它的相关地方)

2. request的传入和dispatch

明白了event队列的基本运行流程,我们可以来看看request是怎么传入和dispatch的了.

层的部分,核心代码在frameworks/base/telephony/java/com/android/internal/telephony

/gsm/RIL.java,这是android

java框架处理radio(gsm)的核心组件.本文因为主要关注rild,也就是驱动部分,所以这里只作简单介绍.

我们看一个具体的例子,RIL.java中的dial函数:

public void

dial (String address, int clirMode, Message result)

{

RILRequest rr = RILRequest.obtain(RIL_REQUEST_DIAL, result);

rr.mp.writeString(address);

rr.mp.writeInt(clirMode);

if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));

send(rr);

}

rr是以RIL_REQUEST_DIAL为request号而申请的一个RILRequest对象.这个request号在java框架和rild库中共享(参考RILConstants.java中这些值的由来:))

RILRequest初始化的时候,会连接名为rild的socket(也就是rild中s_listen_event绑定的socket),初始化数据传输的通道.

rr.mp

是Parcel对象,Parcel是一套简单的序列化协议,用于将对象(或对象的成员)序列化成字节流,以供传递参数之用.这里可以看到String

address和int

clirMode都是将依次序列化的成员.在这之前,rr初始化的时候,request号跟request的序列号(自动生成的递增数),已经成为头两个

将被序列化的成员.这为后面的request解析打下了基础.

接下来是send到handleMessage的流程,send将rr直接传递给另一个线程的handleMessage,handleMessage执行data = rr.mp.marshall()执行序列化操作, 并将data字节流写入到rild socket.

接下来回到我们的rild,select发现rild socket有了请求链接的信号,导致s_listen_event被挂入pending_list,执行event->func,即

static void listenCallback (int fd, short flags, void *param);

接下来,s_fdCommand = accept(s_fdListen, (sockaddr *) &peeraddr, &socklen),获取传入的socket描述符,也就是上层的java RIL传入的连接.

后,通过record_stream_new建立起一个record_stream, 将其与s_fdCommand绑定,

这里我们不关注record_stream 的具体流程, 我们来关注command event的回调,

processCommandsCallback函数, 从前面的event机制分析, 一旦s_fdCommand上有数据,

此回调函数就会被调用. (略过onNewCommandConnect的分析)

processCommandsCallback通过

record_stream_get_next阻塞读取s_fdCommand上发来的 数据,

直到收到一完整的request(request包的完整性由record_stream的机制保证),

然后将其送达processCommandBuffer.

进入processCommandBuffer以后,我们就正式进入了命令的解析部分. 每个命令将以RequestInfo的形式存在.

typedef struct RequestInfo {

int32_t token; //this is not RIL_Token

CommandInfo *pCI;

struct RequestInfo *p_next;

char cancelled;

char local; // responses to local commands do not go back to command process

} RequestInfo;

里的pRI就是一个RequestInfo结构指针, 从socket过来的数据流, 前面提到是Parcel处理过的序列化字节流,

这里会通过反序列化的方法提取出来. 最前面的是request号, 以及token域(request的递增序列号).

我们更关注这个request号, 前面提到, 上层和rild之间, 这个号是统一的. 它的定义是一个包含ril_commands.h的枚举,

在ril.cpp中

static CommandInfo s_commands[] = {

#include "ril_commands.h"

};

pRI直接访问这个数组, 来获取自己的pCI.

这是一个CommandInfo结构:

typedef struct {

int requestNumber;

void (*dispatchFunction) (Parcel &p, struct RequestInfo *pRI);

int(*responseFunction) (Parcel &p, void *response, size_t responselen);

} CommandInfo;

基本解析到这里就完成了, 接下来, pRI被挂入pending的request队列, 执行具体的pCI->dispatchFunction, 进行详细解析.

3. request的详细解析

对dial而言, CommandInfo结构是这样初始化的:

{RIL_REQUEST_DIAL, dispatchDial, responseVoid},

里执行dispatchFunction, 也就是dispatchDial这一函数.我们可以看到其实有很多种类的dispatch

function, 比如dispatchVoid, dispatchStrings, dispatchSIM_IO等等, 这些函数的区别,

在于Parcel传入的参数形式,Void就是不带参数的,Strings是以string[]做参数,又如Dial等,有自己的参数解析方式,以此类

推.

request号和参数现在都有了,那么可以进行具体的request函数调用了.

s_callbacks.onRequest(pRI->pCI->requestNumber, xxx, len, pRI)完成这一操作.

s_callbacks 是上篇文章中提到的获取自libreference-ril的RIL_RadioFunctions结构指针,request请求在这里转入底层的 libreference-ril处理,handler是reference-ril.c中的onRequest.

onRequest进行一个简单的switch分发,我们依然来看RIL_REQUEST_DIAL

流程是 onRequest-->requestDial-->at_send_command-->at_send_command_full-->at_send_command_full_nolock-->writeline

requestDial中将命令和参数转换成对应的AT命令,调用公共send command接口at_send_command.

了这个接口之外,还有

at_send_command_singleline,at_send_command_sms,at_send_command_multiline

等,这是根据at返回值,以及发命令流程的类型来区别的.比如at+csq这类,需要at_send_command_singleline,而发送短

信,因为有prompt提示符">",传裸数据,结束符等一系列操作,需要专门用at_send_command_sms来实现.

然后执行at_send_command_full,前面几个接口都会最终到这里,再通过一个互斥的at_send_command_full_nolock调用,然后完成最终的写出操作,在writeline中,写出到初始化时打开的设备中.

writeline返回之后,还有一些操作,如保存type等信息,供response回来时候使用,以及一些超时处理. 不再详述.

到这里,request的详细流程,就分析完毕了.

ril.java_RIL.java里request流程相关推荐

  1. java里程序控制流程_Java语言中的程序流程控制

    (1. 流程控制 有三种基本技术可以改变程序的控制流程: A.调用方法 :将导致控制流程离开当前方法,转移到被调用的方法. B.选择  :   a. if / else 语句 b. switch语句 ...

  2. android ril.java_Android RIL的java框架

    Android RIL的Java部分也被分为了两个模块,RIL模块与Phone模块.其中RIL模块负责进行请求以及相应的处理,它将直接与RIL的原声代码进行通信.而Phone模块则向应用程序开发者提供 ...

  3. ril.java_Android RIL的java框架

    Android RIL的Java部分也被分为了两个模块,RIL模块与Phone模块.其中RIL模块负责进行请求以及相应的处理,它将直接与RIL的原声代码进行通信.而Phone模块则向应用程序开发者提供 ...

  4. EL在java里的意义

    EL在java里的意义: EL的语法很简单,他最大的特点就是使用上很方便 例: ${sessionScope.user.sex} 所有EL都是以 ${ 为起始.以} 为结尾的. 上述EL范例的意思是: ...

  5. Java里try catch的简单用法

    Java里try catch的简单用法: Java里try catch的简单用法: 1.try+catch 程序的流程是:运行到try块中,如果有异常抛出,则转到catch块去处理.然后执行catch ...

  6. Java编程:Java里的协程

    今天看到这篇博客记录一下,后面有时间来研究一下协程看能不能对现在的项目有所提高 转次时代Java编程(一):Java里的协程_zdy0_2004的博客-CSDN博客 这东西其实有很多名词,比如有的人喜 ...

  7. java中 try用法,Java里try catch的简单用法

    优质回答 回答者:temps1991 Java里try catch的简单用法: 1.try+catch 程序的流程是:运行到try块中,如果有异常抛出,则转到catch块去处理.然后执行catch块后 ...

  8. Java 里的 for (;;) 与 while (true),哪个更快?

    点击关注公众号,Java干货及时送达 在JDK8u的jdk项目下做个很粗略的搜索: mymbp:/Users/me/workspace/jdk8u/jdk/src $ egrep -nr " ...

  9. 快手二面:Java 里的 for (;;) 与 while (true),哪个更快?

    转自:知乎 www.zhihu.com/question/52311366/answer/1300903 在 JDK8u 的 jdk 项目下做个很粗略的搜索: mymbp:/Users/me/work ...

最新文章

  1. Java数据类型以及变量的定义
  2. rails jquery_Spring与Rails的jQuery UJS
  3. mybatis学习(33):动态sql if
  4. MySQL | 数据库的六种约束、表的关系、三大范式
  5. Spring AOP核心原理分析
  6. 常用css样式属性大全(中文注释)
  7. web开发移动端准备工作
  8. 【github相关】之h264bitstream
  9. Visual C++ 2010 新特性:并行计算
  10. presto安装及入门
  11. dos盘启动计算机,u盘制作dos启动盘方法
  12. python如何拼读英语单词怎么写_如何快速拼读英语单词?
  13. Ubiquitous Religions 宗教信仰
  14. 推荐学习!通过五轮面试斩获offer阿里实习生亲述,深度解析,值得收藏
  15. 全球游戏收入将随着电影电视改编作品的不断增多而达到惊人水平 | 美通社头条...
  16. python中对称差_python 合集set,交集,并集,差集,对称差集别搞混
  17. Git和Repository简明理解(GitHub是什么?)
  18. JAVA EE项目开发及应用实训报告——网上考试系统
  19. python首行缩进_python中缩进
  20. 普通人在互联网上赚钱,这几个道理必须要了解一下

热门文章

  1. ax200网卡支持Linux吗,Deepin 20和Win10双系统中AX200网卡不能用的请关闭快速启动
  2. mysql crash定位分析_MySQL实例crash的案例详细分析
  3. java类快速构造_程序员有什么办法能快速梳理java知识点?有这八张图就够了
  4. python下载在哪个盘_Windows下载安装python详情和注意事项
  5. 树莓派 小屏幕_树莓派学习手动积累(1)
  6. 2017韩老师计算机网络,2017年计算机等考三级网络技术辅导:计算机网络拓扑结构...
  7. matlab旋转机械转子故障信号仿真,旋转机械转子不对中故障诊断技术研究解说.docx...
  8. pxc mysql mycat_Mycat+Pxc的配置
  9. pq 中m函数判断嵌套_压轴题的热点,二次函数与几何的结合,谁会谁吃香
  10. TensorFlow2-操作