Telephony之TelephonyRegistry

一、TelephonyRegistry概述


        TelephonyRegistry的作用是检测当前Radio的状态,包括通话、短信、数据连接等状态,当这些状态发生改变时,通知所有向他注册过的客户端。也就是说,他负责Radio状态的通知。
        本质上来讲,TelephonyRegistry是一个Service,在开机时通过SystemServer添加到ServiceManager中:
  1. telephonyRegistry = new TelephonyRegistry(context);  
  2. ServiceManager.addService("telephony.registry", telephonyRegistry);  
        从这个注册过程中看到, 该Service注册的名字为“telephony.registry”

        下面来看TelephonyRegistry的通知机制。


二、TelephonyRegistry通知机制


        既然TelephonyRegistry负责状态的通知,那么就要完成两个工作:
        1、从Radio拿到通知;
        2、将通知发送给相应的监听者;

        下面分别来介绍。


2.1、从Radio拿到通知消息


        TelephonyRegistry的通知,是从他的客户端得到的,这个客户端就是 DefaultPhoneNotifier。下面来看如何从客户端得到通知的。
        在《 Telephony之进程与实体》一文中介绍过,创建GSMPhone时需要传递两个重要参数,其中一个是RILJ对象,另一个就是DefaultPhoneNotifier对象,这里的DefaultPhoneNotifier就是TelephonyRegistry的Client。
        我们来看DefaultPhoneNotifier的构造函数:
  1. protected DefaultPhoneNotifier() {  
  2.     mRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService("telephony.registry"));  
  3. }  
        在这里,我们看到DefaultPhoneNotifier从ServiceManager中获取了TelephonyRegistry的服务,也就是说, DefaultPhoneNotifier是TelephonyRegistry的Client
        这样一来,DefaultPhoneNotifier就将RILJ与TelephonyRegistry联系起来了, 当RILJ接收到RIL上报的Phone状态时,就会通过DefaultPhoneNotifier发送给TelephonyRegistry
        比如对于通话状态的改变,我们在《 Telephony之GsmCallTracker》中介绍过,GsmCallTracker会通过以下方式将状态发送给GSMPhone:
  1. @GsmCallTracker.java  
  2. private void updatePhoneState() {  
  3.     PhoneConstants.State oldState = mState;  
  4.     if (mRingingCall.isRinging()) {  
  5.         mState = PhoneConstants.State.RINGING;  
  6.     } else if (mPendingMO != null ||  
  7.             !(mForegroundCall.isIdle() && mBackgroundCall.isIdle())) {  
  8.         mState = PhoneConstants.State.OFFHOOK;  
  9.     } else {  
  10.         mState = PhoneConstants.State.IDLE;  
  11.     }  
  12.   
  13.     if (mState == PhoneConstants.State.IDLE && oldState != mState) {  
  14.         mVoiceCallEndedRegistrants.notifyRegistrants(  
  15.                 new AsyncResult(nullnullnull));  
  16.     } else if (oldState == PhoneConstants.State.IDLE && oldState != mState) {  
  17.         mVoiceCallStartedRegistrants.notifyRegistrants (  
  18.                 new AsyncResult(nullnullnull));  
  19.     }  
  20.   
  21.     if (mState != oldState) {  
  22.         //给GSMPhone发送通知  
  23.         mPhone.notifyPhoneStateChanged();  
  24.     }  
  25. }  
        上面的mPhone对象就是GSMPhone,接下来我们将会看到,GSMPhone会把通知转交给DefaultPhoneNotifier来处理:
  1. @GSMPhone.java  
  2. void notifyPhoneStateChanged() {  
  3.     mNotifier.notifyPhoneState(this);  
  4. }  
        这里的mNotifier就是创建GSMPhone对象时传递的DefaultPhoneNotifier对象,这样的话,就将通知发送到了DefaultPhoneNotifier内部:
  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  
  10.         mRegistry.notifyCallState(convertCallState(sender.getState()), incomingNumber);  
  11.     } catch (RemoteException ex) {  
  12.     }  
  13. }  
        从这里我们看到,DefaultPhoneNotifier将当前GsmCallTracker中的状态(sender.getState())通过convertCallState()转换后,传递给TelephonyRegistry,这个转换的作用就是,将GsmCallTracker中的IDLE、RINGING、OFFHOOK状态转换为TelephonyManager中的对应状态:
  1. @TelephonyManager.java  
  2. public static final int CALL_STATE_IDLE = 0;  
  3. public static final int CALL_STATE_RINGING = 1;  
  4. public static final int CALL_STATE_OFFHOOK = 2;  

        就这样,DefaultPhoneNotifier作为TelephonyRegistry的Client,将当前通话状态传递给了TelephonyRegistry。


2.2、将消息发送给其他客户端


        TelephonyRegistry拿到相应的通知后,是如何将消息发送给其他客户端呢?我们继续用通话状态来跟踪这一流程。

        在TelephonyRegistry拿到消息后,需要向两个渠道分发消息,一个是通过系统广播,另一个是向自己注册的监听者。我们主要来看向监听者发送消息的流程。


