简介:Android N
第一步
分析初始Log
04-23 20:27:29.713 6464 6464 D TelephonyManager: factoryReset: subId=2 //重置
04-23 20:27:31.546 6464 6464 D ImsManager: updateImsServiceConfig: turnOnIms //更新Ims
04-23 20:26:29.901 3004 3004 I QImsService: ImsConfigImpl : SetServiceStatus = 0 13 2 //正常情况,打开
04-23 20:26:30.522 3004 3004 I QImsService: ImsConfigImpl : SetServiceStatus = 3 13 2
04-23 20:29:07.947 3004 3004 I QImsService: ImsConfigImpl : SetServiceStatus = 0 13 0 //异常情况,关闭
04-23 20:29:07.994 3004 3004 I QImsService: ImsConfigImpl : SetServiceStatus = 3 13 2
此处为高通平台的Log,然后我们要找打印Log的地方。
第二步
找Log出处
从Log打印可知,是在ImsConfigImpl.java里面调用的。
此处为高通的代码,不方便粘贴,能找到的话,分析起来就方便很多了。
第三步
查看异常原因
我们看到此处SetServiceStatus = 0 13 0
异常,并继续查看源码,找到对应的类型。
第一个 0:CALL_TYPE 类型
第二个 13:网络类型
第三个 0:打开类型(一般0是关闭)
此处为高通代码,想要了解的童鞋,可自行查找。
第四步
查看setFeatureValue情况
04-23 20:27:31.326 6464 6464 D ImsConfig: setFeatureValue: feature = 0, network =13, value =0, listener =null //异常,此处value =0
04-23 20:27:31.447 6464 6464 D ImsConfig: setFeatureValue: feature = 2, network =18, value =0, listener =null
04-23 20:27:31.540 6464 6464 D ImsConfig: setFeatureValue: feature = 1, network =13, value =1, listener =null
04-23 20:31:07.853 6464 6464 D ImsConfig: setFeatureValue: feature = 0, network =13, value =1, listener =null //正常,此处value =1
04-23 20:31:07.935 6464 6464 D ImsConfig: setFeatureValue: feature = 2, network =18, value =0, listener =null
04-23 20:31:07.992 6464 6464 D ImsConfig: setFeatureValue: feature = 1, network =13, value =1, listener =null
可以看到feature没有设置成功。
第五步
查看setFeatureValue的源码
看一下源码,在哪里调用的:
public void setFeatureValue(int feature, int network, int value,
ImsConfigListener listener) throws ImsException {
if (DBG) {
Rlog.d(TAG, "setFeatureValue: feature = " + feature + ", network =" + network +
", value =" + value + ", listener =" + listener);
}
try {
miConfig.setFeatureValue(feature, network, value, listener);
} catch (RemoteException e) {
throw new ImsException("setFeatureValue()", e,
ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
}
}
在这里可以看到setFeatureValue()前后的调用情况。
第六步
调用setFeatureValue的地方
继续下一步调用(这里调用的地方比较多,但是我们只关注VoLte的调用就可以):
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;
}
第七步
查看available的值
04-23 20:27:31.322 6464 6464 D ImsManager: updateVolteFeatureValue: available = false, enabled = true, nonTTY = true
available = false
,VoLte故不可用。
从第六步知道 boolean available = isVolteEnabledByPlatform(mContext)
,继续深追。
第八步
查看isVolteEnabledByPlatform()
public static boolean isVolteEnabledByPlatform(Context context) {
if (SystemProperties.getInt(PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE,
PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE_DEFAULT) == 1) {
return true;
}
return context.getResources().getBoolean(
com.android.internal.R.bool.config_device_volte_available)
&& getBooleanCarrierConfig(context,
CarrierConfigManager.KEY_CARRIER_VOLTE_AVAILABLE_BOOL)
&& isGbaValid(context);
}
这里要把
1)context.getResources().getBoolean(com.android.internal.R.bool.config_device_volte_available)
;
2)getBooleanCarrierConfig(context, CarrierConfigManager.KEY_CARRIER_VOLTE_AVAILABLE_BOOL)
;
3)isGbaValid(context)
.
各个调用的值打印出来看
第九步:
添加Log,逐步分析:
04-17 17:14:24.146 4832 4832 D TelephonyManager: factoryReset: subId=1
04-17 17:16:40.270 4832 4832 D TelephonyManager: factoryReset: subId=1
04-17 17:14:24.555 4832 4832 D ImsManager: isVolteEnabledByPlatform :context = com.android.settings.SubSettings@33ff9f3
04-17 17:14:24.555 4832 4832 D ImsManager: isVolteEnabledByPlatform :config_device_volte_available = true
04-17 17:14:24.559 4832 4832 D ImsManager: isVolteEnabledByPlatform :KEY_CARRIER_VOLTE_AVAILABLE_BOOL = false
04-17 17:14:24.563 4832 4832 D ImsManager: isVolteEnabledByPlatform :isGbaValid = true
可以看到此处的KEY_CARRIER_VOLTE_AVAILABLE_BOOL
为false,至此可以定位问题的源头了。
第十步
查看getBooleanCarrierConfig()
private static boolean getBooleanCarrierConfig(Context context, String key) {
CarrierConfigManager configManager = (CarrierConfigManager) context.getSystemService(
Context.CARRIER_CONFIG_SERVICE);
PersistableBundle b = null;
int[] subId = SubscriptionManager.getSubId(mImsPhoneId);
SubscriptionManager subscriptionManager = SubscriptionManager.from(context);
if (configManager != null && subId != null && subscriptionManager != null &&
subscriptionManager.isActiveSubId(subId[0])) {
b = configManager.getConfigForSubId(subId[0]);
}
if (b != null) {
return b.getBoolean(key);
} else {
// Return static default defined in CarrierConfigManager.
return CarrierConfigManager.getDefaultConfig().getBoolean(key);
}
}
看源码,好像也没什么问题,那么问题到底在哪里呢?
第十一步
打印各个变量,分析其值
打印Log :
04-20 14:17:39.625 2984 2984 D ImsManager: getBooleanCarrierConfig :mImsPhoneId = 1
04-20 14:17:39.625 2984 2984 D ImsManager: getBooleanCarrierConfig :subId[0] = 1
04-20 14:17:39.626 2984 2984 D ImsManager: getBooleanCarrierConfig :isActiveSubId = true
04-20 14:17:39.715 3045 3045 D ImsManager: getBooleanCarrierConfig :mImsPhoneId = 0
04-20 14:17:39.715 3045 3045 D ImsManager: getBooleanCarrierConfig :subId[0] = 2147483643
04-20 14:17:39.716 3045 3045 D ImsManager: getBooleanCarrierConfig :isActiveSubId = false
可以看到 这里的mImsPhoneId一瞬间从1
变到0
是问题的关键所在。
移动卡卡二时,mImsPhoneId 为 0,(此处本该为 1 ),导致subId[0] = 2147483643,进而isActiveSubId返回 false,
最后不能正确返回参数。
private static int mImsPhoneId
; (此处的修改 是针对各个开发商,并非正式版)
至于为什么 卡一的时候,没有这个错误,是因为 这个 mImsPhoneId 是静态的,默认为0,所以才不会出问题。
ResetNetwork 里面调用的时候,是新 new 的 ImsManager,而不是之前 赋值过的 Ims,所以才会造成这样的问题。
第十二步
尝试修改
1)调用getDefaultVoicePhoneId
,双卡时,通话卡的选择会影响这个值,此方案不通过。
2)调用getDefaultDataPhoneId
,测试通过,源码如下:
ImsManager open() ---> mImsPhoneId = imsPhoneId;
ImsPhoneCallTracker getImsService() --- >
mImsManager = ImsManager.getInstance(mPhone.getContext(), mPhone.getPhoneId());
mServiceId = mImsManager.open(ImsServiceClass.MMTEL,
createIncomingCallPendingIntent(),
mImsConnectionStateListener, mPhone.getPhoneId());
此处的mPhone.getPhoneId()
,即为getDefaultDataPhoneId()
,
而mPhone
即为默认数据卡对应的phone。
但是,mImsPhoneId
可能还受 高通其他代码 的影响,所以不建议这样修改。
第十三步
正式修改
解决方法是:把mImsPhoneId
写入系统属性,然后读取的时候,直接从系统属性值里面读出来。
在给mImsPhoneId
赋值之后,直接调用SystemProperties.set()
将其写到系统属性里面去。
具体代码就不多说了,就是在这里给大家提个解决的思路。
最后,还是要多练习,多看源码,累计经验,才能知道第一步 是经过了多少失败的分析