Android Rild 概述

1、概述

今天主要讲下RIL相关模块内容,RIL分为RILJ和RILD两部分,RILJ属于Java层,RILD属于C层。那先看下RILD所处于的位置,以及与其相关的模块,如下图1.1使用红色框标注的内容。RILD处于android系统HAL(HARDWARE ABSTRACTION LAYER)这一层。是telephony framework(RILJ属于这一部分,用来与RILD建立通道)与modem(基带芯片)沟通的桥梁。最上层就是通话和短信等APK。

                                                      图1.1

2、RIL Architecture

 

                                             图1.2 RIL Architecture

如上图所示RIL 整体架构分为三层,最上层为RIL-Java 适配层,中间层即为RILD, 下层为Modem. RIL-Java 通过socket与RILD 层对接,RILD层与Modem通过串口对接。

3、RILD 简介

Radio Interface Layer Demon,简称RIL,是手机上Modem(基带芯片,WCDMA,CDMA2000等就是指基带芯片的不同技术)与android系统通讯的桥梁,RIL的角色非常重要,RIL被设计成能够可靠的高效的传输数据一个模块

 

                                                         图1.3 

Android RILD可以分成2个模块,一个部分RIL Demon(RILD),用于通过socket和framework通讯以及处理整个RIL的event;另一部分是手机厂商自己实现的部分,在这里暂时称之为vendor RIL。 之所以这样设计是因为不同的厂商使用的Modem不一样,而RIL又和Modem紧密联系,所以Android有把和Modem联系紧密的部分和公共部分剥离开,让不同的厂商可以自己实现vendor RIL以适应厂商自己的Modem。所以又可以细化如下图所示:

 

图1.4

但就目前来说,不同的芯片厂商都是自己实现了RILD,但基本的架构是沿用了Google rild。

4、RILD File Structure

Android系统的ril代码在hardware/ril 目录如下图所示:

 

图1.5 RIL File

rild:   包括rild.c 以及radiooptions.c, 建立守护进程。可利用radiooptions.c 进行自动或者手动调试, 它的radiooptiongs通过启动参数获取, 利用socket与rild通信,可供调试时配置Modem参数。

libril: 主要包括ril.cpp, ril_event.cpp 等,该包生成动态共享库libril.so, 与rild结合相当紧密。组成部分为ril.cpp,ril_event.cpp。libril.so驻留在 rild这一守护进程中,主要完成同上层通信的工作(启动事件循环机制,以及开启同上层通信的socket),接受rilJ request并传递给reference-ril.so, 同时把来自reference -ril.so的response回传给调用进程。

 reference-ril: 该文件中内容将生成动态库reference-ril.so, 包括的文件主要有atchannel.c,at_tok.c,misc.c等。reference-ril so 和 rild 结合比较松散,通过dlopen去打开库,这也是因为reference-ril.so主要负责跟Modem硬件通信,这样的设计可以方便适配更多不同的Modem。它转换来自libril.so的请求为AT命令,同时监控Modem的反馈信息,并传递回libril.so。在初始化时, rild通过符号RIL_Init获取一组函数指针并以此与之建立联系。atchannels负责处理提交的at commnd, 并通过串口发送给modem, 以及使用reader-loop循环监控串口modem上报的信息。

4.1 RIL Key File Description

rild.c

rild.c 为RILD 的入口,负责初始化事件循环(libril.so),启动关联modem的串口监听(librefrence_ril.so),注册socket监听。

init event loop. 使用ril.cpp 中的RIL_startEventLoop 方法。ril_event_init完成后,通过ril_event_set来配置一新ril_event,并通过ril_event_add加入队列之中(实际通常用rilEventAddWakeup来添加),add会把队列里所有ril_event的fd,放入一个fd集合readFds中。这样 ril_event_loop能通过一个多路复用I/O的机制(select)来等待这些fd,如果任何一个fd有数据写入,则进入分析流程processTimeouts(),processReadReadies(&rfds, n),fire Pending()。并且我们可以看到,在进入ril_event_loop之前,已经挂入了一s_wakeupfd_event,通过pipe的机制实现,这个event的目的是可以在一些情况下,能内部唤醒ril_event_loop的多路复用阻塞,比如一些带timeout的命令timeout到期的时候。

start serial port. 通过动态加载动态库的方式执行reference-ril.c(reference-ril.so)中的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。readerLoop 负责监听modem 发送过来的讯息。

Register socket. RIL_register(funcs);

由RIL_Init的返回RIL_RadioFunctions结构的指针。

typedef struct {

    int version;        /* set to RIL_VERSION */

    RIL_RequestFunc onRequest;

    RIL_RadioStateRequest onStateRequest;

    RIL_Supports supports;

    RIL_Cancel onCancel;

    RIL_GetVersion getVersion;

} RIL_RadioFunctions;

其中最重要的是onRequest域,上层来的请求都由这个函数进行映射后转换成对应的AT命令发给硬件。rild通过RIL_register注册这一指针。

