目录

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向动态库提交一个请求,然后返回,动态库处理完请求后,处理结果通过回调接口通知客户端

Android 电话系统框架介绍相关推荐

  1. android驱动框架介绍

    android驱动框架介绍 了解android驱动框架: 1.方法1--jni调用底层驱动 在android框架中写入c/c++直接调用底层linux驱动,并向上提供jni接口给应用程序: 优点:简单 ...

  2. Android Sendor框架介绍

    1    Sensors介绍 1.1      Android Sensors 简介 每一部搭载Android智能操作系统的设备都具有一系列传感器,用于测量运动,方向,和各种环境条件.如果你想要监测装 ...

  3. android多媒体框架介绍(五)显示图形系统之SurfaceFlinger初步介绍

    前面介绍了比较直观的framebuffer模块(负责把有一个内存地址ADDR的内容显示到屏上),hwc模块(叠加器,负责把surfaceFlinger送来的各种输入layer叠加到显存上),接下来开始 ...

  4. Android单元测试框架介绍 -- 调研篇

    查阅了关于Android单元测试的一些资料后,发现网上对于现有的单元测试框架说法褒贬不一,各有优缺点,在框架的选择上也是需要很多因素来决定,因此我总结了一下最近的调研,对现有的单元测试框架做下简单介绍 ...

  5. android多媒体框架介绍(四)显示图形系统之hwc叠加器

    前面我们讲解了整个android图形显示系统的主要模块关系,和framebuffer,接下来我们讲解hwc叠加模块. Android7.0提供了HWC和HWC2两个版本,到了Android8.0就都默 ...

  6. 【android-tips】SurfaceView的制作android游戏框架介绍

    (转载请注明出处:http://blog.csdn.net/buptgshengod) 1.介绍 我们知道android游戏主要包含两方面.一方面是控制类,这个通过一些循环以及监听机制来实现.另一方面 ...

  7. RK3568平台开发系列讲解(安卓篇)Android Telephony框架介绍

  8. android系统框架()

    Android系统框架介绍:   1.大体框架: -src目录: 主要是完成java代码的编写 -assets目录: 资源目录 -res目录: 存储图片,布局文件和字符串,菜单等文件 -bin目录: ...

  9. Android开源框架PowerfulViewLibrary——PowerfulEditText的介绍和源码解析

    本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 转载请注明出处:http://blog.csdn.net/chay_chan/article/details/63685905 An ...

最新文章

  1. 互联网协议 — Segment Routing(分段路由网络)— SR-MPLS
  2. linux非root用户搭建docker,Linux CentOS 7 非root用户安装源码版Docker
  3. Java ObjectInputStream readLong()方法(带示例)
  4. pyspider all 启动失败:ValueError: Invalid configuration
  5. PHP json_encode
  6. Vue路由history模式踩坑记录:nginx配置解决404问题
  7. 如何用python制作动画_如何基于Python Matplotlib实现网格动画
  8. navigationBar模块未绑定
  9. 我的 Python3.x 的开始-2018.8.3
  10. 单片机12864c语言,51单片机+带字库液晶12864+DS1302数字时钟C源程序
  11. 系统账号自动退出时长哪里设置
  12. Scrum板与Kanban如何抉择?ecusiqoiw板与按照eqymgy
  13. 数据仓库是如何分层的?
  14. SwiftUI 人工智能教程之图像识别植物或花朵通过图片和相机
  15. 提示用户更改计算机密码,验证你的Microsoft账户 温馨提示:在个人电脑上更改微软账户密码...
  16. 基于OpenAI的Chatbot开发记录
  17. ibm服务器面板显示,IBM System x服务器前面板指示灯说明(新版)
  18. IDEA解决打开properties乱码问题
  19. 【面经】迅游、深科技(长城开发)——C++开发
  20. springboot 整合 apache camel实现企业级数据集成和处理

热门文章

  1. C语言 计算存款利息
  2. Kibana导入CVS数据
  3. VS Code 也能预览 Markdown - 一个无意中发现的小技巧
  4. 东京工业大学计算机毕业生去向,打开心扉 收获东京工业大学计算机专业offer
  5. 通过Stream流找出集合中对象中某个属性重复的值.
  6. linux下Found a swap file by the name解决
  7. 老毛桃重启计算机没反应,老毛桃怎么用
  8. 简单表单提交php教程,php教程之表单提交实例
  9. Unity3D 个人尝试经验总结
  10. 刺激前低的EEG alpha功率增强了视觉知觉,但不是视觉知觉敏感度