Android通讯之RIL 机制分析
来源:互联网 发布:淘宝女装背景 编辑:程序博客网 时间:2024/06/01 08:46
Android的Radio Interface Layer (RIL)提供了电话服务和的radio硬件之间的抽象层。
Radio Interface Layer RIL(Radio Interface Layer)负责数据的可靠传输、AT命令的发送以及response的解析。应用处理器通过AT命令集与带GPRS功能的无线通讯模块通信。
AT command由Hayes公司发明,是一个调制解调器制造商采用的一个调制解调器命令语言,每条命令以字母"AT"开头。
JAVA Framework
代码的路径为:
frameworks/base/telephony/java/android/telephony android.telephony以及android.telephony.gsm
Core native:在hardware/ril目录中,提供了对RIL支持的本地代码,包括4个文件夹:
hardware/ril/include hardware/ril/libril hardware/ril/reference-ril hardware/ril/rild
kernel Driver
在Linux内核的驱动中,提供了相关的驱动程序的支持,可以建立在UART或者SDIO,USB等高速的串行总线上。
第二部分 电话功能各个部分
hardware/ril/include/telephony/目录中的ril.h文件是ril部分的基础头文件。
其中定义的结构体RIL_RadioFunctions如下所示:
typedefstruct { int version; RIL_RequestFunc onRequest; RIL_RadioStateRequest onStateRequest; RIL_Supports supports; RIL_Cancel onCancel; RIL_GetVersion getVersion;} RIL_RadioFunctions;
RIL_RadioFunctions中包含了几个函数指针的结构体,这实际上是一个移植层的接口,下层的库实现后,由rild守护进程得到这些函数指针,执行对应的函数。
几个函数指针的原型为:
typedef void(*RIL_RequestFunc) (int request, void *data, size_t datalen, RIL_Token t);typedef RIL_RadioState (*RIL_RadioStateRequest)();typedef int (*RIL_Supports)(int requestCode);typedef void (*RIL_Cancel)(RIL_Token t);typedef const char * (*RIL_GetVersion) (void);
其中最为重要的函数是onRequest(),它是一个请求执行的函数。2.1 rild守护进程
rild 守护进程的文件包含在hardware/ril/rild目录中,其中包含了rild.c和radiooptions.c两个文件,这个目录中的文件经过编译后生成一个可执行程序,这个程序在系统的安装路径在:
/system/bin/rild
rild.c是这个守护进程的入口,它具有一个主函数的入口main,执行的过程是将请求转换成AT命令的字符串,给下层的硬件执行。在运行过程 中,使用dlopen 打开路径为/system/lib/中名称为libreference-ril.so的动态库,然后从中取出 RIL_Init符号来运行。
RIL_Init符号是一个函数指针,执行这个函数后,返回的是一个RIL_RadioFunctions类型的指针。得到这个指针后,调用RIL_register()函数,将这个指针注册到libril库之中,然后进入循环。
事实上,这个守护进程提供了一个申请处理的框架,而具体的功能都是在libril.so和libreference-ril.so中完成的。
2.2libreference-ril.so动态库
libreference-ril.so动态库的路径是:
hardware/ril/reference-ril
其中主要的文件是reference-ril.c和atchannel.c。这个库必须实现的是一个名称为RIL_Init的函数,这个函数执行的结果是返回一个RIL_RadioFunctions结构体的指针,指针指向函数指针。
这个库在执行的过程中需要创建一个线程来执行实际的功能。在执行的过程中,这个库将打开一个/dev/ttySXXX的终端(终端的名字是从上层传入的),然后利用这个终端控制硬件执行。
2.3 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_tresponselen);void RIL_onUnsolicitedResponse(int unsolResponse, void *data, size_tdatalen);RIL_requestTimedCallback (RIL_TimedCallback callback, void *param, conststruct timeval *relativeTime);
这些函数也是被rild守护进程调用的,不同的vendor可以通过自己的方式实现这几个接口,这样可以保证RIL可以在不同系统的移植。其中 RIL_register()函数把外部的RIL_RadioFunctions结构体注册到这个库之中,在恰当的时候调用相应的函数。在执行的过程中, 这个库处理了一些将请求转换成字符串的功能。1.
ITelephony接口和ISms接口以及AIDL 在我们的Android应用中,当需要实现电话拨号时,我们需要进行如下调用 ITelephony phone =(ITelephony)ITelephony.Stub.asInterface(ServiceManager.getService("phon")) phone.dial("10086"); 对于短信应用,我们需要的是调用SmsManager,代码如下 SmsManager manager = SmsManager.getDefault(); manager.sendTextMessage("10086",null,"hi,this issms",null,null); 这里,SmsManager对ISms做了一层包装,实质上是通过调用 ISms simISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); simISms.sendRawPdu....
可以看到,应用都是采用AIDL来实现IPC的跨进程调度。
对于AIDL应用,调用进程方存在的是一个实现接口的Proxy对象,通过Proxy对象与被调用进程中的Stub对象进行
通讯来实现IPC的跨进程调度,所以,在被调用进程一端必定有一个ITelephony.Stub类以及ISms.Stub类的实现
如下图所示
ITelephony.Stub 的实现类为com.android.phone.PhoneInterfaceManager
ISms.Stub的实现类为com.android.internal.telephony.gsm.SimSmsInterfaceManager
从这两个类的构造器的调用代码里可以很清楚的看到进行了Service的注册工作
ServiceManager.addService("phone",this);
ServiceManager.addService("isms",this);
3. PhoneApp,InCallScreen,PhoneUtils及其他相关类
从SimSmsInteferManager的相关方法实现中可以看到,具体就是调用GSMPhone的SmsDispatcher实例来进行相关操作的。
从PhoneInterfaceManager会维持一个Phone对象的引用,当拨号应用时,PhoneInterfaceManager会将构造好的Intent传递
给PhoneApp应用,该Intent的className指定则为InCallScreen,从中我们可以看到InCallScreen具体是通过PhoneUtils调用Phone的
相关方法来实现。
PhoneInterfaceManager怎么获取到对应的Phone对象,然后又怎么将Phone对象传递到InCallScreen中呢?
具体这里涉及到了PhoneApp这个类,从这个类维护了一个 PhoneInterfaceManager的引用(phoneMgr)以及一个Phone引用(phone),
从该类的onCreate方法中我们可以清楚的看到,PhoneApp通过PhoneFactory获取了一个Phone实例,并通过该实例实现了PhoneInterfaceManager对象。
因此,我们现在只需要关注PhoneFactory具体提供的是一个什么样的Phone实例了。
另外,PhoneApp类还提供了一个静态方法getInstance供InCallScreen调用,InCallScreen正是通过调用该方法获得PhoneApp实例从而
获得对应的Phone实例的。
接下来,我们通过查看PhoneFactory的方法可以看到,Phone对象对应的就是一个GSMPhone实例。对应的UML类图结构如下
4。GSMPhone与RIL
从GSM的构造器可以看出,他依赖一个CommandInterface接口实例,通过PhoneFactory的makeDefaultPhones方法,我们可以看到,根据系统环境变量
ro.radio.noril来判断是否需要采用RIL框架实现,如果该参数不为空,则采用Simultedcommands(主要是为了测试需要提供的模拟实现).否则,采用RIL。
通过Google才知道,RIL其实是智能手机上实现AP与BP之间通信的一种设计思想,具体大家可以参见这篇文章http://www.eetchina.com/ARTICLES/2006OCT/PDF/CPCOL_2006OCT26_EMB_TA_170.PDF?SOURCES=DOWNLOAD
在RIL.java 中我们很惊喜的看到,RIL对对消息的处理是将消息通过LocalSocket发送到以rild为名称的有名端口。这个有名Socket的创建在ril.cpp代码中。
s_fdListen = android_get_control_socket(SOCKET_NAME_RIL)
原来Android通话和发短信的应用是JAVA与C++代码之间透过Socket连接来传输消息来实现的。
整个应用的代码可以概括如下图示意
5.关于C代码与硬件之间的交互
这部分工作其实就是C代码通过串口发送AT指令来拨号,收发短信。今天有点累了,具体的实现下次我再分析。
当我们开始编写Android的电话应用程序的时候,如果需要进行电话拨号,可以进行如下调用:
ITelephony tpCallModule = (ITelephony)ITelephony.Stub.asInterface(ServiceManager.getService("phon"));tpCallModule.dial("13800138000");而对于短信的应用,我们需要调用的则是SmsManager:SmsManager SMS = SmsManager.getDefault();SMS.sendTextMessage("13420926323",null,"this is a testsms",null,null);Android采用RIL的架构跟底层GSM模块通讯.
上一张时序图吧
后续更新
- Android通讯之RIL 机制分析
- Android——RIL 机制源码分析
- Android——RIL 机制源码分析
- RIL 机制源码分析
- android电话部分之ril分析
- Android之通信RIL模块分析
- Android电话通信机制之一——RIL类分析
- android-ril 分析 -radiooption
- Android RIL源码分析
- Android RIL源码分析
- Android-RIL流程分析
- Android Ril 分析
- Android Ril 分析
- android ril 调试分析
- Android Ril 分析
- Android Ril 分析
- Android 时间更新机制之RIL更新时间
- android下调试3G之Ril库分析
- windows客户端性能测试之内存泄露检查工具umdh.exe
- Windows10+Python3.6下安装NumPy+SciPy+Matplotlib
- Docker 学习总结——云端基于Docker的微服务与持续交付实践
- 基于XC7K325T光纤传输的PCIE光纤卡、2路光纤的资料
- 指针详解(下)
- Android通讯之RIL 机制分析
- slf4j框架日志记录
- MySQL 报错:5.7版本sql_mode=only_full_group_by问题
- PS轻松制作GIF动态图
- java值传递
- 基于Webrtc的多人视频会议的简单实现
- MyBatis JdbcType 与Oracle、MySql数据类型对应关系详解
- 一个优秀的人的标志和特点 ---俞敏洪公司内部讲话
- jquery实现懒加载