Android RIL结构分析与移植1

本文详细介绍了Android RIL(Radio Interface Layer)的架构原理,涵盖了RIL的原生代码部分,包括框架介绍、与Windows Mobile RIL的对比、移植内容及Java框架等。深入分析了RIL在Android系统中的位置、目录结构、消息队列机制等关键内容。

 

介绍

本文档对 Android RIL 部分的内容进行了介绍,其重点放在了 Android RIL 的原生代码部分。包括四个主题:

 

1.Android RIL 框架介绍

2.Android RIL WindowsMobile RIL

3.Android RIL porting

4.Android RIL java 框架

 

在本文档中将 Android 代码中的重要模块列出进行分析,并给出了相关的程序执行流程介绍,以加深对模块间交互方式的理解。

 

对于 java 代码部分,这里仅进行简单的介绍。如果需要深入了解,可以查看相关参考资料。

 

本文档中还对 Android RIL Porting 部分内容进行了描述和分析。

 

针对对 unix 操作系统环境并不熟悉的读者,本文档中所涉及到的相关知识包括:

  Unix file system

  Unix socket

  Unix thread

  Unix I/O 多路转接

 

以上信息可以在任意一份描述 Unix 系统调用的文档中找到。

 

1.Android RIL 框架介绍

术语:

fd                          unix 文件描述符

pipe                         unix 管道

cond                         一般是 condition variable 的缩写

tty                          通常使用 tty 来简称各种类型的终端设备

unsolicited response           被动请求命令来自 baseband

event loop                  android 的消息队列机制,由 unix 的系统调用 select() 实现

init.rc                     init 守护进程启动后被执行的启动脚本。

HAL                     硬件抽象层( Hardware Abstraction Layer HAL

1.1.Android RIL 概况:

Android RIL 提供了无线硬件设备与电话服务之间的抽象层。

 

下图展示了RILAndroid 体系中的位置。

Android <wbr>RIL结构分析与移植(1)

android ril 位于应用程序框架与内核之间,分成了两个部分,一个部分是 rild, 它负责 socket 与应用程序框架进行通信。另外一个部分是 Vendor RIL ,这个部分负责向下是通过两种方式与 radio 进行通信,它们是直接与 radio 通信的 AT 指令通道和用于传输包数据的通道,数据通道用于手机的上网功能。

 

对于 RIL java 框架部分,也被分成了两个部分,一个是 RIL 模块,这个模块主要用于与下层的 rild 进行通信,另外一个是 Phone 模块,这个模块直接暴露电话功能接口给应用开发用户,供他们调用以进行电话功能的实现。

1.2.Android RIL 目录结构:

Android RIL 模块位于Android/hardware/ril 文件夹,有三个子模块:rild , libril , reference-ril

 

include 文件夹:

包含RIL 头文件, 最主要的是ril.h

 

rild 文件夹:

RIL 守护进程,开机时被init 守护进程调用启动,里面仅有main 函数作为入口点,负责完成RIL 初始化工作。

 

rild.c 文件中,将完成ril 的加载过程,它会执行如下操作:

  动态加载Vendor RIL.so 文件

  执行RIL_startEventLoop() 开启 消息队列以进行事件监听

  通过执行Vendor RILrilInit() 方法来进行Vendor RILlibril 的关系建立。

 

rild 文件夹中还包括一个radiooptions.c 文件, 它的作用是通过串口将一些radio 相关的参数直接传给rild 来对radio 进行配置。

 

libril 文件夹:

在编译时libril 被链入rild, 它为rild 提供了event 处理功能,还提供了在rildVendor RIL 之间传递请求和响应消息的能力。

Libril 提供的主要功能分布在两个主要方法内,一个是RIL_startEventLoop() 方法,另一个是RIL_register() 方法

RIL_startEventLoop() 方法所提供的功能就是启用eventLoop 线程,开始执行RIL 消息队列。

RIL_register() 方法的主要功能是启动名为 rild 的监听端口,等待java 端通过socket 进行连接。

 

reference-ril 文件夹:

Android 自带的Vendor RIL 的参考实现。被编译成.so 文件,由于本部分是厂商定制的重点所在。所以被设计为松散耦合,且可灵活配置的。在rild 中通过opendl() 的方式加载。

librefrence.so 负责直接与radio 通信,这包括将来自libril 的指令转换为AT 指令,并且将AT 指令写入radio 中。

reference-ril 会接收调用者传来的参数,参数内容为与radio 的通信方式。如通过串口连接radio, 那么参数为这种形式:-d /dev/ttySx

1.3.Android RIL 中的消息(event )队列机制:

Android RIL 中,为了达到等待多路输入并且不出现阻塞的目的,使用了IO 多路复用机制。

 

如果使用阻塞I/O 进行网络的读取写入, 这意味着假如需要同时从两个网络文件描述符中读内容,那么如果读取操作在等待网络数据到来,这将可能很长时间阻塞在一个描述符上,另一个网络文件描述符不管有没有数据到来都无法被读取。

 

    一种解决方案是:

如果使用非阻塞I/O 进行网络的读取写入,在读取其中一个网络文件描述符如果阻塞将直接返回,再读取另外一个,这种方式的循环被称之为轮询 。轮询方式确实能解决进行多路io 操作时的阻塞问题,但是这种方法的不足之处是反复的执行读写调用将浪费cpu 时钟。

 

I/O 多路转接技术在这里提供了另一种比较好的解决方案:

它会先构造一张有关I/O 描述符的列表,然后调用select 函数,当IO 描述符列表中的一个描述符准备好进行I/O 时,该函数返回,并告知可以读或写哪个描述符。

 

Android RIL 中消息队列的核心实现思想就是这种I/O 多路转接技术。

 

消息队列机制的实现在ril_event.cpp 中,其中被定义的ril_event 结构是消息的主体。

 

每个ril_event 结构,与一个fd 句柄绑定( 可以是文件,socket ,管道等) ,并且带一个func 指针, 这个func 指针所指的函数是个回调函数,它指定了当所绑定的fd 准备好进行读取时所要进行的操作。

 

消息队列的开始点为RIL_startEventLoop 函数。RIL_startEventLoopril.cpp 中实现,它的主要目的是通过pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL) 建立一个dispatch 线程,线程入口点在eventLoop. 而在eventLoop 中,会调ril_event.cpp 中的ril_event_loop() 函数,建立起消息队列机制。

 

