Android System Server大纲之TelephonyRegistry

Android System Server大纲之TelephonyRegistry

手机数据连接状态

手机无线电网络状态

手机通话状态

前言

Telephony对于一些开发者可能不是很清楚它是什么,Telephony英译汉,电话,所以,所谓Telephony即承载了Android设备无线电业务,包括:

  • 数据连接上网,如2G、3G和当下发展正如火如荼的4G;

  • 无线电连接状态,通俗说,就是生活中常说的手机网络,没有网络就打不了电话等等;

  • 通话状态,也就是管理着手机来电、去电和挂机等行为

TelephonyRegistry,Telephony加上Registry代表什么意思呢?所谓TelephonyRegistry就是Telephony业务的注册状态,反过来就是说,TelephonyRegistry管理着无线电业务的任何状态。如:

  • 设备断网
  • 信号强度减弱/增强
  • 有来电
  • 断开/连接数据网络
  • 通话设置发生变化

等等这些无线电业务发生变化,都会经过TelephonyRegistry这个通道,所以,Android的APP可以通过TelephonyRegistry去获取/监听到这些无线电业务的状态变化。当然,TelephonyRegistry只会去收集到这些变化,要进行相关的操作(如设置上网),TelephonyRegistry就无能为力了,通过TelephonyRegistry和其它操作的模块结合起来,就可以完成非常复杂的功能了。

TelephonyRegistry概览

TelephonyRegistry在AOSP(Android Open Source Project)的路径是frameworks/base/services/core/java/com/android/server/TelephonyRegistry.java,直接上代码看得更直观:

class TelephonyRegistry extends ITelephonyRegistry.Stub {
    // 不向上层APP公开的接口
    public void addOnSubscriptionsChangedListener();
    // 不向上层APP公开的接口
    public void removeOnSubscriptionsChangedListener();
    // 不向上层APP公开的接口
    public void listen();
    // 向上层APP公开的接口
    public void listenForSubscriber();
    // 不向上层APP公开的接口
    public void notifyCallState();
    // 不向上层APP公开的接口
    public void notifyCallStateForPhoneId();
    // 不向上层APP公开的接口
    public void notifyServiceStateForPhoneId();
    // 不向上层APP公开的接口
    public void notifySignalStrengthForPhoneId();
    // 不向上层APP公开的接口
    public void notifyCallForwardingChanged();
    ......
}

TelephonyRegistry的接口很多,这里只是列出来一部分,但是,TelephonyRegistry只有一个接口是向上层APP公开的接口,那就是listenForSubscriber(),唯一一个接口,也就是说,上层APP通过listenForSubscriber()这个接口便可以接收所有的无线电业务变化的状态,而其它接口都是让Android系统相应的模块调用,作用就是通知TelephonyRegistry有无线电状态的变化,TelephonyRegistry最终通过listenForSubscriber()这个接口把这些无线电状态的变化通知到上层APP。

从上述代码中,TelephonyRegistry直接继承了ITelephonyRegistry.Stub,就是说TelephonyRegistry本身是一个Binder通信的实现,作为Android IPC通信中,在C/S架构的模式中,TelephonyRegistry是S端。参考另外一篇文章《Android系统之System Server大纲》中的服务启动过程,可知TelephonyRegistry是通过ServiceManager.addService()的方式启动,其启动的代码在frameworks/base/services/Java/com/android/server/SystemServer.java中:

traceBeginAndSlog("StartTelephonyRegistry");
telephonyRegistry = new TelephonyRegistry(context);
ServiceManager.addService("telephony.registry", telephonyRegistry);
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);

上面的代码中,看ServiceManager.addService()时,传入了”telephony.registry”作为name,这个值请读者先暂时记着,后面会再次提到。

上层APP使用TelephonyRegistry

获取远程服务的句柄对象

获取TelephonyRegistry的远端对象,还是老方法,android.content.Context.getSystemService(Context.TELEPHONY_SERVICE),这里传入的参数是Context.TELEPHONY_SERVICE,值为:

public static final String TELEPHONY_SERVICE = "phone";

上面的代码中,可见传入的值是phone,参考文档《Android System Server大纲之VibratorService》中的第三章节“APP使用VibratorService”中Context.getSystemService()获取对象的过程,Context.getSystemService(Context.TELEPHONY_SERVICE)返回的对象实质是:

registerService(Context.TELEPHONY_SERVICE, TelephonyManager.class,
        new CachedServiceFetcher<TelephonyManager>() {
    @Override
    public TelephonyManager createService(ContextImpl ctx) {
        return new TelephonyManager(ctx.getOuterContext());
    }});

Context.getSystemService(Context.TELEPHONY_SERVICE)实质获取到的是TelephonyManager的对象实例。先来看看TelephonyManager的架构,TelephonyManager能够提供什么功能:

public class TelephonyManager {
    ......

    //系统API,不公开
    public void call(String callingPackage, String number) {
        ......
    }
    public List<CellInfo> getAllCellInfo() {
        ......
    }
    public int getCallState() {
        ......
    }
    // 和TelephonyRegistry概览代码中listenForSubscriber()对应
    public void listen(PhoneStateListener listener, int events) {
        ......
    }
    ......
}

上文提到,TelephonyRegistry只有唯一一个接口listenForSubscriber()向上层公开,也即是上面的代码的listen()方法,那为什么会还有那么多其它的方法呢?上文中提到,TelephonyRegistry只有通知无线电网络状态变化的功能,为什么突然多出那么多功能呢?上文中Context.getSystemService(Context.TELEPHONY_SERVICE)传入的参数的值是“phone”,读者是否有“phone”和TelephonyRegistry有什么关联的关系的疑惑吗?原因就是,TelephonyManager所封装的远程的句柄不只一个,也就是说TelephonyManager封装了TelephonyRegistry的远程句柄,同时也封装了其它System Server的句柄。那么,在TelephonyManager这么多方法中,唯一一个方法listen()是远程调用了TelephonyRegistry的,而其它方法和TelephonyRegistry都没有关系。下面来看看TelephonyManager都封装了那些远程服务的句柄:

public class TelephonyManager {
    //TelephonyRegistry继承了ITelephonyRegistry,sRegistry是持有TelephonyRegistry的远程句柄Binder的实例
    private static ITelephonyRegistry sRegistry;
    public TelephonyManager(Context context, int subId) {
        if (sRegistry == null) {
            //TelephonyRegistry的远程对象
            sRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
                    "telephony.registry"));
        }
    }

    public void listen(PhoneStateListener listener, int events) {
        ......
        try {
            Boolean notifyNow = (getITelephony() != null);
            sRegistry.listenForSubscriber(listener.mSubId, getOpPackageName(),
                    listener.callback, events, notifyNow);
        ......
    }

    //其它System Server的远程句柄
    public void dial(String number) {
        try {
            //获取句柄
            ITelephony telephony = getITelephony();
            if (telephony != null)
                //远程调用
                telephony.dial(number);
        .....
    }
    // 获取Context.TELEPHONY_SERVICE句柄
    private ITelephony getITelephony() {
        return ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));
    }

    //其它System Server的句柄
    private IPhoneSubInfo getSubscriberInfo() {
        // get it each time because that process crashes a lot
        return IPhoneSubInfo.Stub.asInterface(ServiceManager.getService("iphonesubinfo"));
    }
}

上面的代码中,列出了三个远程System Server的句柄,它们分别是:

  • ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
    “telephony.registry”))
  • ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE))
  • IPhoneSubInfo.Stub.asInterface(ServiceManager.getService(“iphonesubinfo”))

它们对应的远程服务分别是:

  • TelephonyRegistry
  • PhoneInterfaceManager
  • PhoneSubInfoController

虽然这三个服务都在ServerManager的管理范围之内,但是它们真正的实现并不在同一个进程中。其中,TelephonyRegistry是真正System Server里面的服务,因为它运行在system_process进程中,但是PhoneInterfaceManager和PhoneSubInfoController却是运行在phone进程中(读者可自行查阅资料了解),关于PhoneInterfaceManager和PhoneSubInfoController将在后面的文章中再详细和读者道来。在上文中,获取System Server的句柄,其中ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE))和Context.getSystemService(Context.TELEPHONY_SERVICE)的参数才真正的一致,所以严格上说,TelephonyManger和PhoneInterfaceManager才是名副其实的“门当户对”。

完成的获取TelephonyRegistry的远端对象的代码如下:

TelephonyManager tm = (TelephonyManager) Context.getSystemService(Context.TELEPHONY_SERVICE);

调用TelephonyRegistry的接口

上文提到,TelephonyRegistry只有唯一一个接口是向上层公开的,那就是listen(PhoneStateListener listener, int events),如下:

