Android中RIL层详细分析_第1页
Android中RIL层详细分析_第2页
Android中RIL层详细分析_第3页
Android中RIL层详细分析_第4页
Android中RIL层详细分析_第5页
已阅读5页,还剩47页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

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

2、。本文档中还对 Android RIL 的 Porting 部分内容进行了描述和分析。 针对对 unix 操作系统环境并不熟悉的读者,本文档中所涉及到的相关知识包括:Unix file systemUnix socketUnix threadUnix 下 I/O 多路转接 以上信息可以在任意一份描述 Unix 系统调用的文档中找到。1. Android RIL 框架介绍术语:fd pipe cond tty unsolicited response event loop init.rcHALLinux 文件描述符Linux 管道 一般是 condition variable 的缩写 通常使用

3、tty 来简称各种类型的终端设备 被动请求命令来自 baseband android 的消息队列机制,由 Linux 的系统调用 select() 实现 init 守护进程启动后被执行的启动脚本。硬件抽象层( Hardware Abstraction Layer , HAL )1.1 Android RIL 概况RIL 在 AndroidAndroid RIL 提供了无线硬件设备与电话服务之间的抽象层。下图展示了 体系中的位置。an droid的ril位于应用程序框架与内核之间,分成了两个部分,一个部分是rild,它负责socket与应用程序框架进行通信。另外一个部分是Vendor RIL,这

4、个部分负责向下是通过两种方式与radio进行通信,它们是直接与radio通信的AT指令通道和用于传输包数据的通道, 数据通道用于手机的上网功能。对于RIL的java框架部分,也被分成了两个部分,一个是RIL模块,这个模块主要用于与下层的rild进行通信,另外一个是Phone模块,这个模块直接暴露电话功能接口给应用开 发用户,供他们调用以进行电话功能的实现。1.2 An droid RIL 目录结构An droid 的 RIL 模块位于An droid/hardware/ril文件夹,有三个子模块: rild , librilrefere nce-ril所在目录结构:/hardware/ril/

5、|- ril(无线电抽象层)|- include (头文件)|- libril (库)|- reference-cdma-sms ( cdma 短信参考)|- reference-ril ( ril 参考)| |- rild( ril后台服务程序)hardware/ril$ ls include libril reference-cdma-sms reference-ril rild1. hardware/ril/rild$ lsAndroid.mk MODULE_LICENSE_APACHE2 NOTICE radiooptions.c rild.c2. hardware/ril/inclu

6、de/telephony$ lsril_cdma_sms.h ril.h3. hardware/ril/libril$ lsAndroid.mk NOTICE ril_event.h ril.cpp ril_event.cpp ril_commands.h ril_unsol_commands.h MODULE_LICENSE_APACHE24. hardware/ril/reference-cdma-sms$ lsAndroid.mk reference-cdma-sms.c reference-cdma-sms.h5. hardware/ril/reference-ril$ lsAndro

7、id.mk atchannel.h at_tok.h misc.h NOTICE atchannel.c at_tok.c ril_event.h reference-ril.c misc.c MODULE_LICENSE_APACHE2 include 文件夹:包含 RIL 头文件 ,最主要的是 ril.hrild 文件夹 :RIL 守护进程,开机时被 init 守护进程调用启动,里面仅有 main 函数作为入口点,负责完成 RIL初始化工作。在 rild.c 文件中,将完成 ril 的加载过程,它会执行如下操作:动态加载 Ven dor RIL的.so文件执行RIL_startEventL

8、oop()开启消息队列以进行事件监听通过执行 Ven dor RIL的rill nit()方法来进行 Ven dor RIL与libril的关系建立。在 rild 文件夹中还包括一个 radiooptions.c 文件 , 它的作用是通过串口将一些 radio 相关的参数直接传给 rild 来对 radio 进行配置。 libril 文件夹:在编译时 libril 被链入 rild, 它为 rild 提供了 event 处理功能,还提供了在 rild 与 Vendor RIL 之间传递请求和响应消息的能力。Libril 提供的主要功能分布在两个主要方法内,一个是 RIL_startEventL

