Android System Server大纲之TelephonyRegistry

来源:互联网 发布:npm淘宝源 编辑:程序博客网 时间:2024/05/18 02:03

Android System Server大纲之TelephonyRegistry

手机数据连接状态

手机无线电网络状态

手机通话状态

  • Android System Server大纲之TelephonyRegistry
    • 前言
    • TelephonyRegistry概览
    • 上层APP使用TelephonyRegistry
      • 获取远程服务的句柄对象
      • 调用TelephonyRegistry的接口
    • 深入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 updatesPhoneStateListener.LISTEN_NONE//Listen for changes to the network service statePhoneStateListener.LISTEN_SERVICE_STATE//Listen for changes to the network signal strengthsPhoneStateListener.LISTEN_SIGNAL_STRENGTHS//Listen for changes to the message-waiting indicatorPhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR//Listen for changes to the call-forwarding indicatorPhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR//Listen for changes to the device's cell locationPhoneStateListener.LISTEN_CELL_LOCATION//Listen for changes to the device call statePhoneStateListener.LISTEN_CALL_STATE//Listen for changes to the data connection statePhoneStateListener.LISTEN_DATA_CONNECTION_STATE//Listen for changes to the direction of data traffic on the data connectionPhoneStateListener.LISTEN_DATA_ACTIVITY//Listen for changes to OTASP modePhoneStateListener.LISTEN_OTASP_CHANGED//Listen for changes to observed cell infoPhoneStateListener.LISTEN_CELL_INFO//Listen for precise changes and fails to the device callsPhoneStateListener.LISTEN_PRECISE_CALL_STATE//Listen for precise changes and fails on the data connectionPhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE//Listen for real time info for all data connectionsPhoneStateListener.LISTEN_DATA_CONNECTION_REAL_TIME_INFO//Listen for changes to LTE network statePhoneStateListener.LISTEN_VOLTE_STATE//Listen for OEM hook raw eventPhoneStateListener.LISTEN_OEM_HOOK_RAW_EVENT//isten for carrier network changes indicated by a carrier appPhoneStateListener.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 0
原创粉丝点击