RIL 机制---rild守护进程

来源:互联网 发布:查看手机端口 编辑:程序博客网 时间:2024/06/11 15:00

3 守护进程

ril与上层的RILJ沟通方式是通过Socket传输数据与命令,而reference-ril与底层Modem的信号传输是通过串口用AT命令来实现。

 RILC是一个守护进程,由init进程启动,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 log qcom_diag

由配置文件可知,

1,如果该守护进程异常退出,android系统会进行重新加载。

2,会建立2个socket,端口号为rild负责和RILJ进行通信。

 

该守护进程的入口为rild.c的main方法,main方法比较长,主要逻辑如下,

 1、开启EventLoop循环,完成RILC与RILJ层数据交互(通过Socket)

 2、打开动态库reference并构建ReaderLoop循环,完成RIL与Modem层数据交互(通过AT)

 3、注册reference的回调函数。

根据通信方法,将该守护进程分为2部分:

1,Event:利用socket完成RILC与RILJ层数据交互。

2, reference-ril:利用AT指令完成RILC与Modem层数据交互。

3.1,EventLoop

ril.cpp的RIL_startEventLoop方法如下,

extern "C" void RIL_startEventLoop(void) {    /* spin up eventLoop thread and wait for it to get started */    s_started = 0;    pthread_mutex_lock(&s_startupMutex);    pthread_attr_t attr;    pthread_attr_init(&attr);    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);    //打开Event线程,并调用eventLoop进入循环    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);}

这样,Event线程就会监听RILJ发过来的数据了,eventLoop方法在后面会详细分析。好了,RILJRILC这条路已经通了。

3.2 ReaderLoop

rild.c中main方法有关加载动态库reference代码如下,

#define  REFERENCE_RIL_PATH  "libreference-ril.so"rilLibPath = REFERENCE_RIL_PATH;rilInit =        (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))        dlsym(dlHandle, "RIL_Init");dlHandle = dlopen(rilLibPath, RTLD_NOW);//加载库•••funcs = rilInit(&s_rilEnv, argc, rilArgv);//初始化   实际调用的是RIL_Init方法

s_rilEnv结构体定义如下,也就是reference-ril可以回调ril的方法

static struct RIL_Env s_rilEnv = {    RIL_onRequestComplete,    RIL_onUnsolicitedResponse,    RIL_requestTimedCallback};

rils_rilEnv传给reference-rils_rilenv之后,reference-ril就可以利用该结构调用ril的方法。这样,reference-rilril这条路也通了。

 

reference-ril.c的RIL_Init主要代码如下,

ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);//创建线程,入口方法是mainLoop    return &s_callbacks;

在此必须要说的是, reference-ril.c还有一个main方法,其实main方法和RIL_Init方法作用几乎完全一样。

只是reference-ril.c作为动态库是调用的是RIL_Init方法,如果作为单独进程就会调用main方法。

这样,mainLoop线程就会监听Modem发过来的数据了, mainLoop方法在后面会详细分析。好了, ModemRILC这条路已经通了。

3.3 RIL_register

rild.c中main方法有关加载动态库RIL注册的代码如下,

funcs = rilInit(&s_rilEnv, argc, rilArgv);RIL_register(funcs); //注册reference  的回调函数

当我们调用reference的初始化函数(也就是RIL_Init)后, 将会得到一个RIL_RadioFunctions类型的返回值,reference-ril.c中如下,

static const RIL_RadioFunctions s_callbacks = {    RIL_VERSION,    onRequest,    currentState,    onSupports,    onCancel,    getVersion};

ril.h中定义这个变量类型如下,也就是ril可以调用reference-ril的方法。

typedef struct {      int version;        //当前链接库的版本信息      RIL_RequestFunc onRequest;  //用于Event侧向动态库发起请求      RIL_RadioStateRequest onStateRequest;   //得到当前库的状态      RIL_Supports supports;  //查询是否支持某个命令      RIL_Cancel onCancel;       //取消一个Event的处理      RIL_GetVersion getVersion;  //得到版本号  } RIL_RadioFunctions;  

RIL_register 主要代码如下,

//把返回值传给s_callbacks(全局变量)memcpy(&s_callbacks, callbacks, sizeof (RIL_RadioFunctions));      //打开RILC与RILJ之间的Socket通道    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 */                        };startListen(RIL_SOCKET_1, &s_ril_param_socket);// 监听rild socket

reference-rilcallbacks传给rils_callbacks之后, ril就可以利用该结构调用reference-ril的方法。这样, rilreference-ril这条路也通了。

 

startListen主要方法如下,

memset(socket_name, 0, sizeof(char)*10);fdListen = android_get_control_socket(socket_name); 打开RILC与RILJ之间的Socket通道    ret = listen(fdListen, 4);socket_listen_p->fdListen = fdListen;    //用这个Socket通道句柄创建一个Eventril_event_set (socket_listen_p->listen_event, fdListen, false, listenCallback, socket_listen_p);    rilEventAddWakeup (socket_listen_p->listen_event); //添加到Eventloop中

ril_event_set方法如下,

void ril_event_set(struct ril_event * ev, int fd, bool persist, ril_event_cb func, void * param){    dlog("~~~~ ril_event_set %x ~~~~", (unsigned int)ev);    memset(ev, 0, sizeof(struct ril_event));    ev->fd = fd;    ev->index = -1;    ev->persist = persist;    ev->func = func;    ev->param = param;    fcntl(fd, F_SETFL, O_NONBLOCK);}

在第五章中,消息从socket读取之后,会回调func方法,这里的func就指向listenCallback。

 

3.4 消息流程

有前面的分析可知,消息会在4个模块中走一遍,消息流动方法如下,

1,从RIL到RIL。

2,从RIL到reference-ril

3, 从reference-ril到Modem

4,Modem处理完成之后,又从modem到reference-ril

5,从reference-ril到RIL

6,从RIL到RILJ。

 

但是,很多时候,比如来电了,这个信息是直接从Modem出发的, 只需要经过以下三个流程。

1,modem到reference-ril

2,从reference-ril到RIL

3,从RIL到RILJ。

 

为了便于论述,将modem主动往上层发送的消息称为上报消息;从RILJ发送出Modem处理完成之后再往上层发送的消息称为回应消息。

 

RILJ和ril利用socket进行通信。

ril和reference-ril在同一个进程,因此只需用简单的回调就可以完成通信。

reference-ril和Modem利用串口进行通信,每个厂商一般都不相同,但是一般都是利用tty端口进行通信。

 

这样,按照发送到接收,从Java层到C/C++层的顺序来仔细的捋一捋整个ril机制。

0 0
原创粉丝点击