Framework中的TelephonyRegistry

一、概述

        这是一个系统服务,主要完成两方面的通知任务:
        1、 监听Phone状态,当有新的状态时,对注册该服务的客户端进行通知。比如:
                notifyCallState:通知通话状态的改变。
                notifySignalStrength:通知信号的改变。
                notifyCallForwardingChanged:通知呼叫转移状态的改变。
                notifyDataConnection:通知数据连接的改变。
        2、 监听Phone状态,当有新的状态时,发送相应的广播到系统中。比如:
                broadcastServiceStateChanged:广播服务状态的改变。
                broadcastSignalStrengthChanged:广播信号的改变。
                broadcastDataConnectionStateChanged:广播数据连接状态的改变。

        客户端在得到这个服务后,可以通过统一的listen方法将自己注册为状态的监听器,如果Phone状态发生了改变,系统就会遍历所有的监听器,主动向他们发消息,调用相应的回调函数。


二、服务端向系统注册过程

        既然他是一个服务,就需要去向ServiceManager注册自己。我们在SystemServer初始化线程中找到了他的注册过程:
  1. @SystemServer.java  
  2. telephonyRegistry = new TelephonyRegistry(context);  
  3. ServiceManager.addService("telephony.registry", telephonyRegistry);  

        由此可见,这个服务被加载为“telephony.registry”的服务。如果需要获取该服务,就需要通过“telephony.registry”的名字向ServiceManager查询。


三、客户端向服务端注册监听过程

3.1、客户端需要做的准备工作

        注册的过程其实就是把客户端添加到一个叫做mRecords的列表中,当Phone状态改变后,TelephonyRegistry会遍历mRecords中的客户端,分别调用他们当初注册的回调函数
        因此,mRecords是TelephonyRegistry核心维护的列表,其中每一项元素都是一个Record型的数据结构,代表着一个客户端。
        我们先来看一下Record的数据结构:
  1. @TelephonyRegistry.java  
  2. private static class Record {  
  3.     //调试用  
  4.     String pkgForDebug;  
  5.     //回调函数的IBinder对象  
  6.     IBinder binder;  
  7.     //回调函数  
  8.     IPhoneStateListener callback;  
  9.     //客户端的uid,用于检查权限  
  10.     int callerUid;  
  11.     //表示客户端注册的是哪个监听器  
  12.     int events;  
  13.     //调试用,不去关心  
  14.     public String toString() {  
  15.     }  
  16. }  
        这样的数据结构说明3个重要信息:1、客户端注册监听器时,需要提供一个IPhoneStateListener类型的对象;2、客户端需要告诉服务端,自己需要监听哪些消息(events);3、并不是所有的客户端都有权限去监听所有的状态(callerUid决定)。
        我们先来看一下IPhoneStateListener的数据结构:
  1. @IPhoneStateListener.aidl  
  2. oneway interface IPhoneStateListener {  
  3.     //服务状态改变  
  4.     void onServiceStateChanged(in ServiceState serviceState);  
  5.     //信号改变  
  6.     void onSignalStrengthChanged(int asu);  
  7.     //等待短信的改变,类似于语音信箱提醒短信  
  8.     void onMessageWaitingIndicatorChanged(boolean mwi);  
  9.     //呼叫转移状态改变  
  10.     void onCallForwardingIndicatorChanged(boolean cfi);  
  11.     void onCellLocationChanged(in Bundle location);  
  12.     //通话状态改变  
  13.     void onCallStateChanged(int state, String incomingNumber);  
  14.     //数据连接状态改变  
  15.     void onDataConnectionStateChanged(int state, int networkType);  
  16.     void onDataActivity(int direction);  
  17.     void onSignalStrengthsChanged(in SignalStrength signalStrength);  
  18.     void onOtaspChanged(in int otaspMode);  
  19.     void onCellInfoChanged(in List<CellInfo> cellInfo);  
  20. }  
        上面看到,IPhoneStateListener接口定义了有关Phone各个状态的监听器的回调函数。
        我们再来看一下客户端可以监听哪些消息:
  1. @PhoneStateListener.java  
  2. LISTEN_SERVICE_STATE  
  3. LISTEN_SIGNAL_STRENGTH  
  4. LISTEN_MESSAGE_WAITING_INDICATOR  
  5. LISTEN_CALL_FORWARDING_INDICATOR  
  6. LISTEN_CELL_LOCATION  
  7. LISTEN_CALL_STATE  
  8. LISTEN_DATA_CONNECTION_STATE  
  9. LISTEN_DATA_ACTIVITY  
  10. LISTEN_SIGNAL_STRENGTHS  
  11. LISTEN_OTASP_CHANGED  
  12. LISTEN_CELL_INFO  
        可以看到,这些监听消息是和上面的IPhoneStateListener相对应的。
        客户端可以指定自己所关注的状态,同时提供自己对该状态的回调函数,当相应的事件发生时,TelephonyRegistry就会去调用客户端的回调函数。

