Telephony之TelephonyRegistry(原)

原创 2014年10月17日 17:37:36

一、TelephonyRegistry概述


        TelephonyRegistry的作用是检测当前Radio的状态,包括通话、短信、数据连接等状态,当这些状态发生改变时,通知所有向他注册过的客户端。也就是说,他负责Radio状态的通知。
        本质上来讲,TelephonyRegistry是一个Service,在开机时通过SystemServer添加到ServiceManager中:
        telephonyRegistry = new TelephonyRegistry(context);
        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的构造函数:
        protected DefaultPhoneNotifier() {
            mRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService("telephony.registry"));
        }
        在这里,我们看到DefaultPhoneNotifier从ServiceManager中获取了TelephonyRegistry的服务,也就是说,DefaultPhoneNotifier是TelephonyRegistry的Client
        这样一来,DefaultPhoneNotifier就将RILJ与TelephonyRegistry联系起来了,当RILJ接收到RIL上报的Phone状态时,就会通过DefaultPhoneNotifier发送给TelephonyRegistry
        比如对于通话状态的改变,我们在《Telephony之GsmCallTracker》中介绍过,GsmCallTracker会通过以下方式将状态发送给GSMPhone:
        @GsmCallTracker.java
        private void updatePhoneState() {
            PhoneConstants.State oldState = mState;
            if (mRingingCall.isRinging()) {
                mState = PhoneConstants.State.RINGING;
            } else if (mPendingMO != null ||
                    !(mForegroundCall.isIdle() && mBackgroundCall.isIdle())) {
                mState = PhoneConstants.State.OFFHOOK;
            } else {
                mState = PhoneConstants.State.IDLE;
            }

            if (mState == PhoneConstants.State.IDLE && oldState != mState) {
                mVoiceCallEndedRegistrants.notifyRegistrants(
                        new AsyncResult(null, null, null));
            } else if (oldState == PhoneConstants.State.IDLE && oldState != mState) {
                mVoiceCallStartedRegistrants.notifyRegistrants (
                        new AsyncResult(null, null, null));
            }

            if (mState != oldState) {
                //给GSMPhone发送通知
                mPhone.notifyPhoneStateChanged();
            }
        }
        上面的mPhone对象就是GSMPhone,接下来我们将会看到,GSMPhone会把通知转交给DefaultPhoneNotifier来处理:
        @GSMPhone.java
        void notifyPhoneStateChanged() {
            mNotifier.notifyPhoneState(this);
        }
        这里的mNotifier就是创建GSMPhone对象时传递的DefaultPhoneNotifier对象,这样的话,就将通知发送到了DefaultPhoneNotifier内部:
        @DefaultPhoneNotifier.java
        public void notifyPhoneState(Phone sender) {
            Call ringingCall = sender.getRingingCall();
            String incomingNumber = "";
            if (ringingCall != null && ringingCall.getEarliestConnection() != null){
                incomingNumber = ringingCall.getEarliestConnection().getAddress();
            }
            try {
                //将状态发送给TelephonyRegistry
                mRegistry.notifyCallState(convertCallState(sender.getState()), incomingNumber);
            } catch (RemoteException ex) {
            }
        }
        从这里我们看到,DefaultPhoneNotifier将当前GsmCallTracker中的状态(sender.getState())通过convertCallState()转换后,传递给TelephonyRegistry,这个转换的作用就是,将GsmCallTracker中的IDLE、RINGING、OFFHOOK状态转换为TelephonyManager中的对应状态:
        @TelephonyManager.java
        public static final int CALL_STATE_IDLE = 0;
        public static final int CALL_STATE_RINGING = 1;
        public static final int CALL_STATE_OFFHOOK = 2;

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


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


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

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


2.2.1、监听者如何注册监听


        首先我们来看如何成为TelephonyRegistry的监听者。
        由于TelephonyRegistry提供关于Radio的多种状态监测,包括通话、信号、呼叫转移、数据连接等状态,所以在向其申请监听时,需要说明监听那种状态,可以通过调用listen()方法来实现,我们来看这个接口:
        @TelephonyRegistry.java
        public void listen(String pkgForDebug, IPhoneStateListener callback, int events, boolean notifyNow) {
            //获取调用者的UID,监测权限
            int callerUid = UserHandle.getCallingUserId();
            int myUid = UserHandle.myUserId();

            if (events != 0) {
                //权限监测
                checkListenerPermission(events);

                synchronized (mRecords) {
                    Record r = null;
                    find_and_add: {
                          //获取当前监听者信息
                          IBinder b = callback.asBinder();
                          final int N = mRecords.size();
                          for (int i = 0; i < N; i++) {
                              r = mRecords.get(i);
                              if (b == r.binder) {
                                  break find_and_add;
                              }
                          }
                          r = new Record();
                          r.binder = b;
                          r.callback = callback;
                          r.pkgForDebug = pkgForDebug;
                          r.callerUid = callerUid;
                          //添加当前的监听者信息
                          mRecords.add(r);
                    }
                    int send = events & (events ^ r.events);
                    r.events = events;
                    //需要立刻通知
                    if (notifyNow) {
                        if ((events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
                            //监听通话状态
                            try {
                                r.callback.onServiceStateChanged(new ServiceState(mServiceState));
                            } catch (RemoteException ex) {
                                remove(r.binder);
                            }
                        }
                        if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) {
                            //监听信号改变
                            try {
                                int gsmSignalStrength = mSignalStrength.getGsmSignalStrength();
                                r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1 : gsmSignalStrength));
                            } catch (RemoteException ex) {
                                remove(r.binder);
                            }
                        }
                        if ((events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) {
                            try {
                                r.callback.onMessageWaitingIndicatorChanged(mMessageWaiting);
                            } catch (RemoteException ex) {
                                remove(r.binder);
                            }
                        }
                        if ((events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) {
                            //监听呼叫转移状态
                            try {
                                r.callback.onCallForwardingIndicatorChanged(mCallForwarding);
                            } catch (RemoteException ex) {
                                remove(r.binder);
                            }
                        }
                    }
                }
            } else {
                remove(callback.asBinder());
            }
        }
        上面的listen()操作,依次完成了如下动作:
        1、通过checkListenerPermission()监测调用者是否有监听权限
        2、将调用者的相关信息保存在mRecords中,保存信息包含IBinder、回调方法、UID、监听事件等
        3、如果listen的同时要求立刻通知,则会立刻调用监听者的回调方法。

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


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


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

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


2.3、小结


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

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


版权声明:本文为博主原创文章,未经博主允许不得转载。

Android 5.0 Telephony关键类初始化和相互关系

1.1.1          Phone进程启动   Phone进程是在系统开机时启动的,它由ActivityManagerService启动。   在5.0,PhoneApp的源码位于(packag...

Android Telephony分析(五) ---- TelephonyRegistry详解

本文紧接着上一篇文章《Android Telephony分析(四) —- TelephonyManager详解 》的1.4小节。 从TelephonyRegistry的大部分方法中: 可以看出...

Framework中的TelephonyRegistry(原)

一、概述         这是一个系统服务,主要完成两方面的通知任务:         1、监听Phone状态,当有新的状态时,对注册该服务的客户端进行通知。比如:                 n...

Framework中的TelephonyRegistry

一、概述         这是一个系统服务,主要完成两方面的通知任务:         1、监听Phone状态,当有新的状态时,对注册该服务的客户端进行通知。比如:               ...

Telephony之GsmCallTracker(原)

在前一篇《Telephony之进程与实体》中我们分析了,Application如果要发起通话相关的动作,可以通过Telephony的实体对象,也就是Phone对象来发起请求,而Phone对象就会通话相...

Telephony之PhoneInterfaceManager(原)

一、概述         PhoneInterfaceManager是一个Service,在被创建时通过ServiceManager注册自己,他作为Telephony对外的接口,可以接受其他进程向T...

Android System Server大纲之TelephonyRegistry

Android System Server大纲之TelephonyRegistry 手机数据连接状态 手机无线电网络状态 手机通话状态 Android System Serve...

Android Telephony启动过程源码分析

2 TelePhony启动代码分析: 2.1 Telephony关键类初始化 2.1.1 Phone进程启动 Phone就象个后台进程一样,开机即运行并一直存在(如果...

Android4.4 Telephony流程分析——GsmServiceStateTracker管理网络服务状态

本文代码以MTK平台Android 4.4为分析对象,与Google原生AOSP有些许差异,请读者知悉。 本文主要介绍GsmServiceStateTracker是怎么管理网络的?手机开机后...

Android 4.4Telephony流程分析SIM卡开机时的初始化

本文代码以MTK平台Android 4.4为分析对象,与Google原生AOSP有些许差异,请读者知悉。 本文主要介绍MTK Android开机时,SIM卡的Framework部分初始化过程。 ...
  • jwc2436
  • jwc2436
  • 2015年12月03日 17:43
  • 1089
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Telephony之TelephonyRegistry(原)
举报原因:
原因补充:

(最多只允许输入30个字)