软件开发设计流程图,seo搜索引擎官网,西安市城乡建设管理局网站的公示栏,德州网络Android作为一个通用的移动平台#xff0c;其首要的功能就是通话、短信以及上网等通信功能。那么#xff0c;从系统的角度来看#xff0c;Android究竟是怎么实现与网络的交互的了#xff1f; 这篇文章里#xff0c;就来看一看Android中负责通信功能的Telephony中间层…Android作为一个通用的移动平台其首要的功能就是通话、短信以及上网等通信功能。那么从系统的角度来看Android究竟是怎么实现与网络的交互的了 这篇文章里就来看一看Android中负责通信功能的Telephony中间层通常也被称之为RIL(Radio Interface Layer无线接口层)的具体实现原理与架构。
Android手机要实现与网络端的通信需要跨越两个层
RIL Java(RILJ)负责将上层APP的通信请求发送给HAL层RIL C(RILD) 系统守护进程负责将RILJ的请求命令发送给CP(Communication Processor)
什么是RIL
简单的说RIL(Radio Interface Layer)就是将应用程序的通信请求发送给CP的中间层其包括两个部分一个是Java层RILJ,一个是C层不妨看作是CP对应的HAL层RILD。RILJ属于系统Phone进程的一部分随Phone进程启动而加载而RILD守护进程是通过Android的Init进程进行加载的。
RIL结构
下图是一个Android RIL的一个结构图。整个通信过程有四个层
最上层的是应用程序如通话短信以及SIM卡管理它们主要负责将用户的指令发送到RIL Framework(以后统称RILJRILJ为上层提供了通用的API如TelephonyManager(包括通话网络状态 SubscriptionManager(卡状态以及SmsManager等同时RILJ还负责维持与RILD的通信并将上层的请求发送给RILDRILD是系统的守护进程对于支持通话功能的移动平台是必不可少的。RILD的功能主要功能是将RILJ发送过来的请求继续传递给CP同时会及时将CP的状态变化发送给RILJLinux驱动层kernel驱动层接受到数据后将指令传给CP最后由CP发送给网络端等网络返回结果后CP将传回给RILD RILJ与RILDRILD与CP的通信都是通过一个个消息进行数据传递。消息主要分两种一种是RILJ主动发送的请求solicited常见的有RIL_REQUEST_GET_SIM_STATUS(获取SIM卡状态 RIL_REQUEST_DIAL(拨打电话RIL_REQUEST_SEND_SMS发送短信 RIL_REQUEST_GET_CURRENT_CALLS获取当前通话状态RIL_REQUEST_VOICE_REGISTRATION_STATE获取网络状态 另一种则是从CP主动上报给RIL的消息unsolicited)如网络状态发生变化时CP会上报RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED有新短信时会上报RIL_UNSOL_RESPONSE_NEW_SMS有来电时会上报RIL_UNSOL_CALL_RING。 RIL相关的请求命令与数据结构都定义在/android/hardware/ril/include/telephony/ril.h
在整个过程中有几个关键问题
上层是如何得知RILJ状态变化的RILJ与RILD是怎么进行通信的RILJD与CP又是如何进行通信的
上层如何得知RILJ状态变化
为方便上层实时监听网络状态、通话状态以及CP的状态变化RIL提供了一个专门的监听接口IPhoneStateListener.aidl上层需要监听上述状态变化时只需要实现上述接口,并在Android系统服务TelephonyRegistry中对上述接口实现进行注册
public void listen(String pkgForDebug, IPhoneStateListener callback, int events, boolean notifyNow);
另外也可以在TelephonyManager中对RIL状态进行监听
public void listen(PhoneStateListener listener, int events)源代码: /android/frameworks/base/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl RILJ与RILD如何通信
RILJ在创建过程中会启动两个线程RILSender和RILReceiver,RILSender负责将指令发送给RILD,而RILReceiver则负责从读取从RILD发送过来的数据。RILJ与RILD的通信通道就是在RILReceiver中建立起来的。
我们来看一看RILReciver的代码 class RILReceiver implements Runnable {byte[] buffer;RILReceiver() {...Overridepublic voidrun() {int retryCount 0;String rilSocket rild;// 尝试与RILD建立连接try {for (;;) {LocalSocket s null;LocalSocketAddress l;if (mInstanceId null || mInstanceId 0 ) {rilSocket SOCKET_NAME_RIL[0];} else {rilSocket SOCKET_NAME_RIL[mInstanceId];}try {s new LocalSocket();l new LocalSocketAddress(rilSocket,LocalSocketAddress.Namespace.RESERVED);s.connect(l);} catch (IOException ex){...// dont print an error message after the the first time// or after the 8th timeif (retryCount 8) {Rlog.e (RILJ_LOG_TAG,Couldnt find rilSocket socket after retryCount times, continuing to retry silently);} else if (retryCount 0 retryCount 8) {Rlog.i (RILJ_LOG_TAG,Couldnt find rilSocket socket; retrying after timeout);}...retryCount;continue;}retryCount 0;mSocket s;// 从socket读取数据int length 0;try {InputStream is mSocket.getInputStream();for (;;) {Parcel p;length readRilMessage(is, buffer);if (length 0) {// End-of-stream reachedbreak;}p Parcel.obtain();p.unmarshall(buffer, 0, length);p.setDataPosition(0);processResponse(p);p.recycle();}} catch (java.io.IOException ex) {Rlog.i(RILJ_LOG_TAG, rilSocket socket closed,ex);} catch (Throwable tr) {Rlog.e(RILJ_LOG_TAG, Uncaught exception read length length Exception: tr.toString());}//无法读取数据将CP状态设置为不可用setRadioState (RadioState.RADIO_UNAVAILABLE);...mSocket null;RILRequest.resetSerial();// Clear request list on closeclearRequestList(RADIO_NOT_AVAILABLE, false);}} catch (Throwable tr) {Rlog.e(RILJ_LOG_TAG,Uncaught exception, tr);}}}
RILReceiver启动时会建立一个UNIX Domain socket(LocalSocketkernel层对应/dev/socket/rild)与RILD进行通信然后一直从socket中读取数据,并将数据传给上层。连接成功后RILD会发送一个消息给RILJ表示连接成功了这样RILJ就可以将请求数据发送给RILD进行通信了。
RILD与CP如何进行通信
RILD与CP可以看做是两个运行在不同CPU上的进程通信交换数据方式一般有两种情况。如果AP与CP集中在一个芯片上如高通的平台就是将AP与CP集中在一块芯片上这时通常采用共享内存的方式实现跨进程通信而如果不是在同一块芯片而是AP与CP分别采用不同厂商的平台则一般采用字符设备(character devices) 进行通信。总的说来共享内存的方式在速度上要优于字符设备。接下来主要介绍下RILJ部分的代码结构。
RILJ代码结构
RIL Framework (RILJ)的代码按照功能来划分的话主要有以下几个组成部分 - 管理网络状态信号强度网络注册状态等:ServiceStateTracker等 - 通话管理拨号接听呼叫等待等 CallManager,GsmCallTracker等 - SMS短信接收发送 InboundSMSHandler,SmsDispater等 - SIM卡管理 UiccController, SubscriptionsController等 - 数据链接管理 DcTracker,DctController等 - Telephony 大管家 PhoneBase,GsmPhone,PhoneProxy等
以上代码主要位于两个目录
/android/frameworks/opt/telephony/ 负责与RILD交互/android/frameworks/base/telephony/ 对上层提供接口
下面以拨打电话的流程作为示例看一看RIL是如何发挥作用的。
示例 CALL流程
下图是一个MO(Mobile Originated) 通话流程简图 1. APP向TelecomManager发送拨号请求关于TelecomManager可以参考另一篇文章Android Telecom系统服务 1. TelecomManager将通话请求发送给GsmPhone 1. GsmPhone继续将指令传递给GsmCallTracker 1. GsmCallTracker调用RILJRILJ将通话请求发送给RILD 1. RILD接收到通话指令时发送给CP 1. CP发送给网络MT(Mobile Terminal)收到通话后告知网络由网络将该信息传递给MO已将通话信息发送给MT了就是手机发出嘟嘟声音的时候通话状态由DIALING – ALERTING 1. RILD收到通话状态变化的消息后发送一个UNSOL_RESPONSE_CALL_STATE_CHANGED的消息给RILJ 1. RILJ通知GsmCallTracker通话状态变化了 1. GsmCallTracker主动查询CALL状态pollCallWhenSafe()确保得到的信息是对的没有发生变化 1. RILJ给RILD发送getCurrentCalls()的请求 1. RILD获取到CALL状态后上报给RILJ再由RILJ返回结果给GsmCallTracker 1. GsmCallTracker得到确定的CALL状态后通知GsmPhonenotifyPreciseCallStateChanged(); 1. GsmPhone将CALL状态变化的消息告知Telecom系统服务 1. 最后Telecom系统服务发送CALL状态变化的广播给上层APP
到这一步后通话并没有开始如果MT接听了电话则MO会收到CALL状态变化的信息然后才真正开始建立通话链接。