Android 4.0.4 data call fail - 数据激活失败处理机制

原理应该是一样的,留下来当学习的素材。


Android数据激活步骤,此处不做详述,主要介绍激活失败后的处理:

1. Android数据连接分为两种:默认连接和个别应用需要时建立的连接两种。默认连接在开机是建立并始终保持,可通过一些控制来断开,另一种连接是应用请求时才建立的连接。

ConnectivityManager.Java  包含了基本所有的API:

申请建立连接 API: public int startUsingNetworkFeature(int networkType, String feature)。

申请断开连接 API:public int stopUsingNetworkFeature(int networkType, String feature)。


2. PDP激活成功比较容易解读,但是数据连接激活失败后Android的处理机制(PDP 激活失败),从代码看激活失败后是有重试的而且默认连接和特殊连接的重试次数不同的。数据处理的核心代码在 GsmDataConnectionTracker.java里,如果想要深入了解可以从这里开始。

[java]  view plain  copy
 print ?
  1. @Override  
  2. protected void onDataSetupComplete(AsyncResult ar) {  
  3.   
  4.     DataConnection.FailCause cause = DataConnection.FailCause.UNKNOWN;  
  5.     boolean handleError = false;  
  6.     ApnContext apnContext = null;  
  7.   
  8.     if(ar.userObj instanceof ApnContext){  
  9.         apnContext = (ApnContext)ar.userObj;  
  10.     } else {  
  11.         throw new RuntimeException("onDataSetupComplete: No apnContext");  
  12.     }  
  13.   
  14.     if (isDataSetupCompleteOk(ar)) {  
  15.         mPdpFailCount = 0;  
  16.         DataConnectionAc dcac = apnContext.getDataConnectionAc();  
  17.   
  18.         if (RADIO_TESTS) {  
  19.             // Note: To change radio.test.onDSC.null.dcac from command line you need to  
  20.             // adb root and adb remount and from the command line you can only change the  
  21.             // value to 1 once. To change it a second time you can reboot or execute  
  22.             // adb shell stop and then adb shell start. The command line to set the value is:  
  23.             //   adb shell sqlite3 /data/data/com.android.providers.settings/databases/settings.db "insert into system (name,value) values ('radio.test.onDSC.null.dcac', '1');"  
  24.             ContentResolver cr = mPhone.getContext().getContentResolver();  
  25.             String radioTestProperty = "radio.test.onDSC.null.dcac";  
  26.             if (Settings.System.getInt(cr, radioTestProperty, 0) == 1) {  
  27.                 log("onDataSetupComplete: " + radioTestProperty +  
  28.                         " is true, set dcac to null and reset property to false");  
  29.                 dcac = null;  
  30.                 Settings.System.putInt(cr, radioTestProperty, 0);  
  31.                 log("onDataSetupComplete: " + radioTestProperty + "=" +  
  32.                         Settings.System.getInt(mPhone.getContext().getContentResolver(),  
  33.                                 radioTestProperty, -1));  
  34.             }  
  35.         }  
  36.         if (dcac == null) {  
  37.             log("onDataSetupComplete: no connection to DC, handle as error");  
  38.             cause = DataConnection.FailCause.CONNECTION_TO_DATACONNECTIONAC_BROKEN;  
  39.             handleError = true;  
  40.         } else {  
  41.             DataConnection dc = apnContext.getDataConnection();  
  42.   
  43.             if (DBG) {  
  44.                 // TODO We may use apnContext.getApnSetting() directly  
  45.                 // instead of getWaitingApns().get(0)  
  46.                 String apnStr = "<unknown>";  
  47.                 if (apnContext.getWaitingApns() != null  
  48.                         && !apnContext.getWaitingApns().isEmpty()){  
  49.                     apnStr = apnContext.getWaitingApns().get(0).apn;  
  50.                 }  
  51.                 log("onDataSetupComplete: success apn=" + apnStr);  
  52.             }  
  53.             ApnSetting apn = apnContext.getApnSetting();  
  54.             if (apn.proxy != null && apn.proxy.length() != 0) {  
  55.                 try {  
  56.                     String port = apn.port;  
  57.                     if (TextUtils.isEmpty(port)) port = "8080";  
  58.                     ProxyProperties proxy = new ProxyProperties(apn.proxy,  
  59.                             Integer.parseInt(port), null);  
  60.                     dcac.setLinkPropertiesHttpProxySync(proxy);  
  61.                 } catch (NumberFormatException e) {  
  62.                     loge("onDataSetupComplete: NumberFormatException making ProxyProperties (" +  
  63.                             apn.port + "): " + e);  
  64.                 }  
  65.             }  
  66.   
  67.             // everything is setup  
  68.             if(TextUtils.equals(apnContext.getApnType(),Phone.APN_TYPE_DEFAULT)) {  
  69.                 SystemProperties.set("gsm.defaultpdpcontext.active""true");  
  70.                 if (canSetPreferApn && mPreferredApn == null) {  
  71.                     if (DBG) log("onDataSetupComplete: PREFERED APN is null");  
  72.                     mPreferredApn = apnContext.getApnSetting();  
  73.                     if (mPreferredApn != null) {  
  74.                         setPreferredApn(mPreferredApn.id);  
  75.                     }  
  76.                 }  
  77.             } else {  
  78.                 SystemProperties.set("gsm.defaultpdpcontext.active""false");  
  79.             }  
  80.             notifyDefaultData(apnContext);  
  81.         }  
  82.     } else {  
  83.         String apnString;  
  84.   
  85.         cause = (DataConnection.FailCause) (ar.result);  
  86.         if (DBG) {  
  87.             try {  
  88.                 apnString = apnContext.getWaitingApns().get(0).apn;  
  89.             } catch (Exception e) {  
  90.                 apnString = "<unknown>";  
  91.             }  
  92.             log(String.format("onDataSetupComplete: error apn=%s cause=%s", apnString, cause));  
  93.         }  
  94.         if (cause.isEventLoggable()) {  
  95.             // Log this failure to the Event Logs.  
  96.             int cid = getCellLocationId();  
  97.             EventLog.writeEvent(EventLogTags.PDP_SETUP_FAIL,  
  98.                     cause.ordinal(), cid, TelephonyManager.getDefault().getNetworkType());  
  99.         }  
  100.   
  101.         // Count permanent failures and remove the APN we just tried  
  102.         if (cause.isPermanentFail()) apnContext.decWaitingApnsPermFailCount();  
  103.   
  104.         apnContext.removeNextWaitingApn();  
  105.         if (DBG) {  
  106.             log(String.format("onDataSetupComplete: WaitingApns.size=%d" +  
  107.                     " WaitingApnsPermFailureCountDown=%d",  
  108.                     apnContext.getWaitingApns().size(),  
  109.                     apnContext.getWaitingApnsPermFailCount()));  
  110.         }  
  111.         handleError = true;  
  112.     }  
  113.   
  114.     if (handleError) {  
  115.         // See if there are more APN's to try  
  116.         if (apnContext.getWaitingApns().isEmpty()) {  
  117.             if (apnContext.getWaitingApnsPermFailCount() == 0) {  
  118.                 if (DBG) {  
  119.                     log("onDataSetupComplete: All APN's had permanent failures, stop retrying");  
  120.                 }  
  121.                 apnContext.setState(State.FAILED);  
  122.                 mPhone.notifyDataConnection(Phone.REASON_APN_FAILED, apnContext.getApnType());  
  123.   
  124.                 apnContext.setDataConnection(null);  
  125.                 apnContext.setDataConnectionAc(null);  
  126.             } else {  
  127.                 if (DBG) log("onDataSetupComplete: Not all permanent failures, retry");  
  128.                 // check to see if retry should be overridden for this failure.  
  129.                 int retryOverride = -1;  
  130.                 if (ar.exception instanceof DataConnection.CallSetupException) {  
  131.                     retryOverride =  
  132.                         ((DataConnection.CallSetupException)ar.exception).getRetryOverride();  
  133.                 }  
  134.                 if (retryOverride == RILConstants.MAX_INT) {  
  135.                     if (DBG) log("No retry is suggested.");  
  136.                 } else {  
  137.                     startDelayedRetry(cause, apnContext, retryOverride);  
  138.                 }  
  139.             }  
  140.         } else {  
  141.             if (DBG) log("onDataSetupComplete: Try next APN");  
  142.             apnContext.setState(State.SCANNING);  
  143.             // Wait a bit before trying the next APN, so that  
  144.             // we're not tying up the RIL command channel  
  145.             startAlarmForReconnect(APN_DELAY_MILLIS, apnContext);  
  146.         }  
  147.     }  
  148. }  

