1、概述android
关于RILD的功能,就很少说了,对上服务于Phone进程,也能够认为是RILJ层,向下同modem层进行通讯,对MTK平台来讲就是使用AT命令了。架构
2、RILD的架构app
RILD主要由三部分组成,一个是rild.c,第二个是libril这个库(对于MTK来讲就是librilmtk),第三个是厂商关于实现同modem进行通讯的reference-ril库,对于MTK来讲就是mtk-ril。出于保护第三方厂商利益的考虑,这个库是在rild运行的时候动态加载进去的,因为运行在同一个进程中,因此rild同reference-ril之间的通讯是函数调用,因此二者之间定义了用于通讯的包含函数指针的结构体。socket
typedef struct { int version; /* set to RIL_VERSION */ RIL_RequestFunc onRequest; RIL_RadioStateRequest onStateRequest; RIL_Supports supports; RIL_Cancel onCancel; RIL_GetVersion getVersion; RIL_ReportUsbDisconn reportUsbDisconn; RIL_ReportSocketConn reportRILDConn; } RIL_RadioFunctions;
static struct RIL_Env s_rilEnv = { RIL_onRequestComplete, RIL_onUnsolicitedResponse, RIL_requestTimedCallback // For multi channel support ,RIL_requestProxyTimedCallback ,RIL_queryMyChannelId ,RIL_queryMyProxyIdByThread };
首先介绍下如何RILJ层下来的请求消息是如何调用到第三方库的,流程以下,对于回调很明显第三方库提供具体实现,而libril提供函数指针,这有点相似于面向对象的多态。函数
rild.coop
RIL_register(funcs);//funnc 指向具体的实现,经过注册使得libril中的指针指向实现
ril.cpp学习
RIL_register (const RIL_RadioFunctions *callbacks) { ... memcpy(&s_callbacks, callbacks, sizeof (RIL_RadioFunctions));//将callbacks赋值给全局变量s_callbacks
#define CALL_ONREQUEST(a, b, c, d, e) s_callbacks.onRequest((a), (b), (c), (d), (e)) #define CALL_ONSTATEREQUEST(a) s_callbacks.onStateRequest(a)
static void dispatchSIM_IO (Parcel &p, RequestInfo *pRI) { union RIL_SIM_IO { RIL_SIM_IO_v6 v6; RIL_SIM_IO_v5 v5; } simIO; int32_t t; int size; status_t status; #if VDBG RLOGD("dispatchSIM_IO"); #endif memset (&simIO, 0, sizeof(simIO)); // note we only check status at the end status = p.readInt32(&t); simIO.v6.command = (int)t; status = p.readInt32(&t); simIO.v6.fileid = (int)t; simIO.v6.path = strdupReadString(p); status = p.readInt32(&t); simIO.v6.p1 = (int)t; status = p.readInt32(&t); simIO.v6.p2 = (int)t; status = p.readInt32(&t); simIO.v6.p3 = (int)t; simIO.v6.data = strdupReadString(p); simIO.v6.pin2 = strdupReadString(p); simIO.v6.aidPtr = strdupReadString(p); startRequest; appendPrintBuf("%scmd=0x%X,efid=0x%X,path=%s,%d,%d,%d,%s,pin2=%s,aid=%s", printBuf, simIO.v6.command, simIO.v6.fileid, (char*)simIO.v6.path, simIO.v6.p1, simIO.v6.p2, simIO.v6.p3, (char*)simIO.v6.data, (char*)simIO.v6.pin2, simIO.v6.aidPtr); closeRequest; printRequest(pRI->token, pRI->pCI->requestNumber); if (status != NO_ERROR) { goto invalid; } size = (s_callbacks.version < 6) ? sizeof(simIO.v5) : sizeof(simIO.v6); CALL_ONREQUEST(pRI->pCI->requestNumber, &simIO, size, pRI, pRI->socket_id);//关于sim卡相关的上层消息分配
3、关于RILD的启动ui
n以前的平台就不说了,网上一搜一大堆,都是在init.rc中启动的,可是Android N以后因为init.rc启动脚本的改动不少deamon程序一下找不到了,如下都是基于mtk 6737n平台的源码为基准的spa
寻找n平台rild启动入口.net
init.rc中有一行
import /init.${ro.hardware}.rc
查看属性值:
[ro.hardware]: [mt6735]
/device/mediatek/mt6735/init.mt6735.rc
其中有一行:
import init.modem.rc
在下面这个rc文件中找到了rild的启动入口
/device/mediatek/mt6735/init.modem.rc
/device/mediatek/common/init.rilproxy.rc
4、RILD的初始化过程
只说最关键的部分,具体怎么衔接起来的,本身阅读代码,由于每一个厂家仍是不同的
dlHandle = dlopen(rilLibPath, RTLD_NOW);//根据路径打开第三方库 if (dlHandle == NULL) { RLOGE("dlopen failed: %s", dlerror()); exit(EXIT_FAILURE); } RIL_startEventLoop();//最重要的就是启动子线程循环监听ril_event
ret = pipe(filedes); if (ret < 0) { RLOGE("Error in pipe() errno:%d", errno); return NULL; } s_fdWakeupRead = filedes[0]; s_fdWakeupWrite = filedes[1]; fcntl(s_fdWakeupRead, F_SETFL, O_NONBLOCK); ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true, processWakeupCallback, NULL); rilEventAddWakeup (&s_wakeupfd_event); // Only returns on error ril_event_loop(); RLOGE ("error in event_loop_base errno:%d", errno); // kill self to restart on error
看到eventLoop这个函数中这些封装的函数主要是来自于Ril_event.cpp,因此搞清这个循环的关键是看懂这个类的原理,其实就是个事件链表,监听到发生的event消息,对应调用这个结构体中的回调函数
struct ril_event { struct ril_event *next; struct ril_event *prev; int fd; int index; bool persist; struct timeval timeout; ril_event_cb func; void *param; };
添加事件
// Add event to watch list void ril_event_add(struct ril_event * ev) { dlog("~~~~ +ril_event_add ~~~~"); MUTEX_ACQUIRE(); for (int i = 0; i < MAX_FD_EVENTS; i++) { if (watch_table[i] == NULL) { watch_table[i] = ev;//ril_event结构全局链表 ev->index = i; dlog("~~~~ added at %d ~~~~", i); dump_event(ev); FD_SET(ev->fd, &readFds);//将ril_event结构体中的成员变量fd添加到全局变量readFds,下面会看到使用select监听这个fd_set类型的变量 if (ev->fd >= nfds) nfds = ev->fd+1; dlog("~~~~ nfds = %d ~~~~", nfds); break; } } MUTEX_RELEASE(); dlog("~~~~ -ril_event_add ~~~~"); }
监听事件
void ril_event_loop() { int n; fd_set rfds; struct timeval tv; struct timeval * ptv; for (;;) { // make local copy of read fd_set memcpy(&rfds, &readFds, sizeof(fd_set)); if (-1 == calcNextTimeout(&tv)) { // no pending timers; block indefinitely dlog("~~~~ no timers; blocking indefinitely ~~~~"); ptv = NULL; } else { dlog("~~~~ blocking for %ds + %dus ~~~~", (int)tv.tv_sec, (int)tv.tv_usec); ptv = &tv; } printReadies(&rfds); n = select(nfds, &rfds, NULL, NULL, ptv);//监听对应的文件描述符是否发生变化 printReadies(&rfds);
第二个关键的函数就是RIL_register
关于怎么把第三方库的具体实现填充到本地指针上的前面已经说过,下面看如何监听socker,获取rilj发过来的消息
// start listen socket1 for (i = 0; i < SIM_COUNT; i++) { startListen((RIL_SOCKET_ID)(RIL_SOCKET_1+i), &s_ril_param_socket[i]);//RIL_SOCKET_ID是个枚举结构,以下,这种用法学习了,主要看startListen的实现 } typedef enum { RIL_SOCKET_1, #if (SIM_COUNT >= 2) RIL_SOCKET_2, #if (SIM_COUNT >= 3) RIL_SOCKET_3, #endif #if (SIM_COUNT >= 4) RIL_SOCKET_4, #endif #endif RIL_SOCKET_NUM } RIL_SOCKET_ID;
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; case RIL_SOCKET_2: strncpy(socket_name, SOCKET2_NAME_RIL, 9); break; case RIL_SOCKET_3: strncpy(socket_name, SOCKET3_NAME_RIL, 9); break; case RIL_SOCKET_4: strncpy(socket_name, SOCKET4_NAME_RIL, 9); break; default: RLOGE("Socket id is wrong!!"); return; } RLOGI("Start to listen socket_name: %s, socketId: %s", socket_name, rilSocketIdToString(socket_id)); fdListen = android_get_control_socket(socket_name);//这个是根据socket的名字得到对应的文件描述符,那么这些socket在哪里建立的呢,答案是在init进程中建立的,init在启动rild服务执行fork之后在子进程的返回中会建立socket if (fdListen < 0) { RLOGE("Failed to get socket %s", socket_name); exit(-1); } ret = listen(fdListen, 4); if (ret < 0) { RLOGE("Failed to listen on control socket '%d': %s", fdListen, strerror(errno)); exit(-1); } socket_listen_p->fdListen = fdListen; /* note: non-persistent so we can accept only one connection at a time */ ril_event_set (socket_listen_p->listen_event, fdListen, false, listenCallback, socket_listen_p);//从这里能够看到当fd发生变化后,也就是收到rilj的消息后调用的是listenCallback rilEventAddWakeup (socket_listen_p->listen_event); }
#define SOCKET_NAME_RIL "rild" //这些均可以和.rc文件中定义的socket对应上,对mtk 6737n能够去我上面说的那个rc文件中去找 #define SOCKET2_NAME_RIL "rild2" #define SOCKET3_NAME_RIL "rild3" #define SOCKET4_NAME_RIL "rild4"
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);//本觉得找到了最终处理ril消息的地方,没想到它只是添加了另外一个ril_event结构体,由这个结构体的回调函数processCommandsCallback处理,而这个函数又会调用到processClientCommandBuffer rilEventAddWakeup (p_info->commands_event);
#ifdef MTK_RIL { enqueue(pRI, buffer, buflen, NULL, socket_id); } #else pRI->pCI->dispatchFunction(p, pRI);//这个应该是寻找对应dispatch函数,分析完这个应该就能够和上面的那个sim卡消息接住了 #endif
而看到每一个ril消息会对应一个处理函数的入口,就应该明白必然是有一张以这种结构体存在的表,而上面提到的函数即是负责为每个ril消息寻找入口
{RIL_REQUEST_SEND_SMS, dispatchStrings, responseSMS}, {RIL_REQUEST_SEND_SMS_EXPECT_MORE, dispatchStrings, responseSMS}, {RIL_REQUEST_SETUP_DATA_CALL, dispatchDataCall, responseSetupDataCall}, {RIL_REQUEST_SIM_IO, dispatchSIM_IO, responseSIM_IO}, {RIL_REQUEST_SEND_USSD, dispatchString, responseVoid},
关于rilj层监听rild socket中创建socket如何经过jni调用本地代码可参考:
http://blog.csdn.net/yangzhihuiguming/article/details/51697801