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处理。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值