前言 在上一篇文章里(http://sniffer.site/2016/11/29/Android-RILD%E8%AF%A6%E8%A7%A3/ ),简要介绍了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的指令, Android有一个基于AT指令的默认参考实现(reference-ril
)
三者之间的关系图如下所示:
从这里可以看到,RILD在启动时,负责将LibRil以及Vendor RIL进行初始化,将相应的回调函数以及调用接口进行注册,LibRIL向vendor RIL提供了接口RIL_Env
,当Vendor有消息时,利用该回调返回;而Vendor RIL 同样提供了接口RIL_RadioFunctions
,给LibRIl调用。这里涉及到3个主要问题:
RILD是如何启动?
RILD是如何进行初始化操作的?
初始完成后,LIBRIL是如何进行消息的接收与发送的?
RILD是如何启动的 RILD(RIL Daemon)是系统的守护进程,系统已启动,就会一直运行。手机开机时,kernel完成初始化后,Android启动一个初始化进程Init用于加载系统基础服务,如文件系统,zygote进程,服务管家ServiceManager,以及RILD:
1 2 3 4 5 6 7 8 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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 int main (int argc, char **argv) { ... const RIL_RadioFunctions *(*rilInit)(const struct RIL_Env *, int , char **); const RIL_RadioFunctions *funcs; ... OpenLib: dlHandle = dlopen (rilLibPath, RTLD_NOW); if (dlHandle == NULL ) { RLOGE ("dlopen failed: %s" , dlerror ()); exit (EXIT_FAILURE); } RIL_startEventLoop (); rilInit = (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int , char **))dlsym (dlHandle, "RIL_Init" ); ... funcs = rilInit (&s_rilEnv, argc, rilArgv); RLOGD ("RIL_Init rilInit completed" ); RIL_register (funcs); RLOGD ("RIL_Init RIL_register completed" ); }
RILD初始化主要完成两件事:(1) 加载Vendor RIL的代码,并对其进行初始化操作,将LIBRIL的接口RIL_Env
传递给Vendor RIL,用于回调;(2)开始RIL事件处理线程;(3)将Vendor RIL的接口注册到LIBRIL中,这样LIBRIL就可以将消息发送给Vendor RIL了。
RIL_startEventLoop()
启动RIL事件处理线程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 extern "C" void RIL_startEventLoop (void ) { s_started = 0 ; pthread_mutex_lock (&s_startupMutex); ... int result = pthread_create (&s_tid_dispatch, &attr, eventLoop, NULL ); if (result != 0 ) { RLOGE ("Failed to create dispatch thread: %s" , strerror (result)); goto done; } while (s_started == 0 ) { pthread_cond_wait (&s_startupCond, &s_startupMutex); } done: pthread_mutex_unlock (&s_startupMutex); } static void *eventLoop (void *param) { int ret; int filedes[2 ]; ril_event_init (); pthread_mutex_lock (&s_startupMutex); s_started = 1 ; pthread_cond_broadcast (&s_startupCond); pthread_mutex_unlock (&s_startupMutex); ret = pipe (filedes); s_fdWakeupRead = filedes[0 ]; s_fdWakeupWrite = filedes[1 ]; ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true , processWakeupCallback, NULL ); rilEventAddWakeup (&s_wakeupfd_event); ril_event_loop (); kill (0 , SIGKILL); return NULL ; }
RILD初始化vendor RIL之后,将返回的RIL_RadioFunctions
返回给RILD,RILD接着将其注册到LIBRIL中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 extern "C" void RIL_register (const RIL_RadioFunctions *callbacks) { ... s_ril_param_socket = { RIL_SOCKET_1, -1 , -1 , PHONE_PROCESS, &s_commands_event, &s_listen_event, processCommandsCallback, NULL }; .... if (s_started == 0 ) { RIL_startEventLoop (); } startListen (RIL_SOCKET_1, &s_ril_param_socket); } static void startListen (RIL_SOCKET_ID socket_id, SocketListenParam* socket_listen_p) { int fdListen = -1 ; int ret; char socket_name[10 ]; memset (socket_name, 0 , sizeof (char )*10 ); switch (socket_id) { case RIL_SOCKET_1: strncpy (socket_name, RIL_getRilSocketName (), 9 ); break ; .... fdListen = android_get_control_socket (socket_name); ret = listen (fdListen, 4 ); socket_listen_p->fdListen = fdListen; ril_event_set (socket_listen_p->listen_event, fdListen, false , listenCallback, socket_listen_p); rilEventAddWakeup (socket_listen_p->listen_event); }
源代码: /hardware/ril/libril/ril.cpp
接下来,我们就来看一看LIBRIL与Vendor RIL各自提供的接口函数。 这两个接口都在/hardware/ril/include/telephony/ril.h
中进行了声明。
Vendor RIL主要提供了5个接口,供LIBRIL调用:
RIL_RequestFunc
是最主要的一个,所有从RILJ发送过来的请求均由该接口发送给Vendor RIL;
RIL_RadioStateRequest
从LIBRIL获取modem的即时状态;
RIL_Supports
判断Vendor RIL是否支持某个请求命令;
RIL_Cancel
取消某个请求命令;
RIL_GetVersion
获取RIL的版本号;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 typedef struct { int version; RIL_RequestFunc onRequest; RIL_RadioStateRequest onStateRequest; RIL_Supports supports; RIL_Cancel onCancel; RIL_GetVersion getVersion; } RIL_RadioFunctions; typedef void (*RIL_RequestFunc) (int request, void *data, size_t datalen, RIL_Token t, RIL_SOCKET_ID socket_id) ;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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 struct RIL_Env { void (*OnRequestComplete)(RIL_Token t, RIL_Errno e, void *response, size_t responselen); #if defined(ANDROID_MULTI_SIM) void (*OnUnsolicitedResponse)(int unsolResponse, const void *data, size_t datalen, RIL_SOCKET_ID socket_id); #else void (*OnUnsolicitedResponse)(int unsolResponse, const void *data, size_t datalen); #endif void (*RequestTimedCallback) (RIL_TimedCallback callback, void *param, const struct timeval *relativeTime); };
代码路径: /hardware/ril/rild/rild.c
初始化完成了 ,那么RIL事件处理线程是从何时开始处理事件的了?RIL事件处理线程是怎么又是同时处理来自RILJ以及Vendor RIL的消息的?下面就来看一看LIBRIL如何处理RIL事件的。
LIBRIL如何处理RIL事件 为处理RIL事件,LIBRIL提供了3个事件队列(由双向列表组成):
1 2 3 4 5 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事件需要处理:
1 2 3 4 5 6 7 8 static struct ril_event s_commands_event;static struct ril_event s_wakeupfd_event;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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 void ril_event_loop () { int n; fd_set rfds; struct timeval tv; struct timeval * ptv; for (;;) { memcpy (&rfds, &readFds, sizeof (fd_set)); .... n = select (nfds, &rfds, NULL , NULL , ptv); .... processTimeouts (); processReadReadies (&rfds, n); firePending (); } }
该线程,一直监听FD(File Descriptor)集合readFds
,如果有数据时,就会立即返回,进而开始执行事件的处理:首先处理定时事件队列中的event,如果发现有超时的事件,就将其加入pending队列中;接着,查看监测表(保存了最多8个事件)中是否有readFds
对应的RIL事件,如果存在,则也将其放入到pending队列。最后,就要开始处理pending队列了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 static void firePending () { dlog ("~~~~ +firePending ~~~~" ); struct ril_event * ev = pending_list.next; while (ev != &pending_list) { struct ril_event * next = ev->next; removeFromList (ev); ev->func (ev->fd, 0 , ev->param); ev = next; } dlog ("~~~~ -firePending ~~~~" ); }
源码:/android/hardware/ril/libril/samsung/ril_event.cpp
LIBRIL事件处理线程开始时,只有两个事件:s_wakeupfd_event
与s_listen_event
,s_wakeupfd_event
事件在添加s_listen_event
事件,需要唤醒RIL事件处理线程被执行:
1 2 3 4 5 6 7 8 9 10 11 12 static void triggerEvLoop () { int ret; if (!pthread_equal (pthread_self (), s_tid_dispatch)) { do { ret = write (s_fdWakeupWrite, " " , 1 ); } while (ret < 0 && errno == EINTR); } }
接着,开始执行s_listen_event
事件,调用回调函数listenCallback
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 static void listenCallback (int fd, short flags, void *param) { .... fdCommand = accept (fd, (sockaddr *) &peeraddr, &socklen); is_phone_socket = 0 ; err = getsockopt (fdCommand, SOL_SOCKET, SO_PEERCRED, &creds, &szCreds); .... ret = fcntl (fdCommand, F_SETFL, O_NONBLOCK); .... p_info->fdCommand = fdCommand; p_rs = record_stream_new (p_info->fdCommand, MAX_COMMAND_BYTES); p_info->p_rs = p_rs; ril_event_set (p_info->commands_event, p_info->fdCommand, 1 , p_info->processCommandsCallback, p_info); rilEventAddWakeup (p_info->commands_event); onNewCommandConnect (p_info->socket_id); }
下次处理pending事件队列时,处理s_commands_event
,调用回调函数processCommandsCallback
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 static void processCommandsCallback (int fd, short flags, void *param) { for (;;) { 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 ) { processCommandBuffer (p_record, recordlen, p_info->socket_id); } } .... static int processCommandBuffer (void *buffer, size_t buflen, RIL_SOCKET_ID socket_id) { RequestInfo *pRI; ... pRI = (RequestInfo *)calloc (1 , sizeof (RequestInfo)); pRI->token = token; pRI->pCI = &(s_commands[request]); pRI->socket_id = socket_id; ... pRI->pCI->dispatchFunction (p, pRI); return 0 ; } }
上述代码中,s_commands
将所有RILJ的请求命令,对应的请求函数以及响应处理函数组成一个类型为commandInfo
的结构体数组,等请求从CP返回时,就可以调用对应的响应函数来处理返回的结果了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 static CommandInfo s_commands[] = { #include "ril_commands.h" }; {0 , NULL , NULL }, {RIL_REQUEST_GET_SIM_STATUS, dispatchVoid, responseSimStatus}, {RIL_REQUEST_ENTER_SIM_PIN, dispatchStrings, responseInts}, {RIL_REQUEST_ENTER_SIM_PUK, dispatchStrings, responseInts}, {RIL_REQUEST_ENTER_SIM_PIN2, dispatchStrings, responseInts}, {RIL_REQUEST_ENTER_SIM_PUK2, dispatchStrings, responseInts}, {RIL_REQUEST_CHANGE_SIM_PIN, dispatchStrings, responseInts}, {RIL_REQUEST_CHANGE_SIM_PIN2, dispatchStrings, responseInts}, ....
源码: /android/hardware/ril/libril/samsung/ril_commands.h
参考文献