Android学习总结 --- RILD概述
管世波
2009-01-21
摘要:本文是对Android中RILD相关内容的学习总结,简要描述了RILD的框架和实现方式。
关键词:Linux;Android;RIL
一、RIL简介:
RIL(Radio Interface Layer)是android中的一个抽象层,位于电信应用与基带之间,RIL层为上层提供统一的接口,使上层开发不需要关注基带的类型,关于电话业务中需要用到的AT命令都封装在这一层中。目前android中实现了对GSM模块的支持。Android的RIL主要由三个部分组成:RILD守护进程、libril静态库、用户自己实现的 vendor lib 动态库。上层的Java应用通过Frameworks中提供的基类来访问RIL提供的命令,关于Java和JNI的内容本文不做涉及。
下面将对RIL的各个组成部分分别进行介绍,由于libril被rild和vendor lib引用,相关内容在rild和vendor lib中介绍,不单独对其进行描述。
二、RILD守护进程
1. RILD的启动和框架:
Rild 是系统的守护进程,由init进程在系统初始化的时候来运行,具体定制在 脚本文件中,内容如下:
service ril-daemon /system/bin/rild -l /system/lib/reference-ril.so -- -d /dev/ttyS0    socket rild stream 660 root radio
socket rild-debug stream 660 radio system
user root
简述android概述group radio cache inet misc
上面的脚本中,服务的名字为ril-daemon,在这个服务中,linux会运行rild这个守护进程,并且使用动态链接库 reference-ril.so,这个so就是用户自己实现的vendor lib动态库,并且指明设备 ttyS0给该动态库使用。另外将创建两个有名socket,分别为rild和rild-debug,并且会把创建得到的文件描述符export为环境变量,以便RIL操作中可以获得对socket的访问。其他内容是关于用户和组信息的。有名
socket rild用来负责RILD与JAVA空间的进程间通信,frameworks/base/telephony/java/com/android/internal/telephony/gsm/RIL.java文件中,会去rild这个socket发起connect,并且在JAVA空间启动两个线程来对该socket 进行读写,分别为RILReceiver 和RILSender,该socket的listen是在rild守护进程中实现,sendResponseRaw函数和ProcessCommandCallback函数用来处理rild守护
进程侧对这个socket的读写,结构示意图如图1所示。rild-debug则用作调试命令的通信。
图1. RIL命令通信结构示意图
Rild对应的源文件为 \hardware\ril\rild 目录下的rild.c,并且依赖libril静态库,libril静态库由 ril.cpp和ril_event.cpp生成。
RILD的结构如下图2所示:
图2. RILD流程图
2. RILD的主消息循环
RIL_startEventLoop创建一个线程,执行event_loop。在event_loop中,将初始化 ril_event,创建管道用来做wakeup,目前看起来wakeup仅是简单的使主消息循环定期退出select阻塞。添加wakeup ev
ent后开始执行 ril_event_loop,该函数是循环的主体。
在继续介绍之前先介绍一下event 结构和工作方式,结构定义如下:
Struct  ril_event {
struct ril_event *next;
struct ril_event *prev;
int fd; //接收消息的文件描述符
int index; //在watch_table中的索引,对于timer列表,为-1
bool persist;    // 事件发生后是否还保留
struct timeval timeout;
ril_event_cb func;  //回调函数
void *param;  //回调函数的参数
};
static struct ril_event * watch_table[MAX_FD_EVENTS];
static struct ril_event timer_list;
static struct ril_event pending_list;
watch_table中的事件是由外部触发,通过向文件描述符中写入内容来触发,timer_list中的事件由超时来触发,这两个列表中的已触发事件会被加入到pending_list中,在ril_event_loop中由firePending函数触发对事件处理函数的回调。
在android中,通过ril_event_set接口来初始化并填充ril_event的各域,指定文件描述符和对应的回调处理函数。
然后使用 ril_event_add 接口来把这个ril_event添加到watch_table 中,此时
ril_event的index会被赋值为与其在watch_table中的索引一致。
timer_list是一个双环链表,用来实现timer的功能,该链表由ril_timer_add、addToList、removeFromL
ist等函数维护。链表的示意图如图3所示,以timer_list 为表头,新加入的元素放在尾端。
图3. timer_list 双链表示意图
RILD的主消息循环如图4所示,用来完成对到期的timer和有事件发生的watch_table的处理。通过ril_event_add函数加入到watch_table中的事件,他们的文件描述符将被加入到select关注的读文件描述符中。
Watch_table中关注的event主要有以下几个:
1)s_listen_event:关注s_fdListen,处理名为rild的socket 的监听,对应回
调接口为listenCallback函数,当发生对该socket的connect请求时触发
事件,触发后将被移除。
2)s_commands_event:关注s_fdCommand,该文件描述符代表通过rild建
立的一条连接,在此连接上对rild的写入将触发事件,对应的回调接口
为processCommandsCallback函数,触发后不会从watch_table中移除该
事件。
3)s_debug_event:关注s_fdDebug,处理对名为rild-debug的socket的监
听,并完成连接后的调试信息通信。对rild-debug的连接将触发事件,
触发后不会从watch_table中移除该事件。
4)s_wakeupfd_event:关注s_fdWakeupRead,是管道的读端,写端在
internalRequestTimedCallback函数中操作。该事件用来唤醒阻塞,由于
定时器列表为空时,循环会以一直阻塞的形式来等待事件,此时新增定
时器后不能生效,需要wakeup原来的阻塞等待,使其使用定时器设定
的超时时间来做超时等待。
图4.  ril_event_loop 处理流程图
3. vendor库的初始化和函数集注册:
在调用RIL_startEventLoop去启动主消息处理线程的同时,原主线程将加载vendor动态库,并从其中取得标号为RIL_Init的函数指针,调用该函数传递函数集s_rilEnv和vendor lib所需的参数为vendor lib的运行进行初始化。
图5. RILD其他部分流程图
在RIL_register函数中完成对各个event事件的添加。
4. Solicited 和Unsoclicted命令的处理结构
RIL_Init传入一个RIL_Env结构,如下所示:
struct RIL_Env {
void (*OnRequestComplete)(RIL_Token t, RIL_Errno e,
void *response, size_t responselen);

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。