一、概述
这是一个系统服务,主要完成两方面的通知任务:1、 监听Phone状态,当有新的状态时,对注册该服务的客户端进行通知。比如:
notifyCallState:通知通话状态的改变。
notifySignalStrength:通知信号的改变。
notifyCallForwardingChanged:通知呼叫转移状态的改变。
notifyDataConnection:通知数据连接的改变。
2、 监听Phone状态,当有新的状态时,发送相应的广播到系统中。比如:
broadcastServiceStateChanged:广播服务状态的改变。
broadcastSignalStrengthChanged:广播信号的改变。
broadcastDataConnectionStateChanged:广播数据连接状态的改变。
客户端在得到这个服务后,可以通过统一的listen方法将自己注册为状态的监听器,如果Phone状态发生了改变,系统就会遍历所有的监听器,主动向他们发消息,调用相应的回调函数。
二、服务端向系统注册过程
既然他是一个服务,就需要去向ServiceManager注册自己。我们在SystemServer初始化线程中找到了他的注册过程:- @SystemServer.java
- telephonyRegistry = new TelephonyRegistry(context);
- ServiceManager.addService("telephony.registry", telephonyRegistry);
由此可见,这个服务被加载为“telephony.registry”的服务。如果需要获取该服务,就需要通过“telephony.registry”的名字向ServiceManager查询。
三、客户端向服务端注册监听过程
3.1、客户端需要做的准备工作
注册的过程其实就是把客户端添加到一个叫做mRecords的列表中,当Phone状态改变后,TelephonyRegistry会遍历mRecords中的客户端,分别调用他们当初注册的回调函数。因此,mRecords是TelephonyRegistry核心维护的列表,其中每一项元素都是一个Record型的数据结构,代表着一个客户端。
我们先来看一下Record的数据结构:
- @TelephonyRegistry.java
- private static class Record {
- //调试用
- String pkgForDebug;
- //回调函数的IBinder对象
- IBinder binder;
- //回调函数
- IPhoneStateListener callback;
- //客户端的uid,用于检查权限
- int callerUid;
- //表示客户端注册的是哪个监听器
- int events;
- //调试用,不去关心
- public String toString() {
- }
- }
我们先来看一下IPhoneStateListener的数据结构:
- @IPhoneStateListener.aidl
- oneway interface IPhoneStateListener {
- //服务状态改变
- void onServiceStateChanged(in ServiceState serviceState);
- //信号改变
- void onSignalStrengthChanged(int asu);
- //等待短信的改变,类似于语音信箱提醒短信
- void onMessageWaitingIndicatorChanged(boolean mwi);
- //呼叫转移状态改变
- void onCallForwardingIndicatorChanged(boolean cfi);
- void onCellLocationChanged(in Bundle location);
- //通话状态改变
- void onCallStateChanged(int state, String incomingNumber);
- //数据连接状态改变
- void onDataConnectionStateChanged(int state, int networkType);
- void onDataActivity(int direction);
- void onSignalStrengthsChanged(in SignalStrength signalStrength);
- void onOtaspChanged(in int otaspMode);
- void onCellInfoChanged(in List<CellInfo> cellInfo);
- }
我们再来看一下客户端可以监听哪些消息:
- @PhoneStateListener.java
- LISTEN_SERVICE_STATE
- LISTEN_SIGNAL_STRENGTH
- LISTEN_MESSAGE_WAITING_INDICATOR
- LISTEN_CALL_FORWARDING_INDICATOR
- LISTEN_CELL_LOCATION
- LISTEN_CALL_STATE
- LISTEN_DATA_CONNECTION_STATE
- LISTEN_DATA_ACTIVITY
- LISTEN_SIGNAL_STRENGTHS
- LISTEN_OTASP_CHANGED
- LISTEN_CELL_INFO
客户端可以指定自己所关注的状态,同时提供自己对该状态的回调函数,当相应的事件发生时,TelephonyRegistry就会去调用客户端的回调函数。
3.2、客户端注册监听过程
我们在《 framework中的TelephonyManager》中讲过,TelephonyManager同时注册了3个SystemServer,而他的客户端可以通过TelephonyManager间接的对3个SystemServer发起请求,而TelephonyRegistry就是其中之一SystemServer。因此,其他客户端对TelephonyRegistry的注册,可以通过TelephonyManager实现。具体做法是:
- @TelephonyManager.java
- public TelephonyManager(Context context) {
- //得到TelephonyRegistry服务
- sRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService( "telephony.registry"));
- }
- //通过TelephonyManager间接实现对TelephonyRegistry的注册:
- public void listen(PhoneStateListener listener, int events) {
- String pkgForDebug = sContext != null ? sContext.getPackageName() : "<unknown>";
- try {
- Boolean notifyNow = (getITelephony() != null);
- sRegistry.listen(pkgForDebug, listener.callback, events, notifyNow);
- } catch (RemoteException ex) {
- } catch (NullPointerException ex) {
- }
- }
而且我们在《 framework中的TelephonyManager》中介绍过,这样做的好处是,客户端在得到TelephonyManager的同时, 不仅得到了TelephonyRegistry的SystemServer,而且同时得到了另外两个SystemServer。
接下来我们继续看在TelephonyManager中调用listen的结果:
- @TelephonyRegistry
- public void listen(String pkgForDebug, IPhoneStateListener callback, int events, boolean notifyNow) {
- int callerUid = UserHandle.getCallingUserId();
- //得到客户端的UID
- int myUid = UserHandle.myUserId();
- //检测调用者是否有权限进行监听
- checkListenerPermission(events);
- 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;
- }
- }
- //构建一个Record对象
- r = new Record();
- r.binder = b;
- r.callback = callback;
- r.pkgForDebug = pkgForDebug;
- r.callerUid = callerUid;
- //把当前客户端信息写入mRecords列表中
- mRecords.add(r);
- //需要立刻发送通知
- if (notifyNow) {
- if ((events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
- r.callback.onServiceStateChanged(new ServiceState(mServiceState));
- }
- ........
- }
- }
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对象的生成过程是这样的:
- @PhoneFactory.java
- sPhoneNotifier = new DefaultPhoneNotifier();
- new GSMPhone(context,sCommandsInterface, sPhoneNotifier)
- @DefaultPhoneNotifier.java
- DefaultPhoneNotifier() {
- mRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService("telephony.registry"));
- }
- @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的notifyCallState方法,通知所有其他的客户端
- mRegistry.notifyCallState(convertCallState(sender.getState()), incomingNumber);
- } catch (RemoteException ex) {
- }
- }
4.2、TelephonyRegistry将消息发送给客户端的路程
上面分析到,RIL最终会调用到TelephonyRegistry中的notifyxxx方法去进行各种消息的通知,我们分析一个典型的CallState消息的方法:也就是TelephonyRegistry的notifyCallState方法:
- @TelephonyRegistry.java
- public void notifyCallState(int state, String incomingNumber) {
- for (Record r : mRecords) {
- if ((r.events & PhoneStateListener.LISTEN_CALL_STATE) != 0) {
- try {
- //通知所有的客户端,调用其onCallStateChanged方法
- r.callback.onCallStateChanged(state, incomingNumber);
- } catch (RemoteException ex) {
- }
- }
- }
- //同时发送广播消息
- broadcastCallStateChanged(state, incomingNumber);
- }
- private void broadcastServiceStateChanged(ServiceState state) {
- long ident = Binder.clearCallingIdentity();
- mBatteryStats.notePhoneState(state.getState());
- //发送ACTION_SERVICE_STATE_CHANGED的广播
- Intent intent = new Intent(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
- Bundle data = new Bundle();
- state.fillInNotifierBundle(data);
- intent.putExtras(data);
- //发送
- mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
- }
1、遍历mRecords,调用当初注册了当前消息监听的所有客户端的回调方法,进行一对一的通知。
2、通过broadcastCallStateChanged方法发送广播。
五、流程图
我们现在用一个流程图来结束这一节的学习: