目录

1.简介

1.1模块组成

1.2系统框架图

1.3代码结构图

2.RILD框架设计

3.RILD源码分析

3.1RILD进程入口函数分析

3.2启动事件循环处理eventLoop工作线程

3.2.1添加事件

3.2.2触发事件

3.2.3处理事件

3.2.4超时事件查询

3.2.5可读事件查询

3.2.6事件处理

3.3RIL_Env定义

3.4RIL_RadioFunctions定义

1.onRequest

2.currentState

3.onSupports

4.onCancel

5.getVersion

3.5注册RIL_Env接口

3.6RIL_Init的主要任务:

3.6.1.打开AT模块

3.6.2.添加定时事件RIL_requestTimedCallback

3.6.3.readLoop工作线程

3.6.4.注册RIL_RadioFunctions接口

3.7.客户端连接处理

3.8.客户端通信处理

4.电话拨打流程


1.简介

在android系统中rild运行在AP上,AP上的应用通过rild发送AT指令给BP,BP接收到信息后又通过rild传送给AP。AP与BP之间有两种通信方式:

  1. Solicited Response:Ap向Bp发送请求,Bp给Ap发送回复,该类型的AT指令及其回调函数以数组的形式存放在Ril_commands.h文件中:{数组中的索引号,请求回调函数,响应回调函数}
  2. unSolicited Response:Bp主动给Ap发送事件,该类型的AT指令及其回调函数以数组的形式存放在ril_unsol_commands.h文件中:{数组中的索引号,响应回调函数,类型}

不同手机厂商使用的AT命令不完全相同,为了保密,AP与BP之间通过各厂商自己的相关动态库来通信。

1.1模块组成

RIL模块由rild守护进程、libril.so、librefrence.so三部分组成:

1.rild模块被编译为一个可执行文件,实现一个main函数作为整个ril模块的入口点。在初始化时使用dlopen打开librefrence_ril.so,从中取出并执行RIL_Init函数,得到RIL_RadioFunctions指针,通过RIL_register()函数注册到libril.so库中,其源码结构如下:

2.libril.so是共享库,主要负责同上层的通信工作,接收ril的请求,并传递给librefrence_ril.so,同时将librefrence_ril.so返回的消息送给调用进程,源码结构如下所示:

 

3.librefrence_ril.so是由各手机厂商自己实现,在rild进程运行中通过dlopen方式加载,主要负责跟modem硬件通信,转换来自libril.so的请求为AT命令,同时监听Modem的反馈信息给libril.so

Android的电话系统主要分为三个部分,java层的各种电话相关应用,java层的Phone Service,主要为上层提供API,同时与native进行通信,可以看做为电话系统的客户端,native层的电话服务进程RILD,负责为上层提供各种电话功能服务,直接与modem进行交互:

1.2系统框架图

Android电话系统设计框架图:

由于Android 开发者使用的Modem 是不一样的,各种指令格式,初始化序列都可能不一样,所以为了消除这些差别,Android 设计者将ril 做了一个抽象,使用一个虚拟电话的概念,不同modem相关的AT指令或者通信协议编译成相应的动态链接库.so文件,Rild 是具体的AT 指令合成者和应答解析者。

1.3代码结构图

Android电话系统代码结构图:

2.RILD框架设计

在android的电话系统中,在native层实现了电话服务的服务端,由RILD服务与modem的交互,在java层实现电话的客户端,本文主要介绍电话系统的服务端RILD进程,以下是RILD的设计框架图:

3.RILD源码分析

在kernel启动完成后,将启动第一个应用进程Init进程,在android之Init进程启动过程源码分析一文中对init进程的启动流程进行了详细的介绍。init进程在启动过程中将读取init.rc文件来启动一些重量级的native服务,rild进程就是通过配置在init.rc中来启动的。

service ril-daemon /system/bin/rild      class main      socket rild stream 660 root radio      socket rild-debug stream 660 radio system      user root      group radio cache inet misc audio sdcard_rw log  

3.1RILD进程入口函数分析

接下来给出的是RILD进程启动的时序图:

hardware\ril\rild\rild.c

