Android Phone模块
Android Phone模块 一
电话管理是Android 系统支持的重要的业务之一,提供接听电话,收发短信、电话薄、网络事件监听、读取用户信息等功能。
从下到上可以分为四层:硬件驱动层、RIL daemon层、Telephony框架实现层、 PHONE应用层,下层为上层提供服务,每层之间采用不同的通讯方式交互。RIL daemon层实现为单独的一个开机启动的进程(rild命令),通过AT命令硬件驱动层交互,Telephony JAVA框架实现层包括一个RIL抽象层,RIL抽象层中通过一个本地socket与RIL daemon层(rild)交互,Phone应用层通过Binder机制与Telephony框架交互。
本文主要分析框架层相关的主要类的结构。
一 Telephony框架
Telephony框架系统类图如下图:
Telephony框架层为应用层和框架层的其它服务提供Telephony服务,提供了如下几个服务:PhoneInterfaceManager服务,是ITelephony接口的实现,IccSmsInterfaceManager短消息服务,是Isms接口的实现;IccPhoneBookInterfaceManager电话本服务,是IIccPhoneBook接口的实现;PhoneSubInfo提供用户信息读取服务,是IPhoneSubInfo接口的实现;TelephonyRegistry提供应用层的消息登记服务,是ITelephonyRegistry接口的实现。
应用程序通过以下几个客户端对象使用Telephony框架提供的服务。
应用程序可以在SmsManager单例对象(通过SmsManager类的getDefault函数返回SmsManager单例对象)中访问IccSmsInterfaceManager服务,用来收发短信。
通过IccProvider一个内容提供对象提供对IccPhoneBookInterfaceManager服务的访问,读取和管理电话本。
通过TelephonyManager对象提供对PhoneSubInfo、PhoneInterfaceManager、TelephonyRegistry服务的访问,TelephonyManager对象通过getSubscriberInfo函数获得PhoneSubInfo服务的远程访问代理对象。通过getITelephony函数获得PhoneInterfaceManager的远程访问代理对象。提供一个对象全局sRegistry(指向TelephonyRegistry服务的远程访问代理对象)访问TelephonyRegistry服务。
TelephonyManager通过这三个接口函数提供对外的TelephonyAPI,因此应用程序可以通过 TelephonyManager对象提供的TelephonyAPI访问这些服务,使用Telephony框架层提供的接口功能。
TelephonyManager对象本身通过Context对象调用getSystemService(Context.TELEPHONY_SERVICE)函数返回,TelephonyManager对象是一个单例对象。
PhoneInterfaceManager服务在默认电话应用的PhoneApp对象中采用单例模式进行初始化(PhoneApp对象本身也是单例对象),和PhoneApp对象公用一个进程,PhoneInterfaceManager为框架层的其它服务提供Telephony API 服务,并通过TelephonyManager对象(通过getITelephony函数获得ITelephony接口)为其它应用提供服务。PhoneInterfaceManager通过PhoneApp、CallManager、Phone对象实现相应功能。CallManager是一个单例对象,CallManager对象提供CALL控制以及登记通知等功能。
Phone对象是整个Telephony服务的核心,主要的Telephony服务(IccSmsInterfaceManager、IccPhoneBookInterfaceManager、PhoneSubInfo)及数据连接功能都通过具体的Phone对象提供,具体的Phone对象包括CDMAPhone、CDMALTEPhone、GSMPhone及SipPhone。
PhoneBase抽象类是这些具体Phone对象的共同的基类,本身一个Handler类,用来提供Phone接口的基实现,PhoneBase通过CommandsInterface接口与RIL daemon层交互,实现短消息提交、数据连接控制、ICC 信息读取等Telephony基类功能。PhoneBase包含SMSDispatcher、DataConnectionTracker、IccFileHandler、IccRecords、IccCard等几个抽象类成员,并通过这些抽象类成员提供某一方面功能的基类实现。
SMSDispatcher 、DataConnectionTracker 、IccFileHandler、IccRecords抽象类也是派生自Handler类,因此都能够向RIL发送命令,接收和处理RIL发来的事件和命令应答。PhoneBase包括一个PhoneNotifier接口,Phone对象本身及内部对象可以通过PhoneNotifier接口向应用发送Telephony事件通知。
CDMAPhone、GSMPhone、CDMALTEPhone三个具体的Phone对象在默认的PhoneApp应用中调用PhoneFactory的makeDefaultPhone函数根据不同的网络模式进行单例实例化,并封装进一个统一的PhoneProxy代理对象中。
[java] view plaincopy
- sCommandsInterface = new RIL(context, networkMode, cdmaSubscription);
- int phoneType = getPhoneType(networkMode);
- if (phoneType == Phone.PHONE_TYPE_GSM) {
- sProxyPhone = new PhoneProxy(new GSMPhone(context,sCommandsInterface, sPhoneNotifier));
- } else if (phoneType == Phone.PHONE_TYPE_CDMA) {
- switch (BaseCommands.getLteOnCdmaModeStatic()) {
- case Phone.LTE_ON_CDMA_TRUE:
- sProxyPhone = new PhoneProxy(new CDMALTEPhone(context,sCommandsInterface, sPhoneNotifier));
- break;
- case Phone.LTE_ON_CDMA_FALSE:
- default:
- sProxyPhone = new PhoneProxy(new CDMAPhone(context,sCommandsInterface, sPhoneNotifier));
- break;
- }
- }
PhoneProxy内部的对象成员mActivePhone指向代理的实际Phone对象。PhoneProxy代理对象实现了Phone接口,使应用能够使用统一的PhoneProxy对象控制操作具体类型的Phone对象,而不用关心它们之间的差异(代理模式的采用),应用程序通过PhoneFactory的getDefaultPhone函数返回统一的PhoneProxy代理对象来访问不同的Phone对象。
因为Telephony框架层支持不同的网络类型的Telephony实现(CDMA、GSM),因此Telephony框架层普遍使用代理模式来对应用提供统一的服务接口。如PhoneProxy代理对象内部还封装了IccSmsInterfaceManager、IccPhoneBookInterfaceManager、PhoneSubInfo三个服务的代理对象,通过代理对象提供对这三个服务的操作控制。
[java] view plaincopy
- public PhoneProxy(Phone phone) {
- mActivePhone = phone;
- mIccSmsInterfaceManagerProxy = new IccSmsInterfaceManagerProxy(phone.getIccSmsInterfaceManager());
- mIccPhoneBookInterfaceManagerProxy = new IccPhoneBookInterfaceManagerProxy(phone.getIccPhoneBookInterfaceManager());
- mPhoneSubInfoProxy = new PhoneSubInfoProxy(phone.getPhoneSubInfo());
- mCommandsInterface = ((PhoneBase)mActivePhone).mCM;
- }
另外CommandsInterface接口的具体实现对象RIL及PhoneNotifier接口的具体实现对象DefaultPhoneNotifier也是在PhoneFactory的makeDefaultPhone中进行单例实例化。
CDMAPhone、GSMPhone对象直接派生自PhoneBase,提供Phone接口的具体实现,GSMPhone是GSM电话的JAVA框架层实现,CDMAPhone是CDMA电话的JAVA框架层实现。
CDMAPhone、GSMPhone对象实例化时除实例化基对象PhoneBase内部抽象对象(SMSDispatcher、DataConnectionTracker、IccFileHandler、IccRecords、IccCard)的具体类外,还实例化用于具体电话对象的Telephony服务(IccSmsInterfaceManager、IccPhoneBookInterfaceManager、PhoneSubInfo三个服务或者服务的派生类)。
二 GSMPhone
如下是GSMPhone对象的相关类图。
SMSDispatcher 、DataConnectionTracker 、IccFileHandler、IccRecords、IccCard等抽象类对应GSMPhone对象中的派生类分别为GsmSMSDispatcher(提供GSM模式的短消息发送和接收提交功能)、GsmDataConnectionTracker(提供GSM模式的数据连接管理功能)、SIMFileHandler(提供SIM File处理)、SIMRecords(提供SIM信息记录功能)、SimCard(提供SIM CARD功能);
IccSmsInterfaceManager、IccPhoneBookInterfaceManager、PhoneSubInfo服务在GSMPhone对象中实现的具体的服务类为SimSmsInterfaceManager、 SimPhoneBookInterfaceManager及PhoneSubInfo;这些对象和服务都在CDMAPhone对象实例化进行实例化。
另外GSMPhone对象在实例化时还实例化GsmCallTracker(提供GSM模式的CALL管理)、GsmServiceStateTracker(提供GSM模式的服务状态管理)、CatService对象(提供STK服务)。
[java] view plaincopy
- mCT = new GsmCallTracker(this);
- mSST = new GsmServiceStateTracker (this);
- mSMS = new GsmSMSDispatcher(this, mSmsStorageMonitor, mSmsUsageMonitor);
- mIccFileHandler = new SIMFileHandler(this);
- mIccRecords = new SIMRecords(this);
- mDataConnectionTracker = new GsmDataConnectionTracker (this);
- mIccCard = new SimCard(this);
- if (!unitTestMode) {
- mSimPhoneBookIntManager = new SimPhoneBookInterfaceManager(this);
- mSimSmsIntManager = new SimSmsInterfaceManager(this, mSMS);
- mSubInfo = new PhoneSubInfo(this);
- }
- mStkService = CatService.getInstance(mCM, mIccRecords, mContext, mIccFileHandler, mIccCard);
GSMCallTracker是Android的通话管理层,GsmCallTracker派生自Handler的虚拟类CallTracker;GsmServiceStateTracker派生自Handler的虚拟类ServiceStateTracker。
GsmCallTracker、GsmServiceStateTracker对象分别提供Call状态(共有IDLE, ACTIVE, HOLDING, DIALING, ALERTING, INCOMING, WAITING, DISCONNECTED, DISCONNECTING九种状态)及ServiceState(共有STATE_IN_SERVICE、STATE_OUT_OF_SERVICE、STATE_EMERGENCY_ONLY、STATE_POWER_OFF四种状态)的跟踪和管理,能够提供向RIL层发送请求,接收和处理RIL层发来的命令响应事件及其它主动通知事件,如振铃等CALL相关事件及Service状态事件。
GsmCallTracker对象中还提供有三个GsmCall对象(派生自抽象类Call):ringingCall(用来管理处于INCOMING和WAITING状态的通话)、foregroundCall(用来管理处于DAILING、ALERTING、ACTIVE状态的通话)、backgroundCall(用来管理HOLD的通话)。
GsmCallTracker是Call应用中的通话管理层,它维护了一个最多MAX_CONNECTIONS=7路GsmConnections通话链路的同时,还维护了三种通话状态(ringingCall,foregroundCall,backgroundCall),GsmCall以及GsmConnection是GsmCallTracker维护的对象,同时GsmConnection又依附于GsmCall的存在,MAX_CONNECTIONS_PER_CALL=5表明最多可以有5路通话处于某一个通话状态(foregroundCall,background,ringing)。GsmConnection继承自Connection类,该类主要是用来维护某一路的通话状态。当它们状态均为DISCONNECTED时意外着该GSMCall为IDLE状态。
在GSMCallTracker中维护着通话列表:connections。顺序记录了正连接上的通话,这些通话包括:ACTIVE,DIALING,ALERTING,HOLDING,INCOMING,WAITING等状态的连接。GSMCallTracker将这些连接分为了三类别进行管理:RingingCall: INCOMING ,WAITING ForegourndCall: ACTIVE, DIALING ,ALERTING BackgroundCall: HOLDING
另外GSMCallTracker还包含一个GsmConnection类型(派生自抽象类Connection)的数组对象Connections,用来维护所有的现行的通话的列表,GSMCallTracker对象最大可维护7路通话。
GsmConnection对象中有个成员变量:GsmCall parent,这个成员变量是用来表示该connection是属于哪个Call的,一个Call可以有多个Connection,但一个Connection只能属于一个Call。
GsmServiceStateTracker对象中除了包括ServiceState状态信息外,还包括SignalStrength信号强度等信息。
GsmServiceStateTracker对象还维护GSM CELL位置信息,因此包含两个GsmCellLocation对象成员cellLoc(当前位置) , newCellLoc( 新位置 )。
GsmCallTracker、GsmServiceStateTracker维护的状态和位置信息都通过RIL从RIL daemon获得,因此两个对象都包括一个指向RIL的CommandsInterface对象。
CatService对象实现STK服务,也是一个Handler对象,并实现AppInterface接口。CatService对象能够与RIL和STK应用交互:可以实现向RIL发送Envelop命令,以及从RIL接收STK事件,解析事件流(包括Proactive Command),从STK应用接收命令执行结果编码后发给RIL。CatService对象采用一个RilMessageDecoder状态机解析RIL发来的STK事件流。
拨打电话(dial)
它首先clearDisconnected()和canDial()清空过去的非连接状态的Connections,然后检查是否可以拨打电话。接着检查foregroundCall是否处于Active状态,若是则调用switchWaitingOrHoldingAndActive将它们切换到后台,调用fakeHoldForegroundBeforeDial将前台中的连接全部切换到后台,并且状态变为HOLDING。在进行这些前期检查和准备后,创建一个GsmConnection实例即pendingMO,检查传递过来的电话号码是否有效合法,若不合法则调用pollCallsWhenSafe(),目的是将其标为dropped;若合法则设置为非静音后,调用RIL.dial进行拨号。最后,更新Phone状态并通知给注册者。
接听电话(acceptCall)
若ringingCall正处于INCOMING则调用RIL.acceptCall去接听电话;若是WAITING状态,则调用switchWaitingOrHoldingAndActive将其切换到前台。
拒接电话(rejectCall)
当ringingCall处于INCOMING时,则调用RIL.rejectCall拒绝;否则抛出异常,表示没有来电却去接听它。
挂断电话(hangup)
它区分是ringingCall、foregroundCall还是backgroundCall。若是ringingCall,则调用RIL.hangupWaitingOrBackground;若是foregroundCall,并且是在DIALING或ALERTING状态则调用调用hangup (GsmConnection conn)挂断,否则调用hangupForegroundResumeBackground挂断前台通话后恢复后台通话;若是backgroundCall且ringingCall在响铃,则调用hangupAllConnections挂断所有在backgroundCall的通话连接,否则调用hangupWaitingOrBackground挂断呼叫等待和后台通话。
switchWaitingOrHoldingAndActive():进行电话切换
conference():进行电话会议
separate():分离出一路通话
fakeHoldForegroundBeforeDial()将前台电话(ForegroundCall)中的电话连接(GSMConnections)clone后台后,将这些连接删除,将Foreground置为IDLE状态,将后台电话BackgroundCall置为HOLDING状态。
clearDisconnected():清除已Disconnected的电话连接并更新电话状态,然后通知注册者当前最新的状态。
internalClearDisconnected():将ringingCall、 foregroundCall和 backgroundCall中状态为DISCONNECTED的 connections清除掉,若没有connection则将该GSMCall置为idle状态。
updatePhoneState():更新Phone状态,并向注册者通知语音通话开始或结束。
canDial():检查是否可以拨打电话,只有同时满足下列条件才可以:(1)射频Raido未关闭(2)PendingMO这个Connection为空(3)RingCall这个GSMCall未处于响铃状态(4)系统没有禁止电话拨打功能(5)ForegroundCall和BackgroundCall这2个GSMCall都不处于活动状态。其中当为INCOMING 和WAITING表示在响铃;当为DIALING 和 ALERTING时 表示在拨号;当不为IDLE 、 DISCONNECTED 和DISCONNECTING时表示活动状态,即处在上述的响铃、拨号、ACTIVE 和HOLDING时表示处于活动状态。
canConference():当ForegroundCall处于Active、BackgroundCall处于HOLDING以及它们的连接数少于5个时则可进行电话会议
canTransfer():当ForegroundCall处于Active、BackgroundCall处于HOLDING时则可进行交换。
hangup (GsmConnection conn):挂断某路电话连接
hangupWaitingOrBackground():挂断呼叫等待和后台电话
hangupForegroundResumeBackground():挂断前台电话并恢复后台电话
hangupConnectionByIndex(GsmCall call, int index):挂断某个索引指定的前台通话
hangupAllConnections(GsmCall call):挂断所有电话通路
Android Phone模块 二
SipPhone实现相关类图
SipPhone对象虽然也派生自PhoneBase,但实现机制及实例化过程与其它Phone对象大大不同。
SipPhone对象的实例化通过PhoneFactory的makeSipPhone的接口调用SipPhoneFactory的makePhone进行实例化。SipPhone对象的实例化调用也不是在PhoneApp对象中进行,而是在默认电话应用的SipBroadcastReceiver对象的onReceive回调函数或者SipCallOptionHandler对象的createSipPhoneIfNeeded函数中被调用,另外不同的是对SipPhone对象的创建个数也没有限制。
虽然实例化过程和CDMAPhone、GSMPhone对象不同,但实例化的SipPhone对象和CDMAPhone、GSMPhone对象一样也被添加到CallManager对象中进行统一管理。
SipPhone实现机制是通过IP通道实现电话功能,而不是通过无线通讯模块,因此没有采用RIL和RIL daemon,因此框架实现层与CDMAPhone、GSMPhone有很大不同,SipPhone框架实现主要是通过SipService系统服务及调用第三方协议栈来完成。SipService系统服务通过JNI来调用本地nist SIP协议堆栈。
SipPhone对象属于SipService服务的客户端对象,其通过SipManager对象的ISipService接口调用SipService。
每个SipPhone对象都对应一个SipProfile对象(包括SIP帐户,地址连接信息以及服务信息等信息)用来标识通话一方。SipProfile对象在SipPhoneFactory调用makePhone实例化SipPhone对象前根据网络通话的sipUri构建,并作为makePhone的参数传给SipPhone对象。
每个SipPhone对象和其它具体Phone对象相同也包括三个Call对象(SipCall):ringingCall、foregroundCall、backgroundCall,每个SipCall对象也包含一个Connection类型的ArrayList对象,用来维护每个CALL拥有的通话连接。不过和其它Phone对象不同SipPhone对象对每个Call对象拥有的connection个数没有限制,SipCall拥有的connection对象对应具体的SipConnection对象。
SipConnection对象包括主动和被动两种类型,主动类型的SipConnection对象在SipCall对象的dial函数调用时创建,被动类型的SipConnection对象在SipCall对象接收到输入CALL时,其initIncomingCall函数调用时创建。创建的SipConnection对象添加到SipCall对象的Connection类型的ArrayList数组列表中进行管理。
每个SipConnection对象也包括一个SipProfile对象和一个SipAudioCall对象。
被动SipConnection类型的SipProfile对象和SipAudioCall对象从对方获得。被动类型的SipAudioCall对象和initIncomingCall函数传进来的SipAudioCall对象相同,SipProfile对象通过调用SipAudioCall的getPeerProfile函数获得发起通话的对方的SipProfile。
主动SipConnection类型的SipProfile对象在dial函数中调用SipProfile.Builder对象的build函数根据发起的通话URL构建,用来标识本地通话方,SipAudioCall对象在调用dial函数时通过调用SipManager对象的makeAudioCall函数创建。
SipAudioCall对象中包括一个客户端SipSession对象,管理客户端的每一个会话过程,SipSession对象中有一个ISipSession接口成员,通过该接口调用服务端对应的会话对象SipSessionImpl对象(一个实现ISipSession接口的会话桩对象),共同完成通话一方的会话过程,客户端通过ISipSession接口向服务端的SipSessionImpl对象发起IPC调用。
主动类型的SipAudioCall对象对应的SipSession对象在makeAudioCall函数中调用createSipSession进行实例化,在makeAudioCall函数调用新创建SipAudioCall对象的makeCall函数时,SipSession对象作为makeCall函数的参数传给SipAudioCall对象。主动类型的SipSession对象中的ISipSession类型的接口成员在createSipSession中通过调用SipService的createSession函数创建,返回服务端SipSessionImpl对象的远程调用对象接口。
SipService的createSession函数创建一个Sip会话对象的整个过程:
1、首先调用createGroup函数实例化一个SipSessionGroupExt对象,SipSessionGroupExt对象派生自SipSessionAdapter,而SipSessionAdapter是一个实现ISipSessionListener接口的桩类;
2、SipSessionGroupExt对象实例化时又调用createSipSessionGroup函数实例化一个SipSessionGroup对象;
3、SipSessionGroup对象实例化时由SipFactory工厂对象实例化底层协议栈类对象SipStack,并有SipStack对象创建一个SipProvider对象和一个SipHelper对象,SipSessionGroup对象本身登记为SipProvider对象的监听对象;
4、然后调用SipSessionGroupExt对象的createSession函数,内部实际调用SipSessionGroup对象的createSession函数,实例化SipSessionImpl对象,并返回实例化后的SipSessionImpl对象引用。
SipSessionImpl属于SipSessionGroup类的内部类,客户端发起的通话请求都通过服务端的SipSessionImpl对象封装成EventObject类型的命令发起异步处理请求(调用SipSessionImpl对象的doCommandAsync函数,doCommandAsync函数的参数是一个EventObject类型的对象),最终通过SipSessionGroup对象的SipHelper对象调用SIP协议栈的接口与通话对方交互。
每个SipSessionImpl会话对象被放到SipSessionGroup对象的HashMap中进行管理。每个实例化的SipSessionGroupExt对象放到SipService的HashMap中进行管理。
客户端也可以通过SipManager对象的open函数发起一个被动会话请求,过程为:
1、 SipManager对象的open函数调用SipService的open3函数,同时也实例化一个PendingIntent对象通过SipService的open3函数传给服务端的SipSessionGroupExt对象中;
2、 在open3函数中调用createGroup函数实例化SipSessionGroupExt对象,并进一步实例化SipSessionGroup对象;
3、 接着调用SipSessionGroup对象的openToReceiveCalls函数来实例化一个SipSessionCallReceiverImpl对象作为接收会话,SipSessionCallReceiverImpl派生自SipSessionImpl,SipSessionGroupExt对象作为函数参数传进openToReceiveCalls函数,并在SipSessionImpl构造函数时调用内部对象成员mProxy(SipSessionListenerProxy类,一个实现ISipSessionListener接口的桩类)的setListener函数,为内部ISipSessionListener类型的成员赋值。
4、 当接收到底层协议发来的会话请求时,监听底层事件的对象SipSessionGroup的processRequest函数被调用;
5、 接着调用接收会话对象SipSessionCallReceiverImpl的process函数,在process函数中判断接收到的事件请求是Request.INVITE时就调用processNewInviteRequest函数;
6、 在processNewInviteRequest函数中调用createNewSession实例化一个SipSessionImpl对象作为新的会话,新的会话状态为INCOMING_CALL。接着调用接收会话SipSessionCallReceiverImpl对象内部成员mProxy的onRinging函数,在onRinging函数中调用其成员mListener(ISipSessionListener类型)的onRinging函数,实际调用SipSessionGroupExt对象的onRinging函数;
7、 在SipSessionGroupExt对象的onRinging函数中通过SipSessionGroupExt对象内部客户端传进来的PendingIntent对象向客户端发送ACTION_SIP_INCOMING_CALL类型广播消息;
8、 客户端在接收到这个广播调用SipManager的takeAudioCall函数。takeAudioCall函数首先通过SipService接口getPendingSession获得一个服务端会话对象引用;接着实例化一个SipAudioCall对象(SipAudioCall对象对应的SipProfile对象调用服务端会话对象的getLocalProfile函数获得);然后根据服务端会话对象引用实例化一个客户端SipSession对象;并调用SipAudioCall对象的attachCall实现SipSession对象与SipAudioCall对象的绑定;
9、 最后调用现有的SipPhone对象的canTake函数,在SipPhone对象的canTake函数中调用SipPhone对象的ringingCall对象的initIncomingCall函数实例化一个SipConnection对象,完成通话建立过程。
数据连接
Telephony框架的数据连接模块负责数据连接通道的建立,使电话能够提供数据服务,如上网等,数据连接模块的类图如下图。
DataConnectionTracker是数据连接功能的核心,GsmDataConnectionTracker、CdmaDataConnectionTracker是DataConnectionTracker的两个派生类,实现具体网络的数据连接的建立和管理。
每一个数据连接用一个DataConnection对象表示,DataConnection对应的具体网络的派生类为GsmDataConnection和CdmaDataConnection。DataConnectionTracker中用一个HashMap类型的变量mDataConnections维护每一个数据连接。CDMA同时只能建立一路数据连接,GSM网络则没有限制。
DataConnection对象是一个是一个状态机对象,维护连接的状态,并提供数据连接的LinkProperties和LinkCapabilities等属性。DataConnection对象的状态包括DcDefaultState、DcInactiveState、DcActivatingState、DcActiveState、DcDisconnectingState、DcDisconnectionErrorCreatingConnection六种状态。
对于GsmDataConnectionTracker对象,ApnContext对象提供数据连接的APN上下文,每一个APN类型都对应一个ApnContext对象,ApnContext对象维护对应的APN设置、DataConnectionTracker的状态、对应的DataConnection和DataConnectionAc等。
数据连接通道的建立过程:
1、 数据连接的建立最终都通过GsmDataConnectionTracker和CdmaDataConnectionTracker的trySetupData函数启动数据连接;
2、 trySetupData函数调用setupData函数,设置数据连接参数(如采用的Apn设置参数,连接建立成功响应消息);
3、 然后调用对应的DataConnection对象的bringUp函数发送数据连接消息(EVENT_CONNECT)。
4、 EVENT_CONNECT消息由DataConnection对象的状态机的相应状态对象接收处理,对于开始尚未建立数据连接时,DataConnection对象处于DcInactiveState状态,因此DcInactiveState状态对象接收处理EVENT_CONNECT事件,调用onConnect函数,并转变为DcActivatingState状态。
5、 在具体DataConnection对象的onConnect函数中调用RIL接口setupDataCall函数启动数据连接;
6、 连接建立后RIL层回应EVENT_SETUP_DATA_CONNECTION_DONE请求应答事件,由DataConnection对象的DcActivatingState状态对象接收处理EVENT_SETUP_DATA_CONNECTION_DONE事件,调用onSetupConnectionCompleted函数,并过渡到DcActiveState状态,连接建立成功。
DataConnectionTracker对象采用DataConnectionAc对象(派生自AsyncChannel)与DataConnection对象通讯。
GsmDataConnectionTracker对象在setupData函数调用createDataConnection函数创建时GsmDataConnection对象和DataConnectionAc对象,并通过DataConnectionAc对象与GsmDataConnection对象建立异步通讯连接。GsmDataConnectionTracker对象对于每类ApnContext都可以建立一个GsmDataConnection对象和一个DataConnectionAc对象。
CdmaDataConnectionTracker对象在实例化时调用createAllDataConnectionList函数创建需要的数据连接对象CdmaDataConnection和DataConnectionAc对象。CdmaDataConnectionTracker对象只支持创建一个CdmaDataConnection对象和DataConnectionAc对象。
boolean trySetupData(String reason) 尝试建立数据连接。它只是检查当前手机状态是具备建立数据连接的条件,当符合条件时,就去建立连接。这些条件包括当前是否处在正常的非连接状态、phone是否处在空闲状态、SIM卡是否就绪、是否允许数据连接、数据连接是否受限、以及电源状态也允许的情况下。接着调用buildWaitingApns去构建一个可供使用的APN列表(用户设置的preferred APN,若没设置则APN的类型匹配亦可,详见buildWaitingApns说明),若列表不为空,若就调用setupData建立数据连接。
boolean setupData(String reason)使用PdpConnection的connect函数(最终调用到RIL的setupDataCall函数),从备选APN列表waitingApns中,选择第一个APN作为配置去建立数据连接,详见buildWaitingApns函数
APN相关API
createAllApnList:用当前SIM卡对应的运营商查询系统的所有APN,并调用createApnList创建APN列表,并找到用户设置的preferred APN
createApnList:用查询得到的数据集,创建APN列表
onApnChanged:当APN被用户更改时,将调用到此函数,重新建立数据连接
buildWaitingApns:使用用户设置的preferred APN构建一个可用于数据连接的备选APN列表,即waitingApns列表(当有preferred APN,该列表就只有一个)。若用户没有设置preferred APN,则将所有类型匹配的APN添加到waitingApns列表(如 default类型)。当trySetupData函数检查有waitingApns列表中有可用的APN时,就会去尝试建立连接。
getNextApn():当PdpConnection需要用到APN建立数据连接时,将调用该函数从waitingApns备选列表中获取第一个APN,直至成功建立数据连接为止。
setPreferredApn:当用户没有设置preferred APN时,将当前数据连接成功的那个APN设置为preferred APN。详见onDataSetupComplete。
getPreferredApn:用户获取用户设置的preferred APN
事件通知机制
整个Telephony事件通知框架包括三层: RIL消息层、框架事件处理层、应用层。类图如下图,主要是请求应答模式和观察者模式的采用。
整个框架层以PhoneBase为中心,向上通过PhoneNotifier接口向应用层发送框架层产生的的事件,应用层通过TelephonyRegistry接口提供对特定事件的监听,由PhoneNotifier接口的默认实现DefaultPhoneNotifier通过TelephonyRegistry对象向应用层发送事件通知。
向下框架层通过CommandsInterface接口注册Unsolicited事件(主动通知事件)及发起AT命令请求。框架层的事件处理对象包括CDMAPhone和GSMPhone两个对象本身及其包含的SMSDispatcher、IccFileHandler、DataConnectionTracker、IccRecords类型的对象以及PhoneBase中的SmsStorageMonitor对象。
这些对象都是Handler对象,都能够向RIL层注册Unsolicited事件及发起AT命令请求。也能够接收和处理RIL层产生的Unsolicited事件及AT命令的响应。
CDMAPhone和GSMPhone对象中的事件处理对象除了CallTracker及ServiceStateTracker对象外,其它都在PhoneBase中由基类实现。
Android Phone模块 三
RIL
[java] view plaincopy
- public RIL(Context context, int preferredNetworkType, int cdmaSubscription,int phoneId) {
- super(context);
- mCdmaSubscription = cdmaSubscription;
- mPreferredNetworkType = preferredNetworkType;
- mPhoneType = RILConstants.NO_PHONE;
- mPhoneId = phoneId;
- if (mPhoneId != PhoneFactory.DEFAULT_PHONE_ID) {
- SOCKET_NAME_RIL = SOCKET_NAME_RIL + phoneId;
- }
- PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
- mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG);
- mWakeLock.setReferenceCounted(false);
- mWakeLockTimeout = SystemProperties.getInt(TelephonyProperties.PROPERTY_WAKE_LOCK_TIMEOUT,DEFAULT_WAKE_LOCK_TIMEOUT);
- mRequestMessagesPending = 0;
- mRequestMessagesWaiting = 0;
- //创建ril发送线程
- mSenderThread = new HandlerThread("RILSender");
- mSenderThread.start();
- Looper looper = mSenderThread.getLooper();
- mSender = new RILSender(looper);
- ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
- if (cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) {
- riljLog("Not starting RILReceiver: wifi-only");
- } else {
- riljLog("Starting RILReceiver");
- //创建接收线程
- mReceiver = new RILReceiver();
- mReceiverThread = new Thread(mReceiver, "RILReceiver");
- mReceiverThread.start();
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_SCREEN_ON);
- filter.addAction(Intent.ACTION_SCREEN_OFF);
- context.registerReceiver(mIntentReceiver, filter);
- }
- }
RIL线程模型:
RILSender
当上层需要向rild服务发送请求时,通过RIL的send函数来完成。
[java] view plaincopy
- public void handleMessage(Message msg) {
- RILRequest rr = (RILRequest) (msg.obj);
- RILRequest req = null;
- switch (msg.what) {
- case EVENT_SEND:
- boolean alreadySubtracted = false;
- try {
- LocalSocket s;
- s = mSocket;
- if (s == null) {
- rr.onError(RADIO_NOT_AVAILABLE, null);
- rr.release();
- if (mRequestMessagesPending > 0)
- mRequestMessagesPending--;
- alreadySubtracted = true;
- return;
- }
- synchronized (mRequestsList) {
- mRequestsList.add(rr);
- mRequestMessagesWaiting++;
- }
- if (mRequestMessagesPending > 0)
- mRequestMessagesPending--;
- alreadySubtracted = true;
- byte[] data;
- data = rr.mp.marshall();
- rr.mp.recycle();
- rr.mp = null;
- if (data.length > RIL_MAX_COMMAND_BYTES) {
- throw new RuntimeException("Parcel larger than max bytes allowed! "+ data.length);
- }
- // parcel length in big endian
- dataLength[0] = dataLength[1] = 0;
- dataLength[2] = (byte) ((data.length >> 8) & 0xff);
- dataLength[3] = (byte) ((data.length) & 0xff);
- s.getOutputStream().write(dataLength);
- s.getOutputStream().write(data);
- } catch (IOException ex) {
- Log.e(LOG_TAG, "IOException", ex);
- req = findAndRemoveRequestFromList(rr.mSerial);
- if (req != null || !alreadySubtracted) {
- rr.onError(RADIO_NOT_AVAILABLE, null);
- rr.release();
- }
- } catch (RuntimeException exc) {
- Log.e(LOG_TAG, "Uncaught exception ", exc);
- req = findAndRemoveRequestFromList(rr.mSerial);
- if (req != null || !alreadySubtracted) {
- rr.onError(GENERIC_FAILURE, null);
- rr.release();
- }
- } finally {
- releaseWakeLockIfDone();
- }
- if (!alreadySubtracted && mRequestMessagesPending > 0) {
- mRequestMessagesPending--;
- }
- break;
- case EVENT_WAKE_LOCK_TIMEOUT:
- synchronized (mWakeLock) {
- if (mWakeLock.isHeld()) {
- if (mRequestMessagesWaiting != 0) {
- mRequestMessagesWaiting = 0;
- }
- if (mRequestMessagesPending != 0) {
- mRequestMessagesPending = 0;
- }
- mWakeLock.release();
- }
- }
- break;
- }
- }
写入rild套接字的数据为:
发送步骤:
1. 生成RILRequest,此时将生成m_Serial(请求的Token)并将请求号,数据,及其Result Message 对象填入到RILRequest中
2. 使用send将RILRequest打包到EVENT_SEND消息中发送到到RIL Sender Handler
3. RilSender 接收到EVENT_SEND消息,将RILRequest通过套接口发送到RILD,同时将RILRequest保存在mRequest中以便应答消息的返回。
RILReceiver
[java] view plaincopy
- public void run() {
- int retryCount = 0;
- try {
- for (;;) {
- LocalSocket s = null;
- LocalSocketAddress l;
- try {
- //创建socket并连接到rild
- s = new LocalSocket();
- l = new LocalSocketAddress(SOCKET_NAME_RIL,LocalSocketAddress.Namespace.RESERVED);
- s.connect(l);
- } catch (IOException ex) {
- try {
- if (s != null) {
- s.close();
- }
- } catch (IOException ex2) {
- // ignore failure to close after failure to connect
- }
- if (retryCount == 8) {
- Log.e(LOG_TAG, "Couldn't find '" + SOCKET_NAME_RIL
- + "' socket after " + retryCount
- + " times, continuing to retry silently");
- } else if (retryCount > 0 && retryCount < 8) {
- Log.i(LOG_TAG, "Couldn't find '" + SOCKET_NAME_RIL
- + "' socket; retrying after timeout");
- }
- try {
- Thread.sleep(SOCKET_OPEN_RETRY_MILLIS);
- } catch (InterruptedException er) {
- }
- retryCount++;
- continue;
- }
- retryCount = 0;
- mSocket = s;
- Log.i(LOG_TAG, "Connected to '" + SOCKET_NAME_RIL + "' socket");
- int length = 0;
- try {
- InputStream is = mSocket.getInputStream();
- //循环从socket中读取消息
- for (;;) {
- Parcel p;
- length = readRilMessage(is, buffer);
- if (length < 0) {
- break;
- }
- p = Parcel.obtain();
- p.unmarshall(buffer, 0, length);
- p.setDataPosition(0);
- processResponse(p);
- p.recycle();
- }
- } catch (java.io.IOException ex) {
- Log.i(LOG_TAG, "'" + SOCKET_NAME_RIL + "' socket closed",ex);
- } catch (Throwable tr) {
- Log.e(LOG_TAG, "Uncaught exception read length=" + length+ "Exception:" + tr.toString());
- }
- //socket连接断开,请求所有请求并重新连接
- Log.i(LOG_TAG, "Disconnected from '" + SOCKET_NAME_RIL+ "' socket");
- setRadioState(RadioState.RADIO_UNAVAILABLE);
- try {
- mSocket.close();
- } catch (IOException ex) {
- }
- mSocket = null;
- RILRequest.resetSerial();
- clearRequestsList(RADIO_NOT_AVAILABLE, false);
- }
- } catch (Throwable tr) {
- Log.e(LOG_TAG, "Uncaught exception", tr);
- }
- notifyRegistrantsRilConnectionChanged(-1);
- }
接收步骤
1. 分析接收到的Parcel,根据类型不同进行处理。
2. 根据数据中的Token(mSerail),反查mRequest,找到对应的请求信息。
3. 将是接收到的数据转换成结果数据。
4. 将结果放在RequestMessage中发回到请求的发起者。
向RIL层注册的Unsolicited事件都登记添加到BaseCommands类中的RegistrantList类型的对象中或者设置为BaseCommands类中的Registrant类型的对象(根据设置函数的参数实例化具体类型的Registrant类型的对象)。
RIL层产生的Unsolicited事件通过在BaseCommands类中登记的RegistrantList对象或设置的Registrant对象向框架层的事件处理对象发送Unsolicited事件。
框架层的事件处理对象向RIL层发送的命令直接发送给RIL对象的相应函数,向RIL层发送的命令中都带有一个Message类型的应答消息,RIL对象的相应函数把接收到的命令携带的参数封装进RILRequest请求中发送给RIL的RILSender对象并marshall后通过LocalSocket发送给rild进程。
RIL的RILReceiver对象通过相同LocalSocket通道收到AT命令的响应unmarshall后调用processSolicited()函数把应答结果封装进命令携带的应答消息中发送回框架层的事件处理对象。
RILSender对象和RILReceiver对象都实现了接口,在独立线程运行。