2019独角兽企业重金招聘Python工程师标准>>>

一、概述

关于RILD的功能,就不多说了,对上服务于Phone进程,也可以认为是RILJ层,向下同modem层进行通信,对MTK平台来说就是使用AT命令了。

二、RILD的架构

RILD主要由三部分组成,一个是rild.c,第二个是libril这个库(对于MTK来说就是librilmtk),第三个是厂商关于实现同modem进行通信的reference-ril库,对于MTK来说就是mtk-ril。出于保护第三方厂商利益的考虑,这个库是在rild运行的时候动态加载进去的,由于运行在同一个进程中,所以rild同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_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.c

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 VDBGRLOGD("dispatchSIM_IO");
#endifmemset (&simIO, 0, sizeof(simIO));// note we only check status at the endstatus = 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卡相关的上层消息分配

三、关于RILD的启动

n之前的平台就不说了,网上一搜一大堆,都是在init.rc中启动的,但是Android N之后由于init.rc启动脚本的改动很多deamon程序一下找不到了,以下都是基于mtk 6737n平台的源码为基准的

寻找n平台rild启动入口

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

四、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 errorril_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_setmemcpy(&rfds, &readFds, sizeof(fd_set));if (-1 == calcNextTimeout(&tv)) {// no pending timers; block indefinitelydlog("~~~~ 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 socket1for (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
#endifRIL_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以后在子进程的返回中会创建socketif (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的消息后调用的是listenCallbackrilEventAddWakeup (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处理,而这个函数又会调用到processClientCommandBufferrilEventAddWakeup (p_info->commands_event);

#ifdef MTK_RIL{enqueue(pRI, buffer, buflen, NULL, socket_id);}
#elsepRI->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

转载于:https://my.oschina.net/u/2829875/blog/853680

MTK 6737平台RILD的实现相关推荐

  1. MTK 驱动(73)---MTK 6761平台 android O bootloader启动之 Pre-loader -amp;gt; Lk

    MTK 6761平台 android O bootloader启动之 Pre-loader -> Lk 1.bootloader到kernel启动总逻辑流程图 ARM架构中,EL0/EL1是必须 ...

  2. MTK旧平台与RDA8851开机详解

    MTK6261D旧平台与RDA8851开机详解.注意,MTK新平台框架已经变了,所以开机流程与下面的有差异! L4是MMI/AT和协议栈的适配层. ATCI是AT命令解析器. UEM是用于抽象如键盘. ...

  3. MTK芯片平台,MT6737烧录工具资料(SP_Flash_Tool_exe_Windows_v5.1712.00.000)

    MTK芯片平台,MT6737烧录工具资料分享,希望能对开发者有所帮助. 资料下载,可到我的下载资源界面下载,也可点击下载(MT6737) 另外,附送 一份MT6737的规格书资料----MT6737 ...

  4. MTK智能平台分区解析

    MTK智能平台分区解析 MTK手机内置4G存储,它是如何分配的? 有些买家看到手机内置存储卡大小连2G都不到,就开始咆哮了:"不是说4G ROM吗???"现在就让我帮你算算这标称的 ...

  5. 关于ASoC中的aux设备及prefix(基于MTK mt6799 平台)

    关于ASoC中的aux设备及prefix(基于MTK mt6799 平台) tags : audio 文章目录 关于ASoC中的aux设备及prefix(基于MTK mt6799 平台) 1 前言 最 ...

  6. MTK手机平台添加资源和菜单的方式

    MTK手机平台添加资源和菜单的方式 一. 菜单的修改或增加: 以一个例子的方式介绍如何添加一个菜单,例子如下:       在主菜单的"设置"菜单下增加一个"我的设定&q ...

  7. MTK 智能机平台系统文件夹文件详解

    MTK6573智能机平台系统文件夹文件详解3 - App目录 欢迎转载收藏,转载请保留如下信息: Mr.ROM出品 Email: iammrrom@gmail.com Blog: http://blo ...

  8. mtk android平台学习,MTK平台的驱动学习——(阶段1规划篇)

    受老罗的影响,由于本人还是菜鸟,不能像老罗一样重头开始研究整个系统,决定从就近的工作开始,从android MTK 的驱动-->中间层-->应用层,一步一步研究. 一边看书,一边搜集网上的 ...

  9. ISP处理流程和MTK历代平台划分

    目录 ISP 处理流程: MTK平台划分: 平台算法差异: ISP 处理流程: Bayer.黑电平补偿 (black level compensation).镜头矫正(lens shading cor ...

  10. MTK驱动---平台待机功耗分析流程

    1.目的 2.MTK平台各个场景功耗数据测试方法 很多功耗问题都是因为测试手法不对,列出一些常用场景功耗测试手法.  测试功耗数据之前,请先确认以下配置:  1.关闭 WIFI/BT/GPS,关闭数据 ...

最新文章

  1. 共享一个对Reflector 反编译支持中文的修正FileGenerator文件
  2. 单片机while用法c语言例子,51单片机-C语言之while(!x)的理解
  3. html下拉列表用ul,Vue.js做select下拉列表的实例(ul-li标签仿select标签)
  4. 小程序triggerevent 传参_微信小程序——无限递归的层次列表
  5. VS2010中不可忽视的部分——VSTO
  6. 11条建议让你成为优秀的JavaScript程序员
  7. 可变化的鸿蒙武器,DNF2018史诗改版大全 武器套装改版属性介绍
  8. Spring笔记02(3种加载配置文件的方式)
  9. java计算两列数据差_DAX计算列基于其他表中的两列
  10. java 强类型 弱类型_强类型,弱类型,静态类型,动态类型的区别
  11. 1004. 成绩排名 (20)-PAT乙级真题
  12. mysql的备份与恢复_实验十一 MySQLl备份与恢复1
  13. 【优化分类】基于matlab遗传算法结合爬山算法优化极限学习机分类【含Matlab源码 1660期】
  14. vSphere ESXI 详细安装教程
  15. 推荐几款不错的企业网站,前端设计师寻求设计灵感!
  16. 逻辑斯谛回归(logistic regression)
  17. 简单控件学习——Lable/HyperLink
  18. Linux 使用ffmpeg修改和压缩视频文件格式
  19. 数据结构(C)必会知识点+易错点:数组和广义表(n维数组地址计算公式,特殊矩阵对称矩阵的存储,广义表的表示方法)
  20. python编程的缩进什么意思_编程缩进是什么意思

热门文章

  1. HDU - 6438 Buy and Resell (贪心 + 优先队列)
  2. 假设一张纸的厚度是1mm,那么这张纸折叠多少次可以到达珠穆朗玛峰的高度(8848m)?
  3. 交换机端口与MAC绑定
  4. bind peeking--绑定变量窥视
  5. Oracle 绑定变量窥视
  6. CSAPP-Architecture lab
  7. make[1]: *** Waiting for unfinished jobs....
  8. 单片机测量脉宽c语言程序,利用51系列单片机定时器功能实现测量脉冲宽度
  9. c语言case后面,switch语句case后面的范围怎么写
  10. java中英文字幕和_为了边看美剧边学英语,我写了个字幕处理脚本