int main(int argc, char **argv)  {      const char * rilLibPath = NULL;      char **rilArgv;      void *dlHandle;      const RIL_RadioFunctions *(*rilInit)(const struct RIL_Env *, int, char **);      const RIL_RadioFunctions *funcs;      char libPath[PROPERTY_VALUE_MAX];      unsigned char hasLibArgs = 0;      int i;    umask(S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH);    //rild启动无参数      for (i = 1; i < argc ;) {          if (0 == strcmp(argv[i], "-l") && (argc - i > 1)) {              rilLibPath = argv[i + 1];              i += 2;          } else if (0 == strcmp(argv[i], "--")) {              i++;              hasLibArgs = 1;              break;          } else {              usage(argv[0]);          }      }    if (rilLibPath == NULL) {        //通过Android属性系统读取属性"rild.libpath"的值,即lib库的存放路径          if ( 0 == property_get(LIB_PATH_PROPERTY, libPath, NULL)) {              goto done;          } else {              rilLibPath = libPath;          }    }  ##################################################################################                              判断是否为模拟器  ##################################################################################  #if 1      {          static char*  arg_overrides[3];          static char   arg_device[32];          int           done = 0;  #define  REFERENCE_RIL_PATH  "/system/lib/libreference-ril.so"          /* first, read /proc/cmdline into memory */          char          buffer[1024], *p, *q;          int           len;          int           fd = open("/proc/cmdline",O_RDONLY);          if (fd < 0) {              LOGD("could not open /proc/cmdline:%s", strerror(errno));              goto OpenLib;          }          //读取/proc/cmdline文件中的内容          do {              len = read(fd,buffer,sizeof(buffer)); }          while (len == -1 && errno == EINTR);          if (len < 0) {              LOGD("could not read /proc/cmdline:%s", strerror(errno));              close(fd);              goto OpenLib;          }          close(fd);          //判断是否为模拟器,对于真机,此处条件为false          if (strstr(buffer, "android.qemud=") != NULL)          {              int  tries = 5;  #define  QEMUD_SOCKET_NAME    "qemud"              while (1) {                  int  fd;                  sleep(1);                  fd = socket_local_client(QEMUD_SOCKET_NAME,                              ANDROID_SOCKET_NAMESPACE_RESERVED,                              SOCK_STREAM );                  if (fd >= 0) {                      close(fd);                      snprintf( arg_device, sizeof(arg_device), "%s/%s",                                  ANDROID_SOCKET_DIR, QEMUD_SOCKET_NAME );                      arg_overrides[1] = "-s";                      arg_overrides[2] = arg_device;                      done = 1;                      break;                  }                  LOGD("could not connect to %s socket: %s",QEMUD_SOCKET_NAME, strerror(errno));                  if (--tries == 0)                      break;              }              if (!done) {                  LOGE("could not connect to %s socket (giving up): %s",                      QEMUD_SOCKET_NAME, strerror(errno));                  while(1)                      sleep(0x00ffffff);              }          }            /* otherwise, try to see if we passed a device name from the kernel */          if (!done) do { //true  #define  KERNEL_OPTION  "android.ril="  #define  DEV_PREFIX     "/dev/"              //判断/proc/cmdline中的内容是否包含"android.ril="              p = strstr( buffer, KERNEL_OPTION );              if (p == NULL)                  break;              p += sizeof(KERNEL_OPTION)-1;              q  = strpbrk( p, " \t\n\r" );              if (q != NULL)                  *q = 0;              snprintf( arg_device, sizeof(arg_device), DEV_PREFIX "%s", p );              arg_device[sizeof(arg_device)-1] = 0;              arg_overrides[1] = "-d";              arg_overrides[2] = arg_device;              done = 1;          } while (0);                    if (done) { //false              argv = arg_overrides;              argc = 3;              i    = 1;              hasLibArgs = 1;              rilLibPath = REFERENCE_RIL_PATH;              LOGD("overriding with %s %s", arg_overrides[1], arg_overrides[2]);          }      }  OpenLib:  #endif  ##################################################################################                              动态库装载  ##################################################################################      switchUser();//设置Rild进程的组用户为radio    //加载厂商自定义的库      ①dlHandle = dlopen(rilLibPath, RTLD_NOW);      if (dlHandle == NULL) {          fprintf(stderr, "dlopen failed: %s\n", dlerror());          exit(-1);    }    //创建客户端事件监听线程    ②RIL_startEventLoop();    //通过dlsym定位到RIL_Init函数的地址,并且强制转换为RIL_RadioFunctions的函数指针      ③rilInit = (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))dlsym(dlHandle, "RIL_Init");      if (rilInit == NULL) {          fprintf(stderr, "RIL_Init not defined or exported in %s\n", rilLibPath);          exit(-1);      }      if (hasLibArgs) { //false          rilArgv = argv + i - 1;          argc = argc -i + 1;      } else {          static char * newArgv[MAX_LIB_ARGS];          static char args[PROPERTY_VALUE_MAX];          rilArgv = newArgv;          property_get(LIB_ARGS_PROPERTY, args, "");//通过属性系统读取"rild.libargs"属性值          argc = make_argv(args, rilArgv);      }      // Make sure there's a reasonable argv[0]    rilArgv[0] = argv[0];    //调用RIL_Init函数来初始化rild,传入参数s_rilEnv,返回RIL_RadioFunctions地址    ④funcs = rilInit(&s_rilEnv, argc, rilArgv);    //注册客户端事件处理接口RIL_RadioFunctions,并创建socket监听事件      ⑤RIL_register(funcs);  done:      while(1) {          // sleep(UINT32_MAX) seems to return immediately on bionic          sleep(0x00ffffff);      }  }  

在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库通信桥梁;

3.2启动事件循环处理eventLoop工作线程

建立多路I/O驱动机制的消息队列,用来接收上层发出的命令以及往Modem发送AT指令的工作,时整个RIL系统的核心部分。创建一个事件分发线程s_tid_dispatch,线程执行体为eventLoop。

hardware\ril\libril\Ril.cpp 

extern "C" void RIL_startEventLoop(void) {      int ret;      pthread_attr_t attr;      /* spin up eventLoop thread and wait for it to get started */      s_started = 0;      pthread_mutex_lock(&s_startupMutex);      pthread_attr_init (&attr);    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);    //创建一个工作线程eventLoop    ret = pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL);    //确保函数返回前eventLoop线程启动运行      while (s_started == 0) {          pthread_cond_wait(&s_startupCond, &s_startupMutex);      }      pthread_mutex_unlock(&s_startupMutex);      if (ret < 0) {          LOGE("Failed to create dispatch thread errno:%d", errno);          return;      }  } 

eventLoop执行时序图:

static void * eventLoop(void *param) {      int ret;      int filedes[2];      ril_event_init(); //初始化请求队列      pthread_mutex_lock(&s_startupMutex);      s_started = 1; //eventLoop线程运行标志位      pthread_cond_broadcast(&s_startupCond);    pthread_mutex_unlock(&s_startupMutex);    //创建匿名管道      ret = pipe(filedes);      if (ret < 0) {          LOGE("Error in pipe() errno:%d", errno);          return NULL;    }    //s_fdWakeupRead为管道读端    s_fdWakeupRead = filedes[0];    //s_fdWakeupWrite为管道写端    s_fdWakeupWrite = filedes[1];    //设置管道读端为O_NONBLOCK非阻塞    fcntl(s_fdWakeupRead, F_SETFL, O_NONBLOCK);    //初始化s_wakeupfd_event结构体的内容,句柄为s_fdWakeupRead,回调函数为   processWakeupCallback      ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true,processWakeupCallback, NULL);      ①rilEventAddWakeup (&s_wakeupfd_event);      // Only returns on error      ②ril_event_loop();      LOGE ("error in event_loop_base errno:%d", errno);      return NULL;  }

在rild中定义了event的概念,Rild支持两种类型的事件:

1. 定时事件:根据事件的执行时间来启动执行,通过ril_timer_add添加到time_list队列中

2. Wakeup事件:这些事件的句柄fd将加入的select IO多路复用的句柄池readFDs中,当对应的fd可读时将触发这些事件。对于处于listen端的socket,fd可读表示有个客户端连接,此时需要调用accept接受连接。

事件定义如下:

struct ril_event {      struct ril_event *next;      struct ril_event *prev;      int fd;  //文件句柄      int index; //该事件在监控表中的索引       bool persist; //如果是保持的,则不从watch_list 中删除      struct timeval timeout; //任务执行时间      ril_event_cb func; //回调事件处理函数      void *param; //回调时参数  };  

在Rild进程中的几个重要事件有

static struct ril_event s_commands_event;  ril_event_set (&s_commands_event, s_fdCommand, 1,processCommandsCallback, p_rs)    static struct ril_event s_wakeupfd_event;  ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true,processWakeupCallback, NULL)    static struct ril_event s_listen_event;  ril_event_set (&s_listen_event, s_fdListen, false,listenCallback, NULL)    static struct ril_event s_wake_timeout_event;  ril_timer_add(&(p_info->event), &myRelativeTime);
static struct ril_event s_debug_event;  ril_event_set (&s_debug_event, s_fdDebug, true,debugCallback, NULL)  

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

/事件监控队列

static struct ril_event * watch_table[MAX_FD_EVENTS];

//定时事件队列

static struct ril_event timer_list;

//处理事件队列

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

3.2.1添加事件

1.添加Wakeup 事件

static void rilEventAddWakeup(struct ril_event *ev) {      ril_event_add(ev); //向监控表watch_table添加一个s_wakeupfd_event事件      triggerEvLoop(); //向管道s_fdWakeupWrite中写入之来触发事件循环  }  
void ril_event_add(struct ril_event * ev)  {      dlog("~~~~ +ril_event_add ~~~~");      MUTEX_ACQUIRE();      for (int i = 0; i < MAX_FD_EVENTS; i++) { //遍历监控表watch_table          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); //将添加的事件对应的句柄添加到句柄池readFds中              if (ev->fd >= nfds) nfds = ev->fd+1; //修改句柄最大值              dlog("~~~~ nfds = %d ~~~~", nfds);              break;          }      }      MUTEX_RELEASE();      dlog("~~~~ -ril_event_add ~~~~");  } 

2.添加定时事件

void ril_timer_add(struct ril_event * ev, struct timeval * tv)  {      dlog("~~~~ +ril_timer_add ~~~~");      MUTEX_ACQUIRE();      struct ril_event * list;      if (tv != NULL) {          list = timer_list.next;          ev->fd = -1; // make sure fd is invalid          struct timeval now;          getNow(&now);          timeradd(&now, tv, &ev->timeout);          // keep list sorted          while (timercmp(&list->timeout, &ev->timeout, < ) && (list != &timer_list)) {              list = list->next;          }          // list now points to the first event older than ev          addToList(ev, list);      }      MUTEX_RELEASE();      dlog("~~~~ -ril_timer_add ~~~~");  }  

3.2.2触发事件

static void triggerEvLoop() {      int ret;    if (!pthread_equal(pthread_self(), s_tid_dispatch)) { //如果当前线程ID不等于事件分发线程eventLoop的线程ID        do {              ret = write (s_fdWakeupWrite, " ", 1); //向管道写端写入值1来触发eventLoop事件循环           } while (ret < 0 && errno == EINTR);      }  }  

3.2.3处理事件

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();      }  }  

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

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

3.2.4超时事件查询

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 ~~~~");  } 

3.2.5可读事件查询

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.2.6事件处理

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 ~~~~");  }  

3.3RIL_Env定义

hardware\ril\include\telephony\ril.h

struct RIL_Env {      //动态库完成请求后通知处理结果的接口    void (*OnRequestComplete)(RIL_Token t, RIL_Errno e,void *response, size_t responselen);      //动态库unSolicited Response通知接口    void (*OnUnsolicitedResponse)(int unsolResponse, const void *data,size_t datalen);      //向Rild提交一个超时任务的接口      void (*RequestTimedCallback) (RIL_TimedCallback callback,void *param, const struct timeval *relativeTime);  };

hardware\ril\rild\rild.c

s_rilEnv变量定义:

static struct RIL_Env s_rilEnv = {      RIL_onRequestComplete,      RIL_onUnsolicitedResponse,      RIL_requestTimedCallback  };  

在hardware\ril\libril\ril.cpp中实现了RIL_Env的各个接口函数

1.RIL_onRequestComplete

extern "C" void RIL_onRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen) {      RequestInfo *pRI;      int ret;      size_t errorOffset;      pRI = (RequestInfo *)t;      if (!checkAndDequeueRequestInfo(pRI)) {          LOGE ("RIL_onRequestComplete: invalid RIL_Token");          return;      }      if (pRI->local > 0) {          // Locally issued command...void only!          // response does not go back up the command socket          LOGD("C[locl]< %s", requestToString(pRI->pCI->requestNumber));          goto done;      }      appendPrintBuf("[%04d]< %s",pRI->token, requestToString(pRI->pCI->requestNumber));      if (pRI->cancelled == 0) {          Parcel p;          p.writeInt32 (RESPONSE_SOLICITED);          p.writeInt32 (pRI->token);          errorOffset = p.dataPosition();          p.writeInt32 (e);          if (response != NULL) {              // there is a response payload, no matter success or not.              ret = pRI->pCI->responseFunction(p, response, responselen);              /* if an error occurred, rewind and mark it */              if (ret != 0) {                  p.setDataPosition(errorOffset);                  p.writeInt32 (ret);              }          }          if (e != RIL_E_SUCCESS) {              appendPrintBuf("%s fails by %s", printBuf, failCauseToString(e));          }          if (s_fdCommand < 0) {              LOGD ("RIL onRequestComplete: Command channel closed");          }          sendResponse(p);      }  done:      free(pRI);  }  

通过调用responseXXX将底层响应传给客户进程

2.RIL_onUnsolicitedResponse

extern "C" void RIL_onUnsolicitedResponse(int unsolResponse, void *data,                                  size_t datalen)  {      int unsolResponseIndex;      int ret;      int64_t timeReceived = 0;      bool shouldScheduleTimeout = false;      if (s_registerCalled == 0) {          // Ignore RIL_onUnsolicitedResponse before RIL_register          LOGW("RIL_onUnsolicitedResponse called before RIL_register");          return;      }      unsolResponseIndex = unsolResponse - RIL_UNSOL_RESPONSE_BASE;      if ((unsolResponseIndex < 0)          || (unsolResponseIndex >= (int32_t)NUM_ELEMS(s_unsolResponses))) {          LOGE("unsupported unsolicited response code %d", unsolResponse);          return;      }      // Grab a wake lock if needed for this reponse,      // as we exit we'll either release it immediately      // or set a timer to release it later.      switch (s_unsolResponses[unsolResponseIndex].wakeType) {          case WAKE_PARTIAL:              grabPartialWakeLock();              shouldScheduleTimeout = true;          break;          case DONT_WAKE:          default:              // No wake lock is grabed so don't set timeout              shouldScheduleTimeout = false;              break;      }      // Mark the time this was received, doing this      // after grabing the wakelock incase getting      // the elapsedRealTime might cause us to goto      // sleep.      if (unsolResponse == RIL_UNSOL_NITZ_TIME_RECEIVED) {          timeReceived = elapsedRealtime();      }      appendPrintBuf("[UNSL]< %s", requestToString(unsolResponse));      Parcel p;      p.writeInt32 (RESPONSE_UNSOLICITED);      p.writeInt32 (unsolResponse);      ret = s_unsolResponses[unsolResponseIndex].responseFunction(p, data, datalen);      if (ret != 0) {          // Problem with the response. Don't continue;          goto error_exit;      }      // some things get more payload      switch(unsolResponse) {          case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED:              p.writeInt32(s_callbacks.onStateRequest());              appendPrintBuf("%s {%s}", printBuf,                  radioStateToString(s_callbacks.onStateRequest()));          break;          case RIL_UNSOL_NITZ_TIME_RECEIVED:              // Store the time that this was received so the              // handler of this message can account for              // the time it takes to arrive and process. In              // particular the system has been known to sleep              // before this message can be processed.              p.writeInt64(timeReceived);          break;      }      ret = sendResponse(p);      if (ret != 0 && unsolResponse == RIL_UNSOL_NITZ_TIME_RECEIVED) {          // Unfortunately, NITZ time is not poll/update like everything          // else in the system. So, if the upstream client isn't connected,          // keep a copy of the last NITZ response (with receive time noted          // above) around so we can deliver it when it is connected          if (s_lastNITZTimeData != NULL) {              free (s_lastNITZTimeData);              s_lastNITZTimeData = NULL;          }          s_lastNITZTimeData = malloc(p.dataSize());          s_lastNITZTimeDataSize = p.dataSize();          memcpy(s_lastNITZTimeData, p.data(), p.dataSize());      }      // For now, we automatically go back to sleep after TIMEVAL_WAKE_TIMEOUT      // FIXME The java code should handshake here to release wake lock      if (shouldScheduleTimeout) {          // Cancel the previous request          if (s_last_wake_timeout_info != NULL) {              s_last_wake_timeout_info->userParam = (void *)1;          }          s_last_wake_timeout_info= internalRequestTimedCallback(wakeTimeoutCallback, NULL,                                              &TIMEVAL_WAKE_TIMEOUT);      }      return;  error_exit:      if (shouldScheduleTimeout) {          releaseWakeLock();      }  }  

这个函数处理modem从网络端接收到的各种事件,如网络信号变化,拨入的电话,收到短信等。然后传给客户进程。

3.RIL_requestTimedCallback

extern "C" void RIL_requestTimedCallback (RIL_TimedCallback callback, void *param,                                  const struct timeval *relativeTime) {      internalRequestTimedCallback (callback, param, relativeTime);  }  
static UserCallbackInfo *internalRequestTimedCallback (RIL_TimedCallback callback, void *param,                                  const struct timeval *relativeTime)  {      struct timeval myRelativeTime;      UserCallbackInfo *p_info;      p_info = (UserCallbackInfo *) malloc (sizeof(UserCallbackInfo));      p_info->p_callback = callback;      p_info->userParam = param;      if (relativeTime == NULL) {          /* treat null parameter as a 0 relative time */          memset (&myRelativeTime, 0, sizeof(myRelativeTime));      } else {          /* FIXME I think event_add's tv param is really const anyway */          memcpy (&myRelativeTime, relativeTime, sizeof(myRelativeTime));      }      ril_event_set(&(p_info->event), -1, false, userTimerCallback, p_info);      ril_timer_add(&(p_info->event), &myRelativeTime);      triggerEvLoop();      return p_info;  }  

3.4RIL_RadioFunctions定义

客户端向Rild发送请求的接口,由各手机厂商实现。

hardware\ril\include\telephony\Ril.h 

typedef struct {      int version; //Rild版本      RIL_RequestFunc onRequest; //AP请求接口      RIL_RadioStateRequest onStateRequest;//BP状态查询      RIL_Supports supports;      RIL_Cancel onCancel;      RIL_GetVersion getVersion;//动态库版本  } RIL_RadioFunctions;  
static const RIL_RadioFunctions s_callbacks = {      RIL_VERSION,      onRequest,      currentState,      onSupports,      onCancel,      getVersion  };  

在hardware\ril\reference-ril\reference-ril.c中实现了RIL_RadioFunctions的各个接口函数

1.onRequest

static void onRequest (int request, void *data, size_t datalen, RIL_Token t)  {      ATResponse *p_response;      int err;      LOGD("onRequest: %s", requestToString(request));      /* Ignore all requests except RIL_REQUEST_GET_SIM_STATUS      * when RADIO_STATE_UNAVAILABLE.      */      if (sState == RADIO_STATE_UNAVAILABLE          && request != RIL_REQUEST_GET_SIM_STATUS      ) {          RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);          return;      }      /* Ignore all non-power requests when RADIO_STATE_OFF      * (except RIL_REQUEST_GET_SIM_STATUS)      */      if (sState == RADIO_STATE_OFF&& !(request == RIL_REQUEST_RADIO_POWER              || request == RIL_REQUEST_GET_SIM_STATUS)      ) {          RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);          return;      }      switch (request) {          case RIL_REQUEST_GET_SIM_STATUS: {              RIL_CardStatus *p_card_status;              char *p_buffer;              int buffer_size;              int result = getCardStatus(&p_card_status);              if (result == RIL_E_SUCCESS) {                  p_buffer = (char *)p_card_status;                  buffer_size = sizeof(*p_card_status);              } else {                  p_buffer = NULL;                  buffer_size = 0;              }              RIL_onRequestComplete(t, result, p_buffer, buffer_size);              freeCardStatus(p_card_status);              break;          }          case RIL_REQUEST_GET_CURRENT_CALLS:              requestGetCurrentCalls(data, datalen, t);              break;          case RIL_REQUEST_DIAL:              requestDial(data, datalen, t);              break;          case RIL_REQUEST_HANGUP:              requestHangup(data, datalen, t);              break;          case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND:              // 3GPP 22.030 6.5.5              // "Releases all held calls or sets User Determined User Busy              //  (UDUB) for a waiting call."              at_send_command("AT+CHLD=0", NULL);              /* success or failure is ignored by the upper layer here.                it will call GET_CURRENT_CALLS and determine success that way */              RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);              break;          case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND:              // 3GPP 22.030 6.5.5              // "Releases all active calls (if any exist) and accepts              //  the other (held or waiting) call."              at_send_command("AT+CHLD=1", NULL);              /* success or failure is ignored by the upper layer here.                it will call GET_CURRENT_CALLS and determine success that way */              RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);              break;          case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE:              // 3GPP 22.030 6.5.5              // "Places all active calls (if any exist) on hold and accepts              //  the other (held or waiting) call."              at_send_command("AT+CHLD=2", NULL);    #ifdef WORKAROUND_ERRONEOUS_ANSWER              s_expectAnswer = 1;  #endif /* WORKAROUND_ERRONEOUS_ANSWER */              /* success or failure is ignored by the upper layer here.                it will call GET_CURRENT_CALLS and determine success that way */              RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);              break;          case RIL_REQUEST_ANSWER:              at_send_command("ATA", NULL);  #ifdef WORKAROUND_ERRONEOUS_ANSWER              s_expectAnswer = 1;  #endif /* WORKAROUND_ERRONEOUS_ANSWER */              /* success or failure is ignored by the upper layer here.                it will call GET_CURRENT_CALLS and determine success that way */              RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);              break;          case RIL_REQUEST_CONFERENCE:              // 3GPP 22.030 6.5.5              // "Adds a held call to the conversation"              at_send_command("AT+CHLD=3", NULL);              /* success or failure is ignored by the upper layer here.                it will call GET_CURRENT_CALLS and determine success that way */              RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);              break;          case RIL_REQUEST_UDUB:              /* user determined user busy */              /* sometimes used: ATH */              at_send_command("ATH", NULL);              /* success or failure is ignored by the upper layer here.                it will call GET_CURRENT_CALLS and determine success that way */              RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);              break;          case RIL_REQUEST_SEPARATE_CONNECTION:              {                  char  cmd[12];                  int   party = ((int*)data)[0];                  // Make sure that party is in a valid range.                  // (Note: The Telephony middle layer imposes a range of 1 to 7.                  // It's sufficient for us to just make sure it's single digit.)                  if (party > 0 && party < 10) {                      sprintf(cmd, "AT+CHLD=2%d", party);                      at_send_command(cmd, NULL);                      RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);                  } else {                      RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);                  }              }              break;          case RIL_REQUEST_SIGNAL_STRENGTH:              requestSignalStrength(data, datalen, t);              break;          case RIL_REQUEST_REGISTRATION_STATE:          case RIL_REQUEST_GPRS_REGISTRATION_STATE:              requestRegistrationState(request, data, datalen, t);              break;          case RIL_REQUEST_OPERATOR:              requestOperator(data, datalen, t);              break;          case RIL_REQUEST_RADIO_POWER:              requestRadioPower(data, datalen, t);              break;          case RIL_REQUEST_DTMF: {              char c = ((char *)data)[0];              char *cmd;              asprintf(&cmd, "AT+VTS=%c", (int)c);              at_send_command(cmd, NULL);              free(cmd);              RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);              break;          }          case RIL_REQUEST_SEND_SMS:              requestSendSMS(data, datalen, t);              break;          case RIL_REQUEST_SETUP_DATA_CALL:              requestSetupDataCall(data, datalen, t);              break;          case RIL_REQUEST_SMS_ACKNOWLEDGE:              requestSMSAcknowledge(data, datalen, t);              break;          case RIL_REQUEST_GET_IMSI:              p_response = NULL;              err = at_send_command_numeric("AT+CIMI", &p_response);              if (err < 0 || p_response->success == 0) {                  RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);              } else {                  RIL_onRequestComplete(t, RIL_E_SUCCESS,                      p_response->p_intermediates->line, sizeof(char *));              }              at_response_free(p_response);              break;          case RIL_REQUEST_GET_IMEI:              p_response = NULL;              err = at_send_command_numeric("AT+CGSN", &p_response);                if (err < 0 || p_response->success == 0) {                  RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);              } else {                  RIL_onRequestComplete(t, RIL_E_SUCCESS,                      p_response->p_intermediates->line, sizeof(char *));              }              at_response_free(p_response);              break;          case RIL_REQUEST_SIM_IO:              requestSIM_IO(data,datalen,t);              break;          case RIL_REQUEST_SEND_USSD:              requestSendUSSD(data, datalen, t);              break;          case RIL_REQUEST_CANCEL_USSD:              p_response = NULL;              err = at_send_command_numeric("AT+CUSD=2", &p_response);              if (err < 0 || p_response->success == 0) {                  RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);              } else {                  RIL_onRequestComplete(t, RIL_E_SUCCESS,                      p_response->p_intermediates->line, sizeof(char *));              }              at_response_free(p_response);              break;          case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC:              at_send_command("AT+COPS=0", NULL);              break;          case RIL_REQUEST_DATA_CALL_LIST:              requestDataCallList(data, datalen, t);              break;          case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE:              requestQueryNetworkSelectionMode(data, datalen, t);              break;          case RIL_REQUEST_OEM_HOOK_RAW:              // echo back data              RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);              break;          case RIL_REQUEST_OEM_HOOK_STRINGS: {              int i;              const char ** cur;              LOGD("got OEM_HOOK_STRINGS: 0x%8p %lu", data, (long)datalen);              for (i = (datalen / sizeof (char *)), cur = (const char **)data ;                      i > 0 ; cur++, i --) {                  LOGD("> '%s'", *cur);              }              // echo back strings              RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);              break;          }          case RIL_REQUEST_WRITE_SMS_TO_SIM:              requestWriteSmsToSim(data, datalen, t);              break;          case RIL_REQUEST_DELETE_SMS_ON_SIM: {              char * cmd;              p_response = NULL;              asprintf(&cmd, "AT+CMGD=%d", ((int *)data)[0]);              err = at_send_command(cmd, &p_response);              free(cmd);              if (err < 0 || p_response->success == 0) {                  RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);              } else {                  RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);              }              at_response_free(p_response);              break;          }          case RIL_REQUEST_ENTER_SIM_PIN:          case RIL_REQUEST_ENTER_SIM_PUK:          case RIL_REQUEST_ENTER_SIM_PIN2:          case RIL_REQUEST_ENTER_SIM_PUK2:          case RIL_REQUEST_CHANGE_SIM_PIN:          case RIL_REQUEST_CHANGE_SIM_PIN2:              requestEnterSimPin(data, datalen, t);              break;          case RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION:              requestSmsBroadcastActivation(0,data, datalen, t);              break;          case RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG:               LOGD("onRequest RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG");              requestSetSmsBroadcastConfig(0,data, datalen, t);              break;          case RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG:              requestGetSmsBroadcastConfig(0,data, datalen, t);              break;          default:              RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);              break;      }  }  

对每一个RIL_REQUEST_XXX请求转化成相应的ATcommand,发送给modem,然后睡眠等待,当收到ATcommand的最终响应后,线程被唤醒,将响应传给客户端进程。

2.currentState

static RIL_RadioState currentState()  {      return sState;  } 

3.onSupports

static int onSupports (int requestCode)  {      //@@@ todo      return 1;  }  

4.onCancel

static void onCancel (RIL_Token t)  {      //@@@todo  }  

5.getVersion

static const char * getVersion(void)  {      return "android reference-ril 1.0";  }  

3.5注册RIL_Env接口

由于各手机厂商的AT指令差异,因此与modem交互层需要各手机厂商实现,以动态库的形式提供。作为介于modem与上层的中间层,即要与底层交互也要与上层通信,因此就需要定义一个接口来衔接RILD与动态库,RIL_Env和RIL_RadioFunctions接口就是libril.so与librefrence.so通信的桥梁。是Rild架构中用于隔离通用代码和厂商代码的接口,RIL_Env由通用代码实现,而RIL_RadioFunctions则是由厂商代码实现。

 

3.6RIL_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;

hardware\ril\reference-ril\reference-ril.c

const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv)  {      int ret;      int fd = -1;      int opt;      pthread_attr_t attr;    s_rilenv = env; //将ril.cpp中定义的RIL_Env注册到reference-ril.c中的s_rilenv      while ( -1 != (opt = getopt(argc, argv, "p:d:s:"))) {          switch (opt) {              case 'p':                  s_port = atoi(optarg);                  if (s_port == 0) {                      usage(argv[0]);                      return NULL;                  }                  LOGI("Opening loopback port %d\n", s_port);              break;              case 'd':                  s_device_path = optarg;                  LOGI("Opening tty device %s\n", s_device_path);              break;              case 's':                  s_device_path   = optarg;                  s_device_socket = 1;                  LOGI("Opening socket %s\n", s_device_path);              break;              default:                  usage(argv[0]);                  return NULL;          }      }      if (s_port < 0 && s_device_path == NULL) {          usage(argv[0]);          return NULL;      }      pthread_attr_init (&attr);    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);    //创建一个mainLoop线程    ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);    //将reference-ril.c中定义的RIL_RadioFunctions返回并注册到ril.cpp中的s_callbacks      return &s_callbacks;  }  

mainLoop工作线程是用来初始化并监控AT模块的,一旦AT模块被关闭,就自动打开。

static void * mainLoop(void *param)  {      int fd;      int ret;    AT_DUMP("== ", "entering mainLoop()", -1 );    //为AT模块设置回调函数      at_set_on_reader_closed(onATReaderClosed);      at_set_on_timeout(onATTimeout);      for (;;) {          fd = -1;          while  (fd < 0) { //获得串口AT模块的设备文件描述符              if (s_port > 0) {                  fd = socket_loopback_client(s_port, SOCK_STREAM);              } else if (s_device_socket) {                  if (!strcmp(s_device_path, "/dev/socket/qemud")) {                      /* Qemu-specific control socket */                      fd = socket_local_client( "qemud",                   ANDROID_SOCKET_NAMESPACE_RESERVED,SOCK_STREAM );                      if (fd >= 0 ) {                          char  answer[2];                          if ( write(fd, "gsm", 3) != 3 ||read(fd, answer, 2) != 2 ||                               memcmp(answer, "OK", 2) != 0)                          {                              close(fd);                              fd = -1;                          }                     }                  }                  else                      fd = socket_local_client( s_device_path,    ANDROID_SOCKET_NAMESPACE_FILESYSTEM,SOCK_STREAM );              } else if (s_device_path != NULL) {                  fd = open (s_device_path, O_RDWR);                  if ( fd >= 0 && !memcmp( s_device_path, "/dev/ttyS", 9 ) ) {                      /* disable echo on serial ports */                      struct termios  ios;                      tcgetattr( fd, &ios );                      ios.c_lflag = 0;  /* disable ECHO, ICANON, etc... */                      tcsetattr( fd, TCSANOW, &ios );                  }              }              if (fd < 0) {                  perror ("opening AT interface. retrying...");                  sleep(10);              }          }          s_closed = 0;          //打开AT模块,创建AT读取线程s_tid_reader,fd为modem设备文件句柄          ret = at_open(fd, onUnsolicited);          if (ret < 0) {              LOGE ("AT error %d on at_open\n", ret);              return 0;          }          //向Rild提交超时任务          RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);          sleep(1);          //如果AT模块被关闭,则waitForClose返回,重新打开AT,如果AT已打开,则阻塞          waitForClose();          LOGI("Re-opening after close");      }  }  

3.6.1.打开AT模块

通过at_open打开文件描述符为fd的AT串口设备,并注册回调函数ATUnsolHandler 

int at_open(int fd, ATUnsolHandler h)  {      int ret;      pthread_t tid;      pthread_attr_t attr;      s_fd = fd;      s_unsolHandler = h;      s_readerClosed = 0;      s_responsePrefix = NULL;      s_smsPDU = NULL;      sp_response = NULL;      /* Android power control ioctl */  #ifdef HAVE_ANDROID_OS  #ifdef OMAP_CSMI_POWER_CONTROL      ret = ioctl(fd, OMAP_CSMI_TTY_ENABLE_ACK);      if(ret == 0) {          int ack_count;          int read_count;          int old_flags;          char sync_buf[256];          old_flags = fcntl(fd, F_GETFL, 0);          fcntl(fd, F_SETFL, old_flags | O_NONBLOCK);          do {              ioctl(fd, OMAP_CSMI_TTY_READ_UNACKED, &ack_count);              read_count = 0;              do {                  ret = read(fd, sync_buf, sizeof(sync_buf));                  if(ret > 0)                      read_count += ret;              } while(ret > 0 || (ret < 0 && errno == EINTR));              ioctl(fd, OMAP_CSMI_TTY_ACK, &ack_count);           } while(ack_count > 0 || read_count > 0);          fcntl(fd, F_SETFL, old_flags);          s_readCount = 0;          s_ackPowerIoctl = 1;      }      else          s_ackPowerIoctl = 0;  #else // OMAP_CSMI_POWER_CONTROL          s_ackPowerIoctl = 0;  #endif // OMAP_CSMI_POWER_CONTROL  #endif /*HAVE_ANDROID_OS*/      pthread_attr_init (&attr);    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);    //创建readerLoop工作线程,该线程用于从串口读取数据      ret = pthread_create(&s_tid_reader, &attr, readerLoop, &attr);      if (ret < 0) {          perror ("pthread_create");          return -1;      }      return 0;  }  

3.6.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.6.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;  }  

3.6.4.注册RIL_RadioFunctions接口

hardware\ril\libril\ril.cpp

extern "C" void RIL_register (const RIL_RadioFunctions *callbacks) {      int ret;    int flags;    //版本验证      if (callbacks == NULL || ((callbacks->version != RIL_VERSION)&& (callbacks->version < 2))) {           return;      }      if (callbacks->version < RIL_VERSION) {          LOGE ("RIL_register: upgrade RIL to version %d current version=%d",                RIL_VERSION, callbacks->version);      }      if (s_registerCalled > 0) {          LOGE("RIL_register has been called more than once. "Subsequent call ignored");          return;    }      //将reference-ril.c中定义的RIL_RadioFunctions注册到ril.cpp中      memcpy(&s_callbacks, callbacks, sizeof (RIL_RadioFunctions));      s_registerCalled = 1;      for (int i = 0; i < (int)NUM_ELEMS(s_commands); i++) {          assert(i == s_commands[i].requestNumber); //序号验证      }      for (int i = 0; i < (int)NUM_ELEMS(s_unsolResponses); i++) {          assert(i + RIL_UNSOL_RESPONSE_BASE== s_unsolResponses[i].requestNumber);      }      // old standalone impl wants it here.      if (s_started == 0) {          RIL_startEventLoop();      }    // 得到名为rild的socket句柄    s_fdListen = android_get_control_socket(SOCKET_NAME_RIL);      if (s_fdListen < 0) {          LOGE("Failed to get socket '" SOCKET_NAME_RIL "'");          exit(-1);    }    // 监听该socket      ret = listen(s_fdListen, 4);      if (ret < 0) {          LOGE("Failed to listen on control socket '%d': %s",s_fdListen, strerror(errno));          exit(-1);      }      /* 设置s_listen_event事件,一旦有客户端连接,即s_fdListen可读就会导致eventLoop工作线程中的select返回,因为该事件不是持久的,因此调用为listenCallback处理完后,将从watch_table移除该事件,所以Rild只支持一个客户端连接*/    ril_event_set (&s_listen_event, s_fdListen, false,listenCallback, NULL);      /* 添加s_listen_event事件,并触发eventLoop工作线程 */      rilEventAddWakeup (&s_listen_event);  #if 1      // 得到调试socket的句柄rild-debug      s_fdDebug = android_get_control_socket(SOCKET_NAME_RIL_DEBUG);      if (s_fdDebug < 0) {          LOGE("Failed to get socket '" SOCKET_NAME_RIL_DEBUG "' errno:%d", errno);          exit(-1);    }    //监听该socket      ret = listen(s_fdDebug, 4);      if (ret < 0) {          LOGE("Failed to listen on ril debug socket '%d': %s",s_fdDebug, strerror(errno));          exit(-1);    }      /* 设置s_debug_event事件 */      ril_event_set (&s_debug_event, s_fdDebug, true,debugCallback, NULL);      /* 添加s_debug_event事件,并触发eventLoop工作线程  */      rilEventAddWakeup (&s_debug_event);  #endif  }  

打开监听端口,接收来自客户端进程的命令请求,当与客户进程连接建立时调用listenCallback函数,创建单独线程监视并处理所有事件源。

3.7.客户端连接处理

s_listen_event事件用于处理上层客户端的socket连接,当得到socket连接请求时,eventLoop工作线程里的select返回并自动调用listenCallback回调函数进行处理:

static void listenCallback (int fd, short flags, void *param) {      int ret;      int err;      int is_phone_socket;      RecordStream *p_rs;      commthread_data_t *user_data = NULL;      user_data =(commthread_data_t *)malloc(sizeof(commthread_data_t));      struct sockaddr_un peeraddr;      socklen_t socklen = sizeof (peeraddr);      struct ucred creds;      socklen_t szCreds = sizeof(creds);      struct passwd *pwd = NULL;      assert (s_fdCommand < 0);    assert (fd == s_fdListen);    //接收一个客户端的连接,并将该socket连接保存在变量s_fdCommand中      s_fdCommand = accept(s_fdListen, (sockaddr *) &peeraddr, &socklen);      if (s_fdCommand < 0 ) {          LOGE("Error on accept() errno:%d", errno);          /* start listening for new connections again */          rilEventAddWakeup(&s_listen_event);            return;      }      /* 对客户端权限判断,判断是否是进程组ID为radio的进程发起的连接*/      errno = 0;      is_phone_socket = 0;      err = getsockopt(s_fdCommand, SOL_SOCKET, SO_PEERCRED, &creds, &szCreds);      if (err == 0 && szCreds > 0) {          errno = 0;          pwd = getpwuid(creds.uid);          if (pwd != NULL) {              if (strcmp(pwd->pw_name, PHONE_PROCESS) == 0) {                  is_phone_socket = 1;              } else {                  LOGE("RILD can't accept socket from process %s", pwd->pw_name);              }          } else {              LOGE("Error on getpwuid() errno: %d", errno);          }      } else {          LOGD("Error on getsockopt() errno: %d", errno);      }            if ( !is_phone_socket ) {        LOGE("RILD must accept socket from %s", PHONE_PROCESS);        close(s_fdCommand);        s_fdCommand = -1;        onCommandsSocketClosed();        /* start listening for new connections again */        rilEventAddWakeup(&s_listen_event);        return;      }  #if 0      if(s_dualSimMode) {          if(s_sim_num == 0) {              property_get(SIM_POWER_PROPERTY, prop, "0");              if(!strcmp(prop, "0")) {                  property_set(SIM_POWER_PROPERTY, "1");                  s_callbacks.powerSIM(NULL);              }          } else if(s_sim_num == 1) {              property_get(SIM_POWER_PROPERTY1, prop, "0");              if(!strcmp(prop, "0")) {                  property_set(SIM_POWER_PROPERTY1, "1");                  s_callbacks.powerSIM(NULL);              }          }      } else {          property_get(SIM_POWER_PROPERTY, prop, "0");          if(!strcmp(prop, "0")) {              property_set(SIM_POWER_PROPERTY, "1");              s_callbacks.powerSIM(NULL);          }      }  #endif      //p_rs为RecordStream类型,它内部会分配一个缓冲区来存储客户端发送过来的数据    p_rs = record_stream_new(s_fdCommand, MAX_COMMAND_BYTES);    //添加一个针对接收到的客户端连接的处理事件,从而在eventLoop工作线程中处理该客户端的各种请求      ril_event_set (&s_commands_event, s_fdCommand, 1,processCommandsCallback, p_rs);      rilEventAddWakeup (&s_commands_event);      onNewCommandConnect();  }  

3.8.客户端通信处理

在listenCallback中首先接收客户端的连接请求,并验证客户端的权限,同时将该客户端以事件的形式添加到eventLoop工作线程中进行监控,当该客户端有数据请求时,eventLoop工作线程从select中返回,并自动调用processCommandsCallback回调函数:

static void processCommandsCallback(int fd, short flags, void *param) {      RecordStream *p_rs;      void *p_record;      size_t recordlen;      int ret;      assert(fd == s_fdCommand);      p_rs = (RecordStream *)param;    for (;;) { //循环处理客户端发送过来的AT命令        //读取一条AT命令          ret = record_stream_get_next(p_rs, &p_record, &recordlen);          if (ret == 0 && p_record == NULL) {              break;          } else if (ret < 0) {              break;          } else if (ret == 0) { /* && p_record != NULL */              //处理客户端发送过来的AT命令              processCommandBuffer(p_record, recordlen);          }      }      if (ret == 0 || !(errno == EAGAIN || errno == EINTR)) {          if (ret != 0) {              LOGE("error on reading command socket errno:%d\n", errno);          } else {              LOGW("EOS.  Closing command socket.");          }          close(s_fdCommand);          s_fdCommand = -1;          ril_event_del(&s_commands_event);          record_stream_free(p_rs);          rilEventAddWakeup(&s_listen_event);          onCommandsSocketClosed();      }  }  

通过processCommandBuffer函数来处理每一条AT命令:

static int processCommandBuffer(void *buffer, size_t buflen) {      Parcel p;      status_t status;      int32_t request;      int32_t token;      RequestInfo *pRI;      int ret;      p.setData((uint8_t *) buffer, buflen);      // status checked at end      status = p.readInt32(&request);      status = p.readInt32 (&token);      if (status != NO_ERROR) {          LOGE("invalid request block");          return 0;      }      if (request < 1 || request >= (int32_t)NUM_ELEMS(s_commands)) {          LOGE("unsupported request code %d token %d", request, token);          return 0;      }      pRI = (RequestInfo *)calloc(1, sizeof(RequestInfo));      pRI->token = token; //AT命令标号      pRI->pCI = &(s_commands[request]); //根据request找到s_commands命令数组中的指定AT命令      ret = pthread_mutex_lock(&s_pendingRequestsMutex);      assert (ret == 0);      pRI->p_next = s_pendingRequests;      s_pendingRequests = pRI;      ret = pthread_mutex_unlock(&s_pendingRequestsMutex);    assert (ret == 0);    //调用指定AT命令的dispatch函数,根据接收来自客户进程的命令和参数,调用onRequest进行处理。      pRI->pCI->dispatchFunction(p, pRI);      return 0;  }  

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

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

4.电话拨打流程

static void dispatchDial (Parcel &p, RequestInfo *pRI) {    RIL_Dial dial; //RIL_Dial存储了打电话的所有信息      RIL_UUS_Info uusInfo;       int32_t sizeOfDial;      int32_t t;      .................. //初始化dial变量      s_callbacks.onRequest(pRI->pCI->requestNumber, &dial, sizeOfDial, pRI);    .................      return;  }  

s_callbacks.onRequest其实就是调用RIL_RadioFunctions中的onRequest函数,该函数在前面已介绍过了。

static void onRequest (int request, void *data, size_t datalen, RIL_Token t)  {      switch (request) {          case RIL_REQUEST_DIAL:              requestDial(data, datalen, t);              break;      }  }
static void requestDial(void *data, size_t datalen, RIL_Token t)  {      RIL_Dial *p_dial;      char *cmd;      const char *clir;      int ret;      p_dial = (RIL_Dial *)data;      switch (p_dial->clir) {          case 1: clir = "I"; break;  /*invocation*/          case 2: clir = "i"; break;  /*suppression*/          default:          case 0: clir = ""; break;   /*subscription default*/    }    //向串口发送AT指令      ret = at_send_command(cmd, NULL);    free(cmd);    //通知请求结果      RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);  }  

向AT发送完拨号指令后,通过RIL_onRequestComplete返回处理结果,RIL_onRequestComplete实际上是RIL_Env中的OnRequestComplete函数,在前面我们也介绍过了

extern "C" void RIL_onRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen) {      RequestInfo *pRI;      int ret;      size_t errorOffset;    pRI = (RequestInfo *)t;    //该请求已经处理,需要从请求队列中移除该请求      if (!checkAndDequeueRequestInfo(pRI)) {          LOGE ("RIL_onRequestComplete: invalid RIL_Token");          return;      }      if (pRI->local > 0) {          ...........          sendResponse(p);      }  done:      free(pRI);  }  
static int sendResponse (Parcel &p) {      return sendResponseRaw(p.data(), p.dataSize()); //将结果发送给JAVA RIL客户端  }  
static int sendResponseRaw (const void *data, size_t dataSize) {      int fd = s_fdCommand;      int ret;      uint32_t header;      if (s_fdCommand < 0) {          return -1;      }      if (dataSize > MAX_COMMAND_BYTES) {          return -1;      }      pthread_mutex_lock(&s_writeMutex);      header = htonl(dataSize);      ret = blockingWrite(fd, (void *)&header, sizeof(header));      if (ret < 0) {          pthread_mutex_unlock(&s_writeMutex);          return ret;      }      ret = blockingWrite(fd, data, dataSize);      if (ret < 0) {          pthread_mutex_unlock(&s_writeMutex);          return ret;      }      pthread_mutex_unlock(&s_writeMutex);      return 0;  } 

拨打电话的时序图如下:

Rild通过onRequest向动态库提交一个请求,然后返回,动态库处理完请求后,处理结果通过回调接口通知客户端

更多相关文章

  1. SpringBoot 2.0 中 HikariCP 数据库连接池原理解析
  2. android自定义控件宽高的获取
  3. Android(安卓)| 如何给Fragment里的button添加监听事件
  4. runOnUiThread()方法
  5. Android(安卓)SurfaceView 双缓冲机制
  6. 异常:ava.lang. NoClassDefFoundError: android .os.AsyncTask
  7. 自定义ViewGroup实现瀑布流效果
  8. Android(安卓)7.0 ActivityManagerService(1) AMS的启动过程
  9. android input 命令总结

随机推荐

  1. mysql5.7.19 安装配置方法图文教程(win10
  2. mysql5.7.19 winx64解压缩版安装配置教程
  3. MySql安装与卸载的详细教程
  4. mysql连接查询(左连接,右连接,内连接)
  5. centos6.4下mysql5.7.18安装配置方法图文
  6. MYSQL日志与备份还原问题详解
  7. 详解MySQL实现主从复制过程
  8. MySQL5.7.18下载和安装过程图文详解
  9. Mysql 5.7.18 利用MySQL proxies_priv实
  10. MySql中使用正则表达式查询的方法