一、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.javaprivate 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.javavoid notifyPhoneStateChanged() {mNotifier.notifyPhoneState(this);}

这里的mNotifier就是创建GSMPhone对象时传递的DefaultPhoneNotifier对象,这样的话,就将通知发送到了DefaultPhoneNotifier内部:

        @DefaultPhoneNotifier.javapublic void notifyPhoneState(Phone sender) {Call ringingCall = sender.getRingingCall();String incomingNumber = "";if (ringingCall != null && ringingCall.getEarliestConnection() != null){incomingNumber = ringingCall.getEarliestConnection().getAddress();}try {//将状态发送给TelephonyRegistrymRegistry.notifyCallState(convertCallState(sender.getState()), incomingNumber);} catch (RemoteException ex) {}}

从这里我们看到,DefaultPhoneNotifier将当前GsmCallTracker中的状态(sender.getState())通过convertCallState()转换后,传递给TelephonyRegistry,这个转换的作用就是,将GsmCallTracker中的IDLE、RINGING、OFFHOOK状态转换为TelephonyManager中的对应状态:

        @TelephonyManager.javapublic 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.javapublic 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.javapublic 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的状态。如下图所示:

Telephony之TelephonyRegistry(原)相关推荐

  1. Telephony之TelephonyManager(原)

    一.TelephonyManager概述 TelephonyManager主要提供Telephony相关实务的处理能力,我们从他所提供的public方法来总览一下其所能提供的功能: //得到软件版本g ...

  2. Android Telephony分析(四) ---- TelephonyManager详解

    前言 TelephonyManager主要提供Telephony相关信息的查询/修改功能,以及Phone状态监听功能,封装的方法主要是提供给APP上层使用.  TelephonyManager.jav ...

  3. Framework中的AIDL(原)

    在上一节(应用层的AIDL调用)中我们介绍了应用层中的AIDL用法, 这一节中,我们来看一下系统Framework层中更为普通的AIDL用法. 为了便于分析,我们挑选了ITelephonyRegist ...

  4. Telephony框架分析

    引子 无论手机如何改变,功能如何丰富,它最核心最关键的功能依旧是通讯,通讯按现在的情况来说主要就是打电话发短信和上网,Android的通讯框架从上往下可以分为4个部分: Modem 这是整个通讯的硬件 ...

  5. Android 10.0 系统启动之SystemServer进程-[Android取经之路]

    摘要:上一节讲解了Zygote进程的整个启动流程.Zygote是所有应用的鼻祖.SystemServer和其他所有Dalivik虚拟机进程都是由Zygote fork而来.Zygote fork的第一 ...

  6. 源码详解Android 9.0(P) 系统启动流程之SystemServer

    源码详解Android 9.0(P) 系统启动流程目录: 源码详解Android 9.0(P)系统启动流程之init进程(第一阶段) 源码详解Android 9.0(P)系统启动流程之init进程(第 ...

  7. 安卓启动相关以及架构设计相关

    安卓启动相关以及架构设计相关 我们知道安卓大多数是服务等的启动是伴随着init进程启动一起启动,这个init进程类似于linux的init,进程pid为1. 读过安卓源代码的人都应该非常熟悉init会 ...

  8. Android系统启动过程详解

    转自:http://www.cloudchou.com/android/post-361.html 前言 一直想研究Android完整的启动过程,网上看了不少资料,也看了书上的一些说明,对这些观点有些 ...

  9. SystemService简介

    1.启动流程: 请参考:https://blog.csdn.net/zhao5214319/article/details/90448185 文章中介绍了Zygote的启动流程,并介绍了SystemS ...

最新文章

  1. 这 4 款 MySQL 调优工具 yyds
  2. 运行Python的三种方法
  3. PIL图像处理:旋转图像
  4. 《Java 高并发》03 线程的生命周期
  5. [USACO10DEC] Treasure Chest
  6. boost库中mutex、condition_variable与mutex::scoped_lock联合使用实现线程之间的通信
  7. maven自动部署到tomcat的问题
  8. Unity整体与单个缩放比例
  9. 独角兽影视APP系统源码/双端影视APP源码
  10. 增量式PID公式的4点疑问和理解
  11. 微博媒体碎片装订版-Arrange01
  12. 使用am instrument验证CTS问题
  13. 自制 12306 抢票工具 5秒内完成订票
  14. Ruby注释的写法 Markup
  15. [云原生专题-4]:云平台 - 在阿里云平台快速搭建服务器集群
  16. 系统虚拟化:原理与实现 读书笔记一: VMM 分类
  17. 判断一个数是否是素数的 n 多种方法
  18. 虚拟化技术——VLAN策略
  19. 使用Python+PCA+SVM算法实现人脸识别模型
  20. html中百分比都支持吗,響應式設計中百分比%的問題_html/css_WEB-ITnose

热门文章

  1. 云服务器跟弹性云主机一样吗,什么是弹性云主机
  2. 学人工智能要看什么书?AI入门到进阶10本必看书
  3. C语言中%s,%m.ns 和 %e,%m.ne 的意思
  4. Win7共享无线 实现iPad 2 WiFi上网
  5. 03-docker系列-docker容器的基本操作
  6. C++:未定义引用静态类成员?
  7. python 安装 SimpleITK 和 pydicom
  8. 手持两把锟斤拷,口中疾呼烫烫烫
  9. python中斐波那契系数实现的几种方法
  10. Single-Stage 6D Object Pose Estimation——6D姿态估计