• Android RILD运行机制详解


    前言

    在上一篇文章里(http://blog.csdn.net/jason_wzn/article/details/53232022),简要介绍了Android RIL的架构。这一篇文章,就来看一看RILD(RIL Daemon)相关的内容。Android RIL在HAL(Hardware Abstract Layer)层(C++层)由三个部分组成:

    • RILD是系统的守护进程,主要用于初始化LIBRIL以及启动厂商自定义的Vendor RIL;
    • LIBRIL被RILD初始化完成后,用于与Vendor RIL之间进行交互,负责接收、发送指令;
    • Vendor RIL是第三方厂商自定义的一个库,用于向Modem发送指令或者接收来自LIBRIL或者Modem的指令。

    三者之间的关系图如下所示:

    RILD and LIBRIL

    从这里可以看到,RILD在启动时,负责将LibRil以及Vendor RIL进行初始化,将相应的回调函数以及调用接口进行注册,LibRIL向vendor RIL提供了接口RIL_Env,当Vendor有消息时,利用该回调返回;而Vendor RIL 同样提供了接口RIL_RadioFunctions,给LibRIl调用。这里涉及到3个主要问题:

    1. RILD是如何启动?
    2. RILD是如何进行初始化操作的?
    3. 初始完成后,LIBRIL是如何进行消息的接收与发送的?

    RILD是如何启动的

    RILD(RIL Daemon)是系统的守护进程,系统已启动,就会一直运行。手机开机时,kernel完成初始化后,Android启动一个初始化进程Init用于加载系统基础服务,如文件系统,zygote进程,服务管家ServiceManager,以及RILD:

    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 log

    这里,init进程从手机文件系统目录system/bin/rild中读取RILD的可执行文件,加载到内存运行;同时,创建两个socket端口:rild和rild-debug,其中rild用于RILJ与RILD之间的数据通信,而rild-debug则用于RILJ与RILD的调试。

    RILD是如何进行初始化的

    RILD启动后,一方面会去初始化Vendor RIL,将LIBRIL的回调接口RIL_Env传递给Vendor RIL;同时将Vendor RIL的接口RIL_RadioFunctions注册到LIBRIL中,这样一旦初始化完成,LIBRIL与Vendor RIL就可以进行数据的交换了。

    来看一看RILD的代码:

     1  int main(int argc, char **argv)
     2     {
     3         ...
     4        // Vendor RIL接口函数
     5         const RIL_RadioFunctions *(*rilInit)(const struct RIL_Env *, int, char **);
     6         const RIL_RadioFunctions *funcs;
     7         ...
     8 
     9     OpenLib:
    10 
    11         //从指定路径加载RILD可执行文件
    12         dlHandle = dlopen(rilLibPath, RTLD_NOW);
    13 
    14         if (dlHandle == NULL) {
    15             RLOGE("dlopen failed: %s", dlerror());
    16             exit(EXIT_FAILURE);
    17         }
    18 
    19         // 启动LIBRIL的事件处理线程
    20         RIL_startEventLoop();
    21         // Vendor RIL初始化函数,返回一个RIL_RadioFunctions
    22         rilInit = (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))dlsym(dlHandle, "RIL_Init");
    23         ...
    24         funcs = rilInit(&s_rilEnv, argc, rilArgv);
    25         RLOGD("RIL_Init rilInit completed");
    26         // 将 RIL_RadioFunctions注册到LIBRIL中
    27         RIL_register(funcs);
    28 
    29         RLOGD("RIL_Init RIL_register completed");
    30     }

    RILD初始化主要完成两件事:(1) 加载Vendor RIL的代码,并对其进行初始化操作,将LIBRIL的接口RIL_Env传递给Vendor RIL,用于回调;(2)开始RIL事件处理线程;(3)将Vendor RIL的接口注册到LIBRIL中,这样LIBRIL就可以将消息发送给Vendor RIL了。

    下图是RILD初始化LIBRIL以及Vendor RIL的一个简化流程:

    RILD init process

    • RIL_startEventLoop()启动RIL事件处理线程:
     1   extern "C" void RIL_startEventLoop(void) {
     2         /* spin up eventLoop thread and wait for it to get started */
     3         s_started = 0;
     4         pthread_mutex_lock(&s_startupMutex);
     5         ...
     6         // eventLoop函数才是真正开始启动事件处理线程的地方
     7         int result = pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL);
     8         if (result != 0) {
     9             RLOGE("Failed to create dispatch thread: %s", strerror(result));
    10             goto done;
    11         }
    12 
    13         while (s_started == 0) {
    14             pthread_cond_wait(&s_startupCond, &s_startupMutex);
    15         }
    16 
    17     done:
    18         pthread_mutex_unlock(&s_startupMutex);
    19     }
    20 
    21     // evetLoop 
    22 
    23     static void *eventLoop(void *param) {
    24         int ret;
    25         int filedes[2];
    26         //初始化事件队列
    27         ril_event_init();
    28 
    29         pthread_mutex_lock(&s_startupMutex);
    30 
    31         s_started = 1;
    32         pthread_cond_broadcast(&s_startupCond);
    33 
    34         pthread_mutex_unlock(&s_startupMutex);
    35 
    36         ret = pipe(filedes);
    37         // 用于监听wakeup事件的pipe端口
    38         s_fdWakeupRead = filedes[0];
    39         s_fdWakeupWrite = filedes[1];
    40         //设置线程唤醒事件,唤醒时,回调processWakeupCallback函数
    41         ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true,
    42                     processWakeupCallback, NULL);
    43 
    44         rilEventAddWakeup (&s_wakeupfd_event);
    45 
    46         // 真正干活的函数
    47         ril_event_loop();
    48         // kill self to restart on error
    49         kill(0, SIGKILL);
    50 
    51         return NULL;
    52     }
    • RILD初始化vendor RIL之后,将返回的RIL_RadioFunctions返回给RILD,RILD接着将其注册到LIBRIL中:
     1     extern "C" void RIL_register (const RIL_RadioFunctions *callbacks) {
     2         ...
     3         /* Initialize socket1 parameters */
     4         s_ril_param_socket = {
     5                             RIL_SOCKET_1,             /* socket_id */
     6                             -1,                       /* fdListen */
     7                             -1,                       /* fdCommand */
     8                             PHONE_PROCESS,            /* processName */
     9                             &s_commands_event,        /* commands_event */
    10                             &s_listen_event,          /* listen_event */
    11                             processCommandsCallback,  /* processCommandsCallback */
    12                             NULL                      /* p_rs */
    13                             };
    14         ....
    15         // back compatibility
    16         if (s_started == 0) {
    17             RIL_startEventLoop();
    18         }
    19 
    20         // start listen socket1
    21         startListen(RIL_SOCKET_1, &s_ril_param_socket);
    22     }
    23 
    24     // startListen
    25     static void startListen(RIL_SOCKET_ID socket_id, SocketListenParam* socket_listen_p) {
    26         int fdListen = -1;
    27         int ret;
    28         char socket_name[10];
    29 
    30         memset(socket_name, 0, sizeof(char)*10);
    31 
    32         switch(socket_id) {
    33             case RIL_SOCKET_1:
    34                 strncpy(socket_name, RIL_getRilSocketName(), 9);
    35                 break;
    36         ....
    37         // 获取 Unix domain socket对应的FD
    38         fdListen = android_get_control_socket(socket_name);
    39         // 监听端口 
    40         ret = listen(fdListen, 4);
    41 
    42         socket_listen_p->fdListen = fdListen;
    43         // 设置监听回调事件 listenCallback,RILJ主动连接RILD时,处理该回调
    44         /* note: non-persistent so we can accept only one connection at a time */
    45         ril_event_set (socket_listen_p->listen_event, fdListen, false,
    46                     listenCallback, socket_listen_p);
    47         //添加到事件队列中,并唤醒事件处理线程
    48         rilEventAddWakeup (socket_listen_p->listen_event);
    49     }

    源代码: /hardware/ril/libril/ril.cpp

    接下来,我们就来看一看LIBRIL与Vendor RIL各自提供的接口函数。 这两个接口都在/hardware/ril/include/telephony/ril.h中进行了声明。

    Vendor RIL主要提供了5个接口,供LIBRIL调用:

    •  1 RIL_RequestFunc是最主要的一个,所有从RILJ发送过来的请求均由该接口发送给Vendor RIL;
       2 RIL_RadioStateRequest从LIBRIL获取modem的即时状态;
       3 RIL_Supports判断Vendor RIL是否支持某个请求命令;
       4 RIL_Cancel取消某个请求命令;
       5 RIL_GetVersion获取RIL的版本号;
       6 
       7     typedef struct {
       8         int version;        /* set to RIL_VERSION */
       9         RIL_RequestFunc onRequest;
      10         RIL_RadioStateRequest onStateRequest;
      11         RIL_Supports supports;
      12         RIL_Cancel onCancel;
      13         RIL_GetVersion getVersion;
      14     } RIL_RadioFunctions;
      15 
      16 
      17     // 将从RILJ发送过来的请求发送给Vendor RIL
      18     typedef void (*RIL_RequestFunc) (int request, void *data,
      19                                         size_t datalen, RIL_Token t, RIL_SOCKET_ID socket_id);
      20     // 获取 modem 状态
      21     typedef RIL_RadioState (*RIL_RadioStateRequest)(RIL_SOCKET_ID socket_id);

    LIBRIL则向Vendor RIL提供了3个接口:

    • OnRequestComplete:RIL请求完成后,通过该接口将数据返回给LIBRIL,由LIBRIL将数据写入socket RILD;
    • OnUnsolicitedResponse:CP主动上报消息给Vendor RIL后,通过该接口将消息传给LIBRIL;
    • RequestTimedCallback:在指定时间内,LIBRIL调用回调函数RequestTimedCallback
     1    struct RIL_Env {
     2         // 请求完成,返回给LIBRIL
     3         void (*OnRequestComplete)(RIL_Token t, RIL_Errno e,
     4                                void *response, size_t responselen);
     5 
     6     // Vendor RIL接收到从CP主动上报的消息后,传给LIBRIL
     7     #if defined(ANDROID_MULTI_SIM)
     8         void (*OnUnsolicitedResponse)(int unsolResponse, const void *data, size_t datalen, RIL_SOCKET_ID socket_id);
     9     #else
    10         /**
    11          * "unsolResponse" is one of RIL_UNSOL_RESPONSE_*
    12          * "data" is pointer to data defined for that RIL_UNSOL_RESPONSE_*
    13          */
    14         void (*OnUnsolicitedResponse)(int unsolResponse, const void *data, size_t datalen);
    15     #endif
    16         /**
    17          * Call user-specifed "callback" function on on the same thread that
    18          * RIL_RequestFunc is called. If "relativeTime" is specified, then it specifies
    19          * a relative time value at which the callback is invoked. If relativeTime is
    20          * NULL or points to a 0-filled structure, the callback will be invoked as
    21          * soon as possible
    22          */
    23         // 指定时间内LIBRIL调用回调函数RIL_TimedCallback
    24         void (*RequestTimedCallback) (RIL_TimedCallback callback,
    25                                        void *param, const struct timeval *relativeTime);
    26     };

    代码路径: /hardware/ril/rild/rild.c

    初始化完成了 ,那么RIL事件处理线程是从何时开始处理事件的了?RIL事件处理线程是怎么又是同时处理来自RILJ以及Vendor RIL的消息的?下面就来看一看LIBRIL如何处理RIL事件的。

    LIBRIL如何处理RIL事件

    为处理RIL事件,LIBRIL提供了3个事件队列(由双向列表组成):

        static struct ril_event * watch_table[MAX_FD_EVENTS];
        static struct ril_event timer_list;
        static struct ril_event pending_list;

    其中,watch_table用于事件的监测,timer_list保存定时事件,而pending_list用于保存即将被处理的事件列表。对LIBRIL来讲,有3种类型的RIL事件需要处理:

     // RILJ请求事件
        static struct ril_event s_commands_event;
        // 事件处理线程唤醒事件
        static struct ril_event s_wakeupfd_event;
        // RILD socket端口监听事件
        static struct ril_event s_listen_event;

    上一节我们了解到,在RIL事件处理线程开始时,LIBRIL会添加一个s_wakeupfd_event的唤醒事件,必要时对线程进行唤醒操作;在注册Vendor RIL的接口时,注册一个监听事件s_listen_event,当RILJ尝试通过socket连接RILD时,处理该事件;当RILJ与RILD连接成功后,处理回调函数listenCallback时,会添加一个 s_commands_event事件,用于处理RILD socket的数据。

    那么,LIBRIL是从何时开始处理这些事件的?上一节我们了解到,初始化时,LIBRIL启动了一个专门的线程来处理RIL事件:

     1  void ril_event_loop()
     2     {
     3         int n;
     4         fd_set rfds;
     5         struct timeval tv;
     6         struct timeval * ptv;
     7 
     8         for (;;) {
     9 
    10             // make local copy of read fd_set
    11             memcpy(&rfds, &readFds, sizeof(fd_set));
    12             ....
    13             // 从FD集合中选择可用的端口
    14             n = select(nfds, &rfds, NULL, NULL, ptv);
    15             ....
    16             // 处理timer队列中超时的事件
    17             processTimeouts();
    18             // 处理监测队列中的事件: listenCallback,
    19             processReadReadies(&rfds, n);
    20             // OK,fire pending list
    21             firePending();
    22         }
    23     }

    该线程,一直监听FD(File Descriptor)集合readFds,如果有数据时,就会立即返回,进而开始执行事件的处理:首先处理定时事件队列中的event,如果发现有超时的事件,就将其加入pending队列中;接着,查看监测表(保存了最多8个事件)中是否有readFds对应的RIL事件,如果存在,则也将其放入到pending队列。最后,就要开始处理pending队列了:

      static void firePending()
        {
            dlog("~~~~ +firePending ~~~~");
            struct ril_event * ev = pending_list.next;
            while (ev != &pending_list) {
                struct ril_event * next = ev->next;
                removeFromList(ev);
                // 执行回调函数: processWakeupCallback,listenCallback,processCommandsCallback...
                ev->func(ev->fd, 0, ev->param);
                ev = next;
            }
            dlog("~~~~ -firePending ~~~~");
        }

    源码:/android/hardware/ril/libril/samsung/ril_event.cpp

    LIBRIL事件处理线程开始时,只有两个事件:s_wakeupfd_events_listen_events_wakeupfd_event事件在添加s_listen_event事件,需要唤醒RIL事件处理线程被执行:

     static void triggerEvLoop() {
            int ret;
            if (!pthread_equal(pthread_self(), s_tid_dispatch)) {
                /* trigger event loop to wakeup. No reason to do this,
                 * if we're in the event loop thread */
                 do {
                    ret = write (s_fdWakeupWrite, " ", 1);
                 } while (ret < 0 && errno == EINTR);
            }
        }

    接着,开始执行s_listen_event事件,调用回调函数listenCallback:

     1   static void listenCallback (int fd, short flags, void *param) {
     2         ....
     3         // 接受RILJ的链接请求
     4         fdCommand = accept(fd, (sockaddr *) &peeraddr, &socklen);
     5 
     6         /* check the credential of the other side and only accept socket from
     7          * phone process
     8          */
     9         is_phone_socket = 0;
    10 
    11         err = getsockopt(fdCommand, SOL_SOCKET, SO_PEERCRED, &creds, &szCreds);
    12 
    13         ....
    14 
    15         ret = fcntl(fdCommand, F_SETFL, O_NONBLOCK);
    16         ....
    17 
    18         p_info->fdCommand = fdCommand;
    19 
    20         p_rs = record_stream_new(p_info->fdCommand, MAX_COMMAND_BYTES);
    21 
    22         p_info->p_rs = p_rs;
    23         ril_event_set (p_info->commands_event, p_info->fdCommand, 1,
    24             p_info->processCommandsCallback, p_info);
    25         // 添加指令事件`s_commands_event`
    26         rilEventAddWakeup (p_info->commands_event);
    27         // 建立新的连接,告知RILJ链接成功,并上报radio状态
    28         onNewCommandConnect(p_info->socket_id);
    29     }

    下次处理pending事件队列时,处理s_commands_event,调用回调函数processCommandsCallback

     1   static void processCommandsCallback(int fd, short flags, void *param) {
     2         // 循环读 RILD socket接口数据流
     3         for (;;) {
     4             /* loop until EAGAIN/EINTR, end of stream, or other error */
     5             // 读取 socket数据流
     6             ret = record_stream_get_next(p_rs, &p_record, &recordlen);
     7 
     8             if (ret == 0 && p_record == NULL) {
     9                 /* end-of-stream */
    10                 break;
    11             } else if (ret < 0) {
    12                 break;
    13             } else if (ret == 0) { /* && p_record != NULL */
    14                 processCommandBuffer(p_record, recordlen, p_info->socket_id);
    15             }
    16         }
    17         ....

       // processCommandBuffer
        static int processCommandBuffer(void *buffer, size_t buflen, RIL_SOCKET_ID socket_id) {
    
            RequestInfo *pRI;
            ...
            pRI = (RequestInfo *)calloc(1, sizeof(RequestInfo));
    
            pRI->token = token;
            // 根据 RILJ的REQUEST类型来获取CommandInfo
            pRI->pCI = &(s_commands[request]);
            pRI->socket_id = socket_id;
            ...
            // 将请求分配给对应的函数处理
            pRI->pCI->dispatchFunction(p, pRI);
    
            return 0;
        }
    
    }

    上述代码中,s_commands将所有RILJ的请求命令,对应的请求函数以及响应处理函数组成一个类型为commandInfo的结构体数组,等请求从CP返回时,就可以调用对应的响应函数来处理返回的结果了:

     1    static CommandInfo s_commands[] = {
     2         #include "ril_commands.h"
     3     };
     4 
     5     {0, NULL, NULL},                   //none
     6     {RIL_REQUEST_GET_SIM_STATUS, dispatchVoid, responseSimStatus},
     7     {RIL_REQUEST_ENTER_SIM_PIN, dispatchStrings, responseInts},
     8     {RIL_REQUEST_ENTER_SIM_PUK, dispatchStrings, responseInts},
     9     {RIL_REQUEST_ENTER_SIM_PIN2, dispatchStrings, responseInts},
    10     {RIL_REQUEST_ENTER_SIM_PUK2, dispatchStrings, responseInts},
    11     {RIL_REQUEST_CHANGE_SIM_PIN, dispatchStrings, responseInts},
    12     {RIL_REQUEST_CHANGE_SIM_PIN2, dispatchStrings, responseInts},
    13     ....

    源码: /android/hardware/ril/libril/samsung/ril_commands.h

    参考文献

    版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wang2119/article/details/53392526
  • 相关阅读:
    ubuntu qtcreator 硬件权限问题
    关于LuCi
    npm 使用记录
    ubuntu 下简单录音
    qthread 使用 signal 方法通信
    线程安全笔记一则
    ubuntu 设置 NAT 转发
    debian 中新建或调整 swap 空间
    关于 htonl 和 ntohl 的实现
    shell 调试手段总结
  • 原文地址:https://www.cnblogs.com/ricks/p/9497426.html
Copyright © 2020-2023  润新知