您的位置:首页 > 移动开发 > Android开发

Android RIL结构分析与移植1

2011-04-25 11:41 239 查看
介绍

本文档对
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
的链表。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: