Android打电话和发送短消息的接口介绍


RIL 设计思想解析(一) 一.RIL 概述 目前的智能机在硬件上多采用双cpu的架构,一个是基带处理器,主要处理数字信号、语 音信号的编码解码以及GSM通信协议,另一个是应用处理器,运行操作系统和各种应用程序。 基带处理器、射频和其它外围芯片作为一个模块,成为GSM/GPRS modem,提供AT命令接口。 网络的应用已经是一个需求的热点,而目前的GSM模块大多都能支持GPRS功能。应用处理器 通过AT命令集与带GPRS功能的无线通讯模块通信,为实现网络的应用提供了一个最底层的支 持。 从软件的角度来看,RIL(Radio Interface Layer)工作在PPP、TCP/IP协议之下,负责数 据的可靠传输、AT命令的发送以及response的解析。当然,除了对网络的支持,RIL也支持 SMS、Voice Call等功能。从这一点来看,RIL的性能好坏影响着所有无线通信应用相关的软 件,而软件设计的合理性又影响着RIL的性能。 Windows Mobile是用在智能手机上的主流操作系统之一。微软是这样介绍RIL的:作为 Windows Mobile的一个非常重要的组件,RIL使各种无线语音和数据应用成为可能。运行在 Windows Mobile上的软件可以通过RIL无缝地与GSM/GPRS或者CDMA2000 1X modem通信。RIL 的位置处于无线基带系统的协议栈之上,Windows Mobile的CellCore层之下。由于RIL隐藏 了硬件上的一些细节,OEM厂商可以根据自己的需要将不同型号的无线modem集成到它们的产 品之中。 Windows Mobile 提供了RIL 的源码,因此在RIL上的开发工作相对来说比较简单了,主 要是根据不同厂商对AT命令以及Telephony features的差异对RIL做一些局部的修改和调 试。 但美中不足的是,微软没有提供 RIL 的设计文档,而且关于 RIL 架构的介绍也是最高层 的,不能够很深入地了解RIL 的设计者在构建这个复杂组件时考虑了哪些问题,又是基于哪 些思想和方法来解决的,最终又是如何把一个个的片断整合起来形成一个精密运转的系统。 对我们而言,一个现实的途径就是通过对源码的分析把这个过程动态地还原出来。 这样做有什么意义?第一,在了解工作原理和结构后,有助于我们在 RIL 开发过程中能 够顺利地解决问题。第二,有利于积累设计经验和提高自己的设计水平。这一点也许是最重 要的,"他山之石,可以攻玉"。在吸收和掌握了 RIL 的设计思想后,也可以在自己的手机平 台上实现自己的 RIL。 当然,关于 RIL 的可讨论的问题很多,对于每一个关键的设计问题都可以单独作为一个 主题来阐述。由于重点是放在介绍 RIL 背后的的设计思想,所以尽量砍去旁支末节,而是专 注于基本问题和方法的讨论。要真正理解这些人怎么想的,所以最好的方式是动态地展现整 个思考过程,去模仿它们的足迹而不是生硬地 copy。 RIL 控制的设备是无线 modem,面临的第一个问题就是怎么把数据发送出去,又怎么接收 发给自己的数据。整篇其实就是围绕这个问题展开的,最终使我们的系统能够建立起数据传 输的双向通道,让数据有效率地往返流动。 二.应用场景和问题域 如图 1,手机中的 GSM/GPRS modem 支持呼叫控制、SMS、GPRS 等功能,以 AT 命令 方式提供了通信接口。对于每一个 AT 命令,Modem 都回返回一个 solicited response。现在 有两个应用程序:SMS_App1 和 SMS_App2。从用户的角度来看,要做到这两个应用程序能 够并发地运行。 作为设计的起点,能够很自然想到需要提供一个基础设施 RIL,为应用程序提供无线通 信相关的服务,包括呼叫控制、短消息、GPRS 等功能。而且对于上层应用程序来说,可以 抽象地把 RIL 看作逻辑设备,它只需要和 RIL 通信就能够获得所需要的服务。RIL 是一个典 型的生产和消费数据的设备,所以暴露的接口可以按照 Stream I/O 的规范来设计。这样做 还有一个好处就是,应用程序可以把设备看作文件,通过文件接口来访问 RIL.如图 2,我们 最初步的层次模型。 RIL_XXX 是提供给 DeviceManger 的 stream Interface,在 RIL Service 这一层,Dispather 将 request code 分发给相应的 function,例如 SMS。然后 SMS 的 function 发消息给 RIL Device 将请求以 AT 命令的形式发送给 GSM modem。 在这个基础上,我们可以慢慢展开我们的分析和设计过程了。 首先,我们先根据我们的应用场景提取出一些设计时要考虑的问题: 1.RIL 必须能够同时为多个请求者提供服务。 2.AT 命令必须与 Response 的绑定,即 AT 命令的发送者、AT 命令和 Response 之间对应关 系必须得到保证。 3.I/O 效率比较高。 4.需要 Notification 机制。 这里面有两层意思:1.怎么把 Response 交给应用程序;2.在多用户环境下,怎么判断该把 Response 交给哪个应用程序。 5. modem 对 AT 命令的处理是串行的,只有第一个 AT 命令发送后才能发送第二个 AT 命令。 6. 程序向 modem 发送 AT 命令,除了 unsolicited response 之外,基本的交互模式就是请求-- 应答模式,即对每一个 AT 命令必须收到一个 solicited response。 其次,为了方便讨论和不过早地涉及到细节问题,对我们的模型作一些理想化的假设: 1.AT命令总是能够通过串口设备发给modem,然后modem又能够通过空中接口发送给基站。总 而言之,在数据的传输过程中,每一个环节都是可靠的,不可能出现数据丢失,数据错误的 问题。 2.对于每一个 AT 命令,modem 都会返回一个 response,不会出现没有应答的情况。 接下来,我们要界定问题域的边界,弄清我们的原型与外界环境的关系,明确 RIL 所处 的位置。当然,我们里的环境就是 windows mobile 软件的总体架构,RIL 作为这个精巧系 统的部件,必须协调好与其它部件关系才能够发挥正常的功能。 如图 3,着色的部分正是我们所关注的问题域。我们从整个系统的角度来观察 RIL 的工 作流程。RIL Stub 和 RIL Driver 拥有自己的线程,名为 RILThread。应用程序调用 RIL 的工作流程如下: 1.应用程序的进程在自己的进程空间里,以调用RIL Proxy方式发送请求。 2.RIL Proxy 以IPC方式穿越进程边界,把请求传给 Device Manager。 3.Device Mananger 根据操作码,将请求分发到相应的驱动程序,在这里当然是 RIL。 4.RIL Stub首先接收操作码,根据PID做Context切换,然后把请求转发给RIL Driver。 5.现在 RIL Driver 已经处于对应于用户进程的 Context 中,开始处理操作码。例如, 将 AT 命令发给 GSM modem,等待返回的 response。当然,RIL Driver 运行在自己的线程里。 为了做到RIL 驱动能为多个应用(在这里就是进程)同时提供服务,RIL Stub需要做这 两件事情: 1.为每一个进程创建一个Context 对象,用来维护处理应用程序请求时的一些私有数据,我 们可以用一个类来表示就是CRilInstance。 2.当应用程序向DevieManger发送操作请求时,DeviceManager 将RIL切换到适当的Context, 然后将请求发给 RIL。 下面是CRilInstance 的创建过程: 1.在用户进程里,调用RIL Proxy 的接口 RIL_Initialize()获得 RIL的一个实例。 2.DeviceManger 将请求分发给 RIL 。 3.RIL Stub 将请求转换为生成 RilInstance 的一个实例。RILStub 调用 RIL Driver 的 RIL_Open 做到这一点,生成的 Context 都由 RIL Driver 来管理。 三.同步 I/O 方案 图 4 给出类之间的关系和它们的接口,下面介绍一些主要类的 role 和 responsibility。 (1)CCommand role:对AT 命令的封装。 (2)CResponse:对Response的封装。Modem通过串口返回的response是一串字符,我们把它封 装在这个类里面。 (3)CNotification:为了程序处理的方便,我们会将response映射为一系列的notification code,封装在CNotification里面。 这些类的responsibility我们将在后面慢慢地明确。 (4)CRilNotificationQueue role:管理对缓冲区的访问,这个缓冲区是队列的形式组织的。 responsibility: 1.出队、入队的操作。 2.数据保护,当队列在多个Thread Context中被调用时,需要保护共享资源的机制。 (5)CRilHandle:RIL 驱动对象。 role:从客户的角度看,把它看作逻辑上的无线设备。 resposibility: 1.管理 RIL 设备的 open context,即对应 CRilInstanceHandle。 2.打包 AT 命令。 3.对串口设备的访问和操作。 4.通过串口将 AT 命令发送给 modem。 5.接收 modem 返回的 response 6.解析 response , 解析结果放在 notification 里 7.通知应用,AT 命令处理后的结果 8.modem 状态的维护 (6)CRilInstance: RIL 的 Open Context role:每个应用程序在 RIL 的 context, responsibility: 1. 管理 notification queue 2. 为应用 提供接口,取出 notification 图 5 是同步 I/O 过程。在 SendCmdWithRsp()里面,SendCmd()和 WaitRsp()被耦合在一 起,只有读写的操作都完成后,函数才会返回。在返回之前,会将解析出来的 response 放进 CRilNotificatioQueue 里存储起来。 上面的设计存在两个问题: 1.I/O 的效率很低。原因有两点: (1)对串口的读写都是同步方式 (2)读写耦合紧密,也就是 AT 命令的写和读该命令的 response 是绑定在一起的。 这种模式的好处是:读的操作和写的操作处理起来都非常简单,不需要复杂的 notification 机制;容易满足请求——应答模式的要求。缺点就是:由于操作的藕和太过于紧 密,而且读写的操作都是堵塞的,这样会导致系统 I/O 效率低。对于通信软件来说,系统的 吞吐量和时间上的响应延迟都是要求较高的,而我们的设计不能适应这种要求。 2.Responsibilty 分配不均衡。CRilHandle 承担了太多的工作,造成性能瓶颈。我们可以创 建新的类,分解 CRilHandle 任务,把它们分配给这些新类。 四.异步 I/O 方案 前面的设计方案由于性能的原因不太可取,但我们可以在它的基础上作进一步的改进。 我们的基本思路就是有两点: 1.将同步 I/O 改为异步 I/O,当然这样做技术上的难度会增加。 2.分解 CRilHandle 的职责。 整个系统可划分为两大部分:命令的发送部分和 response 的接收部分。我们先考虑命 令发送部分。为了使关注问题更集中,只考虑 AT 命令发送部分,并且不考虑超时机制,也 不考虑可靠传输机制和错误处理机制。 改进后的 Class Diagram 如图 6 所示。相对于原来的 Class Diagram,我们主要做了这些 改动: 1.增加一个新的类 CComHandle,作为 modem 的代理,负责对 modem 的读写,以及 modem 状态维护。这样,CRilHandle 的职责就相对简单了 2.将同步写改为异步写。为此我们需要开一个缓冲区,CRilHandle 将 AT Command 写进缓 冲区后就完成了写操作返回;然后 CComHandle 从缓冲区取出 AT Command ,把它通过串 口发送出去。 3.对于缓冲区,我们可以采用队列的数据结构,在这里我们用 CQueue 管理这个队列。 现在有几个问题要考虑: 1.谁来驱动CComHandle工作?可以把CComHandle定义为active object对象,它能够主动 完成这些任务:先从缓冲区取出AT Command ,然后将AT Command发送给modem。为此, CComHandle需要有属于自己的Thread Context,我们将它定义为CommandThread 。 2.对象之间如何协作? 一种方式是让对象之间直接去交互,例如让CRilHandle和CComHandle去调用CQueue提供的 接口。但有两点使得这个方式不合适: (1)从类定义的role来说,CRilHandle 和CComHandle都是设备的抽象,不应该去与CmdQue 打交道,所以这上述方法就不合适。 (2)耦合紧密。如果将来换一种缓冲区管理模式,例如不用队列改用池,还得需要修改 CRilHandle 和CComHandle的实现。 因此,可以使用另一种协作方式:从概念上假设有一个organizer,通过调用这些类的接 口,把这些类的活动有机地组合起来以完成某个任务。这样不同的对象之间就用不着直接发 生交互了,而如果把这个概念映射到软件的设计上就是抽象出来的一个更高级的函数模块。 如图7、8给出了类之间的协作关系和发送命令的过程。Ccommand和CrilHandle的接口我 们在后面的讨论中才能确定下来。 3.共享资源的并发控制问题。 CCommandQueue跨越了两个Thread Context 边界,如果不 采用并发控制策略,在不同的context切换过程中,会导致对数据的操作产生逻辑错误。我 们可以把这个问题归为producer/consumer模型,然后制订我们的控制策略。 首先得考虑下面的问题: (1)为了不使并发控制策略影响这个系统架构,希望将并发控制策略封装起来。 (2)为了简化设计,put(),get()为堵塞式(暂时不考虑超时机制)。 (3)较小的资源开销。加锁的粒度太大,时间太长都会降低系统运行效率;另一方面,过 度使用mutex、event和semaphore都会消耗系统资源。 下面给出共享资源的并发控制策略:m_nUsed 用来标志队列剩余的资源个数。不管是读还 是写操作,在访问m_nUsed时先申请锁,在获得锁之后对临界资源进行操作,然后解锁并发 信号唤醒堵塞在该信号上的任务。 如图9所示,由于锁的粒度很小,put与get竞争的域较小,在系统资源和时间开销上较 小。 如图 10,11.依据相同的设计方法,给出 response 的接收部分。在 ResponseThread 里 面,先从 ComHandle 读取数据保存在 CRilHandle 的缓冲区里,然后创建一个 CResponse 对 象,由 CResponse 负责解析,接下来就将 CResponse 放进队列里面。 五.Notification机制与类图合并 在前面的设计里我们还没有考虑Notification机制的实现问题,即如何把保存在队列里 面的response发送给某个CRilInstance,以便应用程序在未来某个时刻去取走 notification。我们先给出一个简单的方法: 1.从队列取出response 然后分发给某个CRilInstance。 2.CRilInstance把response 转换为Notification,然后放进NotificationQueue. 3.主线程响应应用程序的请求,从Noitfication队列里面取出 Notification. 但这中间有一个很关键的问题:该把Response发给哪个CRilInstance 对象?这实际上是 我们之前没有考虑的一个问题:AT命令必须与Response的绑定,即谁发送的这个AT命令谁就 应该收到这个response。我们可以让CComand拥有CRilInstance实例的Handle,让CComand 判断该把response发给谁。但我们只解决了部分问题,而AT命令与Response之间的绑定关系 仍然没有解决。 我们先考虑另外一个之前被忽略的问题:如何保证请求--应答模式。在RIL目前的架构下, 这个问题似乎很难解决,为此RIL用了一个不太直观的方法,看其来有点晦涩。那就是通过 CommandThread与ResponseThread之间同步来保证请求--应答的要求: 1.在CommandThread里,将CRspQueue清空。 2.向串口发送AT命令,然后CommandThread堵塞在Get()上。 3.在ResponseThread里,如果收到response,调用put将response放进CRspQueue,并唤醒 CommandThread。 4.CommandThread执行Get()。 按照上面的方法,请求--应答模式可以得到保证,并且AT命令与Response之间对应关系 也可以确定。那么在这个基础上,第一个问题也就很容易解决了:CCommand提供接口 SendRsp(),由CCommand负责把Response转换为Notification,在取出CRilInstance的Handle 后,把Notification交给CRilInstanceHandle实例。 如图12,由于Command拥有CRilInstance的Handle,我们可以把response数据传给 Command对象,由它负责通知CrilInstanceHandle 现在可以将发送命令的class diagram 和接收response以及发送notification部分合 成一张完整的类图。当在合并设计图时出现一些新的问题。 CComHandle可能运行在不同的Thread Context:CommandThread 和ResponseThread。 CComHandle 有一些私有数据用来维护串口状态信息和modem的工作模式,对这些数据操作的 过程中可能刚好发生context的切换。因此为了保护共享资源,同样需要在CComanHandle里 面实现共享资源的并发控制策略。另外,要注意的是,对于SetCommMask这类改变串口设备 设置信息的操作,也需要放在临界段里面处理。 CRilHandle也会遇到同样的问题,同样也需要对共享资源的访问进行保护。 接下来,将命令发送部分的类图和response接收部分的类图合并起来就可以得到我们的 完整的设计图,如图13所示。 六.结束语 对于流设备,I/O的效率非常的关键,在硬件不变情况下很大程度上取决于软件设计上 的合理性。所以不论是在软件架构还是实现机制上,我们所做的努力都是为了这个目标。当 然,目前的设计依然不是一个最优的方案而且很脆弱,因为我们忽略了其它方面的考虑。在 将来,我们将针对这些问题一一加以讨论。有一点要注意的是:为了展现设计时候的思考过 程,类的划分和一些接口定义并不完全与Windows Mobile 的RIL完全一致。 现在,RIL已经可以支持让多个SMS的应用程序并发地运行了,但是如果用户想一边通过 GPRS上网一边收发短信,又该怎么办呢?这涉及到状态转换、多路复用等系一列复杂问题, 将来有时间可以继续加以深入讨论。 作者联系方式:redcatlog_hust@hotmail.com或者xiali_hust@163.com
还剩9页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 8 金币 [ 分享pdf获得金币 ] 0 人已下载

下载pdf

pdf贡献者

sun371763619

贡献于2012-10-23

下载需要 8 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!
下载pdf