Android源码目录hardware/ril/libril目录中总共包含5个C/CPP文件,它们分别是ril_commands.h、ril_unsol_commands.h、ril_event.h、ril_event.cpp和ril.cpp。这篇文章主要分析ril_event的相关代码。
ril_event主要处理电话模块涉及的端口、modem等产生的事件,并将多个事件按时间顺序进行组织,并保存在事件队别中,主要使用了三个队列,分别是:watch_table[],timer_list和pending_list。代码是以C语言方式实现的,先来看头文件ril_event.h:
// 每次监视的最大的文件描述符句柄数,可以根据需要自行修改
#define MAX_FD_EVENTS 8
// ril_event的回调函数
typedef void (*ril_event_cb)(int fd, short events, void *userdata);
struct ril_event {
// 用于将ril_event串成双向链表的前向指针和后向指针
struct ril_event *next;
struct ril_event *prev;
//ril事件相关的文件描述符句柄(可以是文件、管道、Socket等)
int fd;
//这个事件在监控列表中的索引
int index;
//当一个事件处理完后(即从watch_table移到pending_list中等待处理),
//persist参数决定这个事件是否一直存在于监控列表watch_table[]中
bool persist;
//事件的超时时间
struct timeval timeout;
//回调函数及其传入的参数
ril_event_cb func;
void *param;
};
//以下是ril事件相关的一些操作函数
// 初始化内部数据结构
void ril_event_init();
// 初始化一个ril事件
void ril_event_set(struct ril_event * ev, int fd, bool persist, ril_event_cb func, void * param);
// 将事件添加到监控列表watch_table[]中
void ril_event_add(struct ril_event * ev);
// 增加一个timer事件到timer_list链表中
void ril_timer_add(struct ril_event * ev, struct timeval * tv);
// 将指定的事件从监控列表watch_table[]中移除
void ril_event_del(struct ril_event * ev);
// 事件循环
void ril_event_loop();
接着分析ril_event .cpp文件:
#define LOG_TAG "RILC"
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <utils/Log.h>
#include <ril_event.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>
#include <pthread.h>
// 使用互斥量mutex进行线程同步,可参见《Linux程序设计》相关章节
static pthread_mutex_t listMutex;
#define MUTEX_ACQUIRE() pthread_mutex_lock(&listMutex)
#define MUTEX_RELEASE() pthread_mutex_unlock(&listMutex)
#define MUTEX_INIT() pthread_mutex_init(&listMutex, NULL)
#define MUTEX_DESTROY() pthread_mutex_destroy(&listMutex)
// 两个timeval类型的值相加
#ifndef timeradd
#define timeradd(tvp, uvp, vvp) \
do { \
(vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \
(vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \
if ((vvp)->tv_usec >= 1000000) { \
(vvp)->tv_sec++; \
(vvp)->tv_usec -= 1000000; \
} \
} while (0)
#endif
// 两个timeval类型的值进行比较
#ifndef timercmp
#define timercmp(a, b, op) \
((a)->tv_sec == (b)->tv_sec \
? (a)->tv_usec op (b)->tv_usec \
: (a)->tv_sec op (b)->tv_sec)
#endif
// 两个timeval类型的值相减
#ifndef timersub
#define timersub(a, b, res) \
do { \
(res)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
(res)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
if ((res)->tv_usec < 0) { \
(res)->tv_usec += 1000000; \
(res)->tv_sec -= 1; \
} \
} while(0);
#endi
// 保存Rild中所有设备文件句柄,便于使用select函数完成事件的监听
static fd_set readFds;
// 记录readFds中最大fd值+1
static int nfds = 0;
// 为了统一管理ril事件,Android提供如下三个队列:
// 监控事件列表,需要检测的事件都需要先存入该列表中
static struct ril_event * watch_table[MAX_FD_EVENTS];
// timer事件队列,事件超时后即移入pending_list队列中
static struct ril_event timer_list;
// 待处理的事件队列,即事件已经触发,后续需要调用事件的回调函数
static struct ril_event pending_list;
#define DEBUG 0
#if DEBUG
#define dlog(x...) LOGD( x )
static void dump_event(struct ril_event * ev)
{
dlog("~~~~ Event %x ~~~~", (unsigned int)ev);
dlog(" next = %x", (unsigned int)ev->next);
dlog(" prev = %x", (unsigned int)ev->prev);
dlog(" fd = %d", ev->fd);
dlog(" pers = %d", ev->persist);
dlog(" timeout = %ds + %dus", (int)ev->timeout.tv_sec, (int)ev->timeout.tv_usec);
dlog(" func = %x", (unsigned int)ev->func);
dlog(" param = %x", (unsigned int)ev->param);
dlog("~~~~~~~~~~~~~~~~~~");
}
#else
#define dlog(x...) do {} while(0)
#define dump_event(x) do {} while(0)
#endif
// 获取此刻timeval值
static void getNow(struct timeval * tv)
{
#ifdef HAVE_POSIX_CLOCKS
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
tv->tv_sec = ts.tv_sec;
tv->tv_usec = ts.tv_nsec/1000;
#else
gettimeofday(tv, NULL);
#endif
}
// 初始化指定的ril_event链表
static void init_list(struct ril_event * list)
{
memset(list, 0, sizeof(struct ril_event));
list->next = list;
list->prev = list;
list->fd = -1;
}
// 增加一个ril_event事件到ril_event队列头
static void addToList(struct ril_event * ev, struct ril_event * list)
{
ev->next = list;
ev->prev = list->prev;
ev->prev->next = ev;
list->prev = ev;
dump_event(ev);
}
// 从ril_event队列中移除指定的ril_event
static void removeFromList(struct ril_event * ev)
{
dlog("~~~~ Removing event ~~~~");
dump_event(ev);
ev->next->prev = ev->prev;
ev->prev->next = ev->next;
ev->next = NULL;
ev->prev = NULL;
}
// 从watch_table[]中移除指定索引的事件
static void removeWatch(struct ril_event * ev, int index)
{
// 索引index对应的事件置为空,同时事件ev的索引设为无效值-1
watch_table[index] = NULL;
ev->index = -1;
// 将该事件对应的文件描述符句柄从readFds中清除
FD_CLR(ev->fd, &readFds);
if (ev->fd+1 == nfds) {
int n = 0;
for (int i = 0; i < MAX_FD_EVENTS; i++) {
struct ril_event * rev = watch_table[i];
if ((rev != NULL) && (rev->fd > n)) {
n = rev->fd;
}
}
nfds = n + 1;
dlog("~~~~ nfds = %d ~~~~", nfds);
}
}
// 遍历timer_list队列中的事件,当事件超时时间到时
// 将事件移除,并添加到pending_list队列中
static void processTimeouts()
{
dlog("~~~~ +processTimeouts ~~~~");
MUTEX_ACQUIRE();
struct timeval now;
struct ril_event * tev = timer_list.next;
struct ril_event * next;
getNow(&now);
// walk list, see if now >= ev->timeout for any events
dlog("~~~~ Looking for timers <= %ds + %dus ~~~~", (int)now.tv_sec, (int)now.tv_usec);
while ((tev != &timer_list) && (timercmp(&now, &tev->timeout, >))) {
// Timer expired
dlog("~~~~ firing timer ~~~~");
next = tev->next;
removeFromList(tev);
addToList(tev, &pending_list);
tev = next;
}
MUTEX_RELEASE();
dlog("~~~~ -processTimeouts ~~~~");
}
// 遍历监控列表watch_table[]中的事件,并将有数据可读的事件
// 添加到pending_list链表中,同时如果事件的persist不为true
// 则将该事件从watch_table[]中移除
static void processReadReadies(fd_set * rfds, int n)
{
dlog("~~~~ +processReadReadies (%d) ~~~~", n);
MUTEX_ACQUIRE();
for (int i = 0; (i < MAX_FD_EVENTS) && (n > 0); i++) {
struct ril_event * rev = watch_table[i];
if (rev != NULL && FD_ISSET(rev->fd, rfds)) {
addToList(rev, &pending_list);
if (rev->persist == false) {
removeWatch(rev, i);
}
n--;
}
}
MUTEX_RELEASE();
dlog("~~~~ -processReadReadies (%d) ~~~~", n);
}
// 依次调用待处理队列pending_list中的事件的回调函数
static void firePending()
{
dlog("~~~~ +firePending ~~~~");
struct ril_event * ev = pending_list.next;
while (ev != &pending_list) {
struct ril_event * next = ev->next;
removeFromList(ev);
ev->func(ev->fd, 0, ev->param);
ev = next;
}
dlog("~~~~ -firePending ~~~~");
}
// 计算timer_list链表中下一个事件的新的超时时间
static int calcNextTimeout(struct timeval * tv)
{
struct ril_event * tev = timer_list.next;
struct timeval now;
getNow(&now);
// Sorted list, so calc based on first node
if (tev == &timer_list) {
// no pending timers
return -1;
}
dlog("~~~~ now = %ds + %dus ~~~~", (int)now.tv_sec, (int)now.tv_usec);
dlog("~~~~ next = %ds + %dus ~~~~",
(int)tev->timeout.tv_sec, (int)tev->timeout.tv_usec);
if (timercmp(&tev->timeout, &now, >)) {
timersub(&tev->timeout, &now, tv);
} else {
// timer already expired.
tv->tv_sec = tv->tv_usec = 0;
}
return 0;
}
// 初始化内部数据结构(互斥量、FD集合、三个事件队列)
void ril_event_init()
{
MUTEX_INIT();
FD_ZERO(&readFds);
init_list(&timer_list);
init_list(&pending_list);
memset(watch_table, 0, sizeof(watch_table));
}
// 初始化一个ril事件
void ril_event_set(struct ril_event * ev, int fd, bool persist, ril_event_cb func, void * param)
{
dlog("~~~~ ril_event_set %x ~~~~", (unsigned int)ev);
memset(ev, 0, sizeof(struct ril_event));
ev->fd = fd;
ev->index = -1;
ev->persist = persist;
ev->func = func;
ev->param = param;
//linux的文件上锁函数,给文件描述符fd上非阻塞的文件锁
fcntl(fd, F_SETFL, O_NONBLOCK);
}
// 将事件添加到监控列表watch_table[]中
void ril_event_add(struct ril_event * ev)
{
dlog("~~~~ +ril_event_add ~~~~");
MUTEX_ACQUIRE();
for (int i = 0; i < MAX_FD_EVENTS; i++) {
if (watch_table[i] == NULL) {
watch_table[i] = ev;
ev->index = i;
dlog("~~~~ added at %d ~~~~", i);
dump_event(ev);
FD_SET(ev->fd, &readFds);
if (ev->fd >= nfds) nfds = ev->fd+1;
dlog("~~~~ nfds = %d ~~~~", nfds);
break;
}
}
MUTEX_RELEASE();
dlog("~~~~ -ril_event_add ~~~~");
}
// 增加一个timer事件到timer_list链表中
void ril_timer_add(struct ril_event * ev, struct timeval * tv)
{
dlog("~~~~ +ril_timer_add ~~~~");
MUTEX_ACQUIRE();
struct ril_event * list;
if (tv != NULL) {
// add to timer list
list = timer_list.next;
ev->fd = -1; // make sure fd is invalid
struct timeval now;
getNow(&now);
timeradd(&now, tv, &ev->timeout);
// 根据timeout值从小到大在链表中排序
while (timercmp(&list->timeout, &ev->timeout, < )
&& (list != &timer_list)) {
list = list->next;
}
// 循环结束后,list指向链表中第一个timeout值大于ev的事件
// 将新加入的事件ev加到list此刻指向的事件前面
addToList(ev, list);
}
MUTEX_RELEASE();
dlog("~~~~ -ril_timer_add ~~~~");
}
// 将事件从watch_table[]中移除
void ril_event_del(struct ril_event * ev)
{
dlog("~~~~ +ril_event_del ~~~~");
MUTEX_ACQUIRE();
if (ev->index < 0 || ev->index >= MAX_FD_EVENTS) {
MUTEX_RELEASE();
return;
}
removeWatch(ev, ev->index);
MUTEX_RELEASE();
dlog("~~~~ -ril_event_del ~~~~");
}
#if DEBUG
// 打印监控列表中可用的事件
static void printReadies(fd_set * rfds)
{
for (int i = 0; (i < MAX_FD_EVENTS); i++) {
struct ril_event * rev = watch_table[i];
if (rev != NULL && FD_ISSET(rev->fd, rfds)) {
dlog("DON: fd=%d is ready", rev->fd);
}
}
}
#else
#define printReadies(rfds) do {} while(0)
#endif
void ril_event_loop()
{
int n;
fd_set rfds;
struct timeval tv;
struct timeval * ptv;
for (;;) {
// make local copy of read fd_set
memcpy(&rfds, &readFds, sizeof(fd_set));
// 根据timer_list来计算select函数的等待时间
// timer_list之前已按事件的超时时间排好序了
if (-1 == calcNextTimeout(&tv)) {
// no pending timers; block indefinitely
dlog("~~~~ no timers; blocking indefinitely ~~~~");
ptv = NULL;
} else {
dlog("~~~~ blocking for %ds + %dus ~~~~", (int)tv.tv_sec, (int)tv.tv_usec);
ptv = &tv;
}
printReadies(&rfds);
// 使用select函数实现多路IO复用
n = select(nfds, &rfds, NULL, NULL, ptv);
printReadies(&rfds);
dlog("~~~~ %d events fired ~~~~", n);
if (n < 0) {
if (errno == EINTR) continue;
LOGE("ril_event: select error (%d)", errno);
// bail?
return;
}
// Check for timeouts
processTimeouts();
// Check for read-ready
processReadReadies(&rfds, n);
// Fire away
firePending();
}
}
==============================================================================================================================
ril_event 事件机制分析
1.主要有2个线程readerLoop,和eventloop------实现event机制
2. 可以从ril_event_add和triggerEvLoop函数看出,每次调用rilEventAddWakeup时,就把安装了 processWakeupCallback(作用是清空管道)处理函数s_wakeupfd_event 事件写入监视列表watch_table[] 数组,然后再向管道内写入一个字节的空格。
管道的作用是这样的,eventloop函数所在的进程向下调用ril_event_loop()函数(ril_event.cpp),后者将 readFds做了一个本地备份(自然s_wakeupfd_event的描述符也在里面,因为ril_event_add已将将ev->fd加入 readFds描述符集)。然后再向下遇到了一个select :n = select(nfds, &rfds, NULL, NULL, ptv);
此时如果管道里面有数据,s_fdWakeupRead即为可用,则select不会阻塞。因此,如果eventloop进程在这里因为没有可用的读描述符而被阻塞的话,执rilEventAddWakeup后,管道内被写入了至少一个空格,则rfds中至少将有一个描述符变得可用,select函数返回。因此eventloop线程(此时该进程正在执行ril_event_loop函数)被select的阻塞的情况(如果被阻塞的话)将被解除。
eventloop线程继续向下执行,被写入监视列表watch_table数组的s_wakeupfd_event事件在ril_event_loop 函数(ril_event.cpp)调用函数processReadReadies(&rfds, n)时放入了pending_list中,并随着firePending()函数的执行,processWakeupCallback函数(作用是清空管道)也得到执行。这样,管道的读描述符重新变得不可用,使其不影响正常的select功能。相当于将唤醒eventloop进程的“扳机”重新归位,等待下一次某个进程需要时再次调用的triggerEvLoop。
总的来说,就是通过管道内的数据有无,控制select是否解除阻塞的过程。
3.rilEventAddWakeup函数:把ev添加到监视列表watch_table数组,并且向管道写一个数据,使select不阻塞。读管道数据-----------添加事件的时候都会解除阻塞。
避免这样情况?:select阻塞,添加事件后,还在阻塞哪里?下一次的select才不会阻塞。
eventLoop----最终调用ril_event_loop这里循环。
1.s_fdListen-------listenCallback------可以开启s_fdCommand事件
2.s_fdCommand-----processCommandsCallback--------dispatchFunction函数处理请求---多个
3.s_fdWakeupRead----processWakeupCallback----//清空用于唤醒管道数据
4.p_info->event--------userTimerCallback--------internalRequestTimedCallback函数???---多个
rilEventAddWakeup---triggerEvLoop-------write (s_fdWakeupWrite, " ", 1);--------写空格。
s_tid_dispatch--eventLoop
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// 为了统一管理ril事件,Android提供如下三个队列:
// 监控事件列表,需要检测的事件都需要先存入该列表中
static struct ril_event * watch_table[MAX_FD_EVENTS];
// timer事件队列,事件超时后即移入pending_list队列中
static struct ril_event timer_list;
// 待处理的事件队列,即事件已经触发,后续需要调用事件的回调函数
static struct ril_event pending_list;
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
RILD进程入口函数分析
在main函数中主要完成以下工作:
1.解析命令行参数,通过判断是否为模拟器采取不同的方式来读取libreference-ril.so库的存放路径;
2.使用dlopen手动装载libreference-ril.so库;
3.启动事件循环处理;
4.从libreference-ril.so库中取得RIL_Init函数地址,并使用该函数将libril.so库中的RIL_Env接口注册到libreference-ril.so库,同时将libreference-ril.so库中的RIL_RadioFunctions接口注册到到libril.so库中,建立起libril.so库与libreference-ril.so库通信桥梁;
---------------------------------------------------------------------------------------------------------------------------------------------------------------
启动事件循环处理eventLoop工作线程
建立多路I/O驱动机制的消息队列,用来接收上层发出的命令以及往Modem发送AT指令的工作,时整个RIL系统的核心部分。创建一个事件分发线程s_tid_dispatch,线程执行体为eventLoop
在rild中定义了event的概念,Rild支持两种类型的事件:
1. 定时事件:根据事件的执行时间来启动执行,通过ril_timer_add添加到time_list队列中
2. Wakeup事件:这些事件的句柄fd将加入的select IO多路复用的句柄池readFDs中,当对应的fd可读时将触发这些事件。对于处于listen端的socket,fd可读表示有个客户端连接,此时需要调用accept接受连接。
/事件监控队列
static struct ril_event * watch_table[MAX_FD_EVENTS];
//定时事件队列
static struct ril_event timer_list;
//处理事件队列
static struct ril_event pending_list; //待处理事件队列,事件已经触发,需要所回调处理的事件
处理事件
- void ril_event_loop()
- {
- int n;
- fd_set rfds;
- struct timeval tv;
- struct timeval * ptv;
- for (;;) {
- memcpy(&rfds, &readFds, sizeof(fd_set));
- if (-1 == calcNextTimeout(&tv)) {
- dlog("~~~~ no timers; blocking indefinitely ~~~~");
- ptv = NULL;
- } else {
- dlog("~~~~ blocking for %ds + %dus ~~~~", (int)tv.tv_sec, (int)tv.tv_usec);
- ptv = &tv;
- }
- //使用select 函数等待在FDS 上,只要FDS 中记录的设备有数据到来,select 就会设置相应的标志位并返回。readFDS 记录了所有的事件相关设备句柄。readFDS 中句柄是在在AddEvent 加入的。
- printReadies(&rfds);
- n = select(nfds, &rfds, NULL, NULL, ptv);
- printReadies(&rfds);
- dlog("~~~~ %d events fired ~~~~", n);
- if (n < 0) {
- if (errno == EINTR) continue;
- LOGE("ril_event: select error (%d)", errno);
- return;
- }
- processTimeouts(); //从timer_list中查询执行时间已到的事件,并添加到pending_list中
- processReadReadies(&rfds, n); //从watch_table中查询数据可读的事件,并添加到pending_list中去处理,如果该事件不是持久事件,则同时从watch_table中删除
- //遍历pending_list,调用事件处理回调函数处理所有事件
- firePending();
- }
- }
1.超时事件查询
- static void processTimeouts()
- {
- dlog("~~~~ +processTimeouts ~~~~");
- MUTEX_ACQUIRE();
- struct timeval now;
- struct ril_event * tev = timer_list.next;
- struct ril_event * next;
- getNow(&now); //获取当前时间
- dlog("~~~~ Looking for timers <= %ds + %dus ~~~~", (int)now.tv_sec, (int)now.tv_usec);
- //如果当前时间大于事件的超时时间,则将该事件从timer_list中移除,添加到pending_list
- while ((tev != &timer_list) && (timercmp(&now, &tev->timeout, >))) {
- dlog("~~~~ firing timer ~~~~");
- next = tev->next;
- removeFromList(tev); //从timer_list中移除事件
- addToList(tev, &pending_list); //将事件添加到pending_list
- tev = next;
- }
- MUTEX_RELEASE();
- dlog("~~~~ -processTimeouts ~~~~");
- }
2.可读事件查询
- static void processReadReadies(fd_set * rfds, int n)
- {
- dlog("~~~~ +processReadReadies (%d) ~~~~", n);
- MUTEX_ACQUIRE();
- //遍历watch_table数组,根据select返回的句柄n查找对应的事件
- for (int i = 0; (i < MAX_FD_EVENTS) && (n > 0); i++) {
- struct ril_event * rev = watch_table[i]; //得到相应的事件
- if (rev != NULL && FD_ISSET(rev->fd, rfds)) {
- addToList(rev, &pending_list); //将该事件添加到pending_list中
- if (rev->persist == false) { //如果该事件不是持久事件还要从watch_table中移除
- removeWatch(rev, i);
- }
- n--;
- }
- }
- MUTEX_RELEASE();
- dlog("~~~~ -processReadReadies (%d) ~~~~", n);
- }
3.事件处理
- static void firePending()
- {
- dlog("~~~~ +firePending ~~~~");
- struct ril_event * ev = pending_list.next;
- while (ev != &pending_list) { //遍历pending_list链表,处理链表中的所有事件
- struct ril_event * next = ev->next;
- removeFromList(ev); //将处理完的事件从pending_list中移除
- ev->func(ev->fd, 0, ev->param); //调用事件处理的回调函数
- ev = next;
- }
- dlog("~~~~ -firePending ~~~~");
- }
RIL_Init的主要任务:
1. 向librefrence.so注册libril.so提供的接口RIL_Env;
2. 创建一个mainLoop工作线程,用于初始化AT模块,并监控AT模块的状态,一旦AT被关闭,则重新打开并初始化AT;
3. 当AT被打开后,mainLoop工作线程将向Rild提交一个定时事件,并触发eventLoop来完成对modem的初始化;
4. 创建一个readLoop工作线程,用于从AT串口中读取数据;
5.返回librefrence.so提供的接口RIL_RadioFunctions;
2.添加定时事件RIL_requestTimedCallback
- RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);
- #define RIL_requestTimedCallback(a,b,c) s_rilenv->RequestTimedCallback(a,b,c)
向定时事件队列中添加一个定时事件,该事件的处理函数为initializeCallback,用于发送一些AT指令来初始化BP的modem。
3.readLoop工作线程
Read loop 解析从Modem 发过来的回应。如果遇到URC 则通过handleUnsolicited 上报的RIL_JAVA。如果是命令的应答,则通过handleFinalResponse 通知send_at_command 有应答结果。
- static void *readerLoop(void *arg)
- {
- for (;;) {
- const char * line;
- line = readline();
- if (line == NULL) {
- break;
- }
- if(isSMSUnsolicited(line)) { //判断是否是SMS 通知
- char *line1;
- const char *line2;
- line1 = strdup(line);
- line2 = readline();
- if (line2 == NULL) {
- break;
- }
- if (s_unsolHandler != NULL) {
- s_unsolHandler (line1, line2); //回调通知SMS
- }
- free(line1);
- } else {
- processLine(line); //处理接收到的数据,根据line中的指令调用不同的回调函数
- }
- #ifdef HAVE_ANDROID_OS
- if (s_ackPowerIoctl > 0) {
- /* acknowledge that bytes have been read and processed */
- ioctl(s_fd, OMAP_CSMI_TTY_ACK, &s_readCount);
- s_readCount = 0;
- }
- #endif /*HAVE_ANDROID_OS*/
- }
- onReaderClosed();
- return NULL;
- }
打电话的AT命令:{RIL_REQUEST_DIAL, dispatchDial, responseVoid},
发短信的AT命令:{RIL_REQUEST_SEND_SMS, dispatchStrings, responseSMS},
3.电话拨打流程
拨打电话的时序图如下: