一、TelephonyRegistry概述
本质上来讲,TelephonyRegistry是一个Service,在开机时通过SystemServer添加到ServiceManager中:
- telephonyRegistry = new TelephonyRegistry(context);
- ServiceManager.addService("telephony.registry", telephonyRegistry);
下面来看TelephonyRegistry的通知机制。
二、TelephonyRegistry通知机制
1、从Radio拿到通知;
2、将通知发送给相应的监听者;
下面分别来介绍。
2.1、从Radio拿到通知消息
在《 Telephony之进程与实体》一文中介绍过,创建GSMPhone时需要传递两个重要参数,其中一个是RILJ对象,另一个就是DefaultPhoneNotifier对象,这里的DefaultPhoneNotifier就是TelephonyRegistry的Client。
我们来看DefaultPhoneNotifier的构造函数:
- protected DefaultPhoneNotifier() {
- mRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService("telephony.registry"));
- }
这样一来,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();
- }
- }
- @GSMPhone.java
- void notifyPhoneStateChanged() {
- mNotifier.notifyPhoneState(this);
- }
- @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) {
- }
- }
- @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拿到消息后,需要向两个渠道分发消息,一个是通过系统广播,另一个是向自己注册的监听者。我们主要来看向监听者发送消息的流程。
2.2.1、监听者如何注册监听
由于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());
- }
- }
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);
- }
至此,通话状态改变的消息就从GsmCallTracker通过DefaultPhoneNotifier传递给了TelephonyRegistry,并从此扩散。类似的,对于数据连接状态来说,将会由DcTracker通过DefaultPhoneNotifier传递给TelephonyRegistry,然后进行扩散。
2.3、小结
1、Client可以将当前Radio的状态发送给TelephonyRegistry,比如GsmCallTracker;
2、Client可以向TelephonyRegistry申请监听Radio的相关状态,比如TelephonyManager;
或者可以这样理解,TelephonyRegistry作为一个中介,转发和扩散有关Radio的状态。如下图所示:
-
顶
- 1
-
踩
- 1