Android中RIL层详细分析

上传人:痛*** 文档编号:62335940 上传时间:2022-03-14 格式:DOC 页数:107 大小:647.50KB
收藏 版权申诉 举报 下载
Android中RIL层详细分析_第1页
第1页 / 共107页
Android中RIL层详细分析_第2页
第2页 / 共107页
Android中RIL层详细分析_第3页
第3页 / 共107页
资源描述:

《Android中RIL层详细分析》由会员分享,可在线阅读,更多相关《Android中RIL层详细分析(107页珍藏版)》请在装配图网上搜索。

1、Android的电话功能介绍整个RIL文件夹的分析介绍本文档对Android RIL部分的内容进行了介绍,其重点放在了Android RIL的原生代码部分。包括四个主题:1.Android RIL框架介绍2.Android RIL与WindowsMobile RIL3.Android RIL porting4.Android RIL的java框架在本文档中将Android代码中的重要模块列出进行分析,并给出了相关的程序执行流程介绍,以加深对模块间交互方式的理解。对于java代码部分,这里仅进行简单的介绍。如果需要深入了解,可以查看相关参考资料。本文档中还对Android RIL的Porting

2、部分内容进行了描述和分析。针对对unix操作系统环境并不熟悉的读者,本文档中所涉及到的相关知识包括: Unix file system Unix socket Unix thread Unix下I/O多路转接以上信息可以在任意一份描述Unix系统调用的文档中找到。1.Android RIL框架介绍术语:fd Linux文件描述符pipe Linux管道cond 一般是condition variable的缩写tty 通常使用tty来简称各种类型的终端设备unsolicited response 被动请求命令来自basebandevent loop android的消息队列机制,由Linux的系

3、统调用select()实现init.rc init守护进程启动后被执行的启动脚本。HAL 硬件抽象层(Hardware Abstraction Layer,HAL)1.1 Android RIL概况Android RIL提供了无线硬件设备与电话服务之间的抽象层。下图展示了RIL在Android体系中的位置。推荐精选android的ril位于应用程序框架与内核之间,分成了两个部分,一个部分是rild,它负责socket与应用程序框架进行通信。另外一个部分是Vendor RIL,这个部分负责向下是通过两种方式与radio进行通信,它们是直接与radio通信的AT指令通道和用于传输包数据的通道,数据

4、通道用于手机的上网功能。对于RIL的java框架部分,也被分成了两个部分,一个是RIL模块,这个模块主要用于与下层的rild进行通信,另外一个是Phone模块,这个模块直接暴露电话功能接口给应用开发用户,供他们调用以进行电话功能的实现。1.2 Android RIL目录结构Android的RIL模块位于Android/hardware/ril文件夹,有三个子模块:rild , libril , reference-ril所在目录结构:/hardware/ril/|- ril (无线电抽象层)| |- include (头文件)| |- libril (库)| |- reference-cdma

5、-sms (cdma短信参考)| |- reference-ril (ril参考)| |- rild (ril后台服务程序)hardware/ril$ ls推荐精选includelibrilreference-cdma-smsreference-rilrild1.hardware/ril/rild$ lsAndroid.mk MODULE_LICENSE_APACHE2 NOTICEradiooptions.crild.c2.hardware/ril/include/telephony$ lsril_cdma_sms.hril.h3.hardware/ril/libril$ lsAndroid

6、.mk NOTICEril_event.hril.cppril_event.cpp ril_commands.hril_unsol_commands.hMODULE_LICENSE_APACHE24.hardware/ril/reference-cdma-sms$ lsAndroid.mk reference-cdma-sms.c reference-cdma-sms.h5.hardware/ril/reference-ril$ lsAndroid.mk atchannel.h at_tok.h misc.h NOTICEatchannel.cat_tok.cril_event.hrefere

7、nce-ril.c misc.c MODULE_LICENSE_APACHE2include文件夹:包含RIL头文件,最主要的是ril.hrild文件夹:RIL守护进程,开机时被init守护进程调用启动,里面仅有main函数作为入口点,负责完成RIL初始化工作。在rild.c文件中,将完成ril的加载过程,它会执行如下操作:动态加载Vendor RIL的.so文件执行RIL_startEventLoop()开启消息队列以进行事件监听通过执行Vendor RIL的rilInit()方法来进行Vendor RIL与libril的关系建立。在rild文件夹中还包括一个radiooptions.c文件

