RILD 启动与实现过程

来源:互联网 发布:手机写作辅助软件 编辑:程序博客网 时间:2024/06/04 00:57
1.在system/core/rootdir/init.rc中ril-daemon定义
Rild是Init进程启动的一个本地服务,采用了socket通讯这种通讯手段,是具体AT指令合成者与应答解析者
RILD管理框架,AT相关的xxxril.so动态链接库,以便适应不同的modem
RILJ <--socket通信--> RILC <--AT()--> modem
#创建一个名为"ril-daemon"的进程,这个进程要执行的程序是/system/bin/rild
service ril-daemon /system/bin/rild #源码在hardware/ril/rild/rild.c, 在Android中指定该文件编译为模块rild, 仅实现一main函数作为整个ril层的入口点,负责完成初始化
   class main #指定分组为main,同一分组的服务,可以统一启动与停止
   socket rild stream 660 root radio #创建一个unix域的名为/dev/socket/rild的套接字,并传递它的文件描述符给已启动的进程.
   socket rild-debug stream 660 radio system #创建一个unix域的名为/dev/socket/rild-debug的套接字,并传递它的文件描述符给已启动的进程.
   user root
   group radio cache inet misc audio log qcom_diag
   
2. rild,libreference-ril.so,libril.so,radiooptions的关系
rild【hardware/ril/rild/rild.c ,ril层的入口点,负责完成初始化,rild的共享库中有一个为libril】
libril【hardware/ril/libril/* ,组成部分为ril.cpp,ril_event.cpp, 主要完成同上层RILJ用socket通信,将ril请求传递给libreference-ril.so,并将其反馈回传给调用进程】
libreference-ril【hardware/ril/libreference-ril/*,libreference-ril的共享库中有一个为libril. 转换libril的请求为AT命令发送给Modem,同时监控Modem的反馈信息,并传递回libril.so】
radiooptions【hardware/ril/rild/radiooptions.c, radiooptiongs通过获取启动参数,利用socket与rild通信,可供调试时配置Modem参数】


3.rild的启动的流程【hardware/ril/rild/rild.c】
........
extern void RIL_register (const RIL_RadioFunctions *callbacks);//【见详解】
........
extern void RIL_startEventLoop();
........
int main(int argc, char **argv) // 被init守护进程调用执行
{
   ........
   //开启EventLoop循环,完成RIL与RILJ层数据交互(通过Socket)
   const RIL_RadioFunctions *(*rilInit)(const struct RIL_Env *, int, char **);
   const RIL_RadioFunctions *funcs;
   ........
   rilLibPath = REFERENCE_RIL_PATH; // 连接库地址:/system/lib/libreference-ril.so
   ........
   switchUser(); // 切换UID为AID_RADIO
   dlHandle = dlopen(rilLibPath, RTLD_NOW); // 以RTLD_NOW(立即决定,返回前解除所有未决定的符号)模式打开libreference-ril.so的动态连接库文件,并返回一个句柄给调用进程
   ........
   RIL_startEventLoop(); // 开启libril.so共享库中的event机制,由于将上层传入的command内容转换为AT命令发送到modem并将回应发回上层,是由多路I/O驱动的消息循环【见详解】
   
   
   //打开动态库reference并构建ReaderLoop循环,完成RIL与Modem层数据交互(通过AT)
   //dlsym通过句柄和连接符名称获取函数名或者变量名,并强制转换为rilInit函数类型
   // 从连接库中寻找RIL_Init函数地址 
   rilInit = (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))dlsym(dlHandle, "RIL_Init"); 
   ........
   funcs = rilInit(&s_rilEnv, argc, rilArgv); //调用rilInit函数进行初始化INIT,同时得到reference-ril的回调函数【见详解RIL_Init】
   
   RLOGD("RIL_Init rilInit completed");
   
   
   // 注册reference的回调函数
   RIL_register(funcs); // 完成注册rilInit得到的回调函数funcs,并打开接收上层RILJ命令的socket通道【见详解】
   ........
}

// hardware/ril/libril/ril.cpp 框架和处理方式由ril.cpp管理,差异化的AT命令由reference实现
........
#include <telephony/ril.h>
........
static void * eventLoop(void *param) { //等待在事件端口(串口,socket),一旦有数据到达就根据登记的event回调函数进行处理,
   int ret;
   int filedes[2];

   ril_event_init();// Event的初始化,初始化ril_event.cpp中几个重要的成员变量【见详解】
   ........
   ret = pipe(filedes);//创建匿名管道
   s_fdWakeupRead = filedes[0]; //s_fdWakeupRead为管道读端
   s_fdWakeupWrite = filedes[1]; //s_fdWakeupWrite为管道写端 
   fcntl(s_fdWakeupRead, F_SETFL, O_NONBLOCK); //设置管道读端为O_NONBLOCK非阻塞 
   ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true, processWakeupCallback, NULL);//创建一个Event
   // 将上面创建的Event加入到watch_table中,这里起到唤醒LoopEvent的作用,
   rilEventAddWakeup (&s_wakeupfd_event);//向监控表watch_table添加一个s_wakeupfd_event事件,通过向管道s_fdWakeupWrite中写入来触发事件循环 

   // 加入到loop循环
   ril_event_loop(); // 建立起消息队列机制【见详解】
   RLOGE ("error in event_loop_base errno:%d", errno);
   // kill self to restart on error
   kill(0, SIGKILL);

   return NULL;
}

extern "C" void RIL_startEventLoop(void) {
   /* spin up eventLoop thread and wait for it to get started */
   s_started = 0;
   ........
   int result = pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL); // 打开Event线程,并调用eventLoop进入循环,s_tid_dispatch为事件分发线程 【见详解】
   if (result != 0) {
       RLOGE("Failed to create dispatch thread: %s", strerror(result));
       goto done;
   }

   while (s_started == 0) { // 如果回调函数eventLoop方法不执行,Ril_startEventLoop()方法就不会返回
       pthread_cond_wait(&s_startupCond, &s_startupMutex);
   }