激活失败后,首先判断是否是永久故障,如果是 apnContext.removeNextWaitingApn(),从数组里移除第一个APNSETTING:

// Count permanent failures and remove the APN we just tried

[java]  view plain  copy
 print ?
  1. public boolean isPermanentFail() {  
  2.     return (this == OPERATOR_BARRED) || (this == MISSING_UNKNOWN_APN) ||  
  3.            (this == UNKNOWN_PDP_ADDRESS_TYPE) || (this == USER_AUTHENTICATION) ||  
  4.            (this == SERVICE_OPTION_NOT_SUPPORTED) ||  
  5.            (this == SERVICE_OPTION_NOT_SUBSCRIBED) || (this == NSAPI_IN_USE) ||  
  6.            (this == PROTOCOL_ERRORS);  
  7. }  

查看WaitingApns是否为空: apnContext.getWaitingApns().isEmpty(),如果不是5秒后重试下一个APN激活PDP:startAlarmForReconnect(APN_DELAY_MILLIS, apnContext);

如果WaitingApns为空,查看 if (apnContext.getWaitingApnsPermFailCount() == 0)  是否为零,mWaitingApnsPermanentFailureCountDown的值在此函数里设置:


[java]  view plain  copy
 print ?
  1. public synchronized void setWaitingApns(ArrayList<ApnSetting> waitingApns) {  
  2.     mWaitingApns = waitingApns;  
  3.     mWaitingApnsPermanentFailureCountDown.set(mWaitingApns.size());  
  4. }  