8、,它的作用是通过串口将一些radio相关的参数直接传给rild来对radio进行配置。libril文件夹:在编译时libril被链入rild,它为rild提供了event处理功能,还提供了在rild与Vendor RIL之间传递请求和响应消息的能力。Libril提供的主要功能分布在两个主要方法内,一个是RIL_startEventLoop()方法,另一个是RIL_register()方法RIL_startEventLoop()方法所提供的功能就是启用eventLoop线程,开始执行RIL消息队列。RIL_register()方法的主要功能是启动名为 rild 的监听端口,等待java 端通过s

9、ocket进行连接。reference-ril文件夹:Android自带的Vendor RIL的参考实现。被编译成.so文件,由于本部分是厂商定制的重点所在。所以被设计为松散耦合,且可灵活配置的。在rild中通过opendl()的方式加载。librefrence.so负责直接与radio通信,这包括将来自libril的指令转换为AT指令,并且将AT指令写入radio中。推荐精选reference-ril会接收调用者传来的参数,参数内容为与radio的通信方式。如通过串口连接radio,那么参数为这种形式:-d /dev/ttySx1.3.Android RIL中的消息(event)队列机制 在

10、Android RIL中,为了达到等待多路输入并且不出现阻塞的目的,使用了IO多路复用机制。 如果使用阻塞I/O进行网络的读取写入,这意味着假如需要同时从两个网络文件描述符中读内容,那么如果读取操作在等待网络数据到来,这将可能很长时间阻塞在一个描述符上,另一个网络文件描述符不管有没有数据到来都无法被读取。一种解决方案是: 如果使用非阻塞I/O进行网络的读取写入,在读取其中一个网络文件描述符如果阻塞将直接返回,再读取另外一个,这种方式的循环被称之为轮询。轮询方式确实能解决进行多路io操作时的阻塞问题,但是这种方法的不足之处是反复的执行读写调用将浪费cpu时钟。I/O多路转接技术在这里提供了另一种

11、比较好的解决方案: 它会先构造一张有关I/O描述符的列表,然后调用select函数,当IO描述符列表中的一个描述符准备好进行I/O时,该函数返回,并告知可以读或写哪个描述符。 Android RIL中消息队列的核心实现思想就是这种I/O多路转接技术。消息队列机制的实现在ril_event.cpp中,其中被定义的ril_event结构是消息的主体。 每个ril_event结构,与一个fd句柄绑定(可以是文件,socket,管道等),并且带一个func指针,这个func指针所指的函数是个回调函数,它指定了当所绑定的fd准备好进行读取时所要进行的操作。 消息队列的开始点为RIL_startEvent

12、Loop函数。RIL_startEventLoop在ril.cpp中实现,它的主要目的是通过pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL)建立一个dispatch线程,线程入口点在eventLoop. 而在eventLoop中,会调ril_event.cpp中的ril_event_loop()函数,建立起消息队列机制。 ril_event是一个带有链表行为的struct,它最主要的成员一个是fd,一个是func:struct ril_event struct ril_event *next;struct ril_event *pr

13、ev;int fd;int index;bool persist;struct timeval timeout;ril_event_cb func;void *param; 初始化一个新ril_event的操作是通过ril_event_set()来完成的,并通过ril_event_add()加入到消息队列之中,add会把队列里所有ril_event的fd,放入一个fd集合readFds中。这样 ril_event_loop能通过一个多路复用I/O的机制(select)来等待这些fd。推荐精选在进入ril_event_loop()之前,在eventLoop中已经创建和挂入了s_wakeupfd_

14、event,它是通过pipe的机制实现的,这个管道fd的回调函数并没有实现什么功能,它的目的只是为了让select方法能返回一次,这样select()方法就能重新跟踪新加入事件队列的fd和timeout设置。所以在添加新fd到eventLoop时,往往不是直接调用ril_event_add,实际通常用rilEventAddWakeup来添加,这个方法除了会间接调用ril_event_add外,还会调用triggerEvLoop()函数来向s_fdWakeupWrite中写入一个空字符,这样select()函数会返回并重新执行,新加入的文件描述符便得以被select()加载并跟踪。如果在ril_

15、event队列中任何一个fd已经准备好,则进入分析流程:processTimeouts(),processReadReadies(&rfds, n),firePending()其中firePending()方法执行这个event的func,也就是回调函数。 在Android RIL初始化完成后,将有几个event被挂入到eventLoop中:1.s_listen_event:名为rild的socket,主要requeset & response通道2.s_debug_event:名为rild-debug的socket,调试用requeset & response通道3.s_wakeupfd_e

16、vent:无名管道,用于队列主动唤醒 这其中最为重要的event就是s_listen_event,它作为request与response的通道实现。在ril_event.cpp中还持有一个watch_table数组,一个timer_list链表和一个pending_list链表。watch_table数组的目的很单纯,存放当前被eventLoop等待的ril_event(非timer event),供eventLoop唤醒时使用。timer_list是存放timer event的链表,在eventLoop唤醒时要对这些timer event单独进行处理pending_list:待处理(对其回调

17、函数进行调用)的所有ril_event的链表。1.4.Android RIL中初始化流程分析Rild的初始化流程初始化流程从rild.c中的main函数开始,它被init守护进行调用执行:首先在main()函数内会首先通过dlopen()函数加载Vendor RIL(在自带的参考实现中为librefrence_ril.so)。接着调用RIL_startEventLoop()函数来启动消息队列机制。调用librefrence_ril.so的RIL_Init()函数来进行Vendor RIL的初始化。RIL_Init()函数执行后会返回一个RIL_RadioFunction结构体,这个结构体内最重

18、要的成员就是onRequest()方法。onRequest()方法会被dispatchFunction调用,也就是说dispatchFunction调用是程序流从rild转入Vendor RIL的分界点。RIL_register()函数将实现两个目地,一个是将RIL_INIT中获得的RIL_RadioFunction进行注册,rild通过此种方式保证自己持有一个RIL_RadioFunction实例,第二个是将s_fdListen加入到消息队列机制中,开启s_fdListen的事件监听。推荐精选Vendor RIL的初始化流程:RIL_Init被调用后首先通过参数获取硬件接口的设备文件或模拟硬

19、件接口的socket。(参见上文中对reference-ril文件夹的介绍)接下来是创建mainLoop线程,并跳入到线程内执行。mainLoop会建立起与硬件的通信,然后通过read方法阻塞等待硬件的主动上报或响应。mainLoop还会调用initlizeCallBack()函数来向radio发送一系列的AT命令来进行radio的初始化设置工作。1.5.Android RIL中request流程分析 上层应用开始向rild通过socket传输数据时,通过RIL消息队列机制,s_listen_event的回调函数listenCallBack将会被调用,开始进行数据流的分析与处理。接下来s_fd

20、Command = accept(s_fdListen, (sockaddr *) &peeraddr, &socklen),获取传入的socket描述符,也就是上层的java RIL传入的连接。然后,通过record_stream_new()建立起一个RecordStream, 将这个record_stream与s_fdCommand绑定, RecordStream实际上是一个用于存放数据的结构体,这个结构体提供了一些操作类来保证这个RecordStream所绑定的文件描述符被读取时里面的数据会被完整读取。一旦s_fdCommand中有数据,它的回调函数processCommandsCall

21、back()将会被调用,processCommandsCallback()通过record_stream_get_next阻塞读取s_fdCommand上发来的 数据, 直到收到一完整的request。然后将其传递进processCommandBuffer()函数,processCommandBuffer()正式进入了命令的解析部分。每个接收到的命令将以RequestInfo的形式存在。从socket过来的数据流,是Parcel处理过的序列化字节流, 在这里会通过反序列化的方法提取出来。最前面的是request号, 以及token域(request的递增序列号)。request号是一个Comm

22、andInfo,它在ril_command.h中定义。接下来, 这个RequestInfo会被挂入pending的request队列, 执行具体的dispatchFunction(), 进行详细解析。dispatchFunction方法有着多种实现,如dispatchVoid, dispatchString, 它们的调用取决于Parcel的参数传入形式。比如说在dispatchDial方法中,Parcel对象将被解析为RIL_Dial结构。这是disptachFunction的任务之一,它的另一个任务就是调用onRequest()方法,并将解析的内容传入onRequest()方法。从onReq

