转载请注明出处:http://blog.csdn.net/aaa111/article/details/73872220
文前
代码基于mkm-mr1 android 7.1.2
本篇记录了调查ims Registered状态和VoLTE enable状态的一些取值和更新的关键方法。
初衷是调查ims
registered
状态和 VoLTE Available
有没有对外提供接口,以及这两者有什么逻辑上的关系。
PS:本文采取“双线叙事”,同时调查ims Registered和Volte enable的关键方法,如果读者感觉有点乱,可以一次只看ims或者volte(这意味着你要看两遍,其实是我懒不想分开写)。
正文
TelephonyManager.java向系统其他应用(Settings,SystemUI)提供接口,为什么说是“
系统其他应用
”呢?
因为以下几个方法都是@hide方法,不对第三方应用公开。
fw/base/telephony
TelephonyManager.java
以下两个方法都是获得ims registered的方法,区别在于第二个方法需传入subId作为参数。
/**
* Returns the IMS Registration Status
* @hide
*/
public boolean isImsRegistered() {
try {
ITelephony telephony = getITelephony();
if (telephony == null)
return false;
return telephony.isImsRegistered();
} catch (RemoteException ex) {
return false;
} catch (NullPointerException ex) {
return false;
}
}
/**
* Returns the IMS Registration Status
* using subId
* @hide
*/
public boolean isImsRegisteredForSubscriber(int subId) {
try {
ITelephony telephony = getITelephony();
if (telephony == null)
return false;
return telephony.isImsRegisteredForSubscriber(subId);
} catch (RemoteException ex) {
return false;
} catch (NullPointerException ex) {
return false;
}
}
下面这个方法返回的是VoLTE status
/**
* Returns the Status of Volte
* @hide
*/
public boolean isVolteAvailable() {
try {
return getITelephony().isVolteAvailable();
} catch (RemoteException ex) {
return false;
} catch (NullPointerException ex) {
return false;
}
}
到现在为止我们知道TelephonyManager.java中有三个hide方法返回ims registered和VoLTE Status,但都是hide方法,不对第三方应用公开。
packages/services/Telephony
PhoneInterfacemanager.java
到了这可以看到,两个方法调用的都是Phone.java 里的registered()方法(当然,实际调用的是ImsPhone.java里的同名方法)。
@Override
public boolean isImsRegistered() {
return mPhone.registered();
}
/*
* {@hide}
* Returns the IMS Registration Status based on subId
*/
public boolean isImsRegisteredForSubscriber(int subId) {
final Phone phone = getPhone(subId);
if (phone != null) {
return phone.isImsRegistered();
}
return false;
}
然后下面这个是VoLTE的,
isVolteAvailable和isVolteEnabled居然是等价的,意味着开启即可用?
/*
* {@hide}
* Returns the IMS Registration Status
*/
public boolean isVolteAvailable() {
return mPhone.isVolteEnabled();
}
然后观察到这个类里面还有个方法来设置ims registration status的,但是吧其实这个方法没有使用到。
public void setImsRegistrationState(boolean registered) {
enforceModifyPermission();
mPhone.setImsRegistrationState(registered);
}
Phone.java
这个方法只在GsmCdmaPhone.java里面重写了,但是GsmCdmaPhone会有ims服务?
/**
* Set IMS registration state
*/
public void setImsRegistrationState(boolean registered) {
}
ImsRegistered的最终取值
fw/opt/telephony
ImsPhone.java
下面便是Ims registered
取值的终点,接下来看的
赋值(更新)的地方。
setImsRegistered()正是给mImsRegistered 赋值的地方
@Override
public boolean isImsRegistered() {
return mImsRegistered;
}
public void setImsRegistered(boolean value) {
mImsRegistered = value;
}
而Volte的取值还需再跟进一步
@Override
public boolean isVolteEnabled() {
return mCT.isVolteEnabled();
}
VolteEnabled的最终取值
fw/opt/telephony
ImsPhoneCallTracker.java
来自一个布尔值,其实是一个布尔数组里面的其中一个值。
public boolean isVolteEnabled() {
return mImsFeatureEnabled[ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE];
}
Ims Registered 的更新
巧合的是ims registered的更新也是在这个类里面
/**
* Listen to the IMS service state change
*
*/
private ImsConnectionStateListener mImsConnectionStateListener =
new ImsConnectionStateListener() {
@Override
public void onImsConnected() {
if (DBG) log("onImsConnected");
mPhone.setServiceState(ServiceState.STATE_IN_SERVICE);
mPhone.setImsRegistered(true);
mMetrics.writeOnImsConnectionState(mPhone.getPhoneId(),
ImsConnectionState.State.CONNECTED, null);
}
@Override
public void onImsDisconnected(ImsReasonInfo imsReasonInfo) {
if (DBG) log("onImsDisconnected imsReasonInfo=" + imsReasonInfo);
mPhone.setServiceState(ServiceState.STATE_OUT_OF_SERVICE);
mPhone.setImsRegistered(false);
mPhone.processDisconnectReason(imsReasonInfo);
mMetrics.writeOnImsConnectionState(mPhone.getPhoneId(),
ImsConnectionState.State.DISCONNECTED, imsReasonInfo);
}
@Override
public void onImsProgressing() {
if (DBG) log("onImsProgressing");
mPhone.setServiceState(ServiceState.STATE_OUT_OF_SERVICE);
mPhone.setImsRegistered(false);
mMetrics.writeOnImsConnectionState(mPhone.getPhoneId(),
ImsConnectionState.State.PROGRESSING, null);
}
...
}
上面的代码显示,在Ims
连接后设置setImsRegistered 为true,在
断开后和
正在连接的时候都设置为false。
VolteEnable 的更新
fw/opt/telephony
ImsPhoneCallTracker.java
Volte的更新也来自ImsConnectionStateListener,更新的是我们取值的那个布尔变量。
除此之外还有两个地方用到了ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE,
但是和这里无关。
其一:
还是在ImsConnectionStateListener里面,
/**
* Listen to the IMS service state change
*
*/
private ImsConnectionStateListener mImsConnectionStateListener =
new ImsConnectionStateListener() {
...
@Override
public void onFeatureCapabilityChanged(int serviceClass,
int[] enabledFeatures, int[] disabledFeatures) {
if (serviceClass == ImsServiceClass.MMTEL) {
boolean tmpIsVideoCallEnabled = isVideoCallEnabled();
// Check enabledFeatures to determine capabilities. We ignore disabledFeatures.
StringBuilder sb;
if (DBG) {
sb = new StringBuilder(120);
sb.append("onFeatureCapabilityChanged: ");
}
for (int i = ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE;
i <= ImsConfig.FeatureConstants.FEATURE_TYPE_UT_OVER_WIFI &&
i < enabledFeatures.length; i++) {
if (enabledFeatures[i] == i) {
// If the feature is set to its own integer value it is enabled.
if (DBG) {
sb.append(mImsFeatureStrings[i]);
sb.append(":true ");
}
mImsFeatureEnabled[i] = true;
} else if (enabledFeatures[i]
== ImsConfig.FeatureConstants.FEATURE_TYPE_UNKNOWN) {
// FEATURE_TYPE_UNKNOWN indicates that a feature is disabled.
if (DBG) {
sb.append(mImsFeatureStrings[i]);
sb.append(":false ");
}
mImsFeatureEnabled[i] = false;
这个方法重写自:
ImsConnectionStateListener.java
这个是跟IMS连接紧密相关的
/**
* Called when its current IMS connection feature capability changes.
*/
public void onFeatureCapabilityChanged(int serviceClass,
int[] enabledFeatures, int[] disabledFeatures) {
// no-op
}
上面的方法调用自:
fw/opt/net
ImsManager.java
@Override
public void registrationFeatureCapabilityChanged(int serviceClass,
int[] enabledFeatures, int[] disabledFeatures) {
log("registrationFeatureCapabilityChanged :: serviceClass=" +
serviceClass);
if (mListener != null) {
mListener.onFeatureCapabilityChanged(serviceClass,
enabledFeatures, disabledFeatures);
}
}
后面两种是在ImsManager.java 这个类中的更新,更新的值保存在新建的ImsConfig对象中,值得注意的是,并没有哪块代码去getFeatureValue。如读者不关心这部分可以直接跳到文末总结部分。
其二:
fw/opt/net
ImsManager.java
可以看到首先创建了一个ImsConfig对象,然后通过setFeatureValue()方法对ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE进行更新。
private void setLteFeatureValues(boolean turnOn) {
log("setLteFeatureValues: " + turnOn);
try {
ImsConfig config = getConfigInterface();
if (config != null) {
config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE,
TelephonyManager.NETWORK_TYPE_LTE, turnOn ? 1 : 0, mImsConfigListener);
if (isVtEnabledByPlatform(mContext)) {
boolean ignoreDataEnabledChanged = getBooleanCarrierConfig(mContext,
CarrierConfigManager.KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS);
boolean enableViLte = turnOn && isVtEnabledByUser(mContext) &&
(ignoreDataEnabledChanged || isDataEnabled());
config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_LTE,
TelephonyManager.NETWORK_TYPE_LTE,
enableViLte ? 1 : 0,
mImsConfigListener);
}
}
} catch (ImsException e) {
loge("setLteFeatureValues: exception ", e);
}
}
查看方法调用得知,是用户在界面上开启enhanced_4g_lte这个开关才更新的,我们推断这次更新只和用户设置有关系,和网络没有关系,但这似乎是不合理的。
除了更新ImsConfig还更新了Settings 数据库中的存储。
图 略
其三:
/**
* Update VoLTE config
* @return whether feature is On
* @throws ImsException
*/
private boolean updateVolteFeatureValue() throws ImsException {
boolean available = isVolteEnabledByPlatform(mContext);//平台支持
boolean enabled = isEnhanced4gLteModeSettingEnabledByUser(mContext);//开关打开
boolean isNonTty = isNonTtyOrTtyOnVolteEnabled(mContext);
boolean isFeatureOn = available && enabled && isNonTty;
log("updateVolteFeatureValue: available = " + available
+ ", enabled = " + enabled
+ ", nonTTY = " + isNonTty);
getConfigInterface().setFeatureValue(
ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE,
TelephonyManager.NETWORK_TYPE_LTE,
isFeatureOn ?
ImsConfig.FeatureValueConstants.ON :
ImsConfig.FeatureValueConstants.OFF,
mImsConfigListener);
return isFeatureOn;
}
查看方法调用我们推断,这次更新依赖于Ims网络服务。但是这个更新条件的Action是Action to broadcast when ImsService is up。这样看来这里似乎只有在IMS服务建立的时候才会执行。
图 略
其中Intent action
/**
* Action to broadcast when ImsService is up.
* Internal use only.
* @hide
*/
public static final String ACTION_IMS_SERVICE_UP =
"com.android.ims.IMS_SERVICE_UP";
整理流程:

总结
ImsRegistered的取值来自ImsPhone.java的mImsRegistered,这个值
取决于ims网络连接状态。在Telephony中的接口为hide方法,对第三方不可见。
VolteAvailable的取值来自ImsPhoneCallTracker.java的
ImsConnectionStateListener,
ImsConnectionStateListener监听onFeatureCapabilityChanged来更新(布尔值)。
在Telephony中的接口为hide方法,同样对第三方不可见。
以上两者更新的关键方法都在ImsPhoneCallTracker.java的
ImsConnectionStateListener里。