ril.java_RIL.java里request流程

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的详细流程,就分析完毕了.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/573041.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

hibernate优化笔记(随时更新)

一:优化配置 1.关联映射的配置:对照之前的博客,如:inverse属性的设置(减少对同一对象的多条update语句):在one端设置为true,只会执行一次update语句 2.级联cascade属性设置:全部或部分设置为级联 如设置为sava-update(级联更新),当进行保存或更新时,会级联保存所有的关联映射的…

oracle 布尔转换java布尔_java 布尔值一种赋值方法

解决在配置Oracle数据库连接错误问题项目开发使用的Oracle,但是使用了不同的版本的Oracle数据库.然后自己在电脑上安装了2个连接客户端,版本分别是: 10.2.0 12.1.0 用Toad for Oracle 9.0的时候,我 ...XSS跨站脚本小结XSS漏洞验证经常遇到一些过滤,如何进行有效验证和绕过过滤呢…

ASP.NET Request.UrlReferrer 问题

ASP.NET Request.UrlReferrer 作用: 官网解释:Gets information about the URL of the clients previous request that linked to the current URL. 获取 到达当前页面之前的URL信息 此Request.UrlReferrer 容易为null, 当第一次打开当前页面…

联合查询(查找所有分类及其父类)

//查找所有分类及其父类SELECT s.type_id, s.type_name, p.type_name FROM 表1 AS s LEFT JOIN 表2 AS p ON s.parent_id p.type_id; 转载于:https://www.cnblogs.com/dengyg200891/p/6030484.html

autoitv3点击windows界面

在自动化测试过程中会遇到如下windows安全认证,需要输入账号和密码,这个认证对话框不属于element元素。无法用selenium操作,需要用autoitv3操作,输入账号密码后,再进行web元素操作。 有2中方式: 第一种&…

java ftp上传文件_jaVA使用FTP上传下载文件的问题

为了实现 FTP上传下载,大概试了两个方法sun.net.ftp.FtpClientorg.apache.commons.net一开始使用sun.net.ftp.FtpClient,结果发现唯一的问题是它不可以创建目录,随后试了下org.apache.commons.net,创建目录倒是没有问题,不过用FTPClient 的storeFile方法存储文件的时候发现文本…

【转载】linux环境下tcpdump源代码分析

linux环境下tcpdump源代码分析 原文时间 2013-10-11 13:13:02 CSDN博客原文链接 http://blog.csdn.net/han_dawei/article/details/12615199主题 Tcpdump 源码分析作者:韩大卫 吉林师范大学tcpdump.c 是tcpdump 工具的main.c, 本文旨对tcpdump的框架有简单了解&a…

java 扩展接口_详解常用的Spring Bean扩展接口

前言Spring是一款非常强大的框架,可以说是几乎所有的企业级Java项目使用了Spring,而Bean又是Spring框架的核心。Spring框架运用了非常多的设计模式,从整体上看,它的设计严格遵循了OCP----开闭原则,即:1、保…

会话控制(session、cookie)

1.session(1)session存储在服务器的(2)session每个人存一份(3)session有默认的过期时间(4)session里面可以存储任意类型的数据安全,对服务造成压力用法:1.当一个页面需要使用session的时候,需要在页面顶部加session_start();2.操作session 赋…

java 批量提交_【INSERT】逐行提交、批量提交及极限提速方法

在Oracle数据库中,不是提交越频繁越好。恰恰相反,批量提交可以得到更好的性能。这篇文章给大家简单展示一下在Oracle数据库中逐行提交于批量提交两者之间的性能差别。最后再给出一种可以极大改变性能的方法。1.创建表t_ref,并初始化880992条数…

自动化测试索引

转自:http://www.cnblogs.com/zhangfei/p/5454682.html 自动化测试全聚合 UI自动化测试:1.基础API:http://www.cnblogs.com/zhangfei/p/3158223.html2.数据驱动:http://www.cnblogs.com/zhangfei/p/5390091.htmlhttp://www.cnblog…

java中p.name_spring如何使用命名空间p简化bean的配置

这篇文章主要介绍了spring如何使用命名空间p简化bean的配置,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下一般情况下,我们是这么配置bean的:说明:cars是公用的集合Bean&…

Codeforces Round #148 (Div. 2)

A. Two Bags of Potatoes 枚举倍数。B. Easy Tape Programming (待补)C. Not Wool Sequences 考虑前缀异或和。\[answer \prod_{i1}^{n}{2^m-i}\]D. Boring Partition \(a_i\)从小到大排序,以某个\(i\)为分界点,考虑各种情况的最…

c盘java文件误删_C盘爆满怎么办,教你有选择性删除文件,恢复空间

有很多朋友说电脑c盘有很多垃圾,占着空间,还导致电脑响应变慢。还不知道能不能删除,很困扰。那么c盘文件都是什么文件呢?哪些能删除,做一次全面的清理呢?下面给大家介绍一下program Date:系统文…

SSAS parent/child dimension

ex: EmployeeKey ParentEmployeeKey FullName . 给层级命名: ParentEmployeeKey-->Properties--> NameTemplate 定义层级名称 . Browse中如果想看到FullName,EmployeeKey-->Properties-->NameColumn: FullName . 上层member不显示在下一层&…

java向另一activity输入_Activity经典实例一:两个Activity传递数据和对象

1、概述:Activity类直接或者间接地继承了Context、ContextWrapper、ContextThemeWrapper等基类,因此Activity可以直接调用它们的方法。创建一个Activity需要实现某些方法,常见的是实现onCreate(Bundle status)方法,该方法将会在Ac…

团队随笔汇总

一、团队展示 二、团队选题报告 三、第二次团队作业——预则立&&他山之石 四、UML 五、团队项目——需求规格说明书 六、第四次团队作业——系统设计 七、体系结构设计MVC 八、【Alpha版本】冲刺随笔汇总 九、第六次团队作业——Alpha冲刺之事后诸葛亮 十、随堂软工团队…

echarts3 graph java_Echarts中graph类型的运用求教

以下是百度Echarts官网上关系图的源码,但是这个关系图的node节点和edge都是静态文件里规定好的,我现在想动态实现,点击其中一个节点A然后新产生一个新节点B,并且有A和B之间的edge,就类似于百度的人物关系图谱那种动态生…

Nginx系列1之部分模块详解

1 内核模块:名称: daemon语法: daemon on |off默认值: on功能: 决定nginx 在前台执行还是后台守护进程执行的名称: Env语法: env var | varvalue默认值: 没有功能: 该指令…

java创建线程哪种方法最好_Java创建线程的三种方法比较

一般有三种方法,Thread,Runnable,Callable.Runnable和Callable的区别(1)Callable规定的方法是call(),Runnable规定的方法是run().(2)Callable的任务执行后可返回值,而Runnable的任务是不能返回值得(3)call方法可以抛出异常,run方法不可以(4)运…