Android平台的RIL层移植到基于LINUX的通用平台的研究与实现
作者:赵国强 彭大芹
来源:《电子世界》2013年第10
        【摘要】本文通过对Android RIL层代码分析,将android RIL层功能在纯LINUX平台上实现,完全脱离了Android系统。为基于LINUX的通用平台实现一套成熟的RIL层代码,并开发出相应的框架层,以便基于LINUX的平台能快速成熟的向3G网络发起相关业务。在OpenWrt系统上验证了移植后的RIL层代码正常工作。
        【关键词】Android RILLINUX;移植;Parcel;验证
        1.课题研究的背景和意义
        1.1 Android RIL简介
        Android RILRadio Interface Layer)提供了无线基带Modem与电话应用之间的抽象层。在Android RIL层中,完善的考虑了电话应用的各种情况,如:双SIM卡;电话,短信,彩信,PS DATA业务,PIN/PUK码等各种3G网络业务。
        RIL层在Android系统中,处于硬件抽象层,运行在一个独立的守护进程中,主要为框架层和基带接口提供适配,具有良好的独立性。其中的通信机制,与框架层接口主要使用Socket通信,内部线程主要使用管道,与基带接口默认使用AT命令。且其代码均由CC++来完成,依赖第三方库较少,所以,Android RIL层具有良好的移植性。
        1.2 移植Android RIL的意义
        目前很多基于LINUX平台的系统,如:PCLINUX操作系统),QT,路由器平台(如OpenWrt系统)等等,都对连接3G网络有需求,但在这些平台原生的功能中,没有独立的RIL接口层,所以开发一套基于LINUX的独立应用,用来支持与基带发起各种3G网络相关业务是很有意义的。Android RIL具有良好的稳定性,独立性,以及对3G网络业务的完整性,所以将其移植成一个独立的,供LINUX通用平台使用的RIL层,可方便所有的基于LINUX的平台完成各种电话应用的开发。
        2.Android系统中RIL层分析
        2.1 RIL层在Android系统中的位置
        RILAndroid系统中,处于硬件抽象层位置。主要通过SOCKET通信连接框架层,将框架层下发的消息解析后,向基带下发相应的AT指令,并将从基带返回的AT指令的响应,封装成消息,返回给框架层。位置如图1所示。
        2.2 Android RIL工作原理
        2.2.1 Android RIL代码说明
        RIL主要由RILDsocket通信在哪一层radio interface layer daemon)守护进程和两个动态库:librefrence_ril.solibril.so组成。Android工程源代码目录中,RIL代码包含于hardware/ril目录中,主要文件说明如表1所示。
        2.2.2 Android RIL工作原理
        rild以一个main函数作为整个RIL层的入口点,负责完成初始化。libril.so库包含了主要的消息循环流程,主要负责与框架层进行交互,在接收框架层命令后,调用相应函数处理,然后将命令响应结果传回客户进程。librefrence_ril.so主要提供各个具体业务的AT指令的封装和解析接口,供libril调用,向下通过AT_COM和基带进行交互。具体工作线程如图2所示。
        3.移植Android RIL层功能
        通过对Android RIL层代码分析,在RIL层主要使用了基于linuxPOSIX Threadpthread)多线程编程和socket IPC通信,这些在移植过程中是无须考虑的。需要移植的是RIL层依赖于Android系统的功能。
        3.1 移植Android系统属性
        系统属性是Android系统的一个重要特性。属性数据由init进程维护,用于管理系统全局配置和状态,每个属性对应一对键值。在RIL层中对系统属性的依赖比较小,所以不需要将Android系统属性机制全部移植。RIL层主要在RILD初始化过程中需要从系统属性读取reference-ril.so路径、AT设备路径,网卡设备等信息,以及运行过程中将从网络中动态获取的IPDNS等信息写入对应系统属性中。
        可根据所处的具体系统,将需要的信息写入系统保存全局共享参数的机制,并根据所处系统的配置方法去获取需要的参数。由于RIL层需要获得的参数非常有限,所以同样可以配置RIL层独有的配置文件,通过配置和解析RIL层的配置文件来达到替换Android系统属性机制。甚至可直接在rild启动的时候,作为应用参数直接传入。
        3.2 移植Android.mk编译文件
        Android.mk机制是Android平台利用makefile封装成一种特有的编译机制,在通用linux平台上,通常每个模块都有自己的Makefile文件。所以我们需要根据./libril./reference-ril./rild文件夹中的Android.mk内容写出对应的Makefile文件。从本质上来讲,Android.mk就是对Makefile的的一部分,所以移植编译文件是很简单的。
        ./libril./reference-ril中的Android.mk描述了libril.solibreference-ril.so两个动态库的生成和安装路径。./rild中的Android.mk描述了rild守护进程的生成和安装路径和链接libril.so库。
        3.3 移植Parcel消息
        由以上对Android RIL层功能分析发现,框架层和RIL层的交互是通过socket消息来互相传递的。消息作为IPC通信的数据单元是通过Parcel容器来进行封装的,用于存储序列化数据。所以在移植过程中,完成相同的消息机制,是整个移植工作的核心任务。源码位于Frameworks/base/libs/binder/parcel.cpp
        分析源码可知:1、整个读写全是在内存中进行,主要根据数据大小需求通过malloc()