23、uest方法开始,程序控制流脱离了RILD,进入到了Vendor RIL中。onRequest方法会通过传入的请求类型来调用指定的request()方法,request()方法则负责组装AT指令并下发给at_send_command()方法集合中的一个,这个方法集合提供了针对不同类型AT指令的实现,如单行AT指令at_send_command_singleline(),短信息指令at_send_command_sms()等。最后,执行at_send_command_full(),再通过一个互斥的at_send_command_full_nolock()调用,完成最终的写出操作,在writeli

24、ne()中,写出到初始化时打开的设备中。需要注意的是:at_send_command_full_nolock()在将指令写入radio后并不会直接返回,而是通过条件变量等待响应信息,得到响应信息后会携带这些信息返回。具体流程可以参考下面的response流程分析。推荐精选1.6.Android RIL中response流程分析AT的response有两种,一种是unsolicited。另一种是普通response,也就是命令的响应。response信息的获取在readerLoop()中。由readline()函数读取上来。读取到的line将被传入processLine()函数进行解析,proc

25、essLine()函数首先会判断当前的响应是主动响应还是普通响应,如果是主动响应,将调用handleUnsolicited()函数,如果为普通响应,那么将调用handleFinalResponse()函数进行处理对响应串的主要的解析过程,由at_tok.c中的各种解析函数完成,提供字符串分析解析功能。对主动上报的解析 handleUnsolicited ()方法处理主动上报,它会调用onUnsolicited()来进行进一步的解析,这个函数在Vendor-RIL初始化时被传入at_open()函数,onUnsolicited只解析出头部(一般是+XXXX的形式),然后按类型决定下一步操作,操作

26、为 RIL_onUnsolicitedResponse和RIL_requestTimedCallback两种。在RIL_onUnsolicitedResponse()函数中,通过Parcel传递,将 RESPONSE_UNSOLICITED,unsolResponse(request号)写入Parcel,然后调用对应的responseFunction完成进一步的的解析,将解析的数据写入Parcel中,最后通过sendResponse()sendResponseRaw()blockingWrite()writeLine()将数据写回给与应用层通信的socket。在RIL_requestTimed

27、Callback()函数中。通过event机制实现的timer机制,回调对应的内部处理函数。通过internalRequestTimedCallback将回调添加到event循环,最终完成callback上挂的函数的回调。比如 pollSIMState,onPDPContextListChanged等回调, 不用返回上层,内部处理就可以。对普通上报的解析 IsFinalResponse()和isFinalResponseError()所处理的是一条AT指令的响应上报,它们将转入handleFinalResponse方法。 handleFinalResponse()函数会将所有响应信息装入sp_

28、response,这是一个ATResponse结构,它的成员包括成功与否(success)以及一个中间结果(p_intermediates)。handleFinalResponse()在将响应结果保存至sp_response后,设置s_commandcond这一条件变量,此条件变量由at_send_command_full_nolock等待。 at_send_command_full_nolock获得到了完整的响应信息(在sp_response中),便开始进行响应信息的处理,最后由RIL_onRequestComplete将响应数据序列化并通过sendResponse传递至与应用层通信的soc

29、ket,这一部分与RIL_onUnsolicitedResponse()函数的功能非常相似,请参考对主动上报的解析部分。2.Android RIL与WindowsMobile RIL Android RIL与WindowsMobile RIL 在设计思路上都是作为一个radio的抽象,为上层提供电话服务,但在实现方式上两者有着一定的差异,这种差异的产生主要是源自操作系统机制的不同。推荐精选Android RIL被实现为HAL,相对于windows mobile中被实现为驱动的方式,Android RIL模块的内聚性更为理想,可维护性也将更强,你也可以把Android Ril 看做一个中间件。A

30、ndroid RIL部分的开发工作,只需要拿到相应的radio文件描述符,就可以进行操作,无需关注radio的I/O驱动实现。2.1两者在与应用通信上的实现对比 WindowsMobile RIL在实现与应用的通信时提供了RIL Proxy,在这个层面中它定义了大量的RIL_*()函数来作为电话服务请求。这一点与Android RIL的实现比较相似,Android RIL中在ril.h内提供了一系列的宏来定义电话服务请求。在Android中的rild功能类似于windows mobile RIL的RIL proxy。它同样也是起到一个中介的作用,为上层接口向下传递请求,并上传回响应。在wind