done:
   pthread_mutex_unlock(&s_startupMutex);
}
........
extern "C" void RIL_register (const RIL_RadioFunctions *callbacks) { // 打开和上层通信的socket管道,在RILJ与EventLoop之间建立了沟通的渠道
   int ret;
   int flags;
   ........
   memcpy(&s_callbacks, callbacks, sizeof (RIL_RadioFunctions));// 将返回值传给s_callbacks

   /* Initialize socket1 parameters */
   s_ril_param_socket = {
                       RIL_SOCKET_1,             /* socket_id */
                       -1,                       /* fdListen */
                       -1,                       /* fdCommand */
                       PHONE_PROCESS,            /* processName */
                       &s_commands_event,        /* commands_event */
                       &s_listen_event,          /* listen_event */
                       processCommandsCallback,  /* processCommandsCallback */
                       NULL                      /* p_rs */
                       };
   ........
   s_registerCalled = 1;
   ........
   if (s_started == 0) {
       RIL_startEventLoop();
   }

   // 监听RIL_SOCKET_1管道
   startListen(RIL_SOCKET_1, &s_ril_param_socket);
   ........
   
   // 打开RILC与RILJ之间的Socket通道  
   s_fdDebug = android_get_control_socket(rildebug); 
   ........
   ret = listen(s_fdDebug, 4); // 监听s_fdDebug接口socket
   ril_event_set (&s_debug_event, s_fdDebug, true, debugCallback, NULL); //用这个Socket通道句柄创建一个Event    
   rilEventAddWakeup (&s_debug_event);//添加到Eventloop中 
}

// hardware/ril/libril/ril_event.h
struct ril_event {
   struct ril_event *next; // vent的管理是通过链表实现的
   struct ril_event *prev;

