Ril分析二——事件机制和客户端请求监听


客户端请求处理和Event事件处理机制


一 事件机制

//ril_event.cpp
event事件数据结构:   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;     //回调函数参数
};

 

相关对象:
  fd_set readFds;     所有事件队列中设备文件句柄的集合
  int nfds = 0;         所有事件设备句柄中最大值 + 1

  ril_event * watch_table[MAX_FD_EVENTS]; 监测事件队列
  ril_event timer_list;      时间事件队列
  ril_event pending_list;         事件触发 待处理的队列

 

过程如下:

  



二 事件机制处理过程


在rild进程的main函数中:

int main(int argc, char **argv) { //创建客户端事件监听线程
 RIL_startEventLoop(); //处理客户端请求的模块reference-ril.c
    funcs_inst[0] = rilInit(&s_rilEnv, argc, s_argv); //注册客户端事件处理接口,并创建socket监听客户端事件
    for (i = 0; i < numClients; i++) { RIL_register(funcs_inst[i], i); } }  

 

1 RIL_startEventLoop 创建线程事件循环处理

extern "C" void RIL_startEventLoop(void) {   //创建eventLoop线程,直到被启动并将s_started置为1返回
  s_started = 0;   pthread_mutex_lock(&s_startupMutex);     //上锁
   pthread_attr_init (&attr);   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);   ret = pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL);   //线程未启动 休眠等待……
  while (s_started == 0) {     pthread_cond_wait(&s_startupCond, &s_startupMutex);   }   pthread_mutex_unlock(&s_startupMutex);     //解锁
}

 

2 RIL_register 注册客户端请求处理接口 创建事件

extern "C" void RIL_register (const           RIL_RadioFunctions *callbacks, int client_id) {   //注册事件处理接口
  memcpy(&s_callbacks[client_id], callbacks, sizeof (RIL_RadioFunctions));   s_registerCalled++;   // Little self-check   //s_commands   //s_unsolResponses   //确保EventLoop启动
  if (s_started == 0) {     RIL_startEventLoop();   }   // 创建rild的socket start listen socket
  s_fdListen = android_get_control_socket(RIL_getRilSocketName());   ret = listen(s_fdListen, 4);   //创建事件s_listen_event 监听和处理客户端请求
  ril_event_set (&s_listen_event, s_fdListen, true,   listenCallback, NULL);   //将s_listen_event事件加入到watch_table队列中 唤醒事件处理线程
  rilEventAddWakeup (&s_listen_event);   //建立s_debug_event事件 监听和处理调试
  ril_event_set (&s_debug_event, s_fdDebug, true,   debugCallback, NULL);   rilEventAddWakeup (&s_debug_event); }

 

  创建了s_listen_event s_debug_event事件,加入到watch_table事件列表中,

  这些事件将何时,如何被执行呢?

3 EventLoop线程执行函数体

static void * eventLoop(void *param) {   int ret;   int filedes[2];   //初始化readFds timer_list pending_list watch_table
  ril_event_init();   pthread_mutex_lock(&s_startupMutex);   s_started = 1;   pthread_mutex_unlock(&s_startupMutex);   //管道 
  ret = pipe(filedes);   s_fdWakeupRead = filedes[0];   s_fdWakeupWrite = filedes[1];   fcntl(s_fdWakeupRead, F_SETFL, O_NONBLOCK); //读写操作非阻塞   //建立s_wakeupfd_event事件
  ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true,   processWakeupCallback, NULL);   rilEventAddWakeup (&s_wakeupfd_event);   //进入Event线程循环处理过程
  ril_event_loop();   kill(0, SIGKILL);   return NULL; }

 

  看到这里使用pipe管道s_fdWakeupRead s_fdWakeupWrite是何用意呢?
  管道的fd s_fdWakeupRead被加入到readFds集合中;
  创建s_wakeupfd_event事件 使用管道fd作为其设备文件描述符


4 Event线程 ril_event_loop循环处理过程