realloc()、memcpy()等内存操作动态分配,这些接口都是标准C所具备的,移植性非常好;2Binder通信中数据对象都是封装成为parcel格式进行传输的,传输的类型包括IBinderFile descriptor等,这些数据在传输过程中需要做特殊处理,移植的依赖较多,好在RIL部分用不到Binder通信,所以这部分代码可以从中删除,降低了移植难度,所以只需要实现普通数据的消息封装。在Parcel中对普通数据的读写,定义了以下方法:writeBytebyte),readByte(),writeDoubledouble),readDouble(),writeFloat(),readFloat(),writeIntint),readInt(),wirteLonglong),readLong(),writeStringString),readString()。基本数据的消息封装通过这些方法来写入Parcel和从Parcel读出。由于AT指令的参数以及AT response均为IntString型数据,所以在RIL层中主要使用到了对这两种数据操作的方法。所以通过C++代码实现一个容器,并含有writeIntint),readInt(),writeStringString),readString()四种处理数据的方法是非常简单的。所以通过自己实现的类来模拟AndroidRIL层中的消息机制是可行的。
        3.4 开发框架层
        综上所述,将Android RIL移植到基于LINUX的通用平台就完全能够实现了。RIL只能支
持一路socket连接,事物处理都是串行的,要让其工作在多任务的系统上,互相不阻塞对方,需要更上层进行封装,Android的移动通信相关业务流程以及策略控制都是在框架层是通过JAVA代码实现的,在Android中叫做TelephonyTelephony为上层应用提供了并行访问的接口,但一般LINUX平台是没有运行JAVA虚拟机的,所以AndroidTelephony是无法进行移植的,所以需要开发一个与Android Telephony对等的框架层。
        框架层主要起连接RIL层和应用的作用,框架内部分为了客户端和服务端,客户端封装成共享库提供函数接口供应用程序使用,函数内部通过socket与服务端通信,服务端可以支持多个客户端同时连接,并将客户端的请求串行化发送到RILD,能够将RILD返回的结果异步地将返回给对应的请求客户端。为避免阻塞,服务端由三个线程来实现,如图3所示。线程一(accept_thread):接收上层应用下发的消息。将应用接入的clients排序,并将发送的消息存入链表data_queue中;线程二(sender_thread):将应用消息写入与RIL层的接口。依次从链表data_queue中取出消息,并依次写入到RIL层的接口;线程三(receiver_thread):将RILresponse写回应用。从RIL层的接口中读出消息,并判断出所属的应用描述符,并写入。
        4.搭建验证平台
        OpenWrt系统是一个运行在嵌入式设备上的LINUX系统,主要实现路由器功能,所以PS DATA是其最基本的业务。将OpenWrt系统移植到ARM开发板上,并加载基带模块。通过移植的RIL层代码,使开发板成功连入3G网络。驱动枚举出/dev/设备作为AT_COMRIL层通信,并创建网卡设备作为网络通信设备,如图4所示。编写应用创建SOCKET,并连入框架层的服务端,并在应用中将PS DATA请求写入Parcel。在系统中成功ping通网络,验证了移植后的RIL层在LINUX平台上运行良好。