3.2、客户端注册监听过程

        我们在《 framework中的TelephonyManager》中讲过,TelephonyManager同时注册了3个SystemServer,而他的客户端可以通过TelephonyManager间接的对3个SystemServer发起请求,而TelephonyRegistry就是其中之一SystemServer。
        因此,其他客户端对TelephonyRegistry的注册,可以通过TelephonyManager实现。具体做法是:
  1. @TelephonyManager.java  
  2. public TelephonyManager(Context context) {  
  3.     //得到TelephonyRegistry服务  
  4.     sRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService( "telephony.registry"));  
  5. }  
  6. //通过TelephonyManager间接实现对TelephonyRegistry的注册:  
  7. public void listen(PhoneStateListener listener, int events) {  
  8.     String pkgForDebug = sContext != null ? sContext.getPackageName() : "<unknown>";  
  9.     try {  
  10.         Boolean notifyNow = (getITelephony() != null);  
  11.         sRegistry.listen(pkgForDebug, listener.callback, events, notifyNow);  
  12.     } catch (RemoteException ex) {  
  13.     } catch (NullPointerException ex) {  
  14.     }  
  15. }  
        也就是说, 客户端如果想要实现对TelephonyRegistry的监听,可以先得到TelephonyManager的服务,然后通过这个服务调用其listen方法把当前客户端注册给TelephonyRegistry,当Phone状态改变时,再由TelephonyRegistry发送通知给当前客户端
        而且我们在《 framework中的TelephonyManager》中介绍过,这样做的好处是,客户端在得到TelephonyManager的同时, 不仅得到了TelephonyRegistry的SystemServer,而且同时得到了另外两个SystemServer
        接下来我们继续看在TelephonyManager中调用listen的结果:
  1. @TelephonyRegistry  
  2. public void listen(String pkgForDebug, IPhoneStateListener callback, int events, boolean notifyNow) {  
  3.     int callerUid = UserHandle.getCallingUserId();  
  4.     //得到客户端的UID  
  5.     int myUid = UserHandle.myUserId();  
  6.     //检测调用者是否有权限进行监听  
  7.     checkListenerPermission(events);  
  8.     IBinder b = callback.asBinder();  
  9.     //先去查找当前的申请者是否已经注册了监听  
  10.     final int N = mRecords.size();  
  11.     for (int i = 0; i < N; i++) {  
  12.         r = mRecords.get(i);  
  13.         if (b == r.binder) {  
  14.             break find_and_add;  
  15.         }  
  16.     }  
  17.     //构建一个Record对象  
  18.     r = new Record();  
  19.     r.binder = b;  
  20.     r.callback = callback;  
  21.     r.pkgForDebug = pkgForDebug;  
  22.     r.callerUid = callerUid;  
  23.     //把当前客户端信息写入mRecords列表中  
  24.     mRecords.add(r);  
  25.     //需要立刻发送通知  
  26.     if (notifyNow) {  
  27.         if ((events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {  
  28.             r.callback.onServiceStateChanged(new ServiceState(mServiceState));  
  29.         }  
  30.         ........  
  31.     }  
  32. }  
        上面的代码说明在listen中主要完成3个任务:
        1、检查客户端是否有权限监听;
        2、构建客户端的Record并添加到mRecords列表中

        3、判断是否需要立刻发送通知


四、服务端通知客户端过程

        上面的第三节中介绍了客户端注册的过程,这一节主要介绍当相应的事件发生时,服务端是如何通知客户端的。

4.1、从RIL到TelephonyRegistry的通知路程

        这个服务很特殊,他对客户端的通知,是由另外的客户端去发起的。具体情况是: 一个叫做DefaultPhoneNotifier的类在自己构造函数中,得到了“telephony.registry”的系统服务,也就是TelephonyRegistry的服务,而DefaultPhoneNotifier同时又注册给了RILJ,我们知道,当Modem有消息上报时,是把消息传递给了RILJ的,此时RILJ将会通知DefaultPhoneNotifier,DefaultPhoneNotifier得到通知后,再根据不同的消息,去调用TelephonyRegistry的相应的通知方法,在TelephonyRegistry的通知方法内部,又对所有注册的客户端进行消息派发
        也就是说, TelephonyRegistry充当了中介的角色,由其中某个客户端通过TelephonyRegistry去向其他所有的客户端进行消息派发
        我们知道,GSMPhone对象的生成过程是这样的:
  1. @PhoneFactory.java  
  2. sPhoneNotifier = new DefaultPhoneNotifier();  
  3. new GSMPhone(context,sCommandsInterface, sPhoneNotifier)  
        也就是说,GSMPhone中的sPhoneNotifier是DefaultPhoneNotifier对象,我们来看看这个对象的构造函数:
  1. @DefaultPhoneNotifier.java  
  2. DefaultPhoneNotifier() {  
  3.     mRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService("telephony.registry"));  
  4. }  
        这说明,DefaultPhoneNotifier是TelephonyRegistry的“客户”,得到了远程的TelephonyRegistry对象。当RILJ中有Phone的消息需要上报时,将会采用如下的形式:
  1. @GSMPhone.java  
  2. void notifyPhoneStateChanged() {  
  3.     mNotifier.notifyPhoneState(this);  
  4. }  
        这里的mNotifier就是当初构建GSMPhone时传递的sPhoneNotifier,也就是DefaultPhoneNotifier对象,此时将会调用他的notifyPhoneState方法:
  1. @DefaultPhoneNotifier.java  
  2. public void notifyPhoneState(Phone sender) {  
  3.     Call ringingCall = sender.getRingingCall();  
  4.     String incomingNumber = "";  
  5.     if (ringingCall != null && ringingCall.getEarliestConnection() != null){  
  6.         incomingNumber = ringingCall.getEarliestConnection().getAddress();  
  7.     }  
  8.     try {  
  9.         //这里就是调用TelephonyRegistry的notifyCallState方法,通知所有其他的客户端  
  10.         mRegistry.notifyCallState(convertCallState(sender.getState()), incomingNumber);  
  11.     } catch (RemoteException ex) {  
  12.     }  
  13. }  
        经过上面的步骤,系统从Modem发送的关于Phone、network的状态的改变,经过RIL和GSMPhone传递给DefaultPhoneNotifier,然后又传递给了TelephonyRegistry,由他负责将当前消息分发给所有注册了监听的客户端。

4.2、TelephonyRegistry将消息发送给客户端的路程

        上面分析到,RIL最终会调用到TelephonyRegistry中的notifyxxx方法去进行各种消息的通知,我们分析一个典型的CallState消息的方法:
        也就是TelephonyRegistry的notifyCallState方法:
  1. @TelephonyRegistry.java  
  2. public void notifyCallState(int state, String incomingNumber) {  
  3.     for (Record r : mRecords) {  
  4.         if ((r.events & PhoneStateListener.LISTEN_CALL_STATE) != 0) {  
  5.             try {  
  6.                 //通知所有的客户端,调用其onCallStateChanged方法  
  7.                 r.callback.onCallStateChanged(state, incomingNumber);  
  8.             } catch (RemoteException ex) {  
  9.             }  
  10.         }  
  11.     }  
  12.     //同时发送广播消息  
  13.     broadcastCallStateChanged(state, incomingNumber);  
  14. }  
  15. private void broadcastServiceStateChanged(ServiceState state) {  
  16.     long ident = Binder.clearCallingIdentity();  
  17.     mBatteryStats.notePhoneState(state.getState());  
  18.     //发送ACTION_SERVICE_STATE_CHANGED的广播  
  19.     Intent intent = new Intent(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);  
  20.     Bundle data = new Bundle();  
  21.     state.fillInNotifierBundle(data);  
  22.     intent.putExtras(data);  
  23.     //发送  
  24.     mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);  
  25. }  
        从上面可以看出,在notifyCallState的过程中,我们看到消息的分发是通过两个通道实现的:
        1、遍历mRecords,调用当初注册了当前消息监听的所有客户端的回调方法,进行一对一的通知

        2、通过broadcastCallStateChanged方法发送广播


五、流程图

        我们现在用一个流程图来结束这一节的学习:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值