   int fd; // 事件相关设备句柄。最重要的就是RILJ与RILC之间的Socket文件句柄
   int index; // 该事件在监控表中的索引 
   bool persist; // 说明当前的Event需要保持,不能从watch_table中删除
   struct timeval timeout; // 任务执行时间 
   ril_event_cb func; // 当前Event的处理函数
   void *param; // 调用当前Event处理函数时的参数
};
// 初始化Event链表
void ril_event_init();

// 初始化一个Event
void ril_event_set(struct ril_event * ev, int fd, bool persist, ril_event_cb func, void * param);

// 把一个Event添加到watch_table中
void ril_event_add(struct ril_event * ev); //遍历监控表watch_table,将任务加入到空闲的索引中

// 把一个Event添加到timer_list中
void ril_timer_add(struct ril_event * ev, struct timeval * tv);

// 把一个Event从watch_table中删除
void ril_event_del(struct ril_event * ev);

// 主循环
void ril_event_loop();
        
        
// Event要做的就是循环检测EventLoop中添加的句柄池,如果在当前的句柄池中有任意一个句柄所代表的通道中有新的数据进来,就去处理当前的新数据。而在句柄池中最重要的句柄就是RILJ与RILC之间的Socket通道
// hardware/ril/libril/ril_event.cpp
........
#include <ril_event.h>
........
static fd_set readFds; // 是linux的fd_set,保存了rild中所有的设备文件句柄,以便利用select函数统一的完成事件监听
static int nfds = 0;

static struct ril_event * watch_table[MAX_FD_EVENTS]; // 监测时间队列,需要检测的事件都放入到这个队列,就是一个ril_event数据类型的列表或者数组
static struct ril_event timer_list; // 超时事件队列,在这个列表中的事件正在被监听,超时时候还没被执行则丢到pending_list里面,待执行.
static struct ril_event pending_list; // 待执行的事件集合,事件已触发,需要回调处理的事件
........
void ril_event_init() // 初始几个重要的属性,文件句柄集和3个重要链表
{
   MUTEX_INIT();

   FD_ZERO(&readFds); // 初始化ril_event
   init_list(&timer_list); // 初始化timer_list
   init_list(&pending_list);// 初始化pending_list
   memset(watch_table, 0, sizeof(watch_table));// 初始化watch_table
}
........
void ril_event_loop() // for循环接收RILJ送过来的事件,当有数据到来,select就会设置相应的标志位并返回.
{
   ........
   for (;;) {// 死循环检查Event消息
       // make local copy of read fd_set
       memcpy(&rfds, &readFds, sizeof(fd_set)); // 读取readFds的一个要监听的fd 到rfds
       ........
       printReadies(&rfds);
       // 用select去检测RILJ是否有新数据出现,ptv为空是阻塞模式,非空说明超时时间内是阻塞模式
       n = select(nfds, &rfds, NULL, NULL, ptv); // select只监测读取到的rfds, 如此在for循环中才能监听到readFds中全部的fd. 
       printReadies(&rfds);
       ........
       // 超时检测事件,如果timer_list中某个Event超时,则从timer_list中移除,并将该Event放入pending_list中
       processTimeouts();
       // 处理select返回的可读事件,检查watch_table,将Event加入pending_list中,如果persist为false才去删除当前Event
       processReadReadies(&rfds, n);
       // 处理事件及可读事件,执行pending_list中的Event,删除当前节点,执行其func并把参数传递进去
       firePending();
   }
}


