介绍
本文档对 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 提供了无线硬件设备与电话服务之间的抽象层。
下图展示了RIL 在Android 体系中的位置。
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 RIL 的rilInit() 方法来进行Vendor RIL 与libril 的关系建立。
在rild 文件夹中还包括一个radiooptions.c 文件, 它的作用是通过串口将一些radio 相关的参数直接传给rild 来对radio 进行配置。
●libril 文件夹:
在编译时libril 被链入rild, 它为rild 提供了event 处理功能,还提供了在rild 与Vendor 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_startEventLoop 在ril.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_event 的fd ,放入一个fd 集合readFds 中。这样 ril_event_loop 能通过一个多路复用I/O 的机制(select) 来等待这些fd 。
在进入ril_event_loop ()之前,在eventLoop 中已经创建和挂入了s_wakeupfd_event ,它是通过pipe 的机制实现的,这个管道fd 的回调函数并没有实现什么功能,它的目的只是为了让select 方法能返回一次,这样select() 方法就能重新跟踪新加入事件队列的fd 和timeout 设置。
所以在添加新fd 到eventLoop 时, 往往不是直接调用ril_event_add ,实际通常用rilEventAddWakeup 来添加,这个方法除了会间接调用ril_event_add 外,还会调用triggerEvLoop() 函数来向s_fdWakeupWrite 中写入一个空字符,这样select() 函数会返回并重新执行,新加入的文件描述符便得以被select() 加载并跟踪。
如果在ril_event 队列中任何一个fd 已经准备好,则进入分析流程:
processTimeouts() ,processReadReadies(&rfds, n) ,firePending()
其中firePending() 方法执行这个event 的func ,也就是回调函数。
在Android RIL 初始化完成后,将有几个event 被挂入到eventLoop 中:
1. s_listen_event: 名为rild 的socket, 主要requeset & response 通道
2. s_debug_event: 名为rild-debug 的socket, 调试用requeset & response 通道
3. s_wakeupfd_event: 无名管道, 用于队列主动唤醒
这其中最为重要的event 就是s_listen_event ,它作为request 与response 的通道实现。
在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 的链表。
本文详细介绍了Android RIL(Radio Interface Layer)的架构原理,涵盖了RIL的原生代码部分,包括框架介绍、与Windows Mobile RIL的对比、移植内容及Java框架等。深入分析了RIL在Android系统中的位置、目录结构、消息队列机制等关键内容。
2256

被折叠的 条评论
为什么被折叠?