RIL_register中要完成的另外一个任务,就是打开前面提到的跟上层通信的socket接口(s_fdListen是主接口,s_fdDebug供调试时使用)。

然后将这两个socket接口使用任务一中实现的机制进行注册(仅列出s_fdListen)ril_event_set (&s_listen_event, s_fdListen, false, listenCallback, NULL);

rilEventAddWakeup (&s_listen_event);

这样将两个socket加到任务一中建立起来多路复用I/O的检查句柄集合中,一旦有上层来的(调试)请求,event机制便能响应处理了。

reference-ril .c & atchannel.c

hardware/ril/reference-ril 包中的两个主体文件,同时也是Android 实现电话功能的两个主体文件,这个库必须实现的是一个名称为RIL_Init的函数,这个函数执行的结果是返回一个RIL_RadioFunctions结构体的指针,指针指向函数指针。即整个库的入口,这个库在执行的过程中需要创建一个线程来执行实际的功能。在执行的过程中,这个库将打开一个/dev/ttySXXX的终端,然后利用这个终端控制硬件执行。

在rild.c 中使用RIL_Init 获取的RIL_RadioFunctions, 实际为reference_ril.c 中的s_callbacks。

关键的入口方法有:

static void onRequest (int request, void *data, size_t datalen, RIL_Token t); reference-ril 的入口函数。

关键的出口方法有:

static void onUnsolicited (const char *s, const char *sms_pdu); 执行URC类型的响应。

static void handleFinalResponse(const char *line); 执行非URC类型的响应,激活s_commandcond 信号,使send_command_xxxx方法返回,从而导致onRequest返回。

libril.so动态库

libril.so库的目录是:hardware/ril/libril  

其中主要的文件为ril.cpp.

RIL_startEventLoop(void);  

void RIL_setcallbacks (const RIL_RadioFunctions *callbacks);  

RIL_register (const RIL_RadioFunctions *callbacks);  

RIL_onRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen);

void RIL_onUnsolicitedResponse(int unsolResponse, void *data,   size_t datalen);  

RIL_requestTimedCallback (RIL_TimedCallback callback, void *param,   const struct timeval *relativeTime);  

这些函数也是被rild守护进程调用的,不同的vendor可以通过自己的方式实现这几个接口,这样可以保证RIL可以在不同系统的移植。其中 RIL_register()函数把外部的RIL_RadioFunctions结构体注册到这个库之中,在恰当的时候调用相应的函数。在Android 电话功能执行的过程中,这个库处理了一些将请求转换成字符串的功能。

RIL_startEventLoop 将启动整个的Event-loop。

RIL_onRequestComplete 当reference-ril执行onRequest完毕后,将执行,把对应的结果返回给上层。

RIL_onUnsolicitedResponse 当reference-ril 执行URC 类型的响应完毕后,将对应的结果返回给上层。

RIL_requestTimedCallback 注入一个新的timer-event到event-loop中。

5、RILD init Flow

RILD初始化过程主要是创建3个主要的线程,readerLoop, mainLoop, EventLoop.如下图所示:

图1.6

1、  在RILD主线程中首先在函数RIL_startEventLoop()启动eventLoop线程然后wait,在eventLoop中初始化主要是初始化ril_event链表timer_list和pending_list,以及ril_event指针数据watch_table,然后添加wakeup event事件到watch_table.

2、  创建mainLoop,在mainLoop中主要是创建readerLoop,然后注册初始化回调函数initializeCallback(),这个函数会被作为一个timeout event添加到timer_list中,当对应的timer到达时进行回调,做一系列的初始化动作,主要向modem下大量的AT Command,初始化SIM卡以及modem。

3、  readerLoop主要是用来循环读取来自modem的message,然后处理判断进行分发。

4、  在主线程后半部分回去向watch_table添加两个EVENT,一个是和RILJ连接的socket fd event,一个用来在命令行(即adb)进行调试的socket连接fd event。

以上各thread在后面都将详细介绍。

6、Event-Loop

Rild管理的真正精髓在ril.cpp,ril_event.cpp中

Event对象定义如下:

struct ril_event {

          struct ril_event *next;

          struct ril_event *prev;

          int fd;               //文件描述符,要添加到fdset集合,select函数用到

          int index;   //watch_table数组的索引,用于清空该数字对应的元素

          bool persist;  //指示该event在触发后是否需要移除watch_table

          struct timeval timeout;  //计时器触发时间,微妙级

         ril_event_cb func;   //事件触发时的回调函数

          void *param;  //以上回调函数的参数

};

通过next和prev组合成Event-Loop.

 fd: 事件相关设备句柄。例如对于串口数据事件,fd就是相关串口的设备句柄。

 index: 为watch_table中的索引,当不在watch_table 中时为-1。

 persist: 是否在watch_table中保持,如果是保持的,则不从watch_table中删除.

 func: 事件回调处理函数.

 param: 回调时处理函数的参数.

为了统一管理事件处理࿰

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值