先看下拨号失败流程是如何的
1、延迟多长时间重试?
//相关Log
Line 67380: 068195 06-06 08:53:10.952 1760 1885 D RILJ : [6812]> SETUP_DATA_CALL,radioTechnology=14,isRoaming=false,allowRoaming=false,DataProfile=0/spmode.ne.jp/IPV4V6/0///0/0/0/0/true/1/IPV4V6/0/0///false [SUB0]
Line 67537: 0685C0 06-06 08:53:12.855 1760 1794 D RilRequest: [6812]< SETUP_DATA_CALL error: com.android.internal.telephony.CommandException: GENERIC_FAILURE ret
=DataCallResponse: { status=65535 retry=-1 cid=-1 active=-1 type= ifname= mtu=0 addresses=[] dnses=[] gateways=[] pcscf=[]}
第9步记录了modem建议的返回时间,第15取相关时间重试
如果为如果retry >0小于最大整形,就用retry值作为delay,如果retry < 0,则使用配置项和随机数组合
private long getSuggestedRetryDelay(DataCallResponse response) {
/** According to ril.h
* The value < 0 means no value is suggested
* The value 0 means retry should be done ASAP.
* The value of Integer.MAX_VALUE(0x7fffffff) means no retry.
*/
// The value < 0 means no value is suggested
if (response.getSuggestedRetryTime() < 0) {
return RetryManager.NO_SUGGESTED_RETRY_DELAY;
}
// The value of Integer.MAX_VALUE(0x7fffffff) means no retry.
else if (response.getSuggestedRetryTime() == Integer.MAX_VALUE) {
if (DBG) log("Modem suggested not retrying.");
return RetryManager.NO_RETRY;
}
// We need to cast it to long because the value returned from RIL is a 32-bit integer,
// but the time values used in AlarmManager are all 64-bit long.
return (long) response.getSuggestedRetryTime();
}
Line 67110: 067E2C 06-06 08:53:10.586 1760 1760 D RetryManager: [default] Setting 1 waiting APNs.
Line 67588: 06863C 06-06 08:53:12.976 1760 1760 D RetryManager: [default] getRetryTimer: 5625
//定时器重试Line 67590: 06863E 06-06 08:53:12.977 1760 1760 D DCT : [0]startAlarmForReconnect: delay=5625 action=com.android.internal.telephony.data-reconnect.default apn={mApnType=default mState=SCANNING mWaitingApns={[[ApnSettingV3] sp-mode, 2550, 44010, spmode.ne.jp, , , , , , 0, default, IPV4V6, IPV4V6, true, 0, 0, 0, false, 0, 0, 0, 0, , , false]} mApnSetting={[ApnSettingV3] sp-mode, 2550, 44010, spmode.ne.jp, , , , , , 0, default, IPV4V6, IPV4V6, true, 0, 0, 0, false, 0, 0, 0, 0, , , false} mReason=dataEnabled mDataEnabled=true mDependencyMet=true}
2、使用什么apn重试?
当Dctracker发起定时器广播后, 最终调到Dctracker中的setupData函数, 在setupData函数中,APN轮询为如下函数
apnContext.getNextApnSetting(); 最后调到RetryManager中的getNextApnSetting
public ApnSetting getNextApnSetting() {
if (mWaitingApns == null || mWaitingApns.size() == 0) {
log("Waiting APN list is null or empty.");
return null;
}
// If the modem had suggested a retry delay, we should retry the current APN again
// (up to MAX_SAME_APN_RETRY times) instead of getting the next APN setting from
// our own list.
// 如果modem有建议delay的时间,并且相同APN的重试小于最大次数,则使用相同APN重试
if (mModemSuggestedDelay != NO_SUGGESTED_RETRY_DELAY &&
mSameApnRetryCount < MAX_SAME_APN_RETRY) {
mSameApnRetryCount++;
return mWaitingApns.get(mCurrentApnIndex);
}
mSameApnRetryCount = 0;
int index = mCurrentApnIndex;
// Loop through the APN list to find out the index of next non-permanent failed APN.
while (true) {
if (++index == mWaitingApns.size()) index = 0;
// Stop if we find the non-failed APN.
if (mWaitingApns.get(index).permanentFailed == false) break;
// If we've already cycled through all the APNs, that means there is no APN we can try
if (index == mCurrentApnIndex) return null;
}
mCurrentApnIndex = index;
//使用下一个APN重试
return mWaitingApns.get(mCurrentApnIndex);
}
简单一点如果Log中retry>0 且重试次数< 最大重试次数MAX_SAME_APN_RETRY 则使用相同的APN重试,否则轮询使用其他的 APN
3、重试和普通正常拨号的区别在什么地方?
拨号的函数最后都会调到setupData,如何区分是否重试拨号还是非重试拨号呢? 排查代码分析如下
private void onDataSetupCompleteError(AsyncResult ar) {
ApnContext apnContext = getValidApnContext(ar, "onDataSetupCompleteError");
if (apnContext == null) return;
long delay = apnContext.getDelayForNextApn(mFailFast);
// Check if we need to retry or not.
if (delay >= 0) {
if (DBG) log("onDataSetupCompleteError: Try next APN. delay = " + delay);
//拨号失败后,apnContext状态变成了SCANNING状态
apnContext.setState(DctConstants.State.SCANNING);
// Wait a bit before trying the next APN, so that
// we're not tying up the RIL command channel
startAlarmForReconnect(delay, apnContext);
在trySetupData中函数中,如果APN状态是DctConstants.State.IDLE状态,重设waitingApn,此逻辑会清空RetryManager的中设置,而拨号失败重试为SCANNING状态,不会清空RetryManager的中设置,因此使用的apn就不一样了
if (apnContext.getState() == DctConstants.State.IDLE) {
if (waitingApns == null) {
waitingApns = buildWaitingApns(apnContext.getApnType(), radioTech);
}
if (waitingApns.isEmpty()) {
notifyNoData(DcFailCause.MISSING_UNKNOWN_APN, apnContext);
notifyOffApnsOfAvailability(apnContext.getReason());
String str = "trySetupData: X No APN found retValue=false";
if (DBG) log(str);
apnContext.requestLog(str);
return false;
} else {
apnContext.setWaitingApns(waitingApns);
if (DBG) {
log ("trySetupData: Create from mAllApnSettings : "
+ apnListToString(mAllApnSettings));
}
}
}
boolean retValue = setupData(apnContext, radioTech);