RILD分析

在Android中,电话系统由三个部分组成,Phone Framework, RIL-Daemon, Vendor-specified RIL。RIL-Daemon的作用是将Android Phone Framework和Vendor-RIL结合起来。这样做的好处是提供了一个松散耦合结构,不同厂家都可以根据自己的实际需求设计Vendor-RIL实现功能. Android Phone Framework 和 Vendor-RIL之间是通过RIL-Daemon进行交互的。Phone Framework和RIL-Daemon之间通过socket进行进程间通讯,RIL-Daemon解析从socket传来的RIL Request,然后调用Vendor-RIL中相对应的函数进行实际的操作

RIL-Daemon 分析

分析从main函数进行,main函数主要工作流程包含一下几点:


 

从上面这个流程来看,RIL-Daemon将用于通知Framework的回调函数注册到了Vendor RIL中,将Vendor RIL中的命令处理函数注册到了RIL-Daemon中。这样以来,Vendor-RIL和Framework就可以通过RILD进行交互了。回调函数接口定义以及意义可以参考.

Event相关分析

在RIL-Daemon的初始化中看来,Deamon启动了eventloop,从命名可以断定RIL-Daemon是事件驱动的。Eventloop有着密切关系的是如下三个结构:

timer_list

 

记录了和延时相关的eventevent按照延时时间,从小到大排序

watch_table

记录了当前RIL-Daemon中所关注的event

 pending_list

录了所有触发了的event,包括timer eventevent

 

Eventloop中的event可以分为三种:

1Time-Event: 超时事件

2Persist FD-Event:永久FD事件,一直监视FD上的变化

3Non-persist FD-Eent:非永久FD时间,仅监视一次FD变化

注:FD-Event有最大数量限制!由MAX_FD_EVENTS宏决定,定义在ril_event.h中。

Eventloop分析:

RIL-Daemonmain()中会通过RIL_startEventLoop()启动Eventloop.启动的过程主要包含如下几方面。

现在具体来看ril_event_loop的工作方式,ril_event_loop是继续select多路复用模型的。也就是说当select函数返回时,要么是对应fd上发生了变化,要么就是超时。在ril_event_loop中,每一次都会通过调用calcNextTimeout()来计算select的等待超时。如果timer_list上没有等待的event,则select采取阻塞等待。否则,select的超时时限有timer_event决定。在select返回后,processTimeout()processReadReadies()两个函数会将满足触发条件的event添加到penging_list中,然后通过调用firePending在执行相对应的处理回调函数。

 1 static void processTimeouts() 
 2 { 
 3     MUTEX_ACQUIRE(); 
 4     /*...*/
 5     while ((tev != &timer_list) && (timercmp(&now, &tev->timeout, >))) { 
 6         next = tev->next; 
 7         removeFromList(tev); 
 8         addToList(tev, &pending_list); 
 9         tev = next; 
10     } 
11     MUTEX_RELEASE(); 
12 }

上面的代码可以看出,所有timeoutevent都从timer_list上移除并加到了pending_list上。

static void processReadReadies(fd_set * rfds, int 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(); 
}

从上面的代码可以看出,所有fd有变化的event也都被加到了pending_list上。但与 processTimeouts不同是,并不是所有满足触发条件的FD-Event都会从watchtable移除,只有哪些非persist的会被移除。

static void 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; 
    }
}

一个特殊的event——s_wakeupfd_event:
在eventloop初始化的时候会创建一个pipe,并在一个endpoint上设置一个persist的wakeupfd_event。这个event的作用只有一个:通知eventloop有新事件到达。具体的来说,针对Timer-Event,event会迫使当前select返回并在下一次循环更新select的超时条件,否则在select阻塞的情况下timer-event不能及时响应。对于FD-Event则是将需要检测的event加入到watch_table,迫使select返回并在下一个循环中更新select的fdset。

RIL_Event结构分析:

typedef void (*ril_event_cb)(int fd, short events, void *userdata); 
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; 
};

综合上面的分析来看这个结构体,可以得到如下的结论:

1、event是一个链表的结构
2、event和一个fd相关连或者timer关联
3、针对和fd相关的event具有persist属性
4、event都有一个处理回调函数
5、每一个回调函数都有一个param参数
6、index用于记录event在watchtable中的位置,方便删除的操作。

RIL_Init:

主要的工作是将通知Phone-Framework的回调函数注册到vendor-ril当中,这样当vendor-ril就可以将来自phone-framwrok的request处理结果,以及unsolicited response的结果返回给framework。此外,还完成了负责和AT模块交流的硬件(串口,socket,etc.)的初始化工作,并建立readerloop,用于监听AT模块返回的结果。vendor-ril可以参考reference-ril。

RIL_register分析:

这里的作用是将vendor-ril中的request处理函数注册到rild中,并建立rild socket的监听事件。这个sockt在init阶段就已经创建好了。在代码中可以看到这一个片段:

ril_event_set (&s_listen_event, s_fdListen, false, listenCallback, NULL);
rilEventAddWakeup (&s_listen_event);

根据之前得分析,我们可以知道,通过这两句话,我们在watch_table中添加了一个fd-event,在这个fd有变化的时候调用listencallback进行处理。由于这个event不是persist的,因此rild每次只能接受一个socket连接。因为phonerild之间采用的是socket通讯,那listencallback中肯定会包含accept

ListenCallback分析:

正如之前分析的一样,Listencallback中确实存在accept。在这个callback中要对socket的合法性进行检查,然后,在accpetfd上建立s_commands_event

ril_event_set (&s_commands_event, s_fdCommand, 1, processCommandsCallback, p_rs); 
rilEventAddWakeup (&s_commands_event); 

这样以来,只要phone端通过socket发送来数据,对应的 processCommandsCallback进行处理。

ProcessCommandsCallback分析:

这个函数会读取一条完整的command,然后调用processCommandBuffer将来自phone端的request进行分发。然后处理完完整的command之后,rild会端来和phone之间的socket链接,并重新监听端口。如下:

close(s_fdCommand);
rilEventAddWakeup(&s_listen_event);

响应command request全过程:

 

 

 

 

posted @ 2014-03-01 13:16  ZHX_1Q89  阅读(1258)  评论(0编辑  收藏  举报