2.2.1、监听者如何注册监听


        首先我们来看如何成为TelephonyRegistry的监听者。
        由于TelephonyRegistry提供关于Radio的多种状态监测,包括通话、信号、呼叫转移、数据连接等状态,所以在向其申请监听时,需要说明监听那种状态,可以通过调用listen()方法来实现,我们来看这个接口:
  1. @TelephonyRegistry.java  
  2. public void listen(String pkgForDebug, IPhoneStateListener callback, int events, boolean notifyNow) {  
  3.     //获取调用者的UID,监测权限  
  4.     int callerUid = UserHandle.getCallingUserId();  
  5.     int myUid = UserHandle.myUserId();  
  6.   
  7.     if (events != 0) {  
  8.         //权限监测  
  9.         checkListenerPermission(events);  
  10.   
  11.         synchronized (mRecords) {  
  12.             Record r = null;  
  13.             find_and_add: {  
  14.                   //获取当前监听者信息  
  15.                   IBinder b = callback.asBinder();  
  16.                   final int N = mRecords.size();  
  17.                   for (int i = 0; i < N; i++) {  
  18.                       r = mRecords.get(i);  
  19.                       if (b == r.binder) {  
  20.                           break find_and_add;  
  21.                       }  
  22.                   }  
  23.                   r = new Record();  
  24.                   r.binder = b;  
  25.                   r.callback = callback;  
  26.                   r.pkgForDebug = pkgForDebug;  
  27.                   r.callerUid = callerUid;  
  28.                   //添加当前的监听者信息  
  29.                   mRecords.add(r);  
  30.             }  
  31.             int send = events & (events ^ r.events);  
  32.             r.events = events;  
  33.             //需要立刻通知  
  34.             if (notifyNow) {  
  35.                 if ((events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {  
  36.                     //监听通话状态  
  37.                     try {  
  38.                         r.callback.onServiceStateChanged(new ServiceState(mServiceState));  
  39.                     } catch (RemoteException ex) {  
  40.                         remove(r.binder);  
  41.                     }  
  42.                 }  
  43.                 if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) {  
  44.                     //监听信号改变  
  45.                     try {  
  46.                         int gsmSignalStrength = mSignalStrength.getGsmSignalStrength();  
  47.                         r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1 : gsmSignalStrength));  
  48.                     } catch (RemoteException ex) {  
  49.                         remove(r.binder);  
  50.                     }  
  51.                 }  
  52.                 if ((events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) {  
  53.                     try {  
  54.                         r.callback.onMessageWaitingIndicatorChanged(mMessageWaiting);  
  55.                     } catch (RemoteException ex) {  
  56.                         remove(r.binder);  
  57.                     }  
  58.                 }  
  59.                 if ((events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) {  
  60.                     //监听呼叫转移状态  
  61.                     try {  
  62.                         r.callback.onCallForwardingIndicatorChanged(mCallForwarding);  
  63.                     } catch (RemoteException ex) {  
  64.                         remove(r.binder);  
  65.                     }  
  66.                 }  
  67.             }  
  68.         }  
  69.     } else {  
  70.         remove(callback.asBinder());  
  71.     }  
  72. }  
        上面的listen()操作,依次完成了如下动作:
        1、通过checkListenerPermission()监测调用者是否有监听权限
        2、将调用者的相关信息保存在mRecords中,保存信息包含IBinder、回调方法、UID、监听事件等
        3、如果listen的同时要求立刻通知,则会立刻调用监听者的回调方法。

        经过这些操作,客户端就完成了对TelephonyRegistry的监听注册,等待接收通知。


2.2.2、如何将消息通知到监听者


        接下来我们分析,如何将通知发送给监听者。
        在2.1中我们知道,DefaultPhoneNotifier作为TelephonyRegistry的Client,通过notifyCallState()将当前通话状态通知到TelephonyRegistry,我们来看这个方法:
  1. @TelephonyRegistry.java  
  2. public void notifyCallState(int state, String incomingNumber) {  
  3.     //权限检查  
  4.     if (!checkNotifyPermission("notifyCallState()")) {  
  5.         return;  
  6.     }  
  7.     synchronized (mRecords) {  
  8.         mCallState = state;  
  9.         mCallIncomingNumber = incomingNumber;  
  10.         for (Record r : mRecords) {  
  11.             if ((r.events & PhoneStateListener.LISTEN_CALL_STATE) != 0) {  
  12.                 try {  
  13.                     //通知所有监听者  
  14.                     r.callback.onCallStateChanged(state, incomingNumber);  
  15.                 } catch (RemoteException ex) {  
  16.                     mRemoveList.add(r.binder);  
  17.                 }  
  18.             }  
  19.         }  
  20.         //发送广播通知  
  21.         handleRemoveListLocked();  
  22.     }  
  23.     broadcastCallStateChanged(state, incomingNumber);  
  24. }  
        在上面这个方法中,先对通知者进行权限检查,然后在mRecords中查找曾经注册了该事件的监听者,并调用他们的回调方法。最后,又将该消息发送到系统广播中。

        至此,通话状态改变的消息就从GsmCallTracker通过DefaultPhoneNotifier传递给了TelephonyRegistry,并从此扩散。类似的,对于数据连接状态来说,将会由DcTracker通过DefaultPhoneNotifier传递给TelephonyRegistry,然后进行扩散。


2.3、小结


        从以上的分析中我们看到,TelephonyRegistry作为一个Service,成为他的Client后可以拥有两种功能:
        1、Client可以将当前Radio的状态发送给TelephonyRegistry,比如GsmCallTracker;
        2、Client可以向TelephonyRegistry申请监听Radio的相关状态,比如TelephonyManager;

        或者可以这样理解,TelephonyRegistry作为一个中介,转发和扩散有关Radio的状态。如下图所示:


1
1
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值