如果预置的APNSeting里有此类型 type的APN,或者APN设置类型type为空,此值就会大于零。当不为零时, 请检查如果重试应该重写此故障。

故障处理实现在:Dataconnection.java

[java]  view plain  copy
 print ?
  1. public static class CallSetupException extends Exception {  
  2.     private int mRetryOverride = -1;  
  3.   
  4.     CallSetupException (int retryOverride) {  
  5.         mRetryOverride = retryOverride;  
  6.     }  
  7.   
  8.     public int getRetryOverride() {  
  9.         return mRetryOverride;  
  10.     }  
  11. }  


[java]  view plain  copy
 print ?
  1. public void setEnterNotificationParams(ConnectionParams cp, FailCause cause,  
  2.                                        int retryOverride) {  
  3.     if (VDBG) log("DcInactiveState: setEnterNoticationParams cp,cause");  
  4.     mConnectionParams = cp;  
  5.     mFailCause = cause;  
  6.     mRetryOverride = retryOverride;  
  7. }  

[java]  view plain  copy
 print ?
  1. /** 
  2.  * The state machine is activating a connection. 
  3.  */  
  4. private class DcActivatingState extends State {  
  5.     @Override  
  6.     public boolean processMessage(Message msg) {  
  7.         boolean retVal;  
  8.         AsyncResult ar;  
  9.         ConnectionParams cp;  
  10.   
  11.         switch (msg.what) {  
  12.             case EVENT_CONNECT:  
  13.                 if (DBG) log("DcActivatingState deferring msg.what=EVENT_CONNECT refCount = "  
  14.                         + mRefCount);  
  15.                 deferMessage(msg);  
  16.                 retVal = HANDLED;  
  17.                 break;  
  18.   
  19.             case EVENT_SETUP_DATA_CONNECTION_DONE:  
  20.                 if (DBG) log("DcActivatingState msg.what=EVENT_SETUP_DATA_CONNECTION_DONE");  
  21.   
  22.                 ar = (AsyncResult) msg.obj;  
  23.                 cp = (ConnectionParams) ar.userObj;  
  24.   
  25.                 DataCallState.SetupResult result = onSetupConnectionCompleted(ar);  
  26.                 if (DBG) log("DcActivatingState onSetupConnectionCompleted result=" + result);  
  27.                 switch (result) {  
  28.                     case SUCCESS:  
  29.                         // All is well  
  30.                         mActiveState.setEnterNotificationParams(cp, FailCause.NONE);  
  31.                         transitionTo(mActiveState);  
  32.                         break;  
  33.                     case ERR_BadCommand:  
  34.                         // Vendor ril rejected the command and didn't connect.  
  35.                         // Transition to inactive but send notifications after  
  36.                         // we've entered the mInactive state.  
  37.                         mInactiveState.setEnterNotificationParams(cp, result.mFailCause, -1);  
  38.                         transitionTo(mInactiveState);  
  39.                         break;  
  40.                     case ERR_UnacceptableParameter:  
  41.                         // The addresses given from the RIL are bad  
  42.                         tearDownData(cp);  
  43.                         transitionTo(mDisconnectingErrorCreatingConnection);  
  44.                         break;  
  45.                     case ERR_GetLastErrorFromRil:  
  46.                         // Request failed and this is an old RIL  
  47.                         phone.mCM.getLastDataCallFailCause(  
  48.                                 obtainMessage(EVENT_GET_LAST_FAIL_DONE, cp));  
  49.                         break;  
  50.                     case ERR_RilError:  
  51.                         // Request failed and mFailCause has the reason  
  52.                         mInactiveState.setEnterNotificationParams(cp, result.mFailCause,  
  53.                                                                   getSuggestedRetryTime(ar));  
  54.                         transitionTo(mInactiveState);  
  55.                         break;  
  56.                     case ERR_Stale:  
  57.                         // Request is stale, ignore.  
  58.                         break;  
  59.                     default:  
  60.                         throw new RuntimeException("Unknown SetupResult, should not happen");  
  61.                 }  
  62.                 retVal = HANDLED;  
  63.                 break;  
  64.   
  65.             case EVENT_GET_LAST_FAIL_DONE:  
  66.                 ar = (AsyncResult) msg.obj;  
  67.                 cp = (ConnectionParams) ar.userObj;  
  68.                 FailCause cause = FailCause.UNKNOWN;  
  69.   
  70.                 if (cp.tag == mTag) {  
  71.                     if (DBG) log("DcActivatingState msg.what=EVENT_GET_LAST_FAIL_DONE");  
  72.                     if (ar.exception == null) {  
  73.                         int rilFailCause = ((int[]) (ar.result))[0];  
  74.                         cause = FailCause.fromInt(rilFailCause);  
  75.                     }  
  76.                     // Transition to inactive but send notifications after  
  77.                     // we've entered the mInactive state.  
  78.                     mInactiveState.setEnterNotificationParams(cp, cause, -1);  
  79.                     transitionTo(mInactiveState);  
  80.                 } else {  
  81.                     if (DBG) {  
  82.                         log("DcActivatingState EVENT_GET_LAST_FAIL_DONE is stale cp.tag="  
  83.                             + cp.tag + ", mTag=" + mTag);  
  84.                     }  
  85.                 }  
  86.   
  87.                 retVal = HANDLED;  
  88.                 break;  
  89.   
  90.             default:  
  91.                 if (VDBG) {  
  92.                     log("DcActivatingState not handled msg.what=0x" +  
  93.                             Integer.toHexString(msg.what));  
  94.                 }  
  95.                 retVal = NOT_HANDLED;  
  96.                 break;  
  97.         }  
  98.         return retVal;  
  99.     }  
  100. }  

