Android RIL源码研究笔记1- ril_event机制

 

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接受连接。

在RILD中定义了三个事件队列,用于处理不同的事件:

/事件监控队列

static struct ril_event * watch_table[MAX_FD_EVENTS];

//定时事件队列

static struct ril_event timer_list;

//处理事件队列

static struct ril_event pending_list; //待处理事件队列,事件已经触发,需要所回调处理的事件


 

处理事件
[cpp] view plaincopy
  1. void ril_event_loop()  
  2. {  
  3.     int n;  
  4.     fd_set rfds;  
  5.     struct timeval tv;  
  6.     struct timeval * ptv;  
  7.     for (;;) {  
  8.         memcpy(&rfds, &readFds, sizeof(fd_set));  
  9.         if (-1 == calcNextTimeout(&tv)) {  
  10.             dlog("~~~~ no timers; blocking indefinitely ~~~~");  
  11.             ptv = NULL;  
  12.         } else {  
  13.             dlog("~~~~ blocking for %ds + %dus ~~~~", (int)tv.tv_sec, (int)tv.tv_usec);  
  14.             ptv = &tv;  
  15.         }  
  16.         //使用select 函数等待在FDS 上,只要FDS 中记录的设备有数据到来,select 就会设置相应的标志位并返回。readFDS 记录了所有的事件相关设备句柄。readFDS 中句柄是在在AddEvent 加入的。  
  17.         printReadies(&rfds);  
  18.         n = select(nfds, &rfds, NULL, NULL, ptv);   
  19.         printReadies(&rfds);  
  20.         dlog("~~~~ %d events fired ~~~~", n);  
  21.         if (n < 0) {  
  22.             if (errno == EINTR) continue;  
  23.             LOGE("ril_event: select error (%d)", errno);  
  24.             return;  
  25.         }  
  26.         processTimeouts(); //从timer_list中查询执行时间已到的事件,并添加到pending_list中  
  27.         processReadReadies(&rfds, n); //从watch_table中查询数据可读的事件,并添加到pending_list中去处理,如果该事件不是持久事件,则同时从watch_table中删除  
  28.         //遍历pending_list,调用事件处理回调函数处理所有事件  
  29.         firePending();  
  30.     }  
  31. }  


在eventLoop工作线程中,循环处理到来的事件及定时结束事件,整个处理流程如下图所示:

首先通过Linux中的select多路I/O复用对句柄池中的所有句柄进行监控,当有事件到来时select返回,否则阻塞。当select返回时,表示有事件的到来,通过调用processTimeouts函数来处理超时事件,处理方式是遍历time_list链表以查询超时事件,并将超时事件移入到pending_list链表中,接着调用processReadReadies函数来处理触发的事件,处理方式为遍历watch_table列表以查询触发的事件,并将触发的事件移入到pending_list链表中,如果该事件不是持久事件,还需要从watch_table列表中移除,当查询完两种待处理的事件并放入到pending_list链表中后,调用firePending函数对待处理的事件进行集中处理,处理方式为遍历链表,调用每一个事件的回调函数。

 1.超时事件查询
[cpp] view plaincopy
  1. static void processTimeouts()  
  2. {  
  3.     dlog("~~~~ +processTimeouts ~~~~");  
  4.     MUTEX_ACQUIRE();  
  5.     struct timeval now;  
  6.     struct ril_event * tev = timer_list.next;  
  7.     struct ril_event * next;  
  8.     getNow(&now); //获取当前时间  
  9.   dlog("~~~~ Looking for timers <= %ds + %dus ~~~~", (int)now.tv_sec, (int)now.tv_usec);  
  10.   //如果当前时间大于事件的超时时间,则将该事件从timer_list中移除,添加到pending_list  
  11.     while ((tev != &timer_list) && (timercmp(&now, &tev->timeout, >))) {  
  12.         dlog("~~~~ firing timer ~~~~");  
  13.         next = tev->next;  
  14.         removeFromList(tev); //从timer_list中移除事件  
  15.         addToList(tev, &pending_list); //将事件添加到pending_list  
  16.         tev = next;  
  17.     }  
  18.     MUTEX_RELEASE();  
  19.     dlog("~~~~ -processTimeouts ~~~~");  
  20. }  
2.可读事件查询
[cpp] view plaincopy
  1. static void processReadReadies(fd_set * rfds, int n)  
  2. {  
  3.     dlog("~~~~ +processReadReadies (%d) ~~~~", n);  
  4.   MUTEX_ACQUIRE();   
  5.   //遍历watch_table数组,根据select返回的句柄n查找对应的事件  
  6.     for (int i = 0; (i < MAX_FD_EVENTS) && (n > 0); i++) {  
  7.         struct ril_event * rev = watch_table[i]; //得到相应的事件  
  8.         if (rev != NULL && FD_ISSET(rev->fd, rfds)) {  
  9.             addToList(rev, &pending_list); //将该事件添加到pending_list中  
  10.             if (rev->persist == false) { //如果该事件不是持久事件还要从watch_table中移除  
  11.                 removeWatch(rev, i);  
  12.             }  
  13.             n--;  
  14.         }  
  15.     }  
  16.     MUTEX_RELEASE();  
  17.     dlog("~~~~ -processReadReadies (%d) ~~~~", n);  
  18. }  
3.事件处理
[cpp] view plaincopy
  1. static void firePending()  
  2. {  
  3.     dlog("~~~~ +firePending ~~~~");  
  4.     struct ril_event * ev = pending_list.next;  
  5.     while (ev != &pending_list) { //遍历pending_list链表,处理链表中的所有事件  
  6.         struct ril_event * next = ev->next;  
  7.         removeFromList(ev); //将处理完的事件从pending_list中移除  
  8.         ev->func(ev->fd, 0, ev->param); //调用事件处理的回调函数  
  9.         ev = next;  
  10.     }  
  11.     dlog("~~~~ -firePending ~~~~");  
  12. }  

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

 

[cpp] view plaincopy
  1. RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);  
  2.   
  3. #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 有应答结果。


[cpp] view plaincopy
  1. static void *readerLoop(void *arg)  
  2. {  
  3.     for (;;) {  
  4.         const char * line;  
  5.         line = readline();  
  6.         if (line == NULL) {  
  7.             break;  
  8.         }  
  9.         if(isSMSUnsolicited(line)) { //判断是否是SMS 通知  
  10.             char *line1;  
  11.             const char *line2;  
  12.             line1 = strdup(line);  
  13.             line2 = readline();  
  14.             if (line2 == NULL) {  
  15.                 break;  
  16.             }  
  17.             if (s_unsolHandler != NULL) {  
  18.                 s_unsolHandler (line1, line2); //回调通知SMS  
  19.             }  
  20.             free(line1);  
  21.         } else {  
  22.             processLine(line); //处理接收到的数据,根据line中的指令调用不同的回调函数  
  23.         }  
  24. #ifdef HAVE_ANDROID_OS  
  25.         if (s_ackPowerIoctl > 0) {  
  26.             /* acknowledge that bytes have been read and processed */  
  27.             ioctl(s_fd, OMAP_CSMI_TTY_ACK, &s_readCount);  
  28.             s_readCount = 0;  
  29.         }  
  30. #endif /*HAVE_ANDROID_OS*/  
  31.     }  
  32.     onReaderClosed();  
  33.     return NULL;  
  34. }  

电话的AT命令:{RIL_REQUEST_DIAL, dispatchDial, responseVoid},

发短信的AT命令:{RIL_REQUEST_SEND_SMS, dispatchStrings, responseSMS},

3.电话拨打流程


 

 

拨打电话的时序图如下:


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值