第一部分简介简单介绍性部分:Android电话系统围绕底层使用Modem硬件来搭建,提供呼叫、短信和网络连接功能,其中modem也称为基带。Modem驱动程序包含在Linux内核层中,所以3G/4G模块的搭建其实就是电话系统的搭建主流3G/4G模块:主要分有内置(集成在处理器中如高通等,高通拥有相关基带的专利,内置模块主要通过共享内存与处理器通信),外置(较常见,大多通过usb转串口接口并利用AT命令与处理器通信,usb串口一般使用标准的驱动,AT命令由Hayes公司发明,一种是调制解调器命令语言每条命令以AT(也有一些笔记本专用的接口类型如PCIE和NGFF,手机上的LGA,工业用B2B等等)对与目前的通信模块来说,都已经非常成熟,有有着接口简单和统一的软件接口一般大多数模块装上SIM卡直接上电即可完成初始找网、网络注册等工作。框架部分主要是Android:1电话系统大体框架(图1):分三大层,硬件(连接modem设备),Android系统(主要包括了Linux内核层,运行库层和Framework层),平台API(即再往上为应用层)图(1)电话系统大体框架2.电话系统部分结构图(2):具体实现自下到上:Modem驱动,RIL库、RIL守护进程,电话JAVA框架和电话应用(其中电话系统部分无JNI)KernelSpace属于驱动层在内核中实现,一般分为AT命令通道和数据通道两路接口。RIL层:贯穿Android的内核层至应用层,由三部分组成:RIL守护进程(本质是rild可执行程序,开机通过init启动,与framework层主要通过socket来进行)、libril库和ril实现库(电话层硬件抽象层)。主要负责负责数据的可靠传输、AT命令的发送以及response(来自modem)的解析图(2)电话系统部分结构图3.RIL接口下层结构(图3)(更细化的下层)ril实现库的接口非常复杂,需要处理的命令,相关结构体比较多,其接口主要定义在hardware/ril/include/telephony目录的ri.h中。rildsocket:与框架层进行通信RIL_Env:主要用于请求完成函数、上报消息响应函数和周期行处理函数三个功能。RIL_RadioFunctions:RIL_REQUEST:RequestCompete:UnsolicitedResponse:RIL_UNSOL:(ril硬件抽象层主要实现ril命令与AT命令的转换。)(电话功能移植的两大部分:Modem驱动和ril硬件抽象层,移植需要注意的问题是省电,因为Modem省电策略复杂,低功耗模式下还要处理来电或短信等唤醒操作。)图(3)RIL接口下层结构Linux部分(具体实现部分):Linux部分(部分与Android相同):1.drivers/usb/serial/option.c#defineXXXX_OPTION_VENDOR_IDXXX(添加PID和VID)#defineXXXX_OPTION_PRODUCT_COLTXXX2.(外置插在usb上的话)usb_modeswitch插入的3G/4G模块被识别成存储设备,用usb_modeswitch转成串口3.在staticstructusb_device_idoption_ids[]={……};(结构结构体中加入加入ID){USB_DEVICE(OPTION_VENDOR_ID,OPTION_PRODUCT_COLT)},…{USB_DEVICE(XXXX_OPTION_VENDOR_ID,XXXX_OPTION_PRODUCT_COLT)},(插上3G/4G模块上电后会出现两个端口:/dev/ttyusb0和/dev/ttyusb1一个用于数据一个用于命令.)(以上Linux和Android相同部分)第二部分RIL源码分析不同设备厂商使用的AT命令不完全相同,为了保密,AP(上层)与BP(板层)之间通过各厂商自己的相关动态库来通信。RIL模块由rild守护进程、libril.so、librefrence.so三部分组成:1.rild模块被编译为一个可执行文件,实现一个main函数作为整个ril模块的入口点。2.libril.so是共享库,主要负责同上层的通信工作,接收ril的请求,并传递给librefrence_ril.so,同时将librefrence_ril.so返回的消息送给调用进程。3.librefrence_ril.so是由各手机厂商自己实现,在rild进程运行中通过dlopen方式加载,主要负责跟modem硬件通信,转换来自libril.so的请求为AT命令,同时监听Modem的反馈信息给libril.so源代码的图谱如下流程框图如下:RILD源码分析在kernel启动完成后,将启动第一个应用进程Init进程,在android之Init进程启动过程源码分析一文中对init进程的启动流程进行了详细的介绍。init进程在启动过程中将读取init.rc文件来启动一些重量级的native服务,rild进程就是通过配置在init.rc中来启动的。在代码中的流程图如下在main函数中主要完成以下工作:1.解析命令行参数,通过判断是否为模拟器采取不同的方式来读取libreference-ril.so库的存放路径;2.使用dlopen手动装载libreference-ril.so库;3.启动事件循环处理;(这里启动另一线程)4.从libreference-ril.so库中取得RIL_Init函数地址,并使用该函数将libril.so库中的RIL_Env接口注册到libreference-ril.so库,同时将libreference-ril.so库中的RIL_RadioFunctions接口注册到到libril.so库中,建立起libril.so库与libreference-ril.so库通信桥梁;启动事件循环处理eventLoop工作线程建立多路I/O驱动机制的消息队列,用来接收上层发出的命令以及往Modem发送AT指令的工作,是整个RIL系统的核心部分。创建一个事件分发线程s_tid_dispatch,线程中主要执行eventLoop(ril_event_loop).ventLoop流程图1.定时事件:根据事件的执行时间来启动执行,通过ril_timer_add添加到time_list队列中2.Wakeup事件:这些事件的句柄fd将加入的selectIO多路复用的句柄池readFDs中,当对应的fd可读时将触发这些事件。对于处于listen端的socket,fd可读表示有个客户端连接,此时需要调用accept接受连接。在eventLoop工作线程中,循环处理到来的事件及定时结束事件,整个处理流程如下图所示:首先通过Linux中的select多路I/O复用对句柄池中的所有句柄进行监控,当有事件到来时select返回,否则阻塞。当select返回时,表示有事件的到来,通过调用processTimeouts函数来处理超时事件,处理方式是遍历time_list链表以查询超时事件,并将超时事件移入到pending_list链表中,接着调用processReadReadies函数来处理触发的事件,处理方式为遍历watch_table列表以查询触发的事件,并将触发的事件移入到pending_list链表中,如果该事件不是持久事件,还需要从watch_table列表中移除,当查询完两种待处理的事件并放入到pending_list链表中后,调用firePending函数对待处理的事件进行集中处理,处理方式为遍历链表,调用每一个事件的回调函数。部分主要代码如下//使用select函数等待在FDS上,只要FDS中记录的设备有数据到来,select就会设置相应的标志位并返回。readFDS记录了所有的事件相关设备句柄。readFDS中句柄是在在AddEvent加入的。printReadies(&rfds);n=select(nfds,&rfds,NULL,NULL,ptv);printReadies(&rfds);dlog(~~~~%deventsfired~~~~,n);if(n0){if(errno==EINTR)continue;LOGE(ril_event:selecterror(%d),errno);return;}processTimeouts();//从timer_list中查询执行时间已到的事件,并添加到pending_list中processReadReadies(&rfds,n);//从watch_table中查询数据可读的事件,并添加到pending_list中去处理,如果该事件不是持久事件,则同时从watch_table中删除//遍历pending_list,调用事件处理回调函数处理所有事件firePending();RIL接口移植Hardware/ril/include/telephony/ril.hRIL_ENC定义StructRIL_ENV{//动态库完成请求后通知处理结果的接口void(*OnRequestComplete)(RIL_Tokent,RIL_Errnoe,void*response,size_tresponselen);//动态库unSolicitedResponse通知接口void(*OnUnsolicitedResponse)(intunsolResponse,constvoid*data,size_tdatalen);//向Rild提交一个超时任务的接口void(*RequestTimedCallback)(RIL_TimedCallbackcallback,void*param,conststructtimeval*relativeTime);}在hardware\ril\libril\ril.cpp中实现了RIL_Env的各个接口函数RIL_onRequestComplete通过调用responseXXX将底层响应传给客户进程RIL_onUnsolicitedResponse函数处理modem从网络端接收到的各种事件,如网络信号变化,拨入的电话,收到短信等。然后传给客户进程。RIL_requestTimedCallback回调对应的内部处理函数,将回调添加到event循环。RIL_RadioFunctions定义客户端向Rild发送请求的接口,由各设备厂商实现。typedefstruct{intversion;//Rild版本RIL_RequestFunconRequest;//AP请求接口RIL_RadioStateRequestonStateRequest;//BP状态查询RIL_Supportssupports;RIL_CancelonCancel;RIL_GetVersiongetVersion;//动态库版本}RIL_RadioFunctions;在hardware\ril\reference-ril\reference-ril.c中实现了RIL_RadioFunctions的各个接口函数(其中最重要的是onRequest函数)onRequest函数对每一个RIL_REQUEST_XXX请求转化成相应的ATcommand,发送给modem,然后睡眠等待,当收到ATcommand的最终响应后,线程被唤醒,将响应传给客户端进程。注册RIL_Env接口主要步骤如下由于各设备厂商的AT指令差异,因此与modem交互层需要各厂商实现,以动态库的形式提供。作为介于modem与上层的中间层,即要与底层交互也要与上层通信,因此就需要定义一个接口来衔接RILD与动态库,RIL_Env和RIL_RadioFunctions接口就是libril.so与librefrence.so通信的桥梁。是Rild架构中用于隔离通用代码和厂商代码的接口,RIL_Env由通用代码实现,而RIL_RadioFunct