public void listen(PhoneStateListener listener, int events) {
    try {
        sRegistry.listenForSubscriber(listener.mSubId, getOpPackageName(),
                listener.callback, events, notifyNow);
    ......
}

第一个参数是PhoneStateListener的对象,第二个参数是整形的events。所以,在APP中调用listen()方法是,需要传入一个实现了接口PhoneStateListener的子类,events代表需要获取的状态类型,当相应的状态发生变化,将会回调APP的PhoneStateListener的子类方法。events的类型有:

//Stop listening for updates
PhoneStateListener.LISTEN_NONE
//Listen for changes to the network service state
PhoneStateListener.LISTEN_SERVICE_STATE
//Listen for changes to the network signal strengths
PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
//Listen for changes to the message-waiting indicator
PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR
//Listen for changes to the call-forwarding indicator
PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR
//Listen for changes to the device's cell location
PhoneStateListener.LISTEN_CELL_LOCATION
//Listen for changes to the device call state
PhoneStateListener.LISTEN_CALL_STATE
//Listen for changes to the data connection state
PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
//Listen for changes to the direction of data traffic on the data connection
PhoneStateListener.LISTEN_DATA_ACTIVITY
//Listen for changes to OTASP mode
PhoneStateListener.LISTEN_OTASP_CHANGED
//Listen for changes to observed cell info
PhoneStateListener.LISTEN_CELL_INFO
//Listen for precise changes and fails to the device calls
PhoneStateListener.LISTEN_PRECISE_CALL_STATE
//Listen for precise changes and fails on the data connection
PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE
//Listen for real time info for all data connections
PhoneStateListener.LISTEN_DATA_CONNECTION_REAL_TIME_INFO
//Listen for changes to LTE network state
PhoneStateListener.LISTEN_VOLTE_STATE
//Listen for OEM hook raw event
PhoneStateListener.LISTEN_OEM_HOOK_RAW_EVENT
//isten for carrier network changes indicated by a carrier app
PhoneStateListener.LISTEN_CARRIER_NETWORK_CHANGE

例如,当网络断开连接后,做一些事情,实现如下:

TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
tm.listen(new PhoneStateListener(){
    @Override
    public void onServiceStateChanged(ServiceState serviceState) {
        super.onServiceStateChanged(serviceState);
        if (serviceState.getState() == ServiceState.STATE_OUT_OF_SERVICE) {
            // do somethings
        } 
    }
}, PhoneStateListener.LISTEN_SERVICE_STATE);

当应用退出后,像Android的广播一样,需要反listen,对于常用的广播,注册调用registerReceiver(),反注册时调用unregisterReceiver(),而TelephonyManager的listen的反listen的方式和广播不一样,当APP不再需要listen状态变化是,应该这样做:

TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
tm.listen(null, PhoneStateListener.LISTEN_NONE);

TelephonyManager调用listen()监听一些无线电状态变化时,需要相应的权限,将在下一个章节深入TelephonyRegistry中详细列出。

深入TelephonyRegistry

调用TelephonyManager的listen()方法后,最终运行到TelephonyRegistry,代码如下:

public class TelephonyManager {
    public void listen(PhoneStateListener listener, int events) {
        try {
            sRegistry.listenForSubscriber(listener.mSubId, getOpPackageName(),
                    listener.callback, events, notifyNow);
        ......
    }
}

然后调用listen():

    public void listenForSubscriber(int subId, String pkgForDebug, IPhoneStateListener callback,
            int events, boolean notifyNow) {
        listen(pkgForDebug, callback, events, notifyNow, subId);
    }

listen()的实现如下:

private void listen(String callingPackage, IPhoneStateListener callback, int events,
        boolean notifyNow, int subId) {
    if (events != PhoneStateListener.LISTEN_NONE) {
        /* Checks permission and throws Security exception */
        checkListenerPermission(events);

        synchronized (mRecords) {
            // register
            Record r;
            ......
            r = new Record();
            r.binder = b;
            mRecords.add(r);
            if (notifyNow && validatePhoneId(phoneId)) {
                ......
            }
        }
    } else {
        if(DBG) log("listen: Unregister");
        remove(callback.asBinder());
    }
}

上面的代码,首先是调用checkListenerPermission(events)检查权限,然后生成一个Record的对象实例,持有PhoneStateListener对象实例,最后add到ArrayList的实例mRecords中。因此当有任何无线电业务状态发生变化时,将从mRecords遍历所有的PhoneStateListener对象实例,将符合events的将会进行回调。

这里先看看APP需要声明那些权限,看checkListenerPermission(events)方法:

private void checkListenerPermission(int events) {
    if ((events & PhoneStateListener.LISTEN_CELL_LOCATION) != 0) {
        //android.permission.ACCESS_COARSE_LOCATION
        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
    }

    if ((events & PRECISE_PHONE_STATE_PERMISSION_MASK) != 0) {
        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE, null);
    }

    if ((events & ENFORCE_PHONE_STATE_PERMISSION_MASK) != 0) {                  
        //android.permission.READ_PHONE_STATE
        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null);  
    }

}

