Android中RIL层详细分析解析 联系客服

发布时间 : 星期三 文章Android中RIL层详细分析解析更新完毕开始阅读124fdd7c657d27284b73f242336c1eb91b37334a

if (ev->fd >= nfds) nfds = ev->fd+1; dlog(\ break;ENTS; i++) { if (watch_table[i] == NU } }

MUTEX_RELEASE();

dlog(\}

4.2---static void triggerEvLoop() { int ret;

LOGD(\ 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, \ } while (ret < 0 && errno == EINTR); } }

5.ril_event_loop(); }

<一>--RIL层代码分析-RIL_RadioFunctions *RIL_Init(funcs =rilInit()->mainloop()

ril/rild/rild.c->main()为函数入口

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

1.消息队列select为非阻塞的去轮询事件 2.read的阻塞的去读取上层发下来的命令,并响应

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

int main(int argc, char **argv) {

const char * rilLibPath = NULL; char **rilArgv; void *dlHandle;

const RIL_RadioFunctions *(*rilInit)(const struct RIL_Env *, int, char **);

const RIL_RadioFunctions *funcs; char libPath[PROPERTY_VALUE_MAX]; unsigned char hasLibArgs = 0; ........ OpenLib: #endif

switchUser();

/*打开dlopen()函数,就会动态去加载动态库vendor RIL 获取由RIL_register(funcs);注册进来的参数,并解析*/ dlHandle = dlopen(rilLibPath, RTLD_NOW); if (dlHandle == NULL) {

fprintf(stderr, \ exit(-1); }

/*消息队列的入口,添加到select,用阻塞方式去读取那些ril_event_set()的数据##每当看到打印信息,不按顺序打下来说明阻塞##*/

RIL_startEventLoop();

/*通过dlsym函数得到rilInit函数指针的引用*/

rilInit = (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))dlsym(dlHandle, \ if (rilInit == NULL) {

fprintf(stderr, \ exit(-1); }

if (hasLibArgs) { rilArgv = argv + i - 1; argc = argc -i + 1; } else {

static char * newArgv[MAX_LIB_ARGS]; static char args[PROPERTY_VALUE_MAX]; rilArgv = newArgv;

property_get(LIB_ARGS_PROPERTY, args, \ argc = make_argv(args, rilArgv); }

// Make sure there's a reasonable argv[0] rilArgv[0] = argv[0];

/*利用得到的rilInit函数指针,调用真正的RIL_Init ,实际是动态加载动态库去链接reference-ril.c ,由dlopen()函数加载*/

funcs = rilInit(&s_rilEnv, argc, rilArgv);

/*RIL_register作用一:把vendor RIL(即RIL_init) 注册到reference-ril库去等待,dopen()函数加载链接

附:RIL_init通过是onRequest()方法,将上层来的请求进行映射后转换成对应的AT命令发给硬件,rild通过RIL_register注册这一指针。

RIL_register作用二:创建rild socket主要是等待java层得数据通过,传到下一层,还创建debug socket*/ RIL_register(funcs); done:

while(1) {

// sleep(UINT32_MAX) seems to return immediately on bionic sleep(0x00ffffff); }

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 所有文件:

hardware/ril/reference-ril$ ls

Android.mk atchannel.h at_tok.h misc.h NOTICE atchannel.c at_tok.c ril_event.h reference-ril.c misc.c MODULE_LICENSE_APACHE2

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

在编译时libril被链入rild,它为rild提供了event处理功能,还提供了在rild与Vendor RIL之间传递请求和响应消息的能力。

libril.so驻留在rild这一守护进程中,主要完成同上层通信的工作,接受ril请求并传递给librefrence_ril.so, 同时把来自librefrence_ril.so的反馈回传给调用进程。

librefrence.so负责直接与modem通信,这包括将来自libril的指令转换为AT指令,并且将AT指令写入modem中。

reference-ril会接收调用者传来的参数,参数内容为与radio的通信方式。如通过串口连接modem,那么参数为这种形式:-d /dev/ttySx

funcs =rilInit(&s_rilEnv, argc, rilArgv);//实际是通过动态加载动态库的方式执行

reference-ril.c中的RIL_Init

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

reference-ril/reference-ril.c ->RIL_RadioFunctions *RIL_Init()函数

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv)

{ int ret; int fd = -1; int opt;

pthread_attr_t attr; s_rilenv = env;

LOGD(\ while ( -1 != (opt = getopt(argc, argv, \ switch (opt) { case 'p':

s_port = atoi(optarg); if (s_port == 0) { usage(argv[0]); return NULL; }

LOGI(\

break;

//获取dev/ttyUSB,只是打开而已,是否获取,由线程mainLoop执行完才知道 case 'd':

s_device_path = optarg;

LOGI(\

break; case 's':

s_device_path = optarg; s_device_socket = 1;

LOGI(\ break; default:

usage(argv[0]); return NULL; } }

if (s_port < 0 && s_device_path == NULL) { usage(argv[0]); return NULL; }

//上面获取了设备节点和socket pthread_attr_init (&attr);

pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

LOGD(\ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);-\ //创建一个线程,单独去读取串口数据

ret = pthread_create(&s_tid_mainloop, &attr,mainLoop, NULL);//创建一个线程mainLoop

return &s_callbacks;//返回一个ril_init,给 RIL_register(&s_callbacks);回调,进行初始化 }

#########################################################################################################################

这个任务的入口是RIL_Init, RIL_Init首先通过参数获取硬件接口的设备文件或模拟硬件接口的socket. 接下来便新开一个线程继续初始化, 即mainLoop。mainLoop的主要任务是建立起与硬件的通信,然后通过read方法阻塞等待硬件的主动上报或响应。

在注册一些基础回调(timeout,readerclose)后,mainLoop首先打开硬件设备文件,建立起与硬件的通信,s_device_path和s_port是前面获取的设备路径参数,将其打开(两者可以同时打开并拥有各自的reader,这里

也很容易添加双卡双待等支持)。接下来通过at_open函数建立起这一设备文件上的reader等待循环,这也是通

过新建一个线程完成, ret = pthread_create(&s_tid_reader, &attr, readerLoop, &attr),入口点readerLoop。 AT命令都是以/r/n或/n/r的换行符来作为分隔符的,所以readerLoop是line驱动的,除非出错,超时等,否则会读到一行完整的响应或主动上报,才会返回。这个循环跑起来以后,我们基本的AT响应机制已经建立了起来。它的具体分析,包括at_open中挂接的ATUnsolHandler, 我们都放到后面分析response的连载文章里去。

有了响应的机制(当然,能与硬件通信也已经可以发请求了),通过RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0),跑到initializeCallback中,执行一些Modem的初始化命令,主要都是AT命令的方式。发AT命令的流程,我们放到后面分析request的连载文章里。这里可以看到,主要是一些参数配置,以及网络状态的检查等