9、oop() 方 法,另一个是 RIL_register() 方法RIL_startEventLoop() 方法所提供的功能就是启用 eventLoop 线程,开始执行 RIL 消息队列。RIL_register() 方法的主要功能是启动名为 rild 的监听端口,等待 java 端通过 socket 进行连接。 reference-ril 文件夹:Android 自带的 Vendor RIL 的参考实现。被编译成 .so 文件,由于本部分是厂商定 制的重点所在。 所以被设计为松散耦合, 且可灵活配置的。 在 rild 中通过 opendl() 的方式加载。librefrence.so 负责直接

10、与radio通信,这包括将来自libril 的指令转换为 AT指 令,并且将 AT 指令写入 radio 中。reference-ril 会接收调用者传来的参数,参数内容为与 radio 的通信方式。如通 过串口连接 radio, 那么参数为这种形式: -d /dev/ttySx1.3. Android RIL 中的消息( event )队列机制在 Android RIL 中,为了达到等待多路输入并且不出现阻塞的目的,使用了 IO 多路复用 机制。如果使用 阻塞 I/O 进行网络的读取写入 ,这意味着假如需要同时从两个网络文件描述符 中读内容,那么如果读取操作在等待网络数据到来, 这将可能很长

11、时间阻塞在一个描述符上, 另一个网络文件描述符不管有没有数据到来都无法被读取。一种解决方案是:如果使用 非阻塞 I/O 进行网络的读取写入, 在读取其中一个网络文件描述符如果阻塞将 直接返回, 再读取另外一个, 这种方式的循环被称之为 轮询 。轮询方式确实能解决进行多路 io操作时的阻塞问题,但是这种方法的不足之处是反复的执行读写调用将浪费cpu时钟。I/O 多路转接技术在这里提供了另一种比较好的解决方案:它会先构造一张有关 I/O 描述符的列表,然后调用 select 函数,当 IO 描述符列表中的 一个描述符准备好进行 I/O 时,该函数返回,并告知可以读或写哪个描述符。An droid

12、RIL中消息队列的核心实现思想就是这种I/O多路转接技术。消息队列机制的实现在 ril_event.cpp 中,其中被定义的 ril_event 结构是消息的主体。每个 ril_event 结构,与一个 fd 句柄绑定 (可以是文件, socket ,管道等 ),并且带一个 func 指针,这个 func 指针所指的函数是个回调函数,它指定了当所绑定的 fd 准备好进行读取时 所要进行的操作。消息队列的开始点为 RIL_startEventLoop 函数。 RIL_startEventLoop 在 ril.cpp 中实现, 它 的主要目的是通过 pthread_create(&s_ti

13、d_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 *prev;int fd;int index;bool persist;struct timeval tim

14、eout;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_event ,它是通过pipe的机制实现的,这个管道fd的回调函数并没有实现什么功能,它的

15、目的只是为了让select方法能返回一次,这样select。方法就能重新跟踪新加入事件队列的fd和timeout 设置。所以在添加新 fd至U eventLoop时,往往不是直接调用ril_event_add,实际通常用rilEve ntAddWakeup 来添加,这个方法除了会间接调用ril_eve nt_add 外,还会调用 triggerEvLoop()函数来向s_fdWakeupWrite中写入一个空字符,这样select()函数会返回并重新执行,新加入的文件描述符便得以被select()加载并跟踪。如果在ril_event队列中任何一个fd已经准备好,则进入分析流程:processT

16、imeouts(), processReadReadies(&rfds, n), firePending() 其中firePe ndi ng()方法执行这个 eve nt的func,也就是回调函数。在An droid RIL初始化完成后,将有几个eve nt被挂入到 even tLoop中:1. s_listen_event:名为 rild 的 socket,主要 requeset & response 通道2. s_debug_event:名为 rild-debug 的 socket,调试用 requeset & response 通道3. s_wakeupfd_ev

17、ent:无名管道,用于队列主动唤醒这其中最为重要的eve nt就是s_liste n_eve nt,它作为request与respo nse的通道实现。在 ril_event.cpp 中还持有一个 watch_table 数组,一个 timer_list 链表和一个 pending_list 链 表。watch_table数组的目的很单纯,存放当前被 even tLoop等待的ril_eve nt (非timer eve nt ), 供even tLoop唤醒时使用。timer_list是存放timer eve nt的链表,在even tLoop唤醒时要对这 些timer event单独进行处

18、理 pendingist :待处理(对其回调函数进行调用 )的所有ril_event 的链表。1.4. A ndroid RIL 中初始化流程分析 Rild的初始化流程初始化流程从rild.c中的main函数开始,它被in it守护进行调用执行:首先在 mai n()函数内会首先通过dlope n()函数加载 Ven dor RIL (在自带的参考实现中为librefrence_ril.so )。接着调用 RIL_startEventLoop ()函数来启动消息队列机制。调用librefre nce_ril.so的RIL_I nit()函数来进行 Ven dor RIL的初始化。RIL_I n

19、it()函数执行后会返 回一个 RIL_RadioFunction结构体,这个结构体内最重要的成员就是onRequest()方法。onRequest()方法会被 dispatchFunction调用,也就是说 dispatchFunction调用是程序流从rild转入 Ven dor RIL的分界点。RIL_register()函数将实现两个目地,一个是将RIL_INIT中获得的RIL_RadioFunction进行注册, rild通过此种方式保证自己持有一个RIL_RadioFunction实例,第二个是将 s_fdListen加入到消息队列机制中,开启 s_fdListen的事件监听。 V

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

21、, 通过 RIL 消息队列机制, s_listen_event 的 回调函数 listenCallBack 将会被调用, 开始进行数据流的分析与处理。 接下来 s_fdCommand = accept(s_fdListen, (sockaddr *) &peeraddr, &socklen), 获取传入的 socket 描述符 , 也就是上层的 java RIL 传入的连接。然后 , 通过 record_stream_new() 建立起一个 RecordStream, 将这个 record_stream 与 s_fdCommand 绑定 , RecordStream 实际上是一

22、个用于存放数据的结构体, 这个结构体提供了一些操作类来保证这个 RecordStream 所绑定的文件描述符被读取时里面 的数据会被完整读取。一旦s_fdCommand中有数据,它的回调函数processCommandsCallback()将会被调用,processCommandsCallback()通过 record_stream_get_next 阻塞读取 s_fdCommand 上发来的 数据,直到收到一完整的request。然后将其传递进processComma ndBuffer()函数, processCommandBuffer() 正式进入了命令的解析部分。每个接收到的命令将以 R

23、equestInfo 的形式存在。从 socket 过来的数据流 , 是 Parcel 处理过的序列化字节流 , 在这里会通过反序列化的方法提取出来。最前面的是 request 号, 以及 token 域(request 的递增序列号)。request 号是一个 Commandlnfo,它在 ril_command.h 中定义。接下来, 这个 Requestlnfo 会被挂入 pending 的 request 队列, 执行具体的 dispatchFunction(), 进行详细解析。dispatchFunction 方法有着多种实现,如 dispatchVoid, dispatchStrin

24、g,它们的调用取决于 Parcel 的参数传入形式。比如说在 dispatchDial 方法中, Parcel 对象将被解析 为 RlL_Dial 结构。这是 disptachFunction 的任务之一,它的另一个任务就是调用 onRequest() 方法,并将解析的内容传入 onRequest() 方法。从 onRequest 方法开始,程序控制流脱离了 RlLD, 进入到了 Vendor RlL 中。on Request方法会通过传入的请求类型来调用指定的request xxx ()方法,requestxxx ()方法则负责组装 AT指令并下发给at_send_command()方法集合

25、中的一个,这个方 法集合提供了针对不同类型 AT指令的实现,如单行AT指令at_send_command_singleline(), 短信息指令 at_send_command_sms() 等。最后, 执行 at_send_command_full(), 再通过一 个互斥的 at_send_command_full_nolock()调用 ,完成最终的写出操作 ,在 writeline()中,写出到初始化时打开的设备中。需要注意的是: at_send_command_full_nolock() 在将指令写入 radio 后并不会直接返 回,而是通过条件变量等待响应信息, 得到响应信息后会携带这些

26、信息返回。 具体流程可以 参考下面的 response 流程分析。1.6. Android RIL 中 response 流程分析AT 的 response 有两种,一种是 unsolicited 。另一种是普通 response ,也就是命令的响 应。 response 信息的获取在 readerLoop() 中。由 readline() 函数读取上来。读取到的line将被传入processLine()函数进行解析,processLine()函数首先会判断当前的 响应是主动响应还是普通响应,如果是主动响应,将调用handleUnsolicited() 函数,如果为普通响应,那么将调用han

27、dleFi nalRespo nse()函数进行处理对响应串的主要的解析过程,由at_tok.c 中的各种解析函数完成,提供字符串分析解析功能。 对主动上报的解析handleUnsolicited () 方法处理主动上报,它会调用 onUnsolicited() 来进行进一步的解析, 这个函数在 Vendor-RIL初始化时被传入 at_open ()函数,onUnsolicited只解析出头部(一般 是 +XXXX 的形式 ),然后按类型决定下一步操作,操作为RIL_onUnsolicitedResponse 和RIL_requestTimedCallback 两种。在 RIL_onUnso

28、licitedResponse() 函 数 中 , 通 过 Parcel 传 递 , 将 RESPONSE_UNSOLICITE,DunsolResponse(request号)写入 Parcel , 然后调用 对应的responseFunction 完成进一 步的的解析 ,将解析的 数据写 入 Parcel 中, 最后通过 sendResponse()宀sendResponseRaw()blockingWrite()writeLine() 将数据写回给与应用层通信的 socket 。在 RIL_requestTimedCallback() 函数中。通过 event 机制实现的 timer 机

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

30、nse, 这 是 一 个 ATResponse 结 构 , 它 的 成 员 包 括 成 功 与 否 ( success ) 以 及 一 个 中 间 结 果 ( p_intermediates )。 handleFinalResponse() 在将响应结果保存至 sp_response 后 , 设 置 s_commandcond 这 一 条 件 变 量 , 此 条 件 变 量 由 at_send_command_full_nolock等待。at_send_command_full_nolock获得到了完整的响应信息 (在 sp_response 中),便开始进行响应信息的处理, 最后由 RIL_

31、onRequestComplete 将响应数据序列化并通过 sendResponse 传 递 至 与 应 用 层 通 信 的 socket , 这 一 部 分 与 RIL_onUnsolicitedResponse() 函数的功能非常相似,请参考对主动上报的解析部分。2. Android RIL 与 WindowsMobile RILAndroid RIL 与 WindowsMobile RIL 在设计思路上都是作为一个 radio 的抽象,为上层提 供电话服务, 但在实现方式上两者有着一定的差异, 这种差异的产生主要是源自操作系统机 制的不同。An droid RIL被实现为 HAL,相对于

32、wi ndows mobile中被实现为驱动的方式,An droid RIL模块的内聚性更为理想,可维护性也将更强,你也可以把Android Ril 看做一个中间件。An droid RIL部分的开发工作,只需要拿到相应的radio文件描述符,就可以进行操作,无需关注 radio 的 I/O 驱动实现。2.1 两者在与应用通信上的实现对比Win dowsMobile RIL在实现与应用的通信时提供了RIL Proxy,在这个层面中它定义了大量的RIL_*()函数来作为电话服务请求。 这一点与An droid RIL的实现比较相似,An droid RIL 中在 ril.h 内提供了一系列的宏来

33、定义电话服务请求。在An droid中的rild功能类似于 wi ndows mobile RIL的RIL proxy。它同样也是起到一个 中介的作用,为上层接口向下传递请求,并上传回响应。在windows mobile RIL 中要为每一个应用程序客户提供一份 Ril Proxy实例。对于这两种操作系统平台,RIL所定义的所有请求是不可更改的。2.2 两者在线程结构与回调机制上的对比在 windows mobile 的设计中, request 与 response 被设计为异步执行的,他们分别使 用两个队列来对它们的异步行为进行管理,执行命令下发和上报命令处理的过程也互不影 响,下发命令与命

34、令的相应响应之间的依赖关系由应用程序来捏合。在 android ril 中的 request 与 response 设计与 windows mobile 不同,它的命令与响 应之间是同步的过程。也就是说一条命令被下发后,将等待执行结果,并进行处理,再上向上层发。而不是直接异步的进行处理和向上发送。3. Android RIL porting3.1. 命名要实现某个无线模块的RIL,需要创建一个实现了所有请求方法的共享库,保证An droid能够响应无线通信请求。所有的请求被定义 ril.h 中。不同的 Modem 使用不同的端口,这个在 init.rc 中设置。An droid 提供了一个参考

35、 Vendor RIL, RIL 参考源码在 refere nce-ril。将你自己的 Vendor RIL 实现编译为共享库形式:libril-<companyname>-<RIL version>.so比如:libril-techfaith-124.so其中:libril :所有 vendor RIL 的开头<companyname> :公司缩写 <RIL version>: RIL版本 number so:文件扩展3.2. A ndroid RIL的配置与加载在in it.rc文件中,将通过这种方式来进行An droid RIL的加载。se

36、rvice ril-daem on /system/bi n/rild -l /system/lib/librefere nce-ril.so - -d /dev/ttySO也可以手动加载:/system/bin/rild -l /system/lib/libreference-ril.so - -d /dev/ttySO这两种方式,都将启动 rild守护进程,然后通过-l参数将libreference-ril.so共享库链入, libreference-ril.so的参数-d是指加载一个串口设备,/dev/ttySO则是这个串口设备的具体设 备文件,除了参数-d外,还有-s代表加载类型为so

37、cket的设备,-p代表回环接口。3.3. A ndroid RIL的编译结构rild:被编译成可执行文件,rild以守进程的形式执行。libril:将被编译为共享库,并被链入rild。Ven dor RIL:可以以两种方式来运行,如果定义了RIL_SHLIB宏,那么它将被编译成共享库,如果没定义RIL_SHLIB宏,它将以守护进程程序的方式被调用执行。4. An droid RIL 的 java 框架An droid RIL 的Java部分也被分为了两个模块, RIL模块与Phone模块。其中RIL 模块负责进行请求以及相应的处理,它将直接与RIL的原声代码进行通信。而 Phone模块则向应

38、用程序开发者提供了一系列的电话功能接口。4.1.RIL模块结构在RIL.java 中实现了几个类来进行与下层rild的通信。它实现了如下几个类来完成操作:RILRequest :代表一个命令请求RlL.RILSender:负责AT指令的发送RlL.RILReceiver:用于处理主动和普通上报信息RlL.RILSe nder与 RlL.RILReceiver是两个线程。RILRequest 提供了 obtai n()方法,用于得到具体的request 操作,这些操作被定义在RILConstants.java 中(RILConstants.java中定义的 request 命令与 RIL 原生代

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

40、RIL 这个 socket,当有数据方法读取到一个完整的响应,然后通过4.2.Phone模块结构An droid通过暴露Pho ne模块来供上层应用程序用户使用电话功能相关的接口。它为用户提供了诸如电话呼叫,短信息,SIM卡管理之类的接口调用。它的核心部分是类 GSMPhone, 这个是Gsm的电话实现,需要通过 PhoneFactory获取这个GSMPhone。GSMPho ne并不是直接提供接口给上层用户使用,而是通过另外一个管理类 TelephonyManager来供应用程序用户使用。类Telepho nyMa nager实现了 an droid的电话相关操作。它主要使用两个服务来访问t

41、eleph ony功能:1.ITelepho ny,提供给上层应用程序用户与telepho ny进行操作,交互的接口,在 packages/apps/Phone 中由 PhoneinterfaceManager.java 实现。2.ItelephonyRegistry提供了一个通知机制,将底层来的上报通知给框架中需要得到通知的部 分,由 Teleph on yRegistry.java 实现。GSMPhone通过PhoneNotifier的实现者 DefaultPhoneNotifier将具体的事件转化为函数 调用,通知到 TelephonyRegistry。TelephonyRegistry

42、再通过两种方式通知给用户,其一是广 播事件,另外一种是通过服务用户在Teleph on yRegistry中注册的Ipho neStateListe ner接口,实现回调(回调方式参见an droid的aidl机制)。参考资料相关网站:http:/code.google.eom/a ndroid/http:/a ndroid-http:/www.ibm.eom/developerworks/c n/ope nsource/theme/a ndroid//wiki/A ndroid_%28operati ng_system%295电话功能概述An dr

43、oid的Radio In terface Layer (RIL)提供了电话服务和的radio硬件之间的抽象层。Radio In terface Layer RIL(Radio In terface Layer)负责数据的可靠传输、AT命令的发送以及response的解析。应用处理器通过AT命令集与带GPRS功能的无线通讯模块通信。AT comma nd由Hayes公司发明,是一个调制解调器制造商采用的一个调制解调器命令语言,每条命令以字母"AT"开头。JAVA Framework代码的路径为:frameworks/base/teleph ony/java/a ndroid/

44、teleph onyandroid.telephony 以及 android.telephony.gsmCore native:在hardware/ril目录中,提供了对 RIL支持的本地代码,包括4个文件夹:hardware/ril/in cludehardware/ril/librilhardware/ril/refere nce-rilhardware/ril/rildkernel Driver在Linux内核的驱动中,提供了相关的驱动程序的支持,可以建立在UART或者SDIO,USB等高速的串行总线上。电话功能各个部分:hardware/ril/include/telephony/目录

45、中的ril.h文件是ril部分的基础头文件。其中定义的结构体RIL_RadioFu nctio ns如下所示:typedef struct int version;RIL_RequestFunc on Request;RIL_RadioStateRequest on StateRequest;RIL_Supports supports;RIL_Ca ncel onCan cel;RIL_GetVersio n getVers ion; RIL_RadioFu nctio ns;RIL_RadioFu nctio ns中包含了几个函数指针的结构体,这实际上是一个移植层的接口,下层的库实现后,由r

46、ild守护进程得到这些函数指针,执行对应的函数。几个函数指针的原型为:typedef void (*RIL_RequestF unc) (int request, void *data,size_t datale n, RIL_Toke n t);typedef RIL_RadioState (*RIL_RadioStateRequest)();typedef int (*RIL_Supports)(int requestCode);typedef void (*RIL_Ca ncel)(RIL_Toke n t);typedef const char * (*RIL_GetVersio n)

47、 (void);其中最为重要的函数是 onRequest(),它是一个请求执行的函数。5.1 rild 守护进程rild 守护进程的文件包含在hardware/ril/rild目录中,其中包含了rild.c和radiooptions.c两个文件,这个目录中的文件经过编译后生成一个可执行程序,这个程序在系统的安装路径在:/system/bi n/rildrild.c是这个守护进程的入口,它具有一个主函数的入口main,执行的过程是将上层来的请求都由这个函数RIL_RadioFunctionsonReques() 的方法进行映射后转换成对应的AT命令的字符串,发给下层的硬件执行。在运行过程中,使用

48、dlopen打开路径为/system/lib/中名称为libreference-ril.so的动态库,然后从中取出 RIL_Init符号来运行。ril_register()注册:RIL_Init符号是一个函数指针,执行这个函数后,返回的是一个 RIL_RadioFunctions类型的指针。得到这个指针后,调用RIL_register()函数,将这个指针注册到libril库之中,然后进入循环ril_event_loop()。事实上,这个守护进程提供了一个申请处理的框架,而具体的功能都是在libril.so和libreference-ril.so 中完成的。附:RIL守护进程,开机时被init守

49、护进程调用启动,里面仅有main函数作为入口点,负责完成RIL初始化工作。在rild.c文件中,将完成ril的加载过程,它会执行如下操作:动态加载 Ven dor RIL的.so文件执行RIL_startEventLoop()开启消息队列以进行事件监听通过执行 Ven dor RIL的rilI nit()方法来进行 Ven dor RIL与libril的关系建立。在rild文件夹中还包括一个radiooptions.c文件,它的作用是通过串口将一些radio相关的参数直接传给rild来对radio进行配置。5.2 librefere nce-ril.so动态库libreference-ril.

50、so动态库的路径是:hardware/ril/refere nce-ril其中主要的文件是 reference-ril.c和atchannel.c。这个库必须实现的是一个名称为RIL_Init的函数,这个函数执行的结果是返回一个RIL_RadioFunctions结构体的指针,指针指向函数指针。这个库在执行的过程中需要创建一个线程来执行实际的功能。在执行的过程中,这个库将打开一个/dev/ttySXXX的终端(终端的名字是从上层传入的),然后利用这个终端控制硬件执行。附:在编译时libril被链入rild,它为rild提供了 event处理功能,还提供了在rild与Ven dor RIL 之间

51、传递请求和响应消息的能力。Libril提供的主要功能分布在两个主要方法内,一个是RIL_startEventLoop()方法,另一个 是 RIL_register()方法RIL_startEventLoop()方法所提供的功能就是启用eventLoop线程,开始执行RIL消息队列。RIL_register()方法的主要功能是启动名为rild的监听端口,等待java端通过socket进行连接。5.3 libril.so 动态库libril.so库的目 录是:hardware/ril/libril其中主要的文件为ril.cpp,这个库主要需要实现的以下几个接口为:RIL_startEve ntLo

52、op(void);void RIL_setcallbacks (const RIL_RadioFunctions *callbacks);RIL_register (const RIL_RadioFunctions *callbacks);RIL_on RequestComplete(RIL_Toke n t, RIL_Err no e, void *resp on se, size_t resp on sele n);void RIL_onUn solicitedResp on se(i nt un solResp on se, void *data,size_t datale n);RIL

53、_requestTimedCallback (RIL_TimedCallback callback, void *param,const struct timeval *relativeTime);这些函数也是被rild守护进程调用的,不同的vendor可以通过自己的方式实现这几个接口,这样可以保证RIL可以在不同系统的移植。其中 RIL_register()函数把外部的 RIL_RadioFunctions结构体注册到这个库之中,在恰当的时候调用相应的函数。在执行的过 程中,这个库处理了一些将请求转换成字符串的功能。附:An droid自带的Ven dorRIL的参考实现。被编译成.so文件

54、,由于本部分是厂商定制的重 点所在。所以被设计为松散耦合,且可灵活配置的。在rild中通过opendl()的方式加载。librefrence.so负责直接与radio通信,这包括将来自libril的指令转换为 AT指令,并且 将AT指令写入radio中。reference-ril会接收调用者传来的参数,参数内容为与radio的通信方式。如通过串口连 接radio,那么参数为这种形式:-d /dev/ttySx5.4 ril层的所有代码分析5.4.1 ril/rild 下的文件 rild.c->mian()为函数入口int main (i nt argc, char *argv)/Open

55、 Lib:#en difswitchUser();/打开dlope n()加载ven dor RIL获取由RIL_register(fu ncs);注册进来的参数,并解析dIHa ndle = dlope n(rilLibPath, RTLD_NOW);if (dlHa ndle = NULL) fprin tf(stderr, "dlope n failed: %sn", dlerror();exit(-1);/1:消息队列的入口1到select阻塞/每当看到打印信息,不按顺序打下来说明阻塞RIL_startEve ntLoop();/通过dlsym函数得到rilInit

56、函数指针的引用rilInit = (const RIL_RadioFunctions *(*)(const struct RIL_Env*, int, char *)dlsym(dlHandle, "RIL_I ni t");if (rilI nit = NULL) fprintf(stderr, "RIL_Init not defined or exported in %sn", rilLibPath);exit(-1);if (hasLibArgs) rilArgv = argv + i - 1;argc = argc -i + 1; else st

57、atic char * newArgvMAX_LIB_ARGS;static char argsPROPERTY_VALUE_MAX;rilArgv = n ewArgv;property_get(LIB_ARGS_PROPERTYirgs, "");argc = make_argv(args, rilArgv);/ Make sure there's a reas on able argv0rilArgv0 = argv0;2:利用得到的rilInit函数指针,调用真正的RIL_Initfuncs = rilInit(&s rilEnv, argc, rilArgv);RIL_register(fu ncs);done:while(1) / sleep(UINT32_MAX) seems to return immediately on bio nic sleep(0x00ffffff);5.4.2 ril/libril->ril.cpp 中 RIL_startEventL

温馨提示

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

评论

0/150

提交评论