4.RIL_Init()方法 hardware/ril/reference-ril/reference-ril.c
........
// RIL_onUnsolicitedResponse的定义 #define RIL_onUnsolicitedResponse(a,b,c) s_rilenv->OnUnsolicitedResponse(a,b,c)
static void onUnsolicited (const char *s, const char *sms_pdu) // 处理由modem上发的通知类的消息
{
   ........
   if (strStartsWith(s, "%CTZV:")) { //时区改变  
       ........
           RIL_onUnsolicitedResponse (RIL_UNSOL_NITZ_TIME_RECEIVED,esponse, strlen(response));
       ........
   } else if (strStartsWith(s,"+CRING:") //通话状态改变 
               || strStartsWith(s,"RING")
               || strStartsWith(s,"NO CARRIER")
               || strStartsWith(s,"+CCWA") ) {
       RIL_onUnsolicitedResponse (RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,NULL, 0);
       ........
   } else if (strStartsWith(s,"+CREG:") || strStartsWith(s,"+CGREG:") ) { //网络注册状态改变
       RIL_onUnsolicitedResponse (RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, NULL, 0);
       ........
   } else if (strStartsWith(s, "+CMT:")) { //新短信通知
       RIL_onUnsolicitedResponse (RIL_UNSOL_RESPONSE_NEW_SMS, sms_pdu, strlen(sms_pdu));
   } else if (strStartsWith(s, "+CDS:")) { //短信报告
       RIL_onUnsolicitedResponse (RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT, sms_pdu, strlen(sms_pdu));
   ........
   }
}
........
static void * mainLoop(void *param __unused) //建立起与硬件的通信,然后通过read方法阻塞
{
   ........
   at_set_on_reader_closed(onATReaderClosed); // 初始化AT通道的关闭方法
   at_set_on_timeout(onATTimeout); // 初始化AT通道的超时方法
   ........
   for (;;) {
       ........
       s_closed = 0;
       ret = at_open(fd, onUnsolicited); // 打开AT并把处理URC消息的方法onUnsolicited传进去 【见详情】
       ........
       waitForClose(); //阻塞AT通道,AT通道在检测超时后,将会主动关闭,此时会激活waitForClose中的阻塞线程,然后waitForClose将会返回,再次进入for循环
   }
}


const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv)
{
   ........
   while ( -1 != (opt = getopt(argc, argv, "p:d:s:c:"))) { // 通过参数获取硬件接口的设备文件或模拟硬件接口的socket. 
   ........
   }
   ........
   ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL); // 新开ril的一个线程,入口函数mainLoop继续初始化【见详情】

   return &s_callbacks;//把ril的回调函数返回出来
}