31、ows mobile RIL中要为每一个应用程序客户提供一份Ril Proxy实例。对于这两种操作系统平台,RIL所定义的所有请求是不可更改的。2.2两者在线程结构与回调机制上的对比 在windows mobile的设计中,request与response被设计为异步执行的,他们分别使用两个队列来对它们的异步行为进行管理,执行命令下发和上报命令处理的过程也互不影响,下发命令与命令的相应响应之间的依赖关系由应用程序来捏合。 在android ril中的request与response设计与windows mobile不同,它的命令与响应之间是同步的过程。也就是说一条命令被下发后,将等待执行结果,

32、并进行处理,再上向上层发。而不是直接异步的进行处理和向上发送。3.Android RIL porting3.1.命名 要实现某个无线模块的RIL,需要创建一个实现了所有请求方法的共享库,保证Android能够响应无线通信请求。所有的请求被定义ril.h中。不同的Modem使用不同的端口,这个在init.rc中设置。Android提供了一个参考Vendor RIL,RIL参考源码在reference-ril。将你自己的Vendor RIL实现编译为共享库形式: libril-.so比如:libril-techfaith-124.so其中: libril:所有vendor RIL的开头 :公司缩写

33、推荐精选:RIL版本number so:文件扩展3.2.Android RIL的配置与加载 在init.rc文件中,将通过这种方式来进行Android RIL的加载。service ril-daemon /system/bin/rild -l /system/lib/libreference-ril.so - -d /dev/ttyS0也可以手动加载:/system/bin/rild -l /system/lib/libreference-ril.so - -d /dev/ttyS0这两种方式,都将启动rild守护进程,然后通过-l参数将libreference-ril.so共享库链入,lib

34、reference-ril.so的参数-d是指加载一个串口设备,/dev/ttyS0则是这个串口设备的具体设备文件,除了参数-d外,还有-s代表加载类型为socket的设备,-p代表回环接口。3.3.Android RIL的编译结构 rild:被编译成可执行文件,rild以守进程的形式执行。libril:将被编译为共享库,并被链入rild。Vendor RIL:可以以两种方式来运行,如果定义了RIL_SHLIB宏,那么它将被编译成共享库,如果没定义RIL_SHLIB宏,它将以守护进程程序的方式被调用执行。4.Android RIL的java框架 Android RIL的Java部分也被分为了两

35、个模块,RIL模块与Phone模块。其中RIL模块负责进行请求以及相应的处理,它将直接与RIL的原声代码进行通信。而Phone模块则向应用程序开发者提供了一系列的电话功能接口。4.1.RIL模块结构推荐精选 在RIL.java中实现了几个类来进行与下层rild的通信。它实现了如下几个类来完成操作:RILRequest:代表一个命令请求RIL.RILSender:负责AT指令的发送RIL.RILReceiver:用于处理主动和普通上报信息RIL.RILSender与RIL.RILReceiver是两个线程。RILRequest提供了obtain()方法,用于得到具体的request操作,这些操作

36、被定义在RILConstants.java中(RILConstants.java中定义的request命令与RIL原生代码中ril.h中定义的request命令是相同的),然后通过send()函数发送EVENT_SEND,在RIL_Sender线程中处理这个EVENT_SEND将命令写入到stream(socket)中去。Socket是来自常量SOCKET_NAME_RIL,它与RIL原生代码部分的s_fdListen所指的socket是同一个。 当有上报信息来到时,系统将通过RILReciver来得到信息,并进行处理。在RILReciver的生命周期里,它一直监视着SOCKET_NAME_R

37、IL这个socket,当有数据到来时,它将通过readRilMessage()方法读取到一个完整的响应,然后通过processResponse来进行处理。4.2.Phone模块结构Android通过暴露Phone模块来供上层应用程序用户使用电话功能相关的接口。它为用户提供了诸如电话呼叫,短信息,SIM卡管理之类的接口调用。它的核心部分是类GSMPhone,这个是Gsm的电话实现,需要通过PhoneFactory获取这个GSMPhone。GSMPhone并不是直接提供接口给上层用户使用,而是通过另外一个管理类TelephonyManager来供应用程序用户使用。类TelephonyManager