重写故障用意不清楚。接下来又是重试激活了:startDelayedRetry(cause, apnContext, retryOverride); 检查 if (!apnContext.getDataConnection().isRetryNeeded()) 是否需要重试激活操作。(疑点)默认连接,判断是否已经注册到网络,如果已经注册,根据配置可以设置为永远重试也可在一定的次数后结束,不是默认连接可以设置为激活失败状态结束:


[java]  view plain  copy
 print ?
  1. private void startDelayedRetry(GsmDataConnection.FailCause cause,  
  2.                                ApnContext apnContext, int retryOverride) {  
  3.     notifyNoData(cause, apnContext);  
  4.     reconnectAfterFail(cause, apnContext, retryOverride);  
  5. }  


[java]  view plain  copy
 print ?
  1. private void reconnectAfterFail(FailCause lastFailCauseCode,  
  2.                                 ApnContext apnContext, int retryOverride) {  
  3.     if (apnContext == null) {  
  4.         loge("reconnectAfterFail: apnContext == null, impossible");  
  5.         return;  
  6.     }  
  7.     if ((apnContext.getState() == State.FAILED) &&  
  8.         (apnContext.getDataConnection() != null)) {  
  9.         if (!apnContext.getDataConnection().isRetryNeeded()) {  
  10.             if (!apnContext.getApnType().equals(Phone.APN_TYPE_DEFAULT)) {  
  11.                 mPhone.notifyDataConnection(Phone.REASON_APN_FAILED, apnContext.getApnType());  
  12.                 return;  
  13.             }  
  14.             if (mReregisterOnReconnectFailure) {  
  15.                 // We've re-registerd once now just retry forever.  
  16.                 apnContext.getDataConnection().retryForeverUsingLastTimeout();  
  17.             } else {  
  18.                 // Try to Re-register to the network.  
  19.                 if (DBG) log("reconnectAfterFail: activate failed, Reregistering to network");  
  20.                 mReregisterOnReconnectFailure = true;  
  21.                 mPhone.getServiceStateTracker().reRegisterNetwork(null);  
  22.                 apnContext.getDataConnection().resetRetryCount();  
  23.                 return;  
  24.             }  
  25.         }  
  26.   
  27.         // If retry needs to be backed off for specific case (determined by RIL/Modem)  
  28.         // use the specified timer instead of pre-configured retry pattern.  
  29.         int nextReconnectDelay = retryOverride;  
  30.         if (nextReconnectDelay < 0) {  
  31.             nextReconnectDelay = apnContext.getDataConnection().getRetryTimer();  
  32.             apnContext.getDataConnection().increaseRetryCount();  
  33.         }  
  34.         startAlarmForReconnect(nextReconnectDelay, apnContext);  
  35.   
  36.         if (!shouldPostNotification(lastFailCauseCode)) {  
  37.             if (DBG) {  
  38.                 log("reconnectAfterFail: NOT Posting GPRS Unavailable notification "  
  39.                             + "-- likely transient error");  
  40.             }  
  41.         } else {  
  42.             notifyNoData(lastFailCauseCode, apnContext);  
  43.         }  
  44.     }  
  45. }  

