RILC

RIL层的作用大体上就是将上层的命令转换成相应的AT指令,控制modem工作。生产modem的厂家有很多:Qualcomm, STE, Infineon... 不同的厂家都有各自的特点,当然也会有各自不同的驱动,但驱动代码的公开多少会涉及到modem厂家的技术细节,所以,Android系统开源了绝大部分代码,对于 部分驱动(Reference-RIL)  允许厂家以二进制Lib的形式成为一套完整Android系统的一部分。

  有Lib就需要有加载的概念,能够加载各种驱动说明驱动们都遵从一个统一的接口。这个接口是什么?RILC又是如何接收并处理RILJ向下传来的请求?


  

  进入hardware\ril\rild\rild.c,一切从main开始。

int main(int argc, char **argv)
{
... ... dlHandle = dlopen(rilLibPath, RTLD_NOW);
if (dlHandle == NULL) {
fprintf(stderr, "dlopen failed: %s\n", dlerror());
exit(-1);
} RIL_startEventLoop(); // ril_event rilInit = (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))dlsym(dlHandle, "RIL_Init");
if (rilInit == NULL) {
fprintf(stderr, "RIL_Init not defined or exported in %s\n", rilLibPath);
exit(-1); }
... ... funcs = rilInit(&s_rilEnv, argc, rilArgv); // Reference-RIL 获得 LibRIL 的Interface

RIL_register
(funcs); // LibRIL 获得 Reference-RIL 的Interface }

  从dlopen看到了动态加载的痕迹,加载Reference-RIL之后便启动了监听线程,也就在RIL_startEventLoop。每一次从上层传来的请求都是一个event,可见要了解该层的消息传输,关键是要了解  结构体 ril_event

  与其相关的文件是ril_event.h、ril_event.cpp,对于文件的分析还是引用ACE1985兄台的博文为好,抱拳为敬。

 

ril_event.h

 

ril_event.c

 

若干ril_event构成watch_table数组,同时也被两个双向链表timer_list、pending_list串起来,不禁想起了内核链表。select对watch_table数组上的ril_event们进行监听。

RILJ与RILC通过socket连接,前者为client,后者为server。

  server通过select监听对外开放的socket端口fd,若RILJ请求连接,则回调listenCallback(),accept()出一个s_fdCommand,加入select监听数组,这个s_fdCommand便成为了上层传入请求的通道,RILC通过这个通道接收具体的command,而后转化为AT指令。

static struct ril_event s_commands_event;
static struct ril_event s_wakeupfd_event;
static struct ril_event s_listen_event;
static struct ril_event s_wake_timeout_event;
static struct ril_event s_debug_event;

  以上便是大致的思路,select+socket连接的经典模式。通道打通后,从s_fdCommand中到底会接收到什么?

ril_event_set (&s_commands_event, s_fdCommand, 1,
processCommandsCallback, p_rs);

  

  函数层层嵌套,终会有一个办实事的命令。

static int
processCommandBuffer
(void *buffer, size_t buflen) {
Parcel p;
status_t status;
int32_t request;
int32_t token;
RequestInfo *pRI; //构造该结构体,尤其是其中的pCI
int ret; p.setData((uint8_t *) buffer, buflen); //获得有效p // status checked at end
status = p.readInt32(&request); //取得request值
status = p.readInt32 (&token); if (status != NO_ERROR) {
LOGE("invalid request block");
return 0;
} if (request < 1 || request >= (int32_t)NUM_ELEMS(s_commands)) {
LOGE("unsupported request code %d token %d", request, token);
// FIXME this should perhaps return a response
return 0;
} pRI = (RequestInfo *)calloc(1, sizeof(RequestInfo)); pRI->token = token;
pRI->pCI = &(s_commands[request]); //确定早已待命的command号 ret = pthread_mutex_lock(&s_pendingRequestsMutex);
assert (ret == 0); pRI->p_next = s_pendingRequests;
s_pendingRequests = pRI; ret = pthread_mutex_unlock(&s_pendingRequestsMutex);
assert (ret == 0); /* sLastDispatchedToken = token; */ pRI->pCI->dispatchFunction(p, pRI); //命令,发射! return 0;
}

  Ok,这个办实事的命令就是s_comands数组第request个结构体中的dispatchFunction().

  s_comands数组是个啥?

static CommandInfo s_commands[] = {
#include "ril_commands.h"
}; typedef struct {
    int requestNumber;
    void (*dispatchFunction) (Parcel &p, struct RequestInfo *pRI);
    int (*responseFunction) (Parcel &p, void *response, size_t responselen);
} CommandInfo;

  

  Ref: http://blog.csdn.net/ace1985/article/details/7051522

 

RIL中有两种Response类型:

一是Solicited Response(经过请求的回复),应用的场景是AP主动向BP发送一个AT指令,请求BP进行相应处理并在处理结束时回复一个AT指令通知AP执行的结果。源码中对应的文件是ril_commands.h。

一是Unsolicited Response(未经请求的回复),应用场景是BP主动向AP发送AT指令,用于通知AP当前系统发生的与Telephony相关的事件,例如网络信号变化,有电话呼入等。源码中对应的文件是ril_unsol_commands.h。

static UnsolResponseInfo s_unsolResponses[] = {
#include "ril_unsol_commands.h"
}; typedef struct {
int requestNumber;
int (*responseFunction) (Parcel &p, void *response, size_t responselen);
WakeType wakeType;
} UnsolResponseInfo;

  面对这上百的s_command元素们,顿觉代码的流程并非难点,难在对每一个s_command的理解。

  Ref:hardware\ril\include\telephony\Ril.h

 

打电话,则调用的是:

{RIL_REQUEST_DIAL, dispatchDial, responseVoid},

看来dispatchDial才是办实事的好同志,而dispatchDial中最终调用了s_callbacks,即之前通过 RIL_register(funcs),LibRIL 获得 Reference-RIL 的Interface 。

s_callbacks.onRequest(pRI->pCI->requestNumber, &dial, sizeOfDial, pRI);

至此,终于进入了Reference-RIL。

中场休息,做个简单的回顾:

1. 我们构造了RequestInfo,pCI指向了对应的s_commands:

typedef struct RequestInfo {
int32_t token; //this is not RIL_Token
CommandInfo *pCI;
struct RequestInfo *p_next;
char cancelled;
char local; // responses to local commands do not go back to command process
} RequestInfo;

  2. CommandInfo中的dispatchFunction最终调用了Reference-RIL提供的接口。

typedef struct {
int requestNumber;
void (*dispatchFunction) (Parcel &p, struct RequestInfo *pRI);
int(*responseFunction) (Parcel &p, void *response, size_t responselen);
} CommandInfo;

3. RIL_RadioFunctions 便是RIL对Reference-RIL的实现要求。

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;

4. onRequest 根据request号做出对应的处理,也就是ril_commands.h。

/**
* RIL_Request Function pointer
*
* @param request is one of RIL_REQUEST_*
* @param data is pointer to data defined for that RIL_REQUEST_*
* data is owned by caller, and should not be modified or freed by callee
* @param t should be used in subsequent call to RIL_onResponse
* @param datalen the length of data
*
*/
typedef void (*RIL_RequestFunc) (int request, void *data,
size_t datalen, RIL_Token t);

RIL_RadioFunctions需要实现ril_commands.h中定义的request,当然,不一定全部支持。

  

  OK,继续 dialing...

case RIL_REQUEST_DIAL:
requestDial(data, datalen, t);

终于要见到AT的影子:

static void requestDial(void *data, size_t datalen, RIL_Token t)
{
RIL_Dial *p_dial;
char *cmd;
const char *clir;
int ret; p_dial = (RIL_Dial *)data; switch (p_dial->clir) {
case 1: clir = "I"; break; /*invocation*/
case 2: clir = "i"; break; /*suppression*/
default:
case 0: clir = ""; break; /*subscription default*/
} asprintf(&cmd, "ATD%s%s;", p_dial->address, clir); ret = at_send_command(cmd, NULL); free(cmd); /* success or failure is ignored by the upper layer here.
it will call GET_CURRENT_CALLS and determine success that way */
RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
}

  之后的事情便是将AT string通过某种通道发送给BP。至于这个通道的建立,可能是串口也可能是其他,但最终都会表现为一个文件描述符,这就是 rilInit 的事儿了。

以上便是基于Dial的流程浏览,到这一层,重点还是对ril_commands.h, ril_unsol_commands.h的理解,"得此二物者得RIL"!

NEXT, LET'S GO INTO BP.

 
 
分类: Communication

RILC的更多相关文章

  1. Communication - 03.RILC

    RIL层的作用大体上就是将上层的命令转换成相应的AT指令,控制modem工作.生产modem的厂家有很多:Qualcomm, STE, Infineon... 不同的厂家都有各自的特点,当然也会有各自 ...

  2. Android 7.0 UICC 分析(一)

    UICC(Universal Intergrated Circuit Card) 框架 * Following is class diagram for uicc classes: * * UiccC ...

  3. [Code::Blocks] Install wxWidgets & openCV

    The open source, cross platform, free C++ IDE. Code::Blocks is a free C++ IDE built to meet the most ...

  4. Windows Thin PC 激活方法

    Windows Thin PC 激活方法 笔者之前分享了Windows Thin PC ,如果你已经安装了Windows Thin PC ,但还没有激活,可以参照以下方式进行Windows Thin ...

  5. 说Win7激活

    今天晚上给电脑来了个强制关机,后来打开后提示我,该Windos不是正版,顿时无语.诺,看下图:我的桌面也全部变成黑色了…… 后来一想……哦,应该是我的安装光盘里的激活工具激活的不彻底,或者说只是给我激 ...

  6. win7旗舰版通知windows不是正版副本解决方法

    原文转载http://www.cnblogs.com/simple_666/archive/2013/04/13/win7%E6%97%97%E8%88%B0%E7%89%88%E9%80%9A%E7 ...

  7. Android4.0(Phone)来电过程分析

    在开机时.系统会启动PhoneApp类,那是由于在AndroidManifest.xml文件里配置了 <application android:name="PhoneApp" ...

  8. Android RIL Log

    转载: 要调试 RIL,最好的方法就是打开 radio的log: $ adb logcat -b radio 最好加上 log语法亮度工具coloredlogcat.py ,一些常见的LOG TAG要 ...

  9. Logcat过滤及常见用法整理

    Usage: logcat [options] [filterspecs] options include:-s              Set default filter to silent.  ...

随机推荐

  1. 各种oracle参数查询语句

    各种oracle参数查询语句 1.show parameter:--显示各个系统参数配置 2.select * from v$parameter;--显示各个系统参数配置 2.show paramet ...

  2. jQuery UI dialog 參数说明

    前段时间碰到个问题 jquery UI dialog弹出层 弹出多个层是 比方弹出两个层A和B  B层假设显示的数据表格太大,伸到了A层的外面,那伸到A层之外的部分就看不到了,由于B层是在A层上弹出的 ...

  3. 基于OCR的SeeTest框架可行性分析总结

    总的来说相比其他几个免费框架,SeeTest功能更全面和易用,但收费有点昂贵:License 3500/年:多平台和多语言(基于OCR)还需要额外购买,分别是500/Year和1750$/.详情请查看 ...

  4. jQuery多文件

    jQuery多文件下载 文件下载是一个Web中非常常用的功能,不过你是做内部管理系统还是做面向公众的互联网公司都会遇到这个问题,对于下载一般有点实际开发经验的都会自己解决,上周弄了一下多文件下载,业务 ...

  5. OCP-1Z0-051-题目解析-第7题

    7. Which two  statements are true regarding the USING and ON clauses in table joins? (Choose two.) A ...

  6. 打印man手册为pdf文件

    只需要一个命令就可以了! merlin@tfAnalysis:~/projects/tfadc$ man -t errno | ps2pdf - ~/errno.pdf 输出的文件很漂亮.

  7. leetcode第11题--Container With Most Water

    Problem: Given n non-negative integers a1, a2, ..., an, where each represents a point at coordinate ...

  8. Zend Server更新至6.2版本——虚拟主机全方位管理

    Zend Server自从发布6.0以来,并支持云服务,成为很多PHP程序所选择的Web服务器. Zend Server 6.2版本从更新内容来看,解决了Web服务器与虚拟主机之间的协同管理.并在细节 ...

  9. C#发送邮件三种方法(Localhost,SMTP,SSL-SMTP)

    原文:C#发送邮件三种方法(Localhost,SMTP,SSL-SMTP) 最近公司由于一个R&I项目的需要,用户要求在购买产品或出货等一些环节,需要发送邮件提醒或者说每周一让系统自动采集数 ...

  10. oracle中sql语句的优化

    oracle中sql语句的优化 一.执行顺序及优化细则 1.表名顺序优化 (1) 基础表放下面,当两表进行关联时数据量少的表的表名放右边表或视图: Student_info   (30000条数据)D ...