38、实现了android的电话相关操作。它主要使用两个服务来访问telephony功能:1.ITelephony,提供给上层应用程序用户与telephony进行操作,交互的接口,在packages/apps/Phone中由PhoneInterfaceManager.java实现。2.ItelephonyRegistry提供了一个通知机制,将底层来的上报通知给框架中需要得到通知的部分,由TelephonyRegistry.java实现。 GSMPhone通过PhoneNotifier的实现者DefaultPhoneNotifier将具体的事件转化为函数调用,通知到TelephonyRegistry。

39、TelephonyRegistry再通过两种方式通知给用户,其一是广播事件,另外一种是通过服务用户在TelephonyRegistry中注册的IphoneStateListener接口,实现回调(回调方式参见android的aidl机制)。参考资料 相关网站:http:/android-推荐精选http:/en.wikipedia.org/wiki/Android_%28operating_system%295 电话功能概述Android的Radio Interface Layer (RIL)提供了电话服务和的radio硬件之间的抽象层。Radio Interface Layer RIL(Ra

40、dio Interface Layer)负责数据的可靠传输、AT命令的发送以及response的解析。应用处理器通过AT命令集与带GPRS功能的无线通讯模块通信。AT command由Hayes公司发明,是一个调制解调器制造商采用的一个调制解调器命令语言,每条命令以字母AT开头。JAVA Framework代码的路径为:frameworks/base/telephony/java/android/telephonyandroid.telephony以及android.telephony.gsmCorenative:在hardware/ril目录中,提供了对RIL支持的本地代码,包括4个文件夹:

41、hardware/ril/includehardware/ril/librilhardware/ril/reference-rilhardware/ril/rildkernel Driver 在Linux内核的驱动中,提供了相关的驱动程序的支持,可以建立在UART或者SDIO,USB等高速的串行总线上。电话功能各个部分: hardware/ril/include/telephony/目录中的ril.h文件是ril部分的基础头文件。其中定义的结构体RIL_RadioFunctions如下所示:typedef struct int version; RIL_RequestFunc onReques

42、t; 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, RI

43、L_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(),它是一个请求执行的函数。5.1 rild守护进程rild 守护进程的文件包含在hardware/ril/rild目录中,其中包含了rild.c和radiooptio

44、ns.c两个文件,这个目录中的文件经过编译后生成一个可执行程序,这个程序在系统的安装路径在:/system/bin/rildrild.c是这个守护进程的入口,它具有一个主函数的入口main,执行的过程是将上层来的请求都由这个函数RIL_RadioFunctionsonReques()的方法进行映射后转换成对应的AT命令的字符串,发给下层的硬件执行。在运行过程中,使用dlopen 打开路径为/system/lib/中名称为libreference-ril.so的动态库,然后从中取出 RIL_Init符号来运行。ril_register()注册:RIL_Init符号是一个函数指针,执行这个函数后,

45、返回的是一个RIL_RadioFunctions类型的指针。得到这个指针后,调用RIL_register()函数,将这个指针注册到libril库之中,然后进入循环ril_event_loop()。 事实上,这个守护进程提供了一个申请处理的框架,而具体的功能都是在libril.so和libreference-ril.so中完成的。附:RIL守护进程,开机时被init守护进程调用启动,里面仅有main函数作为入口点,负责完成RIL初始化工作。在rild.c文件中,将完成ril的加载过程,它会执行如下操作:动态加载Vendor RIL的.so文件执行RIL_startEventLoop()开启消息队

46、列以进行事件监听通过执行Vendor RIL的rilInit()方法来进行Vendor RIL与libril的关系建立。在rild文件夹中还包括一个radiooptions.c文件,它的作用是通过串口将一些radio相关的参数直接传给rild来对radio进行配置。5.2 libreference-ril.so动态库libreference-ril.so动态库的路径是:hardware/ril/reference-ril其中主要的文件是reference-ril.c和atchannel.c。这个库必须实现的是一个名称为RIL_Init的函数,这个函数执行的结果是返回一个RIL_RadioFun

