Add CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA to DcTracker.

To fail fast we turn off data stall detection and do no retires.

Bug: 9279964
Change-Id: I42c326a21e05aa301e9d974ed9ac1d59472780ec
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
index 507a796..8dd4810 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
@@ -1595,10 +1595,22 @@
     }
 
     /**
+     * @return number of milli-seconds to delay between trying apns'
+     */
+    private int getApnDelay() {
+        if (mFailFast) {
+            return SystemProperties.getInt("persist.radio.apn_ff_delay",
+                    APN_FAIL_FAST_DELAY_DEFAULT_MILLIS);
+        } else {
+            return SystemProperties.getInt("persist.radio.apn_delay", APN_DELAY_DEFAULT_MILLIS);
+        }
+    }
+
+    /**
      * Error has occurred during the SETUP {aka bringUP} request and the DCT
      * should either try the next waiting APN or start over from the
      * beginning if the list is empty. Between each SETUP request there will
-     * be a delay defined by {@link #APN_DELAY_MILLIS}.
+     * be a delay defined by {@link #getApnDelay()}.
      */
     @Override
     protected void onDataSetupCompleteError(AsyncResult ar) {
@@ -1626,14 +1638,14 @@
                 if (DBG) {
                     log("onDataSetupComplete: Not all APN's had permanent failures, short delay");
                 }
-                startAlarmForRestartTrySetup(APN_DELAY_MILLIS, apnContext);
+                startAlarmForRestartTrySetup(getApnDelay(), apnContext);
             }
         } else {
             if (DBG) log("onDataSetupComplete: Try next APN");
             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(APN_DELAY_MILLIS, apnContext);
+            startAlarmForReconnect(getApnDelay(), apnContext);
         }
     }
 
@@ -1673,7 +1685,7 @@
             // Wait a bit before trying the next APN, so that
             // we're not tying up the RIL command channel.
             // This also helps in any external dependency to turn off the context.
-            startAlarmForReconnect(APN_DELAY_MILLIS, apnContext);
+            startAlarmForReconnect(getApnDelay(), apnContext);
         } else {
             apnContext.setApnSetting(null);
             apnContext.setDataConnectionAc(null);
@@ -1712,6 +1724,7 @@
     @Override
     protected void onVoiceCallStarted() {
         if (DBG) log("onVoiceCallStarted");
+        mInVoiceCall = true;
         if (isConnected() && ! mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) {
             if (DBG) log("onVoiceCallStarted stop polling");
             stopNetStatPoll();
@@ -1723,6 +1736,7 @@
     @Override
     protected void onVoiceCallEnded() {
         if (DBG) log("onVoiceCallEnded");
+        mInVoiceCall = false;
         if (isConnected()) {
             if (!mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) {
                 startNetStatPoll();
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTrackerBase.java b/src/java/com/android/internal/telephony/dataconnection/DcTrackerBase.java
index 6c21a35..0c18ab7 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcTrackerBase.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcTrackerBase.java
@@ -85,8 +85,10 @@
 
     /** Delay between APN attempts.
         Note the property override mechanism is there just for testing purpose only. */
-    protected static final int APN_DELAY_MILLIS =
-                                SystemProperties.getInt("persist.radio.apn_delay", 20000);
+    protected static final int APN_DELAY_DEFAULT_MILLIS = 20000;
+
+    /** Delay between APN attempts when in fail fast mode */
+    protected static final int APN_FAIL_FAST_DELAY_DEFAULT_MILLIS = 3000;
 
     AlarmManager mAlarmManager;
 
@@ -202,6 +204,13 @@
     protected long mSentSinceLastRecv;
     // Controls when a simple recovery attempt it to be tried
     protected int mNoRecvPollCount = 0;
+    // True if data stall detection is enabled
+    protected volatile boolean mDataStallDetectionEnabled = true;
+
+    protected volatile boolean mFailFast = false;
+
+    // True when in voice call
+    protected boolean mInVoiceCall = false;
 
     // wifi connection status will be updated by sticky intent
     protected boolean mIsWifiConnected = false;
@@ -356,6 +365,9 @@
      */
     private static final int DEFAULT_MDC_INITIAL_RETRY = 1;
     protected int getInitialMaxRetry() {
+        if (mFailFast) {
+            return 0;
+        }
         // Get default value from system property or use DEFAULT_MDC_INITIAL_RETRY
         int value = SystemProperties.getInt(
                 Settings.Global.MDC_INITIAL_MAX_RETRY, DEFAULT_MDC_INITIAL_RETRY);
@@ -741,6 +753,28 @@
                 onSetPolicyDataEnabled(enabled);
                 break;
             }
+            case DctConstants.CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: {
+                final boolean enabled = (msg.arg1 == DctConstants.ENABLED) ? true : false;
+                if (DBG) log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: enabled=" + enabled);
+                if (mFailFast != enabled) {
+                    mFailFast = enabled;
+                    mDataStallDetectionEnabled = !enabled;
+                    if (mDataStallDetectionEnabled
+                            && (getOverallState() == DctConstants.State.CONNECTED)
+                            && (!mInVoiceCall ||
+                                    mPhone.getServiceStateTracker()
+                                        .isConcurrentVoiceAndDataAllowed())) {
+                        if (DBG) log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: start data stall");
+                        stopDataStallAlarm();
+                        startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
+                    } else {
+                        if (DBG) log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: stop data stall");
+                        stopDataStallAlarm();
+                    }
+                }
+
+                break;
+            }
             case DctConstants.EVENT_ICC_CHANGED: {
                 onUpdateIcc();
                 break;
@@ -1183,7 +1217,8 @@
     protected abstract DctConstants.State getOverallState();
 
     protected void startNetStatPoll() {
-        if (getOverallState() == DctConstants.State.CONNECTED && mNetStatPollEnabled == false) {
+        if (getOverallState() == DctConstants.State.CONNECTED
+                && mNetStatPollEnabled == false) {
             if (DBG) log("startNetStatPoll");
             resetPollStats();
             mNetStatPollEnabled = true;
@@ -1403,7 +1438,7 @@
         int nextAction = getRecoveryAction();
         int delayInMs;
 
-        if (getOverallState() == DctConstants.State.CONNECTED) {
+        if (mDataStallDetectionEnabled && getOverallState() == DctConstants.State.CONNECTED) {
             // If screen is on or data stall is currently suspected, set the alarm
             // with an aggresive timeout.
             if (mIsScreenOn || suspectedStall || RecoveryAction.isAggressiveRecovery(nextAction)) {
@@ -1492,6 +1527,7 @@
         pw.println(" mNetStatPollEnabled=" + mNetStatPollEnabled);
         pw.println(" mDataStallTxRxSum=" + mDataStallTxRxSum);
         pw.println(" mDataStallAlarmTag=" + mDataStallAlarmTag);
+        pw.println(" mDataStallDetectionEanbled=" + mDataStallDetectionEnabled);
         pw.println(" mSentSinceLastRecv=" + mSentSinceLastRecv);
         pw.println(" mNoRecvPollCount=" + mNoRecvPollCount);
         pw.println(" mResolver=" + mResolver);