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的运作机制。