47、ctions结构体的指针,指针指向函数指针。这个库在执行的过程中需要创建一个线程来执行实际的功能。在执行的过程中,这个库将打开一个/dev/ttySXXX的终端(终端的名字是从上层传入的),然后利用这个终端控制硬件执行。附:在编译时libril被链入rild,它为rild提供了event处理功能,还提供了在rild与Vendor RIL之间传递请求和响应消息的能力。推荐精选Libril提供的主要功能分布在两个主要方法内,一个是RIL_startEventLoop()方法,另一个是RIL_register()方法RIL_startEventLoop()方法所提供的功能就是启用eventLoop线

48、程,开始执行RIL消息队列。RIL_register()方法的主要功能是启动名为rild的监听端口,等待java端通过socket进行连接。5.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_onRe

49、questComplete(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可以通过自己的方式实现这几个

50、接口,这样可以保证RIL可以在不同系统的移植。其中 RIL_register()函数把外部的RIL_RadioFunctions结构体注册到这个库之中,在恰当的时候调用相应的函数。在执行的过程中,这个库处理了一些将请求转换成字符串的功能。附:Android自带的VendorRIL的参考实现。被编译成.so文件,由于本部分是厂商定制的重点所在。所以被设计为松散耦合,且可灵活配置的。在rild中通过opendl()的方式加载。librefrence.so负责直接与radio通信,这包括将来自libril的指令转换为AT指令,并且将AT指令写入radio中。reference-ril会接收调用者传来

51、的参数,参数内容为与radio的通信方式。如通过串口连接radio,那么参数为这种形式:-d /dev/ttySx5.4 ril层的所有代码分析5.4.1 ril/rild下的文件 rild.c-mian()为函数入口int main(int argc, char *argv)/推荐精选./OpenLib:#endif switchUser();/打开dlopen()加载vendor RIL 获取由RIL_register(funcs);注册进来的参数,并解析dlHandle = dlopen(rilLibPath, RTLD_NOW); if (dlHandle = NULL) fprint

52、f(stderr, dlopen failed: %sn, dlerror(); exit(-1);/1:消息队列的入口1.到select阻塞/每当看到打印信息,不按顺序打下来说明阻塞RIL_startEventLoop();/通过dlsym函数得到rilInit函数指针的引用rilInit = (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char *)dlsym(dlHandle, RIL_Init);if (rilInit = NULL) fprintf(stderr, RIL_Init not defined o

53、r exported in %sn, rilLibPath); exit(-1); if (hasLibArgs) rilArgv = argv + i - 1; argc = argc -i + 1; else static char * newArgvMAX_LIB_ARGS; static char argsPROPERTY_VALUE_MAX; rilArgv = newArgv; property_get(LIB_ARGS_PROPERTY, args, ); argc = make_argv(args, rilArgv); / Make sure theres a reasonab

54、le argv0 rilArgv0 = argv0;/2:利用得到的rilInit函数指针,调用真正的RIL_Initfuncs = rilInit(&s_rilEnv, argc, rilArgv);RIL_register(funcs);done: while(1) / sleep(UINT32_MAX) seems to return immediately on bionic sleep(0x00ffffff); 推荐精选5.4.2 ril/libril-ril.cpp中RIL_startEventLoop()函数分析RIL_startEventLoop(void) int ret;

55、pthread_attr_t attr;LOGD(-2-ril.cpp-RIL_startEventLoop-); /* spin up eventLoop thread and wait for it to get started */ s_started = 0; pthread_mutex_lock(&s_startupMutex); pthread_attr_init (&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);LOGD(-1-ril.cpp-kai-kou-pthread_create(&s

56、_tid_dispatch, &attr, eventLoop, NULL);-);ret = pthread_create(&s_tid_dispatch, &attr,eventLoop, NULL);/创建线程,为入口函数LOGD(-2.-ril.cpp-tiao-chu-rpthread_create(&s_tid_dispatch, &attr, eventLoop, NULL);-); while (s_started = 0) pthread_cond_wait(&s_startupCond, &s_startupMutex); pthread_mutex_unlock(&s_startupMutex); if (ret fd = fd; ev-index = -1; ev-persist = persist; ev-func = func; ev-param = param; fcntl(fd, F_SETFL, O_NONBLOCK);3.1processWakeupCallbackstatic void processWakeupCallback(int fd, short flags, void *param) char buff16;

展开阅读全文
温馨提示:
1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
2: 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
3.本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
关于我们 - 网站声明 - 网站地图 - 资源地图 - 友情链接 - 网站客服 - 联系我们

copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!