void ril_event_loop() {   for (;;) {     // make local copy of read fd_set
    memcpy(&rfds, &readFds, sizeof(fd_set));     //计算
    calcNextTimeout(&tv);
    
//从设备节点中读取有变化的值并返回     n = select(nfds, &rfds, NULL, NULL, ptv);
    
//处理timer_list中事件 将过时事件移到pending_list中     processTimeouts();
    
//处理watch_table中事件 将其移到pending_list中     processReadReadies(&rfds, n);
    
//处理pending_list中事件     firePending();   } }

 

事件处理:

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处理的大致流程。这里处理的事件不是外部而是来自内部自定义的事件。


5 pipe 与 select rilEventAddWakeup


这里需要关注的几个地方是:
  pipe管道的使用
  rilEventAddWakeup 如何唤醒线程
  ril_event_loop 中select调用
  这之间是什么关系呢?
定义了管道:
  s_fdWakeupRead = filedes[0];
  s_fdWakeupWrite = filedes[1];

rilEventAddWakeup函数:

  static void rilEventAddWakeup(struct ril_event *ev) {     ril_event_add(ev);     triggerEvLoop();   }


ril_event_add函数:

void ril_event_add(struct ril_event * ev) {   for (int i = 0; i < MAX_FD_EVENTS; i++) {     if (watch_table[i] == NULL) {     watch_table[i] = ev;     ev->index = i;
    
//将当前事件的设备节点文件描述符加入到集合readFds     FD_SET(ev->fd, &readFds);     if (ev->fd >= nfds) nfds = ev->fd+1;       break;     }   } }

readFds定义:static fd_set readFds;
    struct fd_set一个存放文件描述符(file descriptor),即文件句柄的聚合管道文件句柄就是被加入到此集合当中。

  这个文件句柄集合 就是用selecet函数进行监听,一旦文件句柄任一有变化,select就会读取相关变化的值,并返回。

  select可以阻塞也可以是非阻塞,根据传递参数而定。
triggerEvLoop函数:

static void triggerEvLoop() { int ret; if (!pthread_equal(pthread_self(), s_tid_dispatch)) {    do {       //若当前的执行进程不是s_tid_dispatch       //则向管道中写入数据,使readFds集合中文件描述符有变化 以触发线程
      ret = write (s_fdWakeupWrite, " ", 1);     } while (ret < 0 && errno == EINTR);   } }

ril_event_loop函数:

void ril_event_loop() {   for (;;) {     n = select(nfds, &rfds, NULL, NULL, ptv);     ……   } }


  select函数监听文件句柄集合,当句柄中任何一个数据变化时,就会读取它并返回。

否则为定时情况有可能会一直处于阻塞之中,事件得不到执行。

  事件调度处理过程如上所述,事件的作用如何呢,通过这些事件做了些什么事情,客户端的请求是如何处理的,这些并不清楚。

 

三 事件处理


从前面可以看到创建了事件,事件在被移动到待执行列表pending_list后,将在线程循环结构中得到处理,

调用事件的回调处理函数,有如下事件:
  ril_event s_wakeupfd_event;    //清空用于唤醒管道数据
  ril_event s_listen_event;       //接收客户端socket请求
  ril_event s_debug_event;      //用于调试
  ril_event s_commands_event;   //执行客户端请求

 

 

   s_listen_event监听rild端口的客户端连接,如果监听到有新的连接就会执行,使用fd = accept(s_fdListen,…);

得到一个新的套接字文件描述符,用来和建立连接的客户端进行通信:接收和发送消息。

只有新客户端与Rild Sokcet建立连接时,才会触发s_listen_event事件

 

  s_commands_events_listen_event监听到客户端连接,使用accept并建立新的通信套接字fd后,

使用新建立的fd创建s_commands_event事件,从客户端接收消息和向客户端发送消息;

 

 

1 s_wakeupfd_event

  processWakeupCallback:

static void processWakeupCallback(int fd, short flags, void *param) {   /* empty our wakeup socket out */
  do {     ret = read(s_fdWakeupRead, &buff, sizeof(buff));   } while (ret > 0 || (ret < 0 && errno == EINTR)); }

 

  Pipe管道的特性,分为读取端和写入端,读取之后会将其中所有数据清空。

2 s_listen_event

  listenCallback:

static void listenCallback (int fd, short flags, void *param) {   int is_phone_socket = 0;   char *p_record;   RecordStreamInfo *p_rsInfo;   struct passwd *pwd = NULL;   //监听socket连接
  fd = accept(s_fdListen, (sockaddr *) &peeraddr, &socklen);   //判断是否是PHONE_PROCESS 连接 否则返回
  err = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &creds, &szCreds);   pwd = getpwuid(creds.uid);   if (strcmp(pwd->pw_name, PHONE_PROCESS) == 0) {     is_phone_socket = 1;   }   // 创建RecordStream数据结构record_stream.c
  p_rsInfo = new RecordStreamInfo();   p_rsInfo->p_rs = record_stream_new(fd, MAX_COMMAND_BYTES);   p_record = (char *)malloc(sizeof(char) * SUB_DATA_LENGTH);   //从socket中读取数据
  ret = read(fd, p_record, SUB_DATA_LENGTH);   s_fdCommand[p_rsInfo->client_id] = fd;   //创建事件s_commands_event 处理socket请求
  ril_event_set (&s_commands_event[client_id], s_fdCommand[client_id], 1,   processCommandsCallback, p_rsInfo);   rilEventAddWakeup (&s_commands_event[p_rsInfo->client_id]);
  
//通知客户端已建立连接   onNewCommandConnect(p_rsInfo->client_id); }


  s_listen_event事件监听客户端连接,创建s_commands_event事件来处理请求。

3 s_commands_event processCommandsCallback:

static void processCommandsCallback(int fd, short flags, void *param) {   void *p_record;   RecordStreamInfo *p_rsInfo;   p_rsInfo = (RecordStreamInfo *)param;   for (;;) {     /* loop until EAGAIN/EINTR, end of stream, or other error */     ret = record_stream_get_next(p_rsInfo->p_rs, &p_record, &recordlen);     if (ret == 0 && p_record == NULL) {     /* end-of-stream */
    break;   } else if (ret < 0) {     break;   } else if (ret == 0) { /* && p_record != NULL */     processCommandBuffer(p_record, recordlen, p_rsInfo->client_id);   }   } }

 

static int processCommandBuffer(void *buffer, size_t buflen, int client_id) {   Parcel p;   status_t status;   int32_t request;   int32_t token;   RequestInfo *pRI;   //将数据转化成Parcel类型
  p.setData((uint8_t *) buffer, buflen);   // 读取请求的标识
  status = p.readInt32(&request);   status = p.readInt32 (&token);   //将数据请求转化成RequestInfo类型
  pRI = (RequestInfo *)calloc(1, sizeof(RequestInfo));   //查询获取客户端请求处理接口 CommandInfo
  pRI->pCI = &(s_commands[request]);   pRI->token = token;   pRI->client_id = client_id;   pRI->p_next = s_pendingRequests;   s_pendingRequests = pRI;   //调用请求对应的处理函数
  pRI->pCI->dispatchFunction(p, pRI);   return 0; }

   客户端传来的请求都对应着相应的请求标识号,通过该标识号查询每一个客户端请求RequestInfo对应着 处理和响应接口信息CommandInfo

查询是通过s_commands数组进行的。


四 客户端请求处理接口

将客户端通过socket发来请求转化成RequestInfo进行处理,然后查询对应请求的处理接口CommandInfo。

 

    

 

typedef struct {   int requestNumber;   void (*dispatchFunction) (Parcel &p, struct RequestInfo *pRI);   int(*responseFunction) (Parcel &p, void *response, size_t responselen); } CommandInfo;

static CommandInfo s_commands[] = {   #include "ril_commands.h" };

 


ril_commands.h:

{RIL_REQUEST_GET_SIM_STATUS, dispatchVoid, responseSimStatus},
{RIL_REQUEST_ENTER_SIM_PIN, dispatchStrings, responseInts},
{RIL_REQUEST_ENTER_SIM_PUK, dispatchStrings, responseInts},
{RIL_REQUEST_ENTER_SIM_PIN2, dispatchStrings, responseInts},
{RIL_REQUEST_ENTER_SIM_PUK2, dispatchStrings, responseInts},
……

 

调用其处理函数:RequestInfo-> CommandInfo ->dispatchFunction(p, pRI);

  dispatchFunction函数中调用s_callbacks中的请求处理函数onRequest
  s_callbacks就是在rild的main函数中RIL_Init初始化(reference-ril.c),是所返回的接口,注册到EventLoop(Ril.cpp)中.
  static const RIL_RadioFunctions s_callbacks = {
    onRequest,
    ……
  };

dispatchFunction——>onRequest:将客户端请求派发给reference-ril处理。

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM