前言
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的一个结构图。整个通信html" target="_blank">过程有四个层:
RILJ与RILD(RILD与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状态变化
为方便上层实时监听网络状态、通话状态以及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
oneway interface IPhoneStateListener { void onServiceStateChanged(in ServiceState serviceState); void onSignalStrengthChanged(int asu); void onMessageWaitingIndicatorChanged(boolean mwi); void onCallForwardingIndicatorChanged(boolean cfi); // we use bundle here instead of CellLocation so it can get the right subclass void onCellLocationChanged(in Bundle location); void onCallStateChanged(int state, String incomingNumber); void onDataConnectionStateChanged(int state, int networkType); void onDataActivity(int direction); void onSignalStrengthsChanged(in SignalStrength signalStrength); void onOtaspChanged(in int otaspMode); void onCellInfoChanged(in List<CellInfo> cellInfo); void onPreciseCallStateChanged(in PreciseCallState callState); void onPreciseDataConnectionStateChanged(in PreciseDataConnectionState dataConnectionState); void onDataConnectionRealTimeInfoChanged(in DataConnectionRealTimeInfo dcRtInfo); void onVoLteServiceStateChanged(in VoLteServiceState lteState); void onOemHookRawEvent(in byte[] rawData); void onCarrierNetworkChange(in boolean active); void onFdnUpdated(); void onVoiceRadioBearerHoStateChanged(int state); }
RILJ与RILD如何通信
RILJ在创建过程中,会启动两个线程:RILSender和RILReceiver,RILSender负责将指令发送给RILD,而RILReceiver则负责从读取从RILD发送过来的数据。RILJ与RILD的通信通道就是在RILReceiver中建立起来的。
我们来看一看RILReciver的代码:
class RILReceiver implements Runnable { byte[] buffer; RILReceiver() { ... @Override public void run() { 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){ ... // don't print an error message after the the first time // or after the 8th time if (retryCount == 8) { Rlog.e (RILJ_LOG_TAG, "Couldn't find '" + rilSocket + "' socket after " + retryCount + " times, continuing to retry silently"); } else if (retryCount >= 0 && retryCount < 8) { Rlog.i (RILJ_LOG_TAG, "Couldn't 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 reached break; } 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 close clearRequestList(RADIO_NOT_AVAILABLE, false); }} catch (Throwable tr) { Rlog.e(RILJ_LOG_TAG,"Uncaught exception", tr); } } }
RILReceiver启动时,会建立一个UNIX Domain socket(LocalSocket,kernel层对应/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)的代码按照功能来划分的话,主要有以下几个组成部分:
以上代码主要位于两个目录:
下面,以拨打电话的流程作为示例看一看RIL是如何发挥作用的。
示例:CALL流程
下图是一个MO(Mobile Originated) 通话流程简图:
到这一步后,通话并没有开始,如果MT接听了电话,则MO会收到CALL状态变化的信息,然后,才真正开始建立通话链接。
到此这篇关于Android RIL使用详解的文章就介绍到这了,更多相关Android RIL内容请搜索小牛知识库以前的文章或继续浏览下面的相关文章希望大家以后多多支持小牛知识库!
本文向大家介绍RecyclerView使用详解,包括了RecyclerView使用详解的使用技巧和注意事项,需要的朋友参考一下 RecylerView介绍 RecylerView是support-v7包中的新组件,是一个强大的滑动组件,与经典的ListView相比,同样拥有item回收复用的功能,这一点从它的名字recylerview即回收view也可以看出。官方对于它的介绍则是:Recycler
本文向大家介绍详解log4net的使用,包括了详解log4net的使用的使用技巧和注意事项,需要的朋友参考一下 程序中只需要引用log4net.dll文件即可 配置的引用 首先添加以上代码。 CS程序:在Main方法中添加; BS程序:Application_Start方法中添加; 或是两者都可以在AssemblyInfo.cs(Properties中)文件里添加以下的语句: 详细配置 log4n
本文向大家介绍Android iconify 使用详解,包括了Android iconify 使用详解的使用技巧和注意事项,需要的朋友参考一下 android-iconify 使用详解 ,下文图文并茂给大家介绍的非常详细,具体内容详情请参考下文。 1、android-iconify简介 iconify的github地址:https://github.com/JoanZapata/android-i
本文向大家介绍Android5.0+ CollapsingToolbarLayout使用详解,包括了Android5.0+ CollapsingToolbarLayout使用详解的使用技巧和注意事项,需要的朋友参考一下 CollapsingToolbarLayout作用是提供了一个可以折叠的Toolbar,它继承至FrameLayout,给它设置layout_scrollFlags,它可以控制包含
本文向大家介绍详解使用Maven开发Web应用详细步骤,包括了详解使用Maven开发Web应用详细步骤的使用技巧和注意事项,需要的朋友参考一下 开发 Web 应用的思路 实现一个简单的 JSP/Servlet。 搭建创建 Web 应用工程的环境。 创建 Web 应用工程。 Web 应用工程的目录结构。 结合 Web 服务器,发布 Web 应用。 体验 Web 应用的开发和发布测试过程。 实现经典的
本文向大家介绍Jquery Datatables的使用详解,包括了Jquery Datatables的使用详解的使用技巧和注意事项,需要的朋友参考一下 参考: Datatables中文网 Datatables官网 Datatables 是一款强大的Jquery表格处理插件,样式方面可以兼容bootstrap3/4、JqueryUi等,也有默认的样式可以选择。使用Datatables可以很灵活的从