ril_event 是一个带有链表行为的struct ,它最主要的成员一个是fd, 一个是func

 

struct ril_event {

struct ril_event *next;

struct ril_event *prev;

int fd;

int index;

bool persist;

struct timeval timeout;

ril_event_cb func;

void *param;

};

 

初始化一个新ril_event 的操作是通过ril_event_set ()来完成的,并通过ril_event_add ()加入到消息队列之中,add 会把队列里所有ril_eventfd ,放入一个fd 集合readFds 中。这样 ril_event_loop 能通过一个多路复用I/O 的机制(select) 来等待这些fd

 

在进入ril_event_loop ()之前,在eventLoop 中已经创建和挂入了s_wakeupfd_event ,它是通过pipe 的机制实现的,这个管道fd 的回调函数并没有实现什么功能,它的目的只是为了让select 方法能返回一次,这样select() 方法就能重新跟踪新加入事件队列的fdtimeout 设置。

 

所以在添加新fdeventLoop, 往往不是直接调用ril_event_add ,实际通常用rilEventAddWakeup 来添加,这个方法除了会间接调用ril_event_add 外,还会调用triggerEvLoop() 函数来向s_fdWakeupWrite 中写入一个空字符,这样select() 函数会返回并重新执行,新加入的文件描述符便得以被select() 加载并跟踪。

 

如果在ril_event 队列中任何一个fd 已经准备好,则进入分析流程:

processTimeouts() processReadReadies(&rfds, n)firePending()

   其中firePending() 方法执行这个eventfunc ,也就是回调函数。

 

Android RIL 初始化完成后,将有几个event 被挂入到eventLoop 中:

1.      s_listen_event: 名为rildsocket, 主要requeset & response 通道

2.      s_debug_event: 名为rild-debugsocket, 调试用requeset & response 通道

3.      s_wakeupfd_event: 无名管道, 用于队列主动唤醒

 

这其中最为重要的event 就是s_listen_event ,它作为requestresponse 的通道实现。

 

ril_event.cpp 中还持有一个watch_table 数组,一个timer_list 链表和一个pending_list 链表。

watch_table 数组的目的很单纯,存放当前被eventLoop 等待的ril_event (非timer event ),供eventLoop 唤醒时使用。

timer_list 是存放timer event 的链表,在eventLoop 唤醒时要对这些timer event 单独进行处理

pending_list :待处理( 对其回调函数进行调用) 的所有ril_event 的链表。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值