以通话为例,当通话状态发生变化时,如何通知到APP。当通话状态变化时,通话模块会调用TelephonyRegistry的notifyCallState()方法,如下:

class TelephonyRegistry extends ITelephonyRegistry.Stub {
    public void notifyCallState(int state, String incomingNumber) {
        ......
            for (Record r : mRecords) {
                if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_CALL_STATE) &&
                        (r.subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)) {
                    try {
                        String incomingNumberOrEmpty = r.canReadPhoneState ? incomingNumber : "";
                        r.callback.onCallStateChanged(state, incomingNumberOrEmpty);
                    } catch (RemoteException ex) {
                        mRemoveList.add(r.binder);
                    }
                }
            }
            handleRemoveListLocked();
        }
        broadcastCallStateChanged(state, incomingNumber,
                SubscriptionManager.INVALID_PHONE_INDEX,
                SubscriptionManager.INVALID_SUBSCRIPTION_ID);
    }
}

在上文中listen()方法的代码中提到,所有的PhoneStateListener被封装到ArrayList的实例mRecords中,这里便遍历mRecords,r.matchPhoneStateListenerEvent()配备APP是否listen了PhoneStateListener.LISTEN_CALL_STATE event,然后调用r.callback.onCallStateChanged(),r.callback实质就是PhoneStateListener的实例。后面,系统还会发送一个广播,所以,APP也可用通过接收广播的方式接收通话的状态:

private void broadcastCallStateChanged(int state, String incomingNumber, int phoneId,
            int subId) {
    Intent intent = new Intent(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
    intent.putExtra(PhoneConstants.STATE_KEY,
            DefaultPhoneNotifier.convertCallState(state).toString());
    if (!TextUtils.isEmpty(incomingNumber)) {
        intent.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER, incomingNumber);
    }

    // If a valid subId was specified, we should fire off a subId-specific state
    // change intent and include the subId.
    if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
        intent.setAction(PhoneConstants.ACTION_SUBSCRIPTION_PHONE_STATE_CHANGED);
        intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
    }
    // If the phoneId is invalid, the broadcast is for overall call state.
    if (phoneId != SubscriptionManager.INVALID_PHONE_INDEX) {
        intent.putExtra(PhoneConstants.SLOT_KEY, phoneId);
    }

    // Send broadcast twice, once for apps that have PRIVILEGED permission and once for those
    // that have the runtime one
    mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
            android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
    mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
            android.Manifest.permission.READ_PHONE_STATE,
            AppOpsManager.OP_READ_PHONE_STATE);
}

如上面的代码,APP可以写一个广播接收器,接收的action是TelephonyManager.ACTION_PHONE_STATE_CHANGED即可。除开通话状态的广播,系统还会发送其它一些状态的广播,如下:

数据连接:

private void broadcastDataConnectionFailed(String reason, String apnType,
        int subId) {
    Intent intent = new Intent(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED);
    intent.putExtra(PhoneConstants.FAILURE_REASON_KEY, reason);
    intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType);
    intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
    mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}

所有数据连接:

//The data connection state has changed for any one of the
     //* phone's mobile data connections (eg, default, MMS or GPS specific connection)
private void broadcastDataConnectionStateChanged(int state,
        boolean isDataConnectivityPossible,
        String reason, String apn, String apnType, LinkProperties linkProperties,
        NetworkCapabilities networkCapabilities, boolean roaming, int subId) {
    ......
    Intent intent = new Intent(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
    ......
    intent.putExtra(PhoneConstants.DATA_APN_KEY, apn);
    intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType);
    intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
    mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}

无限电状态:

private void broadcastServiceStateChanged(ServiceState state, int phoneId, int subId) {
    ......
    Intent intent = new Intent(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
    Bundle data = new Bundle();
    state.fillInNotifierBundle(data);
    intent.putExtras(data);
    // Pass the subscription along with the intent.
    intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
    intent.putExtra(PhoneConstants.SLOT_KEY, phoneId);
    mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}

无线电信号强度:

private void broadcastSignalStrengthChanged(SignalStrength signalStrength, int phoneId,
        int subId) {
    ......
    Intent intent = new Intent(TelephonyIntents.ACTION_SIGNAL_STRENGTH_CHANGED);
    intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
    Bundle data = new Bundle();
    signalStrength.fillInNotifierBundle(data);
    intent.putExtras(data);
    intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
    intent.putExtra(PhoneConstants.SLOT_KEY, phoneId);
    mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}

总结

TelephonyRegistry就介绍到这里,本文讲述了APP如果使用TelephonyRegistry监听无线电业务的状态变化,以及一些无线电状态状态变化的广播,了解了TelephonyRegistry的运作机制。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值