还有一个重试管理的类 RetryManager.java, 判断是否有重试的必要,而且重试次数是可配置的: 

[java]  view plain  copy
 print ?
  1. /** 
  2.  * Report whether data reconnection should be retried 
  3.  * 
  4.  * @return {@code true} if the max retries has not been reached. {@code 
  5.  *         false} otherwise. 
  6.  */  
  7. public boolean isRetryNeeded() {  
  8.     boolean retVal = mRetryForever || (mRetryCount < mMaxRetryCount);  
  9.     if (DBG) log("isRetryNeeded: " + retVal);  
  10.     return retVal;  
  11. }  


[java]  view plain  copy
 print ?
  1. /** 
  2.  * Configure for a simple linear sequence of times plus 
  3.  * a random value. 
  4.  * 
  5.  * @param maxRetryCount is the maximum number of retries 
  6.  *        before isRetryNeeded returns false. 
  7.  * @param retryTime is a time that will be returned by getRetryTime. 
  8.  * @param randomizationTime a random value between 0 and 
  9.  *        randomizationTime will be added to retryTime. this 
  10.  *        parameter may be 0. 
  11.  * @return true if successful 
  12.  */  
  13. public boolean configure(int maxRetryCount, int retryTime, int randomizationTime) {  


[java]  view plain  copy
 print ?
  1. /** 
  2.  * Configure for using string which allow arbitrary 
  3.  * sequences of times. See class comments for the 
  4.  * string format. 
  5.  * 
  6.  * @return true if successful 
  7.  */  
  8. public boolean configure(String configStr) {  


重试次数的配置变量和函数,可见默认连接(重试配置:增加了一倍的重试时间从5秒到30分钟),其它连接(重试配置为二级网络:4次尝试在20秒内),异常情况:不应该发生,记录一个错误,默认情况下,一个简单的线性序列,如真的发生了,就重新配置。

[java]  view plain  copy
 print ?
  1. /** Retry configuration: A doubling of retry times from 5secs to 30minutes */  
  2. protected static final String DEFAULT_DATA_RETRY_CONFIG = "default_randomization=2000,"  
  3.     + "5000,10000,20000,40000,80000:5000,160000:5000,"  
  4.     + "320000:5000,640000:5000,1280000:5000,1800000:5000";  
  5.   
  6. /** Retry configuration for secondary networks: 4 tries in 20 sec */  
  7. protected static final String SECONDARY_DATA_RETRY_CONFIG =  
  8.         "max_retries=3, 5000, 5000, 5000";  

[java]  view plain  copy
 print ?
  1. private void configureRetry(DataConnection dc, boolean forDefault) {  
  2.     if (dc == nullreturn;  
  3.   
  4.     if (!dc.configureRetry(getReryConfig(forDefault))) {  
  5.         if (forDefault) {  
  6.             if (!dc.configureRetry(DEFAULT_DATA_RETRY_CONFIG)) {  //默认两千  
  7.                 // Should never happen, log an error and default to a simple linear sequence.  
  8.                 loge("configureRetry: Could not configure using " +  
  9.                         "DEFAULT_DATA_RETRY_CONFIG=" + DEFAULT_DATA_RETRY_CONFIG);  
  10.                 dc.configureRetry(2020001000);  
  11.             }  
  12.         } else {  
  13.             if (!dc.configureRetry(SECONDARY_DATA_RETRY_CONFIG)) {  
  14.                 // Should never happen, log an error and default to a simple sequence.  
  15.                 loge("configureRetry: Could note configure using " +  
  16.                         "SECONDARY_DATA_RETRY_CONFIG=" + SECONDARY_DATA_RETRY_CONFIG);  
  17.                 dc.configureRetry("max_retries=3, 333, 333, 333");  
  18.             }  
  19.         }  
  20.     }  
  21. }  


设置重试的地方:

[java]  view plain  copy
 print ?
  1.     private void setupDataOnReadyApns(String reason) {  
  2.         // Stop reconnect alarms on all data connections pending  
  3.         // retry. Reset ApnContext state to IDLE.  
  4.         for (DataConnectionAc dcac : mDataConnectionAsyncChannels.values()) {  
  5.             if (dcac.getReconnectIntentSync() != null) {  
  6.                 cancelReconnectAlarm(dcac);  
  7.             }  
  8.             // update retry config for existing calls to match up  
  9.             // ones for the new RAT.  
  10.             if (dcac.dataConnection != null) {  
  11.                 Collection<ApnContext> apns = dcac.getApnListSync();  
  12.   
  13.                 boolean hasDefault = false;  
  14.                 for (ApnContext apnContext : apns) {  
  15.                     if (apnContext.getApnType().equals(Phone.APN_TYPE_DEFAULT)) {  
  16.                         hasDefault = true;  
  17.                         break;  
  18.                     }  
  19.                 }  
  20.                 //此处设置重试  
  21.                 configureRetry(dcac.dataConnection, hasDefault);  


[java]  view plain  copy
 print ?
  1. private boolean setupData(ApnContext apnContext) {  
  2.       if (DBG) log("setupData: apnContext=" + apnContext);  
  3.       ApnSetting apn;  
  4.       GsmDataConnection dc;  
  5.   
  6.       int profileId = getApnProfileID(apnContext.getApnType());  
  7.       apn = apnContext.getNextWaitingApn();  
  8.       if (apn == null) {  
  9.           if (DBG) log("setupData: return for no apn found!");  
  10.           return false;  
  11.       }  
  12.   
  13.       // First, check to see if ApnContext already has DC.  
  14.       // This could happen if the retries are currently  engaged.  
  15.       dc = (GsmDataConnection)apnContext.getDataConnection();  
  16.   
  17.       if (dc == null) {  
  18.   
  19.           dc = (GsmDataConnection) checkForConnectionForApnContext(apnContext);  
  20.   
  21.           if (dc == null) {  
  22.               dc = findReadyDataConnection(apn);  
  23.           }  
  24.   
  25.           if (dc == null) {  
  26.               if (DBG) log("setupData: No ready GsmDataConnection found!");  
  27.               // TODO: When allocating you are mapping type to id. If more than 1 free,  
  28.               // then could findFreeDataConnection get the wrong one??  
  29.               dc = findFreeDataConnection();  
  30.           }  
  31.   
  32.           if (dc == null) {  
  33.               dc = createDataConnection();  
  34.           }  
  35.   
  36.           if (dc == null) {  
  37.               if (DBG) log("setupData: No free GsmDataConnection found!");  
  38.               return false;  
  39.           }  
  40.   
  41.           DataConnectionAc dcac = mDataConnectionAsyncChannels.get(dc.getDataConnectionId());  
  42.           dc.setProfileId( profileId );  
  43.           dc.setActiveApnType(apnContext.getApnType());  
  44.           int refCount = dcac.getRefCountSync();  
  45.           if (DBG) log("setupData: init dc and apnContext refCount=" + refCount);  
  46.   
  47.           // configure retry count if no other Apn is using the same connection.  
  48.           if (refCount == 0) {  
  49.               log("refCount=0.");   
  50.               configureRetry(dc, apn.canHandleType(Phone.APN_TYPE_DEFAULT));  //此处设置重试  
  51.           }  

个人学习记录,如有理解错误之处请不吝指出,谢谢!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值