// hardware\ril\reference-ril\Atchannel.c
........
static ATUnsolHandler s_unsolHandler;
........
static void addIntermediate(const char *line) // 将数据放到反馈数据中
{
   ATLine *p_new;

   p_new = (ATLine  *) malloc(sizeof(ATLine));

   p_new->line = strdup(line);

   /* note: this adds to the head of the list, so the list
      will be in reverse order of lines received. the order is flipped
      again before passing on to the command issuer */
   p_new->p_next = sp_response->p_intermediates;
   sp_response->p_intermediates = p_new; // 把有效的返回值放到sp_response->p_intermediates中
}
........
static void handleFinalResponse(const char *line) // 把响应消息返回给eventloop,发送信号给线程使其脱离阻塞状态
{
   sp_response->finalResponse = strdup(line); //把回应消息返回给eventLoop  
   pthread_cond_signal(&s_commandcond); //发信号给s_commandcond线程,使其脱离阻塞状态  
}
static void handleUnsolicited(const char *line) // 处理URC消息
{
   if (s_unsolHandler != NULL) {
       s_unsolHandler(line, NULL); // s_unsolHandler来自于at_open时的参数onUnsolicited
   }
}
static void processLine(const char *line) //判断是否是URC消息并采用不同的处理方式
{
   pthread_mutex_lock(&s_commandmutex);

   if (sp_response == NULL) {//sp_response为给modem发送消息时注册的用于放置modem返回值的指针
       // modem返回值的指针为空则是URC消息
       handleUnsolicited(line);// 处理URC消息
   } else if (isFinalResponseSuccess(line)) { //判断是否已经把所有有效数据传输完毕
       // 非URC消息处理,且modem处理成功
       sp_response->success = 1;
       handleFinalResponse(line);// 发送回应消息给EventLoop,取消Event侧阻塞的线程
       ........
   } else switch (s_type) {
       case NO_RESULT:
           handleUnsolicited(line);
           break;
       case NUMERIC:
           if (sp_response->p_intermediates == NULL
               && isdigit(line[0])
           ) {
               addIntermediate(line);//非URC消息处理,把当前的数据放入到反馈数据的sp_response->p_intermediates里面【见详解】
           } else {
               /* either we already have an intermediate response or
                  the line doesn't begin with a digit */
               handleUnsolicited(line);
           }
           break;
       ........
   }

   pthread_mutex_unlock(&s_commandmutex);
}
........
static void *readerLoop(void *arg) // 不断侦测Modem上报的消息,然后根据是否是URC消息来采用不同的处理方式
{
   for (;;) { //for循环读取modem送过来的事件
       const char * line;

       line = readline();// AT命令都是以/n/r/t结束的,都是以一行为单位读取的

       if (line == NULL) {
           break;
       }

       if(isSMSUnsolicited(line)) { //如果以CMT/CDS/CBM开头则判断成立, 根据是否是URC消息来采用不同的处理方式
          ........
          if (s_unsolHandler != NULL) {
                s_unsolHandler (line1, line2);// URC消息可以直接发送给RILJ  
          }
          free(line1);
       } else {
           processLine(line); // 处理读取到的内容, 根据是否是URC消息来采用不同的处理方式
       }
   }

   onReaderClosed();//关闭read 

   return NULL;
}
........
int at_open(int fd, ATUnsolHandler h)
{
   ........
   s_unsolHandler = h; // 保存通知类消息的响应事件
   ........
   // 创建一个s_tid_reader线程,AT命令都是以/r/n或/n/r的换行符来作为分隔符的
   // 所以readerLoop是line驱动的,除非出错,否则会读到一行完整的相应或自动上报,才会返回.
   // 创建线程s_tid_reader来读取AT命令,并处理Modem发送过来的信息
   ret = pthread_create(&s_tid_reader, &attr, readerLoop, &attr); //回调readerLoop 【readerLoop见详解】

   if (ret < 0) {
       perror ("pthread_create");
       return -1;
   }

   return 0;
}
........


5.Event框架

 RIL的Event管理体系中存在3个链表结构:watch_table,timer_list,pending_list,并使用了一个设备句柄池readFDS,把所有的Socket管道的文件句柄保存起来。而管理的过程可以归纳为以下6点:
    1、可以将一个Event添加到watch_table或者timer_list中;
    2、如果Event是添加到watch_table中,需要把当前Event的fd(事件设备句柄)添加到readFDS中;
    3、如果Event是添加到timer_list中,不需要把当前Event的fd(事件设备句柄)添加到readFDS中,而且当前Event的fd值是无效的;
    4、在循环检测过程中,如果发现watch_table中有Event就会把当前Event添加到pending_list中,如果当前Event的persist属性为false,就把当前的Event从watch_table中删除;如果persist为true,就不需要从watch_table中删除当前节点。
    5、在循环检测过程中,如果发现timer_list中的Event超时时,把当前Event移动到pending_list中,同时删除timer_list中的节点。
    6、在循环检测的过程中,等watch_table和timer_list处理完毕后,就去pending_list中执行里面的Event所指向的func。


6.reference库的加载
 reference库需要完成两个任务:
    1、将eventLoop中的命令通过AT发送给Modem;
    2、构建一个readerLoop循环,接受Modem消息,并根据消息的不同(URC和非URC)将消息返回给eventLoop(非URC消息)或者直接发送给RILJ(URC消息)。


7.完整的流程

    1、Eventloop接收RILJ的请求,并负责把请求发送给reference库:Eventloop--->reference
    2、reference负责把命令转化为AT命令,然后发送给Modem:reference--->Modem
    3、reference通过readerLoop得到Modem回应后把数据返回给Eventloop:   Modem--->ReaderLoop
    4、Eventloop再把数据返回给RILJ:ReaderLoop--->Eventloop
0 0
原创粉丝点击