Move retrying into DC.

This is the first step in refactoring for bug 4772191.

Bug: 4772191
Change-Id: Id54a20ab192783c63939158670faaf531a527640
diff --git a/README.txt b/README.txt
new file mode 100644
index 0000000..4afeefc
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,55 @@
+This package contains classes used to manage a DataConnection.
+
+A criticial aspect of this class is that most objects in this
+package run on the same thread except DataConnectionTracker
+This makes processing efficient as it minimizes context
+switching and it eliminates issues with multi-threading.
+
+This can be done because all actions are either asynchronous
+or are known to be non-blocking and fast. At this time only
+DcTesterDeactivateAll takes specific advantage of this
+single threading knowledge by using Dcc#mDcListAll so be
+very careful when making changes that break this assumption.
+
+A related change was in DataConnectionAc I added code that
+checks to see if the caller is on a different thread. If
+it is then the AsyncChannel#sendMessageSynchronously is
+used. If the caller is on the same thread then a getter
+is used. This allows the DCAC to be used from any thread
+and was required to fix a bug when Dcc called
+PhoneBase#notifyDataConnection which calls DCT#getLinkProperties
+and DCT#getLinkCapabilities which call Dcc all on the same
+thread. Without this change there was a dead lock when
+sendMessageSynchronously blocks.
+
+
+Testing:
+
+There are three Intents that can be sent for testing pruproses:
+
+The first two cause bringUp and retry requests to fail and the first
+causes all DC's to fail the second causes a specific DC to fail:
+
+  adb shell am broadcast -a com.android.internal.telephony.dataconnection.action_fail_bringup --ei counter 2 --ei fail_cause -3
+  adb shell am broadcast -a com.android.internal.telephony.dataconnection.DC-1.action_fail_bringup --ei counter 2 --ei fail_cause -3
+
+The other causes all DC's to get torn down, simulating a temporary network outage:
+
+  adb shell am broadcast -a com.android.internal.telephony.dataconnection.action_deactivate_all
+
+To simplify testing we also have detach and attach simulations below where {x} is gsm, cdma or sip
+
+  adb shell am broadcast -a com.android.internal.telephony.{x}.action_detached
+  adb shell am broadcast -a com.android.internal.telephony.{x}.action_attached
+
+
+Additionally, you on DEGUGGABLE builds (userdebug, eng) you can replace the retry configuration
+by setting the SystemProperty: test.data_retry_config for instance:
+
+  adb shell setprop test.data_retry_config "5000,5000,5000"
+
+Which changes the retry to 3 retires at 5 second intervals. This can be added to
+/data/local.prop, don't forget to "adb shell chmod 0600 /data/local.prop":
+  $ cat local.prop.test.data_retry_config
+  test.data_retry_config=5000,5000,5000,5000
+
diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java
index 0ea8035..27b0d68 100644
--- a/src/java/com/android/internal/telephony/CommandsInterface.java
+++ b/src/java/com/android/internal/telephony/CommandsInterface.java
@@ -705,7 +705,7 @@
      *  retMsg.obj = AsyncResult ar
      *  ar.exception carries exception on failure
      *  ar.userObject contains the orignal value of result.obj
-     *  ar.result contains a List of DataCallState
+     *  ar.result contains a List of DataCallResponse
      *  @deprecated Do not use.
      */
     @Deprecated
@@ -716,7 +716,7 @@
      *  retMsg.obj = AsyncResult ar
      *  ar.exception carries exception on failure
      *  ar.userObject contains the orignal value of result.obj
-     *  ar.result contains a List of DataCallState
+     *  ar.result contains a List of DataCallResponse
      */
     void getDataCallList(Message result);
 
@@ -1471,8 +1471,8 @@
 
     /**
      * Setup a packet data connection On successful completion, the result
-     * message will return a {@link DataCallState} object containing the connection
-     * information.
+     * message will return a {@link com.android.internal.telephony.dataconnection.DataCallResponse}
+     * object containing the connection information.
      *
      * @param radioTechnology
      *            indicates whether to setup connection on radio technology CDMA
diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java
index 13c99ea..d67884d 100644
--- a/src/java/com/android/internal/telephony/Phone.java
+++ b/src/java/com/android/internal/telephony/Phone.java
@@ -101,6 +101,8 @@
     static final String REASON_NW_TYPE_CHANGED = "nwTypeChanged";
     static final String REASON_DATA_DEPENDENCY_MET = "dependencyMet";
     static final String REASON_DATA_DEPENDENCY_UNMET = "dependencyUnmet";
+    static final String REASON_LOST_DATA_CONNECTION = "lostDataConnection";
+    static final String REASON_CONNECTED = "connected";
 
     // Used for band mode selection methods
     static final int BM_UNSPECIFIED = 0; // selected by baseband automatically
diff --git a/src/java/com/android/internal/telephony/PhoneBase.java b/src/java/com/android/internal/telephony/PhoneBase.java
index 145cbea..04ec3ea 100644
--- a/src/java/com/android/internal/telephony/PhoneBase.java
+++ b/src/java/com/android/internal/telephony/PhoneBase.java
@@ -65,6 +65,8 @@
 
 public abstract class PhoneBase extends Handler implements Phone {
     private static final String LOG_TAG = "PhoneBase";
+    protected static final boolean DEBUGGABLE = SystemProperties.getInt("ro.debuggable", 0) == 1;
+
     // Key used to read and write the saved network selection numeric value
     public static final String NETWORK_SELECTION_KEY = "network_selection_key";
     // Key used to read and write the saved network selection operator name
@@ -136,11 +138,42 @@
             new AtomicReference<UiccCardApplication>();
     public SMSDispatcher mSMS;
 
+    private TelephonyTester mTelephonyTester;
+    private final String mName;
+    private final String mActionDetached;
+    private final String mActionAttached;
+
+    @Override
+    public String getPhoneName() {
+        return mName;
+    }
+
+    /**
+     * Return the ActionDetached string. When this action is received by components
+     * they are to simulate detaching from the network.
+     *
+     * @return com.android.internal.telephony.{mName}.action_detached
+     *          {mName} is GSM, CDMA ...
+     */
+    public String getActionDetached() {
+        return mActionDetached;
+    }
+
+    /**
+     * Return the ActionAttached string. When this action is received by components
+     * they are to simulate attaching to the network.
+     *
+     * @return com.android.internal.telephony.{mName}.action_detached
+     *          {mName} is GSM, CDMA ...
+     */
+    public String getActionAttached() {
+        return mActionAttached;
+    }
+
     /**
      * Set a system property, unless we're in unit test mode
      */
-    public void
-    setSystemProperty(String property, String value) {
+    public void setSystemProperty(String property, String value) {
         if(getUnitTestMode()) {
             return;
         }
@@ -198,8 +231,8 @@
      * unless unit testing.
      * @param ci the CommandsInterface
      */
-    protected PhoneBase(PhoneNotifier notifier, Context context, CommandsInterface ci) {
-        this(notifier, context, ci, false);
+    protected PhoneBase(String name, PhoneNotifier notifier, Context context, CommandsInterface ci) {
+        this(name, notifier, context, ci, false);
     }
 
     /**
@@ -212,12 +245,19 @@
      * @param unitTestMode when true, prevents notifications
      * of state change events
      */
-    protected PhoneBase(PhoneNotifier notifier, Context context, CommandsInterface ci,
+    protected PhoneBase(String name, PhoneNotifier notifier, Context context, CommandsInterface ci,
             boolean unitTestMode) {
+        mName = name;
         mNotifier = notifier;
         mContext = context;
         mLooper = Looper.myLooper();
         mCi = ci;
+        mActionDetached = this.getClass().getPackage().getName() + ".action_detached";
+        mActionAttached = this.getClass().getPackage().getName() + ".action_attached";
+
+        if (DEBUGGABLE) {
+            mTelephonyTester = new TelephonyTester(this);
+        }
 
         setPropertiesByCarrier();
 
@@ -272,6 +312,10 @@
             mSmsStorageMonitor.dispose();
             mSmsUsageMonitor.dispose();
             mUiccController.unregisterForIccChanged(this);
+
+            if (mTelephonyTester != null) {
+                mTelephonyTester.dispose();
+            }
         }
     }
 
@@ -920,9 +964,6 @@
     }
 
     @Override
-    public abstract String getPhoneName();
-
-    @Override
     public abstract int getPhoneType();
 
     /** @hide */
diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java
index d54d1ec..3885dbe 100644
--- a/src/java/com/android/internal/telephony/RIL.java
+++ b/src/java/com/android/internal/telephony/RIL.java
@@ -59,7 +59,8 @@
 import com.android.internal.telephony.cdma.CdmaCallWaitingNotification;
 import com.android.internal.telephony.cdma.CdmaInformationRecords;
 import com.android.internal.telephony.cdma.CdmaSmsBroadcastConfigInfo;
-import com.android.internal.telephony.dataconnection.DataConnectionBase;
+import com.android.internal.telephony.dataconnection.DcFailCause;
+import com.android.internal.telephony.dataconnection.DataCallResponse;
 
 import java.io.ByteArrayInputStream;
 import java.io.DataInputStream;
@@ -3230,8 +3231,8 @@
         return response;
     }
 
-    private DataCallState getDataCallState(Parcel p, int version) {
-        DataCallState dataCall = new DataCallState();
+    private DataCallResponse getDataCallResponse(Parcel p, int version) {
+        DataCallResponse dataCall = new DataCallResponse();
 
         dataCall.version = version;
         if (version < 5) {
@@ -3249,9 +3250,9 @@
             dataCall.active = p.readInt();
             dataCall.type = p.readString();
             dataCall.ifname = p.readString();
-            if ((dataCall.status == DataConnectionBase.FailCause.NONE.getErrorCode()) &&
+            if ((dataCall.status == DcFailCause.NONE.getErrorCode()) &&
                     TextUtils.isEmpty(dataCall.ifname)) {
-              throw new RuntimeException("getDataCallState, no ifname");
+              throw new RuntimeException("getDataCallResponse, no ifname");
             }
             String addresses = p.readString();
             if (!TextUtils.isEmpty(addresses)) {
@@ -3271,15 +3272,15 @@
 
     private Object
     responseDataCallList(Parcel p) {
-        ArrayList<DataCallState> response;
+        ArrayList<DataCallResponse> response;
 
         int ver = p.readInt();
         int num = p.readInt();
         riljLog("responseDataCallList ver=" + ver + " num=" + num);
 
-        response = new ArrayList<DataCallState>(num);
+        response = new ArrayList<DataCallResponse>(num);
         for (int i = 0; i < num; i++) {
-            response.add(getDataCallState(p, ver));
+            response.add(getDataCallResponse(p, ver));
         }
 
         return response;
@@ -3291,10 +3292,10 @@
         int num = p.readInt();
         if (RILJ_LOGV) riljLog("responseSetupDataCall ver=" + ver + " num=" + num);
 
-        DataCallState dataCall;
+        DataCallResponse dataCall;
 
         if (ver < 5) {
-            dataCall = new DataCallState();
+            dataCall = new DataCallResponse();
             dataCall.version = ver;
             dataCall.cid = Integer.parseInt(p.readString());
             dataCall.ifname = p.readString();
@@ -3326,7 +3327,7 @@
                         "RIL_REQUEST_SETUP_DATA_CALL response expecting 1 RIL_Data_Call_response_v5"
                         + " got " + num);
             }
-            dataCall = getDataCallState(p, ver);
+            dataCall = getDataCallResponse(p, ver);
         }
 
         return dataCall;
diff --git a/src/java/com/android/internal/telephony/RetryManager.java b/src/java/com/android/internal/telephony/RetryManager.java
index c0222e9..ad073b7 100644
--- a/src/java/com/android/internal/telephony/RetryManager.java
+++ b/src/java/com/android/internal/telephony/RetryManager.java
@@ -74,7 +74,7 @@
  */
 public class RetryManager {
     static public final String LOG_TAG = "RetryManager";
-    static public final boolean DBG = true;
+    static public final boolean DBG = false;
     static public final boolean VDBG = false;
 
     /**
@@ -102,6 +102,8 @@
      */
     private int mMaxRetryCount;
 
+    private int mCurMaxRetryCount;
+
     /** The current number of retries */
     private int mRetryCount;
 
@@ -117,11 +119,13 @@
 
     @Override
     public String toString() {
-        String ret = "RetryManager: forever=" + mRetryForever + ", maxRetry=" + mMaxRetryCount +
-                ", retry=" + mRetryCount + ",\n    " + mConfig;
+        String ret = "RetryManager: { forever=" + mRetryForever + " maxRetry=" + mMaxRetryCount
+                + " curMaxRetry=" + mCurMaxRetryCount + " retry=" + mRetryCount
+                + " config={" + mConfig + "} retryArray={";
         for (RetryRec r : mRetryArray) {
-            ret += "\n    " + r.mDelayTime + ":" + r.mRandomizationTime;
+            ret += r.mDelayTime + ":" + r.mRandomizationTime + " ";
         }
+        ret += "}}";
         return ret;
     }
 
@@ -155,6 +159,8 @@
         }
 
         mMaxRetryCount = maxRetryCount;
+        mCurMaxRetryCount = mMaxRetryCount;
+
         resetRetryCount();
         mRetryArray.clear();
         mRetryArray.add(new RetryRec(retryTime, randomizationTime));
@@ -242,6 +248,7 @@
                 mMaxRetryCount = mRetryArray.size();
                 if (VDBG) log("configure: setting mMaxRetryCount=" + mMaxRetryCount);
             }
+            mCurMaxRetryCount = mMaxRetryCount;
             if (VDBG) log("configure: true");
             return true;
         } else {
@@ -257,7 +264,7 @@
      *         false} otherwise.
      */
     public boolean isRetryNeeded() {
-        boolean retVal = mRetryForever || (mRetryCount < mMaxRetryCount);
+        boolean retVal = mRetryForever || (mRetryCount < mCurMaxRetryCount);
         if (DBG) log("isRetryNeeded: " + retVal);
         return retVal;
     }
@@ -297,8 +304,8 @@
      */
     public void increaseRetryCount() {
         mRetryCount++;
-        if (mRetryCount > mMaxRetryCount) {
-            mRetryCount = mMaxRetryCount;
+        if (mRetryCount > mCurMaxRetryCount) {
+            mRetryCount = mCurMaxRetryCount;
         }
         if (DBG) log("increaseRetryCount: " + mRetryCount);
     }
@@ -308,8 +315,8 @@
      */
     public void setRetryCount(int count) {
         mRetryCount = count;
-        if (mRetryCount > mMaxRetryCount) {
-            mRetryCount = mMaxRetryCount;
+        if (mRetryCount > mCurMaxRetryCount) {
+            mRetryCount = mCurMaxRetryCount;
         }
 
         if (mRetryCount < 0) {
@@ -320,6 +327,33 @@
     }
 
     /**
+     * Set current maximum retry count to the specified value
+     */
+    public void setCurMaxRetryCount(int count) {
+        mCurMaxRetryCount = count;
+
+        // Make sure it's not negative
+        if (mCurMaxRetryCount < 0) {
+            mCurMaxRetryCount = 0;
+        }
+
+        // Make sure mRetryCount is within range
+        setRetryCount(mRetryCount);
+
+        if (DBG) log("setCurMaxRetryCount: " + mCurMaxRetryCount);
+    }
+
+    /**
+     * Restore CurMaxRetryCount
+     */
+    public void restoreCurMaxRetryCount() {
+        mCurMaxRetryCount = mMaxRetryCount;
+
+        // Make sure mRetryCount is within range
+        setRetryCount(mRetryCount);
+    }
+
+    /**
      * Set retry forever to the specified value
      */
     public void setRetryForever(boolean retryForever) {
@@ -339,7 +373,7 @@
      * Retry forever using last timeout time.
      */
     public void retryForeverUsingLastTimeout() {
-        mRetryCount = mMaxRetryCount;
+        mRetryCount = mCurMaxRetryCount;
         mRetryForever = true;
         if (DBG) log("retryForeverUsingLastTimeout: " + mRetryForever + ", " + mRetryCount);
     }
diff --git a/src/java/com/android/internal/telephony/TelephonyTester.java b/src/java/com/android/internal/telephony/TelephonyTester.java
new file mode 100644
index 0000000..eafd248
--- /dev/null
+++ b/src/java/com/android/internal/telephony/TelephonyTester.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Handler;
+import android.os.SystemProperties;
+import android.telephony.Rlog;
+
+import com.android.internal.telephony.PhoneBase;
+
+/**
+ * Telephony tester receives the following intents where {name} is the phone name
+ *
+ * adb shell am broadcast -a com.android.internal.telephony.{name}.action_detached
+ * adb shell am broadcast -a com.android.internal.telephony.{name}.action_attached
+ */
+public class TelephonyTester {
+    private static final String LOG_TAG = "TelephonyTester";
+    private static final boolean DBG = true;
+    private static final boolean DEBUGGABLE = SystemProperties.getInt("ro.debuggable", 0) == 1;
+
+    private PhoneBase mPhone;
+
+    // The static intent receiver one for all instances and we assume this
+    // is running on the same thread as Dcc.
+    protected BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+            @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (DBG) log("sIntentReceiver.onReceive: action=" + action);
+            if (action.equals(mPhone.getActionDetached())) {
+                log("simulate detaching");
+                mPhone.getServiceStateTracker().mDetachedRegistrants.notifyRegistrants();
+            } else if (action.equals(mPhone.getActionAttached())) {
+                log("simulate attaching");
+                mPhone.getServiceStateTracker().mAttachedRegistrants.notifyRegistrants();
+            } else {
+                if (DBG) log("onReceive: unknown action=" + action);
+            }
+        }
+    };
+
+    TelephonyTester(PhoneBase phone) {
+        mPhone = phone;
+
+        if (DEBUGGABLE) {
+            IntentFilter filter = new IntentFilter();
+
+            filter.addAction(mPhone.getActionDetached());
+            log("register for intent action=" + mPhone.getActionDetached());
+
+            filter.addAction(mPhone.getActionAttached());
+            log("register for intent action=" + mPhone.getActionAttached());
+
+            phone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone.getHandler());
+        }
+    }
+
+    void dispose() {
+        mPhone.getContext().unregisterReceiver(mIntentReceiver);
+    }
+
+    private static void log(String s) {
+        Rlog.d(LOG_TAG, s);
+    }
+}
diff --git a/src/java/com/android/internal/telephony/cdma/CDMALTEPhone.java b/src/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
index 988f36a..3fefa9b 100644
--- a/src/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
+++ b/src/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
@@ -139,6 +139,7 @@
                     }
                     break;
 
+                case RETRYING:
                 case CONNECTING:
                 case SCANNING:
                     ret = PhoneConstants.DataState.CONNECTING;
diff --git a/src/java/com/android/internal/telephony/cdma/CDMAPhone.java b/src/java/com/android/internal/telephony/cdma/CDMAPhone.java
index b304e81..139bf2a 100755
--- a/src/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/src/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -138,14 +138,14 @@
 
     // Constructors
     public CDMAPhone(Context context, CommandsInterface ci, PhoneNotifier notifier) {
-        super(notifier, context, ci, false);
+        super("CDMA", notifier, context, ci, false);
         initSstIcc();
         init(context, notifier);
     }
 
     public CDMAPhone(Context context, CommandsInterface ci, PhoneNotifier notifier,
             boolean unitTestMode) {
-        super(notifier, context, ci, unitTestMode);
+        super("CDMA", notifier, context, ci, unitTestMode);
         initSstIcc();
         init(context, notifier);
     }
@@ -286,11 +286,6 @@
     }
 
     @Override
-    public String getPhoneName() {
-        return "CDMA";
-    }
-
-    @Override
     public int getPhoneType() {
         return PhoneConstants.PHONE_TYPE_CDMA;
     }
@@ -690,6 +685,7 @@
                     }
                 break;
 
+                case RETRYING:
                 case CONNECTING:
                 case SCANNING:
                     ret = PhoneConstants.DataState.CONNECTING;
diff --git a/src/java/com/android/internal/telephony/dataconnection/ApnContext.java b/src/java/com/android/internal/telephony/dataconnection/ApnContext.java
index a7c4af5..a4c322d 100644
--- a/src/java/com/android/internal/telephony/dataconnection/ApnContext.java
+++ b/src/java/com/android/internal/telephony/dataconnection/ApnContext.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.telephony.dataconnection;
 
+import android.app.PendingIntent;
 import android.telephony.Rlog;
 
 import com.android.internal.telephony.DctConstants;
@@ -34,7 +35,7 @@
 
     public final String LOG_TAG;
 
-    protected static final boolean DBG = true;
+    protected static final boolean DBG = false;
 
     private final String mApnType;
 
@@ -47,13 +48,11 @@
 
     private ApnSetting mApnSetting;
 
-    DataConnectionBase mDataConnection;
-
     DataConnectionAc mDataConnectionAc;
 
     String mReason;
 
-    int mRetryCount;
+    PendingIntent mReconnectAlarmIntent;
 
     /**
      * user/app requested connection on this APN
@@ -69,7 +68,6 @@
         mApnType = apnType;
         mState = DctConstants.State.IDLE;
         setReason(Phone.REASON_DATA_ENABLED);
-        setRetryCount(0);
         mDataEnabled = new AtomicBoolean(false);
         mDependencyMet = new AtomicBoolean(true);
         mWaitingApnsPermanentFailureCountDown = new AtomicInteger(0);
@@ -80,19 +78,7 @@
         return mApnType;
     }
 
-    public synchronized DataConnectionBase getDataConnection() {
-        return mDataConnection;
-    }
-
-    public synchronized void setDataConnection(DataConnectionBase dc) {
-        if (DBG) {
-            log("setDataConnection: old dc=" + mDataConnection + " new dc=" + dc + " this=" + this);
-        }
-        mDataConnection = dc;
-    }
-
-
-    public synchronized DataConnectionAc getDataConnectionAc() {
+    public synchronized DataConnectionAc getDcAc() {
         return mDataConnectionAc;
     }
 
@@ -101,20 +87,29 @@
             log("setDataConnectionAc: old dcac=" + mDataConnectionAc + " new dcac=" + dcac
                     + " this=" + this);
         }
-        if ((dcac == null) && (mDataConnectionAc != null) &&
-                (mDataConnectionAc.dataConnection != null)) {
+        if ((dcac == null) && (mDataConnectionAc != null)) {
             // TODO: This tearDown should be done by caller, but for now we'll do it
             if (DBG) log("setDataConnection: call tearDown");
-            mDataConnectionAc.dataConnection.tearDown(this, "", null);
+            mDataConnectionAc.tearDown(this, "", null);
         }
         mDataConnectionAc = dcac;
     }
 
+    public synchronized PendingIntent getReconnectIntent() {
+        return mReconnectAlarmIntent;
+    }
+
+    public synchronized void setReconnectIntent(PendingIntent intent) {
+        mReconnectAlarmIntent = intent;
+    }
+
     public synchronized ApnSetting getApnSetting() {
+        log("getApnSetting: apnSetting=" + mApnSetting);
         return mApnSetting;
     }
 
     public synchronized void setApnSetting(ApnSetting apnSetting) {
+        log("setApnSetting: apnSetting=" + apnSetting);
         mApnSetting = apnSetting;
     }
 
@@ -188,25 +183,17 @@
         return mReason;
     }
 
-    public synchronized void setRetryCount(int retryCount) {
-        if (DBG) {
-            log("setRetryCount: " + retryCount);
-        }
-        mRetryCount = retryCount;
-        DataConnectionBase dc = mDataConnection;
-        if (dc != null) {
-            dc.setRetryCount(retryCount);
-        }
-    }
-
-    public synchronized int getRetryCount() {
-        return mRetryCount;
-    }
-
     public boolean isReady() {
         return mDataEnabled.get() && mDependencyMet.get();
     }
 
+    public boolean isConnectable() {
+        return isReady() && ((mState == DctConstants.State.IDLE)
+                                || (mState == DctConstants.State.SCANNING)
+                                || (mState == DctConstants.State.RETRYING)
+                                || (mState == DctConstants.State.FAILED));
+    }
+
     public void setEnabled(boolean enabled) {
         if (DBG) {
             log("set enabled as " + enabled + ", current state is " + mDataEnabled.get());
@@ -232,12 +219,9 @@
     @Override
     public String toString() {
         // We don't print mDataConnection because its recursive.
-        return "{mApnType=" + mApnType + " mState=" + getState() + " mWaitingApns=" + mWaitingApns +
-                " mWaitingApnsPermanentFailureCountDown=" + mWaitingApnsPermanentFailureCountDown +
-                " mApnSetting=" + mApnSetting +
-                " mDataConnection=" + ((mDataConnection != null)
-                                            ? mDataConnection.toStringSimple() : "null") +
-                " mReason=" + mReason + " mRetryCount=" + mRetryCount +
+        return "{mApnType=" + mApnType + " mState=" + getState() + " mWaitingApns={" + mWaitingApns +
+                "} mWaitingApnsPermanentFailureCountDown=" + mWaitingApnsPermanentFailureCountDown +
+                " mApnSetting={" + mApnSetting + "} mReason=" + mReason +
                 " mDataEnabled=" + mDataEnabled + " mDependencyMet=" + mDependencyMet + "}";
     }
 
diff --git a/src/java/com/android/internal/telephony/DataCallState.java b/src/java/com/android/internal/telephony/dataconnection/DataCallResponse.java
similarity index 94%
rename from src/java/com/android/internal/telephony/DataCallState.java
rename to src/java/com/android/internal/telephony/dataconnection/DataCallResponse.java
index 12ebc1a..ca9624c 100644
--- a/src/java/com/android/internal/telephony/DataCallState.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataCallResponse.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.telephony;
+package com.android.internal.telephony.dataconnection;
 
 import android.net.LinkAddress;
 import android.net.LinkProperties;
@@ -24,7 +24,7 @@
 import android.os.SystemProperties;
 import android.telephony.Rlog;
 
-import com.android.internal.telephony.dataconnection.DataConnectionBase.FailCause;
+import com.android.internal.telephony.dataconnection.DcFailCause;
 
 import java.net.Inet4Address;
 import java.net.InetAddress;
@@ -32,11 +32,10 @@
 
 /**
  * This is RIL_Data_Call_Response_v5 from ril.h
- * TODO: Rename to DataCallResponse.
  */
-public class DataCallState {
+public class DataCallResponse {
     private final boolean DBG = true;
-    private final String LOG_TAG = "DataCallState";
+    private final String LOG_TAG = "DataCallResponse";
 
     public int version = 0;
     public int status = 0;
@@ -60,10 +59,10 @@
         ERR_Stale,
         ERR_RilError;
 
-        public FailCause mFailCause;
+        public DcFailCause mFailCause;
 
         SetupResult() {
-            mFailCause = FailCause.fromInt(0);
+            mFailCause = DcFailCause.fromInt(0);
         }
 
         @Override
@@ -75,7 +74,7 @@
     @Override
     public String toString() {
         StringBuffer sb = new StringBuffer();
-        sb.append("DataCallState: {")
+        sb.append("DataCallResponse: {")
            .append("version=").append(version)
            .append(" status=").append(status)
            .append(" retry=").append(suggestedRetryTime)
@@ -116,7 +115,7 @@
         else
             linkProperties.clear();
 
-        if (status == FailCause.NONE.getErrorCode()) {
+        if (status == DcFailCause.NONE.getErrorCode()) {
             String propertyPrefix = "net." + ifname + ".";
 
             try {
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
index 0858931..e70f418 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
@@ -16,30 +16,200 @@
 
 package com.android.internal.telephony.dataconnection;
 
-import android.os.Message;
-import android.telephony.Rlog;
-import android.util.Patterns;
-import android.text.TextUtils;
 
+import com.android.internal.telephony.CommandException;
+import com.android.internal.telephony.DctConstants;
+import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneBase;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.RILConstants;
 import com.android.internal.telephony.RetryManager;
+import com.android.internal.util.AsyncChannel;
+import com.android.internal.util.Protocol;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
+
+import android.app.PendingIntent;
+import android.net.LinkCapabilities;
+import android.net.LinkProperties;
+import android.net.ProxyProperties;
+import android.os.AsyncResult;
+import android.os.Message;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.text.TextUtils;
+import android.telephony.Rlog;
+import android.telephony.TelephonyManager;
+import android.util.Patterns;
+import android.util.TimeUtils;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * {@hide}
+ *
+ * DataConnection StateMachine.
+ *
+ * This a class for representing a single data connection, with instances of this
+ * class representing a connection via the cellular network. There may be multiple
+ * data connections and all of them are managed by the <code>DataConnectionTracker</code>.
+ *
+ * A recent change is to move retry handling into this class, with that change the
+ * old retry manager is now used internally rather than exposed to the DCT. Also,
+ * bringUp now has an initialRetry which is used limit the number of retries
+ * during the initial bring up of the connection. After the connection becomes active
+ * the current max retry is restored to the configured value.
+ *
+ * NOTE: All DataConnection objects must be running on the same looper, which is the default
+ * as the coordinator has members which are used without synchronization.
  */
-public class DataConnection extends DataConnectionBase {
+public final class DataConnection extends StateMachine {
+    private static final boolean DBG = true;
+    private static final boolean VDBG = true;
+    private static final boolean DEBUGGABLE = SystemProperties.getInt("ro.debuggable", 0) == 1;
 
-    //***** Instance Variables
-    protected int mProfileId = RILConstants.DATA_PROFILE_DEFAULT;
-    //***** Constructor
-    private DataConnection(PhoneBase phone, String name, int id, RetryManager rm,
-            DataConnectionTrackerBase dct) {
-        super(phone, name, id, rm, dct);
+    /** Retry configuration: A doubling of retry times from 5secs to 30minutes */
+    private static final String DEFAULT_DATA_RETRY_CONFIG = "default_randomization=2000,"
+        + "5000,10000,20000,40000,80000:5000,160000:5000,"
+        + "320000:5000,640000:5000,1280000:5000,1800000:5000";
+
+    /** Retry configuration for secondary networks: 4 tries in 20 sec */
+    private static final String SECONDARY_DATA_RETRY_CONFIG =
+            "max_retries=3, 5000, 5000, 5000";
+
+    // The data connection controller
+    private DcController mDcController;
+
+    // The Tester for failing all bringup's
+    private DcTesterFailBringUpAll mDcTesterFailBringUpAll;
+
+    private static AtomicInteger mInstanceNumber = new AtomicInteger(0);
+    private AsyncChannel mAc;
+
+    // Utilities for the DataConnection
+    private DcRetryAlarmController mDcRetryAlarmController;
+
+    // The DCT that's talking to us, we only support one!
+    private DataConnectionTrackerBase mDct = null;
+
+    /**
+     * Used internally for saving connecting parameters.
+     */
+    static class ConnectionParams {
+        int mTag;
+        ApnContext mApnContext;
+        int mInitialMaxRetry;
+        int mProfileId;
+        Message mOnCompletedMsg;
+
+        ConnectionParams(ApnContext apnContext, int initialMaxRetry, int profileId,
+                Message onCompletedMsg) {
+            mApnContext = apnContext;
+            mInitialMaxRetry = initialMaxRetry;
+            mProfileId = profileId;
+            mOnCompletedMsg = onCompletedMsg;
+        }
+
+        @Override
+        public String toString() {
+            return "{mTag=" + mTag + " mApnContext=" + mApnContext
+                    + " mInitialMaxRetry=" + mInitialMaxRetry + " mProfileId=" + mProfileId
+                    + " mOnCompletedMsg=" + msgToString(mOnCompletedMsg) + "}";
+        }
+    }
+
+    /**
+     * Used internally for saving disconnecting parameters.
+     */
+    static class DisconnectParams {
+        int mTag;
+        ApnContext mApnContext;
+        String mReason;
+        Message mOnCompletedMsg;
+
+        DisconnectParams(ApnContext apnContext, String reason, Message onCompletedMsg) {
+            mApnContext = apnContext;
+            mReason = reason;
+            mOnCompletedMsg = onCompletedMsg;
+        }
+
+        @Override
+        public String toString() {
+            return "{mTag=" + mTag + " mApnContext=" + mApnContext
+                    + " mReason=" + mReason
+                    + " mOnCompletedMsg=" + msgToString(mOnCompletedMsg) + "}";
+        }
+    }
+
+    private ApnSetting mApnSetting;
+    private ConnectionParams mConnectionParams;
+    private DisconnectParams mDisconnectParams;
+    private DcFailCause mDcFailCause;
+
+    private PhoneBase mPhone;
+    private LinkProperties mLinkProperties = new LinkProperties();
+    private LinkCapabilities mLinkCapabilities = new LinkCapabilities();
+    private long mCreateTime;
+    private long mLastFailTime;
+    private DcFailCause mLastFailCause;
+    private static final String NULL_IP = "0.0.0.0";
+    private Object mUserData;
+
+    //***** Package visible variables
+    int mTag;
+    int mCid;
+    List<ApnContext> mApnContexts = null;
+    PendingIntent mReconnectIntent = null;
+    RetryManager mRetryManager = new RetryManager();
+
+
+    // ***** Event codes for driving the state machine, package visible for Dcc
+    static final int BASE = Protocol.BASE_DATA_CONNECTION;
+    static final int EVENT_CONNECT = BASE + 0;
+    static final int EVENT_SETUP_DATA_CONNECTION_DONE = BASE + 1;
+    static final int EVENT_GET_LAST_FAIL_DONE = BASE + 2;
+    static final int EVENT_DEACTIVATE_DONE = BASE + 3;
+    static final int EVENT_DISCONNECT = BASE + 4;
+    static final int EVENT_RIL_CONNECTED = BASE + 5;
+    static final int EVENT_DISCONNECT_ALL = BASE + 6;
+    static final int EVENT_DATA_STATE_CHANGED = BASE + 7;
+    static final int EVENT_TEAR_DOWN_NOW = BASE + 8;
+    static final int EVENT_LOST_CONNECTION = BASE + 9;
+    static final int EVENT_RETRY_CONNECTION = BASE + 10;
+
+    private static final int CMD_TO_STRING_COUNT = EVENT_RETRY_CONNECTION - BASE + 1;
+    private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT];
+    static {
+        sCmdToString[EVENT_CONNECT - BASE] = "EVENT_CONNECT";
+        sCmdToString[EVENT_SETUP_DATA_CONNECTION_DONE - BASE] =
+                "EVENT_SETUP_DATA_CONNECTION_DONE";
+        sCmdToString[EVENT_GET_LAST_FAIL_DONE - BASE] = "EVENT_GET_LAST_FAIL_DONE";
+        sCmdToString[EVENT_DEACTIVATE_DONE - BASE] = "EVENT_DEACTIVATE_DONE";
+        sCmdToString[EVENT_DISCONNECT - BASE] = "EVENT_DISCONNECT";
+        sCmdToString[EVENT_RIL_CONNECTED - BASE] = "EVENT_RIL_CONNECTED";
+        sCmdToString[EVENT_DISCONNECT_ALL - BASE] = "EVENT_DISCONNECT_ALL";
+        sCmdToString[EVENT_DATA_STATE_CHANGED - BASE] = "EVENT_DATA_STATE_CHANGED";
+        sCmdToString[EVENT_TEAR_DOWN_NOW - BASE] = "EVENT_TEAR_DOWN_NOW";
+        sCmdToString[EVENT_LOST_CONNECTION - BASE] = "EVENT_LOST_CONNECTION";
+        sCmdToString[EVENT_RETRY_CONNECTION - BASE] = "EVENT_RETRY_CONNECTION";
+    }
+    // Convert cmd to string or null if unknown
+    static String cmdToString(int cmd) {
+        String value;
+        cmd -= BASE;
+        if ((cmd >= 0) && (cmd < sCmdToString.length)) {
+            value = sCmdToString[cmd];
+        } else {
+            value = DataConnectionAc.cmdToString(cmd + BASE);
+        }
+        if (value == null) {
+            value = "0x" + Integer.toHexString(cmd + BASE);
+        }
+        return value;
     }
 
     /**
@@ -47,16 +217,166 @@
      *
      * @param phone the Phone
      * @param id the connection id
-     * @param rm the RetryManager
      * @return DataConnection that was created.
      */
-    static DataConnection makeDataConnection(PhoneBase phone, int id, RetryManager rm,
-            DataConnectionTrackerBase dct) {
-        DataConnection gsmDc = new DataConnection(phone,
-                "DC-" + mCount.incrementAndGet(), id, rm, dct);
-        gsmDc.start();
-        if (DBG) gsmDc.log("Made " + gsmDc.getName());
-        return gsmDc;
+    static DataConnection makeDataConnection(PhoneBase phone, int id,
+            DataConnectionTrackerBase dct, DcTesterFailBringUpAll failBringUpAll,
+            DcController dcc) {
+        DataConnection dc = new DataConnection(phone,
+                "DC-" + mInstanceNumber.incrementAndGet(), id, dct, failBringUpAll, dcc);
+        dc.start();
+        if (DBG) dc.log("Made " + dc.getName());
+        return dc;
+    }
+
+    void dispose() {
+        log("dispose: call quiteNow()");
+        quitNow();
+    }
+
+    /* Getter functions */
+
+    LinkCapabilities getCopyLinkCapabilities() {
+        return new LinkCapabilities(mLinkCapabilities);
+    }
+
+    LinkProperties getCopyLinkProperties() {
+        return new LinkProperties(mLinkProperties);
+    }
+
+    boolean getIsInactive() {
+        return getCurrentState() == mInactiveState;
+    }
+
+    int getCid() {
+        return mCid;
+    }
+
+    ApnSetting getApnSetting() {
+        return mApnSetting;
+    }
+
+    void setLinkPropertiesHttpProxy(ProxyProperties proxy) {
+        mLinkProperties.setHttpProxy(proxy);
+    }
+
+    static class UpdateLinkPropertyResult {
+        public DataCallResponse.SetupResult setupResult = DataCallResponse.SetupResult.SUCCESS;
+        public LinkProperties oldLp;
+        public LinkProperties newLp;
+        public UpdateLinkPropertyResult(LinkProperties curLp) {
+            oldLp = curLp;
+            newLp = curLp;
+        }
+    }
+
+    UpdateLinkPropertyResult updateLinkProperty(DataCallResponse newState) {
+        UpdateLinkPropertyResult result = new UpdateLinkPropertyResult(mLinkProperties);
+
+        if (newState == null) return result;
+
+        DataCallResponse.SetupResult setupResult;
+        result.newLp = new LinkProperties();
+
+        // set link properties based on data call response
+        result.setupResult = setLinkProperties(newState, result.newLp);
+        if (result.setupResult != DataCallResponse.SetupResult.SUCCESS) {
+            if (DBG) log("updateLinkProperty failed : " + result.setupResult);
+            return result;
+        }
+        // copy HTTP proxy as it is not part DataCallResponse.
+        result.newLp.setHttpProxy(mLinkProperties.getHttpProxy());
+
+        if (DBG && (! result.oldLp.equals(result.newLp))) {
+            log("updateLinkProperty old LP=" + result.oldLp);
+            log("updateLinkProperty new LP=" + result.newLp);
+        }
+        mLinkProperties = result.newLp;
+
+        return result;
+    }
+
+    //***** Constructor (NOTE: uses dcc.getHandler() as its Handler)
+    private DataConnection(PhoneBase phone, String name, int id,
+                DataConnectionTrackerBase dct, DcTesterFailBringUpAll failBringUpAll,
+                DcController dcc) {
+        super(name, dcc.getHandler());
+        setLogRecSize(300);
+        setLogOnlyTransitions(true);
+        if (DBG) log("DataConnection constructor E");
+
+        mPhone = phone;
+        mDct = dct;
+        mDcTesterFailBringUpAll = failBringUpAll;
+        mDcController = dcc;
+        mId = id;
+        mCid = -1;
+        mDcRetryAlarmController = new DcRetryAlarmController(mPhone, this);
+
+        addState(mDefaultState);
+            addState(mInactiveState, mDefaultState);
+            addState(mActivatingState, mDefaultState);
+            addState(mRetryingState, mDefaultState);
+            addState(mActiveState, mDefaultState);
+            addState(mDisconnectingState, mDefaultState);
+            addState(mDisconnectingErrorCreatingConnection, mDefaultState);
+        setInitialState(mInactiveState);
+
+        mApnContexts = new ArrayList<ApnContext>();
+        if (DBG) log("DataConnection constructor X");
+    }
+
+    private String getRetryConfig(boolean forDefault) {
+        int nt = mPhone.getServiceState().getNetworkType();
+
+        if (DEBUGGABLE) {
+            String config = SystemProperties.get("test.data_retry_config");
+            if (! TextUtils.isEmpty(config)) {
+                return config;
+            }
+        }
+
+        if ((nt == TelephonyManager.NETWORK_TYPE_CDMA) ||
+            (nt == TelephonyManager.NETWORK_TYPE_1xRTT) ||
+            (nt == TelephonyManager.NETWORK_TYPE_EVDO_0) ||
+            (nt == TelephonyManager.NETWORK_TYPE_EVDO_A) ||
+            (nt == TelephonyManager.NETWORK_TYPE_EVDO_B) ||
+            (nt == TelephonyManager.NETWORK_TYPE_EHRPD)) {
+            // CDMA variant
+            return SystemProperties.get("ro.cdma.data_retry_config");
+        } else {
+            // Use GSM variant for all others.
+            if (forDefault) {
+                return SystemProperties.get("ro.gsm.data_retry_config");
+            } else {
+                return SystemProperties.get("ro.gsm.2nd_data_retry_config");
+            }
+        }
+    }
+
+    private void configureRetry(boolean forDefault) {
+        String retryConfig = getRetryConfig(forDefault);
+
+        if (!mRetryManager.configure(retryConfig)) {
+            if (forDefault) {
+                if (!mRetryManager.configure(DEFAULT_DATA_RETRY_CONFIG)) {
+                    // Should never happen, log an error and default to a simple linear sequence.
+                    loge("configureRetry: Could not configure using " +
+                            "DEFAULT_DATA_RETRY_CONFIG=" + DEFAULT_DATA_RETRY_CONFIG);
+                    mRetryManager.configure(5, 2000, 1000);
+                }
+            } else {
+                if (!mRetryManager.configure(SECONDARY_DATA_RETRY_CONFIG)) {
+                    // Should never happen, log an error and default to a simple sequence.
+                    loge("configureRetry: Could note configure using " +
+                            "SECONDARY_DATA_RETRY_CONFIG=" + SECONDARY_DATA_RETRY_CONFIG);
+                    mRetryManager.configure(5, 2000, 1000);
+                }
+            }
+        }
+        if (DBG) {
+            log("configureRetry: forDefault=" + forDefault + " mRetryManager=" + mRetryManager);
+        }
     }
 
     /**
@@ -66,68 +386,296 @@
      *
      * @param cp is the connection parameters
      */
-    @Override
-    protected
-    void onConnect(ConnectionParams cp) {
-        mApn = cp.mApnContext.getApnSetting();
+    private void onConnect(ConnectionParams cp) {
+        if (DBG) log("onConnect: carrier='" + mApnSetting.carrier
+                + "' APN='" + mApnSetting.apn
+                + "' proxy='" + mApnSetting.proxy + "' port='" + mApnSetting.port + "'");
 
-        if (DBG) log("onConnect: carrier='" + mApn.carrier
-                + "' APN='" + mApn.apn
-                + "' proxy='" + mApn.proxy + "' port='" + mApn.port + "'");
+        // Check if we should fake an error.
+        if (mDcTesterFailBringUpAll.getDcFailBringUp().mCounter  > 0) {
+            DataCallResponse response = new DataCallResponse();
+            response.version = mPhone.mCi.getRilVersion();
+            response.status = mDcTesterFailBringUpAll.getDcFailBringUp().mFailCause.getErrorCode();
+            response.cid = 0;
+            response.active = 0;
+            response.type = "";
+            response.ifname = "";
+            response.addresses = new String[0];
+            response.dnses = new String[0];
+            response.gateways = new String[0];
+            response.suggestedRetryTime =
+                    mDcTesterFailBringUpAll.getDcFailBringUp().mSuggestedRetryTime;
+
+            Message msg = obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE, cp);
+            AsyncResult.forMessage(msg, response, null);
+            sendMessage(msg);
+            if (DBG) {
+                log("onConnect: FailBringUpAll=" + mDcTesterFailBringUpAll.getDcFailBringUp()
+                        + " send error response=" + response);
+            }
+            mDcTesterFailBringUpAll.getDcFailBringUp().mCounter -= 1;
+            return;
+        }
 
         mCreateTime = -1;
         mLastFailTime = -1;
-        mLastFailCause = FailCause.NONE;
+        mLastFailCause = DcFailCause.NONE;
 
         // msg.obj will be returned in AsyncResult.userObj;
         Message msg = obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE, cp);
         msg.obj = cp;
 
-        int authType = mApn.authType;
+        int authType = mApnSetting.authType;
         if (authType == -1) {
-            authType = TextUtils.isEmpty(mApn.user) ? RILConstants.SETUP_DATA_AUTH_NONE
+            authType = TextUtils.isEmpty(mApnSetting.user) ? RILConstants.SETUP_DATA_AUTH_NONE
                     : RILConstants.SETUP_DATA_AUTH_PAP_CHAP;
         }
 
         String protocol;
         if (mPhone.getServiceState().getRoaming()) {
-            protocol = mApn.roamingProtocol;
+            protocol = mApnSetting.roamingProtocol;
         } else {
-            protocol = mApn.protocol;
+            protocol = mApnSetting.protocol;
         }
 
         mPhone.mCi.setupDataCall(
                 Integer.toString(getRilRadioTechnology()),
-                Integer.toString(mProfileId),
-                mApn.apn, mApn.user, mApn.password,
+                Integer.toString(cp.mProfileId),
+                mApnSetting.apn, mApnSetting.user, mApnSetting.password,
                 Integer.toString(authType),
                 protocol, msg);
     }
 
-    public void setProfileId(int profileId) {
-        mProfileId = profileId;
+    /**
+     * TearDown the data connection when the deactivation is complete a Message with
+     * msg.what == EVENT_DEACTIVATE_DONE and msg.obj == AsyncResult with AsyncResult.obj
+     * containing the parameter o.
+     *
+     * @param o is the object returned in the AsyncResult.obj.
+     */
+    private void tearDownData(Object o) {
+        int discReason = RILConstants.DEACTIVATE_REASON_NONE;
+        if ((o != null) && (o instanceof DisconnectParams)) {
+            DisconnectParams dp = (DisconnectParams)o;
+
+            if (TextUtils.equals(dp.mReason, Phone.REASON_RADIO_TURNED_OFF)) {
+                discReason = RILConstants.DEACTIVATE_REASON_RADIO_OFF;
+            } else if (TextUtils.equals(dp.mReason, Phone.REASON_PDP_RESET)) {
+                discReason = RILConstants.DEACTIVATE_REASON_PDP_RESET;
+            }
+        }
+        if (mPhone.mCi.getRadioState().isOn()) {
+            if (DBG) log("tearDownData radio is on, call deactivateDataCall");
+            mPhone.mCi.deactivateDataCall(mCid, discReason,
+                    obtainMessage(EVENT_DEACTIVATE_DONE, mTag, 0, o));
+        } else {
+            if (DBG) log("tearDownData radio is off sendMessage EVENT_DEACTIVATE_DONE immediately");
+            AsyncResult ar = new AsyncResult(o, null, null);
+            sendMessage(obtainMessage(EVENT_DEACTIVATE_DONE, mTag, 0, ar));
+        }
     }
 
-    public int getProfileId() {
-        return mProfileId;
+    private void notifyAllWithEvent(ApnContext alreadySent, int event, String reason) {
+        for (ApnContext apnContext : mApnContexts) {
+            if (apnContext == alreadySent) continue;
+            if (reason != null) apnContext.setReason(reason);
+            Message msg = mDct.obtainMessage(event, apnContext);
+            AsyncResult.forMessage(msg);
+            msg.sendToTarget();
+        }
     }
 
-    /** Doesn't print mApnList of ApnContext's which would be recursive */
-    @Override
-    public String toStringSimple() {
-        return getName() + ": State=" + getCurrentState().getName() +
-                " apnSetting=" + mApn + " RefCount=" + mApnList.size() +
-                " cid=" + mCid + " create=" + mCreateTime + " lastFail=" + mLastFailTime +
-                " lastFailCause=" + mLastFailCause;
+    private void notifyAllOfConnected(String reason) {
+        notifyAllWithEvent(null, DctConstants.EVENT_DATA_SETUP_COMPLETE, reason);
     }
 
-    @Override
-    public String toString() {
-        return "{" + toStringSimple() + " mApnList=" + mApnList + "}";
+    private void notifyAllOfDisconnectDcRetrying(String reason) {
+        notifyAllWithEvent(null, DctConstants.EVENT_DISCONNECT_DC_RETRYING, reason);
+    }
+    private void notifyAllDisconnectCompleted(DcFailCause cause) {
+        notifyAllWithEvent(null, DctConstants.EVENT_DISCONNECT_DONE, cause.toString());
     }
 
-    @Override
-    protected boolean isDnsOk(String[] domainNameServers) {
+
+    /**
+     * Send the connectionCompletedMsg.
+     *
+     * @param cp is the ConnectionParams
+     * @param cause and if no error the cause is DcFailCause.NONE
+     * @param sendAll is true if all contexts are to be notified
+     */
+    private void notifyConnectCompleted(ConnectionParams cp, DcFailCause cause, boolean sendAll) {
+        ApnContext alreadySent = null;
+
+        if (cp != null && cp.mOnCompletedMsg != null) {
+            // Get the completed message but only use it once
+            Message connectionCompletedMsg = cp.mOnCompletedMsg;
+            cp.mOnCompletedMsg = null;
+            if (connectionCompletedMsg.obj instanceof ApnContext) {
+                alreadySent = (ApnContext)connectionCompletedMsg.obj;
+            }
+
+            long timeStamp = System.currentTimeMillis();
+            connectionCompletedMsg.arg1 = mCid;
+
+            if (cause == DcFailCause.NONE) {
+                mCreateTime = timeStamp;
+                AsyncResult.forMessage(connectionCompletedMsg);
+            } else {
+                mLastFailCause = cause;
+                mLastFailTime = timeStamp;
+
+                // Return message with a Throwable exception to signify an error.
+                if (cause == null) cause = DcFailCause.UNKNOWN;
+                AsyncResult.forMessage(connectionCompletedMsg, cause,
+                        new Throwable(cause.toString()));
+            }
+            if (DBG) {
+                log("notifyConnectCompleted at " + timeStamp + " cause=" + cause
+                        + " connectionCompletedMsg=" + msgToString(connectionCompletedMsg));
+            }
+
+            connectionCompletedMsg.sendToTarget();
+        }
+        if (sendAll) {
+            notifyAllWithEvent(alreadySent, DctConstants.EVENT_DATA_SETUP_COMPLETE_ERROR,
+                    cause.toString());
+        }
+    }
+
+    /**
+     * Send ar.userObj if its a message, which is should be back to originator.
+     *
+     * @param dp is the DisconnectParams.
+     */
+    private void notifyDisconnectCompleted(DisconnectParams dp, boolean sendAll) {
+        if (VDBG) log("NotifyDisconnectCompleted");
+
+        ApnContext alreadySent = null;
+        String reason = null;
+
+        if (dp != null && dp.mOnCompletedMsg != null) {
+            // Get the completed message but only use it once
+            Message msg = dp.mOnCompletedMsg;
+            dp.mOnCompletedMsg = null;
+            if (msg.obj instanceof ApnContext) {
+                alreadySent = (ApnContext)msg.obj;
+            }
+            reason = dp.mReason;
+            if (VDBG) {
+                log(String.format("msg=%s msg.obj=%s", msg.toString(),
+                    ((msg.obj instanceof String) ? (String) msg.obj : "<no-reason>")));
+            }
+            AsyncResult.forMessage(msg);
+            msg.sendToTarget();
+        }
+        if (sendAll) {
+            if (reason == null) {
+                reason = DcFailCause.UNKNOWN.toString();
+            }
+            notifyAllWithEvent(alreadySent, DctConstants.EVENT_DISCONNECT_DONE, reason);
+        }
+        if (DBG) log("NotifyDisconnectCompleted DisconnectParams=" + dp);
+    }
+
+    private int getRilRadioTechnology() {
+        int rilRadioTechnology;
+        if (mApnSetting.bearer > 0) {
+            rilRadioTechnology = mApnSetting.bearer + 2;
+        } else {
+            rilRadioTechnology = mPhone.getServiceState().getRilDataRadioTechnology() + 2;
+        }
+        return rilRadioTechnology;
+    }
+
+    /*
+     * **************************************************************************
+     * Begin Members and methods owned by DataConnectionTracker but stored
+     * in a DataConnection because there is one per connection.
+     * **************************************************************************
+     */
+
+    /*
+     * The id is owned by DataConnectionTracker.
+     */
+    private int mId;
+
+    /**
+     * Get the DataConnection ID
+     */
+    public int getDataConnectionId() {
+        return mId;
+    }
+
+    /*
+     * **************************************************************************
+     * End members owned by DataConnectionTracker
+     * **************************************************************************
+     */
+
+    /**
+     * Clear all settings called when entering mInactiveState.
+     */
+    private void clearSettings() {
+        if (DBG) log("clearSettings");
+
+        mCreateTime = -1;
+        mLastFailTime = -1;
+        mLastFailCause = DcFailCause.NONE;
+        mCid = -1;
+
+        mLinkProperties = new LinkProperties();
+        mApnContexts.clear();
+        mApnSetting = null;
+        mDcFailCause = null;
+    }
+
+    /**
+     * Process setup completion.
+     *
+     * @param ar is the result
+     * @return SetupResult.
+     */
+    private DataCallResponse.SetupResult onSetupConnectionCompleted(AsyncResult ar) {
+        DataCallResponse response = (DataCallResponse) ar.result;
+        ConnectionParams cp = (ConnectionParams) ar.userObj;
+        DataCallResponse.SetupResult result;
+
+        if (cp.mTag != mTag) {
+            if (DBG) {
+                log("onSetupConnectionCompleted stale cp.tag=" + cp.mTag + ", mtag=" + mTag);
+            }
+            result = DataCallResponse.SetupResult.ERR_Stale;
+        } else if (ar.exception != null) {
+            if (DBG) {
+                log("onSetupConnectionCompleted failed, ar.exception=" + ar.exception +
+                    " response=" + response);
+            }
+
+            if (ar.exception instanceof CommandException
+                    && ((CommandException) (ar.exception)).getCommandError()
+                    == CommandException.Error.RADIO_NOT_AVAILABLE) {
+                result = DataCallResponse.SetupResult.ERR_BadCommand;
+                result.mFailCause = DcFailCause.RADIO_NOT_AVAILABLE;
+            } else if ((response == null) || (response.version < 4)) {
+                result = DataCallResponse.SetupResult.ERR_GetLastErrorFromRil;
+            } else {
+                result = DataCallResponse.SetupResult.ERR_RilError;
+                result.mFailCause = DcFailCause.fromInt(response.status);
+            }
+        } else if (response.status != 0) {
+            result = DataCallResponse.SetupResult.ERR_RilError;
+            result.mFailCause = DcFailCause.fromInt(response.status);
+        } else {
+            if (DBG) log("onSetupConnectionCompleted received DataCallResponse: " + response);
+            mCid = response.cid;
+            result = updateLinkProperty(response).setupResult;
+        }
+
+        return result;
+    }
+
+    private boolean isDnsOk(String[] domainNameServers) {
         if (NULL_IP.equals(domainNameServers[0]) && NULL_IP.equals(domainNameServers[1])
                 && !mPhone.isDnsCheckDisabled()) {
             // Work around a race condition where QMI does not fill in DNS:
@@ -135,33 +683,966 @@
             // Do not apply the race condition workaround for MMS APN
             // if Proxy is an IP-address.
             // Otherwise, the default APN will not be restored anymore.
-            if (!mApn.types[0].equals(PhoneConstants.APN_TYPE_MMS)
-                || !isIpAddress(mApn.mmsProxy)) {
+            if (!mApnSetting.types[0].equals(PhoneConstants.APN_TYPE_MMS)
+                || !isIpAddress(mApnSetting.mmsProxy)) {
                 log(String.format(
                         "isDnsOk: return false apn.types[0]=%s APN_TYPE_MMS=%s isIpAddress(%s)=%s",
-                        mApn.types[0], PhoneConstants.APN_TYPE_MMS, mApn.mmsProxy,
-                        isIpAddress(mApn.mmsProxy)));
+                        mApnSetting.types[0], PhoneConstants.APN_TYPE_MMS, mApnSetting.mmsProxy,
+                        isIpAddress(mApnSetting.mmsProxy)));
                 return false;
             }
         }
         return true;
     }
 
-    @Override
-    protected void log(String s) {
-        Rlog.d(getName(), s);
-    }
-
     private boolean isIpAddress(String address) {
         if (address == null) return false;
 
         return Patterns.IP_ADDRESS.matcher(address).matches();
     }
 
+    private DataCallResponse.SetupResult setLinkProperties(DataCallResponse response,
+            LinkProperties lp) {
+        // Check if system property dns usable
+        boolean okToUseSystemPropertyDns = false;
+        String propertyPrefix = "net." + response.ifname + ".";
+        String dnsServers[] = new String[2];
+        dnsServers[0] = SystemProperties.get(propertyPrefix + "dns1");
+        dnsServers[1] = SystemProperties.get(propertyPrefix + "dns2");
+        okToUseSystemPropertyDns = isDnsOk(dnsServers);
+
+        // set link properties based on data call response
+        return response.setLinkProperties(lp, okToUseSystemPropertyDns);
+    }
+
+    /**
+     * The parent state for all other states.
+     */
+    private class DcDefaultState extends State {
+        @Override
+        public void enter() {
+            if (DBG) log("DcDefaultState: enter");
+
+            // Add ourselves to the list of data connections
+            mDcController.addDc(DataConnection.this);
+        }
+        @Override
+        public void exit() {
+            if (DBG) log("DcDefaultState: exit");
+
+
+            if (mAc != null) {
+                mAc.disconnected();
+                mAc = null;
+            }
+            mDcRetryAlarmController.dispose();
+            mDcRetryAlarmController = null;
+            mApnContexts = null;
+            mReconnectIntent = null;
+            mDct = null;
+            mApnSetting = null;
+            mPhone = null;
+            mLinkProperties = null;
+            mLinkCapabilities = null;
+            mLastFailCause = null;
+            mUserData = null;
+
+            // Remove ourselves from the DC lists
+            mDcController.removeDc(DataConnection.this);
+
+            mDcController = null;
+            mDcTesterFailBringUpAll = null;
+        }
+
+        @Override
+        public boolean processMessage(Message msg) {
+            boolean retVal = HANDLED;
+            AsyncResult ar;
+
+            if (VDBG) {
+                log("DcDefault msg=" + getWhatToString(msg.what)
+                        + " RefCount=" + mApnContexts.size());
+            }
+            switch (msg.what) {
+                case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
+                    if (mAc != null) {
+                        if (VDBG) log("Disconnecting to previous connection mAc=" + mAc);
+                        mAc.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
+                                AsyncChannel.STATUS_FULL_CONNECTION_REFUSED_ALREADY_CONNECTED);
+                    } else {
+                        mAc = new AsyncChannel();
+                        mAc.connected(null, getHandler(), msg.replyTo);
+                        if (VDBG) log("DcDefaultState: FULL_CONNECTION reply connected");
+                        mAc.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
+                                AsyncChannel.STATUS_SUCCESSFUL, mId, "hi");
+                    }
+                    break;
+                }
+                case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
+                    if (VDBG) log("CMD_CHANNEL_DISCONNECTED");
+                    quit();
+                    break;
+                }
+                case DataConnectionAc.REQ_IS_INACTIVE: {
+                    boolean val = getIsInactive();
+                    if (VDBG) log("REQ_IS_INACTIVE  isInactive=" + val);
+                    mAc.replyToMessage(msg, DataConnectionAc.RSP_IS_INACTIVE, val ? 1 : 0);
+                    break;
+                }
+                case DataConnectionAc.REQ_GET_CID: {
+                    int cid = getCid();
+                    if (VDBG) log("REQ_GET_CID  cid=" + cid);
+                    mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_CID, cid);
+                    break;
+                }
+                case DataConnectionAc.REQ_GET_APNSETTING: {
+                    ApnSetting apnSetting = getApnSetting();
+                    if (VDBG) log("REQ_GET_APNSETTING  mApnSetting=" + apnSetting);
+                    mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_APNSETTING, apnSetting);
+                    break;
+                }
+                case DataConnectionAc.REQ_GET_LINK_PROPERTIES: {
+                    LinkProperties lp = getCopyLinkProperties();
+                    if (VDBG) log("REQ_GET_LINK_PROPERTIES linkProperties" + lp);
+                    mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_LINK_PROPERTIES, lp);
+                    break;
+                }
+                case DataConnectionAc.REQ_SET_LINK_PROPERTIES_HTTP_PROXY: {
+                    ProxyProperties proxy = (ProxyProperties) msg.obj;
+                    if (VDBG) log("REQ_SET_LINK_PROPERTIES_HTTP_PROXY proxy=" + proxy);
+                    setLinkPropertiesHttpProxy(proxy);
+                    mAc.replyToMessage(msg, DataConnectionAc.RSP_SET_LINK_PROPERTIES_HTTP_PROXY);
+                    break;
+                }
+                case DataConnectionAc.REQ_GET_LINK_CAPABILITIES: {
+                    LinkCapabilities lc = getCopyLinkCapabilities();
+                    if (VDBG) log("REQ_GET_LINK_CAPABILITIES linkCapabilities" + lc);
+                    mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_LINK_CAPABILITIES, lc);
+                    break;
+                }
+                case DataConnectionAc.REQ_RESET:
+                    if (VDBG) log("DcDefaultState: msg.what=REQ_RESET");
+                    transitionTo(mInactiveState);
+                    break;
+                case EVENT_CONNECT:
+                    if (DBG) log("DcDefaultState: msg.what=EVENT_CONNECT, fail not expected");
+                    ConnectionParams cp = (ConnectionParams) msg.obj;
+                    notifyConnectCompleted(cp, DcFailCause.UNKNOWN, false);
+                    break;
+
+                case EVENT_DISCONNECT:
+                    if (DBG) {
+                        log("DcDefaultState deferring msg.what=EVENT_DISCONNECT RefCount="
+                                + mApnContexts.size());
+                    }
+                    deferMessage(msg);
+                    break;
+
+                case EVENT_DISCONNECT_ALL:
+                    if (DBG) {
+                        log("DcDefaultState deferring msg.what=EVENT_DISCONNECT_ALL RefCount="
+                                + mApnContexts.size());
+                    }
+                    deferMessage(msg);
+                    break;
+
+                case EVENT_TEAR_DOWN_NOW:
+                    if (DBG) log("DcDefaultState EVENT_TEAR_DOWN_NOW");
+                    mPhone.mCi.deactivateDataCall(mCid, 0,  null);
+                    break;
+
+                case EVENT_LOST_CONNECTION:
+                    if (DBG) {
+                        String s = "DcDefaultState ignore EVENT_LOST_CONNECTION"
+                            + " tag=" + msg.arg1 + ":mTag=" + mTag;
+                        logAndAddLogRec(s);
+                    }
+                    break;
+
+                case EVENT_RETRY_CONNECTION:
+                    if (DBG) {
+                        String s = "DcDefaultState ignore EVENT_RETRY_CONNECTION"
+                                + " tag=" + msg.arg1 + ":mTag=" + mTag;
+                        logAndAddLogRec(s);
+                    }
+                    break;
+
+                default:
+                    if (DBG) {
+                        log("DcDefaultState: shouldn't happen but ignore msg.what="
+                                + getWhatToString(msg.what));
+                    }
+                    break;
+            }
+
+            return retVal;
+        }
+    }
+    private DcDefaultState mDefaultState = new DcDefaultState();
+
+    /**
+     * The state machine is inactive and expects a EVENT_CONNECT.
+     */
+    private class DcInactiveState extends State {
+        // Inform all contexts we've failed connecting
+        public void setEnterNotificationParams(ConnectionParams cp, DcFailCause cause) {
+            if (VDBG) log("DcInactiveState: setEnterNoticationParams cp,cause");
+            mConnectionParams = cp;
+            mDisconnectParams = null;
+            mDcFailCause = cause;
+        }
+
+        // Inform all contexts we've failed disconnected
+        public void setEnterNotificationParams(DisconnectParams dp) {
+            if (VDBG) log("DcInactiveState: setEnterNoticationParams dp");
+            mConnectionParams = null;
+            mDisconnectParams = dp;
+            mDcFailCause = DcFailCause.NONE;
+        }
+
+        // Inform all contexts of the failure cause
+        public void setEnterNotificationParams(DcFailCause cause) {
+            mConnectionParams = null;
+            mDisconnectParams = null;
+            mDcFailCause = cause;
+        }
+
+        // We won't be informing anyone
+        public void setEnterNotificationParams() {
+            mConnectionParams = null;
+            mDisconnectParams = null;
+            mDcFailCause = null;
+        }
+
+        @Override
+        public void enter() {
+            mTag += 1;
+            if (DBG) log("DcInactiveState: enter() mTag=" + mTag);
+
+            if (mConnectionParams != null) {
+                if (DBG) {
+                    log("DcInactiveState: enter notifyConnectCompleted +ALL failCause="
+                            + mDcFailCause);
+                }
+                notifyConnectCompleted(mConnectionParams, mDcFailCause, true);
+            }
+            if (mDisconnectParams != null) {
+                if (DBG) {
+                    log("DcInactiveState: enter notifyDisconnectCompleted +ALL failCause="
+                            + mDcFailCause);
+                }
+                notifyDisconnectCompleted(mDisconnectParams, true);
+            }
+            if (mDisconnectParams == null && mConnectionParams == null && mDcFailCause != null) {
+                if (DBG) {
+                    log("DcInactiveState: enter notifyAllDisconnectCompleted failCause="
+                            + mDcFailCause);
+                }
+                notifyAllDisconnectCompleted(mDcFailCause);
+            }
+
+            // Remove ourselves from cid mapping, before clearSettings
+            mDcController.removeActiveDcByCid(DataConnection.this);
+
+            clearSettings();
+        }
+
+        @Override
+        public void exit() {
+        }
+
+        @Override
+        public boolean processMessage(Message msg) {
+            boolean retVal;
+
+            switch (msg.what) {
+                case DataConnectionAc.REQ_RESET:
+                    if (DBG) {
+                        log("DcInactiveState: msg.what=RSP_RESET, ignore we're already reset");
+                    }
+                    retVal = HANDLED;
+                    break;
+
+                case EVENT_CONNECT:
+                    mConnectionParams = (ConnectionParams) msg.obj;
+                    mConnectionParams.mTag = mTag;
+
+                    ApnContext apnContext = mConnectionParams.mApnContext;
+                    mApnSetting = apnContext.getApnSetting();
+                    mApnContexts.add(apnContext);
+                    configureRetry(mApnSetting.canHandleType(PhoneConstants.APN_TYPE_DEFAULT));
+                    mRetryManager.setRetryCount(0);
+                    mRetryManager.setCurMaxRetryCount(mConnectionParams.mInitialMaxRetry);
+
+                    if (DBG) {
+                        log("DcInactiveState msg.what=EVENT_CONNECT"
+                                + " RefCount=" + mApnContexts.size()
+                                + " mApnList=" + mApnContexts
+                                + " mConnectionParams=" + mConnectionParams);
+                    }
+
+                    onConnect(mConnectionParams);
+                    transitionTo(mActivatingState);
+                    retVal = HANDLED;
+                    break;
+
+                case EVENT_DISCONNECT:
+                    if (DBG) log("DcInactiveState: msg.what=EVENT_DISCONNECT");
+                    notifyDisconnectCompleted((DisconnectParams)msg.obj, false);
+                    retVal = HANDLED;
+                    break;
+
+                case EVENT_DISCONNECT_ALL:
+                    if (DBG) log("DcInactiveState: msg.what=EVENT_DISCONNECT_ALL");
+                    notifyDisconnectCompleted((DisconnectParams)msg.obj, false);
+                    retVal = HANDLED;
+                    break;
+
+                default:
+                    if (VDBG) {
+                        log("DcInactiveState nothandled msg.what=" + getWhatToString(msg.what));
+                    }
+                    retVal = NOT_HANDLED;
+                    break;
+            }
+            return retVal;
+        }
+    }
+    private DcInactiveState mInactiveState = new DcInactiveState();
+
+    /**
+     * The state machine is retrying and expects a EVENT_RETRY_CONNECTION.
+     */
+    private class DcRetryingState extends State {
+        @Override
+        public void enter() {
+            if (DBG) {
+                log("DcRetryingState: enter() mTag=" + mTag
+                    + ", call notifyAllOfDisconnectDcRetrying lostConnection");
+            }
+
+            notifyAllOfDisconnectDcRetrying(Phone.REASON_LOST_DATA_CONNECTION);
+
+            // Remove ourselves from cid mapping
+            mDcController.removeActiveDcByCid(DataConnection.this);
+            mCid = -1;
+        }
+
+        @Override
+        public boolean processMessage(Message msg) {
+            boolean retVal;
+
+            switch (msg.what) {
+                case EVENT_RETRY_CONNECTION: {
+                    if (msg.arg1 == mTag) {
+                        mRetryManager.increaseRetryCount();
+                        if (DBG) {
+                            log("DcRetryingState EVENT_RETRY_CONNECTION"
+                                    + " RetryCount=" +  mRetryManager.getRetryCount()
+                                    + " mConnectionParams=" + mConnectionParams);
+                        }
+                        onConnect(mConnectionParams);
+                        transitionTo(mActivatingState);
+                    } else {
+                        if (DBG) {
+                            log("DcRetryingState stale EVENT_RETRY_CONNECTION"
+                                    + " tag:" + msg.arg1 + " != mTag:" + mTag);
+                        }
+                    }
+                    retVal = HANDLED;
+                    break;
+                }
+                case DataConnectionAc.REQ_RESET: {
+                    if (DBG) {
+                        log("DcRetryingState: msg.what=RSP_RESET, ignore we're already reset");
+                    }
+                    mInactiveState.setEnterNotificationParams(mConnectionParams,
+                            DcFailCause.RESET_BY_FRAMEWORK);
+                    transitionTo(mInactiveState);
+                    retVal = HANDLED;
+                    break;
+                }
+                case EVENT_CONNECT: {
+                    if (DBG) {
+                        ConnectionParams cp = (ConnectionParams) msg.obj;
+                        log("DcRetryingState msg.what=EVENT_CONNECT "
+                                + "RefCount=" + mApnContexts.size() + " cp=" + cp
+                                + " mConnectionParams=" + mConnectionParams);
+                    }
+                    // Enter inactive state and skip notification as
+                    // it will be assumed this EVENT_CONNECT failed.
+                    mInactiveState.setEnterNotificationParams();
+                    deferMessage(msg);
+                    transitionTo(mInactiveState);
+                    retVal = HANDLED;
+                    break;
+                }
+                case EVENT_DISCONNECT: {
+                    DisconnectParams dp = (DisconnectParams) msg.obj;
+
+                    if (mApnContexts.remove(dp.mApnContext) && mApnContexts.size() == 0) {
+                        if (DBG) {
+                            log("DcRetryingState msg.what=EVENT_DISCONNECT " + " RefCount="
+                                    + mApnContexts.size() + " dp=" + dp);
+                        }
+                        mInactiveState.setEnterNotificationParams(dp);
+                        transitionTo(mInactiveState);
+                    } else {
+                        if (DBG) log("DcInactiveState: msg.what=EVENT_DISCONNECT");
+                        notifyDisconnectCompleted(dp, false);
+                    }
+                    retVal = HANDLED;
+                    break;
+                }
+                case EVENT_DISCONNECT_ALL: {
+                    if (DBG) {
+                        log("DcRetryingState msg.what=EVENT_DISCONNECT/DISCONNECT_ALL "
+                                + "RefCount=" + mApnContexts.size());
+                    }
+                    mInactiveState.setEnterNotificationParams(DcFailCause.LOST_CONNECTION);
+                    deferMessage(msg);
+                    transitionTo(mInactiveState);
+                    retVal = HANDLED;
+                    break;
+                }
+                default: {
+                    if (VDBG) {
+                        log("DcRetryingState nothandled msg.what=" + getWhatToString(msg.what));
+                    }
+                    retVal = NOT_HANDLED;
+                    break;
+                }
+            }
+            return retVal;
+        }
+    }
+    private DcRetryingState mRetryingState = new DcRetryingState();
+
+    /**
+     * The state machine is activating a connection.
+     */
+    private class DcActivatingState extends State {
+        @Override
+        public boolean processMessage(Message msg) {
+            boolean retVal;
+            AsyncResult ar;
+            ConnectionParams cp;
+
+            if (DBG) log("DcActivatingState: msg=" + msgToString(msg));
+            switch (msg.what) {
+                case EVENT_CONNECT:
+                    deferMessage(msg);
+                    retVal = HANDLED;
+                    break;
+
+                case EVENT_SETUP_DATA_CONNECTION_DONE:
+                    ar = (AsyncResult) msg.obj;
+                    cp = (ConnectionParams) ar.userObj;
+
+                    DataCallResponse.SetupResult result = onSetupConnectionCompleted(ar);
+                    if (result != DataCallResponse.SetupResult.ERR_Stale) {
+                        if (mConnectionParams != cp) {
+                            loge("DcActivatingState: WEIRD mConnectionsParams:"+ mConnectionParams
+                                    + " != cp:" + cp);
+                        }
+                    }
+                    if (DBG) log("DcActivatingState onSetupConnectionCompleted result=" + result);
+                    switch (result) {
+                        case SUCCESS:
+                            // All is well
+                            mDcFailCause = DcFailCause.NONE;
+                            transitionTo(mActiveState);
+                            break;
+                        case ERR_BadCommand:
+                            // Vendor ril rejected the command and didn't connect.
+                            // Transition to inactive but send notifications after
+                            // we've entered the mInactive state.
+                            mInactiveState.setEnterNotificationParams(cp, result.mFailCause);
+                            transitionTo(mInactiveState);
+                            break;
+                        case ERR_UnacceptableParameter:
+                            // The addresses given from the RIL are bad
+                            tearDownData(cp);
+                            transitionTo(mDisconnectingErrorCreatingConnection);
+                            break;
+                        case ERR_GetLastErrorFromRil:
+                            // Request failed and this is an old RIL
+                            mPhone.mCi.getLastDataCallFailCause(
+                                    obtainMessage(EVENT_GET_LAST_FAIL_DONE, cp));
+                            break;
+                        case ERR_RilError:
+                            int delay = mDcRetryAlarmController.getSuggestedRetryTime(
+                                                                    DataConnection.this, ar);
+                            if (delay >= 0) {
+                                mDcRetryAlarmController.startRetryAlarm(EVENT_RETRY_CONNECTION,
+                                                            mTag, delay);
+                                transitionTo(mRetryingState);
+                            } else {
+                                mInactiveState.setEnterNotificationParams(cp, result.mFailCause);
+                                transitionTo(mInactiveState);
+                            }
+                            break;
+                        case ERR_Stale:
+                            loge("DcActivatingState: stale EVENT_SETUP_DATA_CONNECTION_DONE"
+                                    + " tag:" + cp.mTag + " != mTag:" + mTag);
+                            break;
+                        default:
+                            throw new RuntimeException("Unknown SetupResult, should not happen");
+                    }
+                    retVal = HANDLED;
+                    break;
+
+                case EVENT_GET_LAST_FAIL_DONE:
+                    ar = (AsyncResult) msg.obj;
+                    cp = (ConnectionParams) ar.userObj;
+                    if (cp.mTag == mTag) {
+                        if (mConnectionParams != cp) {
+                            loge("DcActivatingState: WEIRD mConnectionsParams:" + mConnectionParams
+                                    + " != cp:" + cp);
+                        }
+
+                        DcFailCause cause = DcFailCause.UNKNOWN;
+
+                        if (DBG) {
+                            log("DcActivatingState msg.what=EVENT_GET_LAST_FAIL_DONE"
+                                    + " RefCount=" + mApnContexts.size());
+                        }
+                        if (ar.exception == null) {
+                            int rilFailCause = ((int[]) (ar.result))[0];
+                            cause = DcFailCause.fromInt(rilFailCause);
+                        }
+                        mDcFailCause = cause;
+
+                        int retryDelay = mRetryManager.getRetryTimer();
+                        if (mRetryManager.isRetryNeeded()) {
+                            mDcRetryAlarmController.startRetryAlarm(EVENT_RETRY_CONNECTION, mTag,
+                                                            retryDelay);
+                            transitionTo(mRetryingState);
+                        } else {
+                            // Transition to inactive but send notifications after
+                            // we've entered the mInactive state.
+                            mInactiveState.setEnterNotificationParams(cp, cause);
+                            transitionTo(mInactiveState);
+                        }
+                    } else {
+                        loge("DcActivatingState: stale EVENT_GET_LAST_FAIL_DONE"
+                                + " tag:" + cp.mTag + " != mTag:" + mTag);
+                    }
+
+                    retVal = HANDLED;
+                    break;
+
+                default:
+                    if (VDBG) {
+                        log("DcActivatingState not handled msg.what=" +
+                                getWhatToString(msg.what) + " RefCount=" + mApnContexts.size());
+                    }
+                    retVal = NOT_HANDLED;
+                    break;
+            }
+            return retVal;
+        }
+    }
+    private DcActivatingState mActivatingState = new DcActivatingState();
+
+    /**
+     * The state machine is connected, expecting an EVENT_DISCONNECT.
+     */
+    private class DcActiveState extends State {
+        @Override public void enter() {
+            if (DBG) log("DcActiveState: enter dc=" + DataConnection.this);
+
+            if (mRetryManager.getRetryCount() != 0) {
+                log("DcActiveState: connected after retrying call notifyAllOfConnected");
+                mRetryManager.setRetryCount(0);
+            }
+            // If we were retrying there maybe more than one, otherwise they'll only be one.
+            notifyAllOfConnected(Phone.REASON_CONNECTED);
+
+            // If the EVENT_CONNECT set the current max retry restore it here
+            // if it didn't then this is effectively a NOP.
+            mRetryManager.restoreCurMaxRetryCount();
+            mDcController.addActiveDcByCid(DataConnection.this);
+        }
+
+        @Override
+        public void exit() {
+            if (DBG) log("DcActiveState: exit dc=" + this);
+        }
+
+        @Override
+        public boolean processMessage(Message msg) {
+            boolean retVal;
+
+            switch (msg.what) {
+                case EVENT_CONNECT: {
+                    ConnectionParams cp = (ConnectionParams) msg.obj;
+                    if (mApnContexts.contains(cp.mApnContext)) {
+                        log("DcActiveState ERROR already added apnContext=" + cp.mApnContext
+                                    + " to this DC=" + this);
+                    } else {
+                        mApnContexts.add(cp.mApnContext);
+                        if (DBG) {
+                            log("DcActiveState msg.what=EVENT_CONNECT RefCount="
+                                    + mApnContexts.size());
+                        }
+                    }
+                    notifyConnectCompleted(cp, DcFailCause.NONE, false);
+                    retVal = HANDLED;
+                    break;
+                }
+                case EVENT_DISCONNECT: {
+                    DisconnectParams dp = (DisconnectParams) msg.obj;
+                    if (mApnContexts.contains(dp.mApnContext)) {
+                        if (DBG) {
+                            log("DcActiveState msg.what=EVENT_DISCONNECT RefCount="
+                                    + mApnContexts.size());
+                        }
+
+                        if (mApnContexts.size() == 1) {
+                            mApnContexts.clear();
+                            mDisconnectParams = dp;
+                            mConnectionParams = null;
+                            dp.mTag = mTag;
+                            tearDownData(dp);
+                            transitionTo(mDisconnectingState);
+                        } else {
+                            mApnContexts.remove(dp.mApnContext);
+                            notifyDisconnectCompleted(dp, false);
+                        }
+                    } else {
+                        log("DcActiveState ERROR no such apnContext=" + dp.mApnContext
+                                + " in this DC=" + this);
+                        notifyDisconnectCompleted(dp, false);
+                    }
+                    retVal = HANDLED;
+                    break;
+                }
+                case EVENT_DISCONNECT_ALL: {
+                    if (DBG) {
+                        log("DcActiveState msg.what=EVENT_DISCONNECT_ALL RefCount="
+                                + mApnContexts.size() + " clearing apn contexts");
+                    }
+                    mApnContexts.clear();
+                    DisconnectParams dp = (DisconnectParams) msg.obj;
+                    mDisconnectParams = dp;
+                    mConnectionParams = null;
+                    dp.mTag = mTag;
+                    tearDownData(dp);
+                    transitionTo(mDisconnectingState);
+                    retVal = HANDLED;
+                    break;
+                }
+                case EVENT_LOST_CONNECTION: {
+                    if (mRetryManager.isRetryNeeded()) {
+                        // We're going to retry
+                        int delayMillis = mRetryManager.getRetryTimer();
+                        if (DBG) {
+                            log("DcActiveState EVENT_LOST_CONNECTION startRetryAlarm"
+                                    + " mTag=" + mTag + " delay=" + delayMillis + "ms");
+                        }
+                        mDcRetryAlarmController.startRetryAlarm(EVENT_RETRY_CONNECTION, mTag,
+                                delayMillis);
+                        transitionTo(mRetryingState);
+                    } else {
+                        mInactiveState.setEnterNotificationParams(DcFailCause.LOST_CONNECTION);
+                        transitionTo(mInactiveState);
+                    }
+                    retVal = HANDLED;
+                    break;
+                }
+                default:
+                    if (VDBG) {
+                        log("DcActiveState not handled msg.what=" + getWhatToString(msg.what));
+                    }
+                    retVal = NOT_HANDLED;
+                    break;
+            }
+            return retVal;
+        }
+    }
+    private DcActiveState mActiveState = new DcActiveState();
+
+    /**
+     * The state machine is disconnecting.
+     */
+    private class DcDisconnectingState extends State {
+        @Override
+        public boolean processMessage(Message msg) {
+            boolean retVal;
+
+            switch (msg.what) {
+                case EVENT_CONNECT:
+                    if (DBG) log("DcDisconnectingState msg.what=EVENT_CONNECT. Defer. RefCount = "
+                            + mApnContexts.size());
+                    deferMessage(msg);
+                    retVal = HANDLED;
+                    break;
+
+                case EVENT_DEACTIVATE_DONE:
+                    if (DBG) log("DcDisconnectingState msg.what=EVENT_DEACTIVATE_DONE RefCount="
+                            + mApnContexts.size());
+                    AsyncResult ar = (AsyncResult) msg.obj;
+                    DisconnectParams dp = (DisconnectParams) ar.userObj;
+                    if (dp.mTag == mTag) {
+                        // Transition to inactive but send notifications after
+                        // we've entered the mInactive state.
+                        mInactiveState.setEnterNotificationParams((DisconnectParams) ar.userObj);
+                        transitionTo(mInactiveState);
+                    } else {
+                        if (DBG) log("DcDisconnectState stale EVENT_DEACTIVATE_DONE"
+                                + " dp.tag=" + dp.mTag + " mTag=" + mTag);
+                    }
+                    retVal = HANDLED;
+                    break;
+
+                default:
+                    if (VDBG) {
+                        log("DcDisconnectingState not handled msg.what="
+                                + getWhatToString(msg.what));
+                    }
+                    retVal = NOT_HANDLED;
+                    break;
+            }
+            return retVal;
+        }
+    }
+    private DcDisconnectingState mDisconnectingState = new DcDisconnectingState();
+
+    /**
+     * The state machine is disconnecting after an creating a connection.
+     */
+    private class DcDisconnectionErrorCreatingConnection extends State {
+        @Override
+        public boolean processMessage(Message msg) {
+            boolean retVal;
+
+            switch (msg.what) {
+                case EVENT_DEACTIVATE_DONE:
+                    AsyncResult ar = (AsyncResult) msg.obj;
+                    ConnectionParams cp = (ConnectionParams) ar.userObj;
+                    if (cp.mTag == mTag) {
+                        if (DBG) {
+                            log("DcDisconnectionErrorCreatingConnection" +
+                                " msg.what=EVENT_DEACTIVATE_DONE");
+                        }
+
+                        // Transition to inactive but send notifications after
+                        // we've entered the mInactive state.
+                        mInactiveState.setEnterNotificationParams(cp,
+                                DcFailCause.UNACCEPTABLE_NETWORK_PARAMETER);
+                        transitionTo(mInactiveState);
+                    } else {
+                        if (DBG) {
+                            log("DcDisconnectionErrorCreatingConnection stale EVENT_DEACTIVATE_DONE"
+                                    + " dp.tag=" + cp.mTag + ", mTag=" + mTag);
+                        }
+                    }
+                    retVal = HANDLED;
+                    break;
+
+                default:
+                    if (VDBG) {
+                        log("DcDisconnectionErrorCreatingConnection not handled msg.what="
+                                + getWhatToString(msg.what));
+                    }
+                    retVal = NOT_HANDLED;
+                    break;
+            }
+            return retVal;
+        }
+    }
+    private DcDisconnectionErrorCreatingConnection mDisconnectingErrorCreatingConnection =
+                new DcDisconnectionErrorCreatingConnection();
+
+    // ******* "public" interface
+
+    /**
+     * Used for testing purposes.
+     */
+    /* package */ void tearDownNow() {
+        if (DBG) log("tearDownNow()");
+        sendMessage(obtainMessage(EVENT_TEAR_DOWN_NOW));
+    }
+
+    /**
+     * @return the string for msg.what as our info.
+     */
+    @Override
+    protected String getWhatToString(int what) {
+        return cmdToString(what);
+    }
+
+    private static String msgToString(Message msg) {
+        String retVal;
+        if (msg == null) {
+            retVal = "null";
+        } else {
+            StringBuilder   b = new StringBuilder();
+
+            b.append("{what=");
+            b.append(cmdToString(msg.what));
+
+            b.append(" when=");
+            TimeUtils.formatDuration(msg.getWhen() - SystemClock.uptimeMillis(), b);
+
+            if (msg.arg1 != 0) {
+                b.append(" arg1=");
+                b.append(msg.arg1);
+            }
+
+            if (msg.arg2 != 0) {
+                b.append(" arg2=");
+                b.append(msg.arg2);
+            }
+
+            if (msg.obj != null) {
+                b.append(" obj=");
+                b.append(msg.obj);
+            }
+
+            b.append(" target=");
+            b.append(msg.getTarget());
+
+            b.append(" replyTo=");
+            b.append(msg.replyTo);
+
+            b.append("}");
+
+            retVal = b.toString();
+        }
+        return retVal;
+    }
+
+    static void slog(String s) {
+        Rlog.d("DC", s);
+    }
+
+    /**
+     * Log with debug
+     *
+     * @param s is string log
+     */
+    @Override
+    protected void log(String s) {
+        Rlog.d(getName(), s);
+    }
+
+    /**
+     * Log with debug attribute
+     *
+     * @param s is string log
+     */
+    @Override
+    protected void logd(String s) {
+        Rlog.d(getName(), s);
+    }
+
+    /**
+     * Log with verbose attribute
+     *
+     * @param s is string log
+     */
+    @Override
+    protected void logv(String s) {
+        Rlog.v(getName(), s);
+    }
+
+    /**
+     * Log with info attribute
+     *
+     * @param s is string log
+     */
+    @Override
+    protected void logi(String s) {
+        Rlog.i(getName(), s);
+    }
+
+    /**
+     * Log with warning attribute
+     *
+     * @param s is string log
+     */
+    @Override
+    protected void logw(String s) {
+        Rlog.w(getName(), s);
+    }
+
+    /**
+     * Log with error attribute
+     *
+     * @param s is string log
+     */
+    @Override
+    protected void loge(String s) {
+        Rlog.e(getName(), s);
+    }
+
+    /**
+     * Log with error attribute
+     *
+     * @param s is string log
+     * @param e is a Throwable which logs additional information.
+     */
+    @Override
+    protected void loge(String s, Throwable e) {
+        Rlog.e(getName(), s, e);
+    }
+
+    /** Doesn't print mApnList of ApnContext's which would be recursive */
+    public String toStringSimple() {
+        return getName() + ": State=" + getCurrentState().getName()
+                + " mApnSetting=" + mApnSetting + " RefCount=" + mApnContexts.size()
+                + " mCid=" + mCid + " mCreateTime=" + mCreateTime
+                + " mLastastFailTime=" + mLastFailTime
+                + " mLastFailCause=" + mLastFailCause
+                + " mTag=" + mTag
+                + " mRetryManager=" + mRetryManager
+                + " mLinkProperties=" + mLinkProperties
+                + " mLinkCapabilities=" + mLinkCapabilities;
+    }
+
+    @Override
+    public String toString() {
+        return "{" + toStringSimple() + " mApnContexts=" + mApnContexts + "}";
+    }
+
+    /**
+     * Dump the current state.
+     *
+     * @param fd
+     * @param pw
+     * @param args
+     */
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        pw.println("DataConnection extends:");
+        pw.print("DataConnection ");
         super.dump(fd, pw, args);
-        pw.println(" mProfileId=" + mProfileId);
+        pw.println(" mApnContexts.size=" + mApnContexts.size());
+        pw.println(" mApnContexts=" + mApnContexts);
+        pw.flush();
+        pw.println(" mDataConnectionTracker=" + mDct);
+        pw.println(" mApnSetting=" + mApnSetting);
+        pw.println(" mTag=" + mTag);
+        pw.println(" mCid=" + mCid);
+        pw.println(" mRetryManager=" + mRetryManager);
+        pw.println(" mConnectionParams=" + mConnectionParams);
+        pw.println(" mDisconnectParams=" + mDisconnectParams);
+        pw.println(" mDcFailCause=" + mDcFailCause);
+        pw.flush();
+        pw.println(" mPhone=" + mPhone);
+        pw.flush();
+        pw.println(" mLinkProperties=" + mLinkProperties);
+        pw.flush();
+        pw.println(" mLinkCapabilities=" + mLinkCapabilities);
+        pw.println(" mCreateTime=" + TimeUtils.logTimeOfDay(mCreateTime));
+        pw.println(" mLastFailTime=" + TimeUtils.logTimeOfDay(mLastFailTime));
+        pw.println(" mLastFailCause=" + mLastFailCause);
+        pw.flush();
+        pw.println(" mUserData=" + mUserData);
+        pw.println(" mInstanceNumber=" + mInstanceNumber);
+        pw.println(" mAc=" + mAc);
+        pw.println(" mDcRetryAlarmController=" + mDcRetryAlarmController);
+        pw.flush();
     }
 }
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataConnectionAc.java b/src/java/com/android/internal/telephony/dataconnection/DataConnectionAc.java
index 245223b..7b1e596 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataConnectionAc.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataConnectionAc.java
@@ -16,20 +16,16 @@
 
 package com.android.internal.telephony.dataconnection;
 
-import com.android.internal.telephony.DataCallState;
-import com.android.internal.telephony.dataconnection.DataConnectionBase.UpdateLinkPropertyResult;
+import com.android.internal.telephony.dataconnection.DataConnection.ConnectionParams;
+import com.android.internal.telephony.dataconnection.DataConnection.DisconnectParams;
 import com.android.internal.util.AsyncChannel;
 import com.android.internal.util.Protocol;
 
-import android.app.PendingIntent;
 import android.net.LinkCapabilities;
 import android.net.LinkProperties;
 import android.net.ProxyProperties;
 import android.os.Message;
 
-import java.util.ArrayList;
-import java.util.Collection;
-
 /**
  * AsyncChannel to a DataConnection
  */
@@ -37,7 +33,8 @@
     private static final boolean DBG = false;
     private String mLogTag;
 
-    public DataConnectionBase dataConnection;
+    private DataConnection mDc;
+    private long mDcThreadId;
 
     public static final int BASE = Protocol.BASE_DATA_CONNECTION_AC;
 
@@ -59,25 +56,10 @@
     public static final int REQ_GET_LINK_CAPABILITIES = BASE + 10;
     public static final int RSP_GET_LINK_CAPABILITIES = BASE + 11;
 
-    public static final int REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE = BASE + 12;
-    public static final int RSP_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE = BASE + 13;
+    public static final int REQ_RESET = BASE + 12;
+    public static final int RSP_RESET = BASE + 13;
 
-    public static final int REQ_RESET = BASE + 14;
-    public static final int RSP_RESET = BASE + 15;
-
-    public static final int REQ_GET_REFCOUNT = BASE + 16;
-    public static final int RSP_GET_REFCOUNT = BASE + 17;
-
-    public static final int REQ_GET_APNCONTEXT_LIST = BASE + 18;
-    public static final int RSP_GET_APNCONTEXT_LIST = BASE + 19;
-
-    public static final int REQ_SET_RECONNECT_INTENT = BASE + 20;
-    public static final int RSP_SET_RECONNECT_INTENT = BASE + 21;
-
-    public static final int REQ_GET_RECONNECT_INTENT = BASE + 22;
-    public static final int RSP_GET_RECONNECT_INTENT = BASE + 23;
-
-    private static final int CMD_TO_STRING_COUNT = RSP_GET_RECONNECT_INTENT - BASE + 1;
+    private static final int CMD_TO_STRING_COUNT = RSP_RESET - BASE + 1;
     private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT];
     static {
         sCmdToString[REQ_IS_INACTIVE - BASE] = "REQ_IS_INACTIVE";
@@ -94,21 +76,11 @@
                 "RSP_SET_LINK_PROPERTIES_HTTP_PROXY";
         sCmdToString[REQ_GET_LINK_CAPABILITIES - BASE] = "REQ_GET_LINK_CAPABILITIES";
         sCmdToString[RSP_GET_LINK_CAPABILITIES - BASE] = "RSP_GET_LINK_CAPABILITIES";
-        sCmdToString[REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE - BASE] =
-                "REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE";
-        sCmdToString[RSP_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE - BASE] =
-                "RSP_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE";
         sCmdToString[REQ_RESET - BASE] = "REQ_RESET";
         sCmdToString[RSP_RESET - BASE] = "RSP_RESET";
-        sCmdToString[REQ_GET_REFCOUNT - BASE] = "REQ_GET_REFCOUNT";
-        sCmdToString[RSP_GET_REFCOUNT - BASE] = "RSP_GET_REFCOUNT";
-        sCmdToString[REQ_GET_APNCONTEXT_LIST - BASE] = "REQ_GET_APNCONTEXT_LIST";
-        sCmdToString[RSP_GET_APNCONTEXT_LIST - BASE] = "RSP_GET_APNCONTEXT_LIST";
-        sCmdToString[REQ_SET_RECONNECT_INTENT - BASE] = "REQ_SET_RECONNECT_INTENT";
-        sCmdToString[RSP_SET_RECONNECT_INTENT - BASE] = "RSP_SET_RECONNECT_INTENT";
-        sCmdToString[REQ_GET_RECONNECT_INTENT - BASE] = "REQ_GET_RECONNECT_INTENT";
-        sCmdToString[RSP_GET_RECONNECT_INTENT - BASE] = "RSP_GET_RECONNECT_INTENT";
     }
+
+    // Convert cmd to string or null if unknown
     protected static String cmdToString(int cmd) {
         cmd -= BASE;
         if ((cmd >= 0) && (cmd < sCmdToString.length)) {
@@ -138,8 +110,9 @@
         }
     }
 
-    public DataConnectionAc(DataConnectionBase dc, String logTag) {
-        dataConnection = dc;
+    public DataConnectionAc(DataConnection dc, String logTag) {
+        mDc = dc;
+        mDcThreadId = mDc.getHandler().getLooper().getThread().getId();
         mLogTag = logTag;
     }
 
@@ -164,16 +137,23 @@
     }
 
     /**
-     * @return true if the state machine is in the inactive state.
+     * @return true if the state machine is in the inactive state
+     * and can be used for a new connection.
      */
     public boolean isInactiveSync() {
-        Message response = sendMessageSynchronously(REQ_IS_INACTIVE);
-        if ((response != null) && (response.what == RSP_IS_INACTIVE)) {
-            return rspIsInactive(response);
+        boolean value;
+        if (isCallerOnDifferentThread()) {
+            Message response = sendMessageSynchronously(REQ_IS_INACTIVE);
+            if ((response != null) && (response.what == RSP_IS_INACTIVE)) {
+                value = rspIsInactive(response);
+            } else {
+                log("rspIsInactive error response=" + response);
+                value = false;
+            }
         } else {
-            log("rspIsInactive error response=" + response);
-            return false;
+            value = mDc.getIsInactive();
         }
+        return value;
     }
 
     /**
@@ -201,47 +181,19 @@
      * @return connection id or -1 if an error
      */
     public int getCidSync() {
-        Message response = sendMessageSynchronously(REQ_GET_CID);
-        if ((response != null) && (response.what == RSP_GET_CID)) {
-            return rspCid(response);
+        int value;
+        if (isCallerOnDifferentThread()) {
+            Message response = sendMessageSynchronously(REQ_GET_CID);
+            if ((response != null) && (response.what == RSP_GET_CID)) {
+                value = rspCid(response);
+            } else {
+                log("rspCid error response=" + response);
+                value = -1;
+            }
         } else {
-            log("rspCid error response=" + response);
-            return -1;
+            value = mDc.getCid();
         }
-    }
-
-    /**
-     * Request the Reference Count.
-     * Response {@link #rspRefCount}
-     */
-    public void reqRefCount() {
-        sendMessage(REQ_GET_REFCOUNT);
-        if (DBG) log("reqRefCount");
-    }
-
-    /**
-     * Evaluate a RSP_GET_REFCOUNT message and return the refCount.
-     *
-     * @param response Message
-     * @return ref count or -1 if an error
-     */
-    public int rspRefCount(Message response) {
-        int retVal = response.arg1;
-        if (DBG) log("rspRefCount=" + retVal);
-        return retVal;
-    }
-
-    /**
-     * @return connection id or -1 if an error
-     */
-    public int getRefCountSync() {
-        Message response = sendMessageSynchronously(REQ_GET_REFCOUNT);
-        if ((response != null) && (response.what == RSP_GET_REFCOUNT)) {
-            return rspRefCount(response);
-        } else {
-            log("rspRefCount error response=" + response);
-            return -1;
-        }
+        return value;
     }
 
     /**
@@ -271,13 +223,19 @@
      * @return ApnSetting or null if an error
      */
     public ApnSetting getApnSettingSync() {
-        Message response = sendMessageSynchronously(REQ_GET_APNSETTING);
-        if ((response != null) && (response.what == RSP_GET_APNSETTING)) {
-            return rspApnSetting(response);
+        ApnSetting value;
+        if (isCallerOnDifferentThread()) {
+            Message response = sendMessageSynchronously(REQ_GET_APNSETTING);
+            if ((response != null) && (response.what == RSP_GET_APNSETTING)) {
+                value = rspApnSetting(response);
+            } else {
+                log("getApnSetting error response=" + response);
+                value = null;
+            }
         } else {
-            log("getApnSetting error response=" + response);
-            return null;
+            value = mDc.getApnSetting();
         }
+        return value;
     }
 
     /**
@@ -307,13 +265,19 @@
      * @return LinkProperties or null if an error
      */
     public LinkProperties getLinkPropertiesSync() {
-        Message response = sendMessageSynchronously(REQ_GET_LINK_PROPERTIES);
-        if ((response != null) && (response.what == RSP_GET_LINK_PROPERTIES)) {
-            return rspLinkProperties(response);
+        LinkProperties value;
+        if (isCallerOnDifferentThread()) {
+            Message response = sendMessageSynchronously(REQ_GET_LINK_PROPERTIES);
+            if ((response != null) && (response.what == RSP_GET_LINK_PROPERTIES)) {
+                value = rspLinkProperties(response);
+            } else {
+                log("getLinkProperties error response=" + response);
+                value = null;
+            }
         } else {
-            log("getLinkProperties error response=" + response);
-            return null;
+            value = mDc.getCopyLinkProperties();
         }
+        return value;
     }
 
     /**
@@ -329,44 +293,16 @@
      * Set the connections LinkProperties.HttpProxy
      */
     public void setLinkPropertiesHttpProxySync(ProxyProperties proxy) {
-        Message response =
-            sendMessageSynchronously(REQ_SET_LINK_PROPERTIES_HTTP_PROXY, proxy);
-        if ((response != null) && (response.what == RSP_SET_LINK_PROPERTIES_HTTP_PROXY)) {
-            if (DBG) log("setLinkPropertiesHttpPoxy ok");
+        if (isCallerOnDifferentThread()) {
+            Message response =
+                sendMessageSynchronously(REQ_SET_LINK_PROPERTIES_HTTP_PROXY, proxy);
+            if ((response != null) && (response.what == RSP_SET_LINK_PROPERTIES_HTTP_PROXY)) {
+                if (DBG) log("setLinkPropertiesHttpPoxy ok");
+            } else {
+                log("setLinkPropertiesHttpPoxy error response=" + response);
+            }
         } else {
-            log("setLinkPropertiesHttpPoxy error response=" + response);
-        }
-    }
-
-    /**
-     * Request update LinkProperties from DataCallState
-     * Response {@link #rspUpdateLinkPropertiesDataCallState}
-     */
-    public void reqUpdateLinkPropertiesDataCallState(DataCallState newState) {
-        sendMessage(REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE, newState);
-        if (DBG) log("reqUpdateLinkPropertiesDataCallState");
-    }
-
-    public UpdateLinkPropertyResult rspUpdateLinkPropertiesDataCallState(Message response) {
-        UpdateLinkPropertyResult retVal = (UpdateLinkPropertyResult)response.obj;
-        if (DBG) log("rspUpdateLinkPropertiesState: retVal=" + retVal);
-        return retVal;
-    }
-
-    /**
-     * Update link properties in the data connection
-     *
-     * @return the removed and added addresses.
-     */
-    public UpdateLinkPropertyResult updateLinkPropertiesDataCallStateSync(DataCallState newState) {
-        Message response =
-            sendMessageSynchronously(REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE, newState);
-        if ((response != null) &&
-            (response.what == RSP_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE)) {
-            return rspUpdateLinkPropertiesDataCallState(response);
-        } else {
-            log("getLinkProperties error response=" + response);
-            return new UpdateLinkPropertyResult(new LinkProperties());
+            mDc.setLinkPropertiesHttpProxy(proxy);
         }
     }
 
@@ -397,13 +333,18 @@
      * @return LinkCapabilities or null if an error
      */
     public LinkCapabilities getLinkCapabilitiesSync() {
-        Message response = sendMessageSynchronously(REQ_GET_LINK_CAPABILITIES);
-        if ((response != null) && (response.what == RSP_GET_LINK_CAPABILITIES)) {
-            return rspLinkCapabilities(response);
+        LinkCapabilities value;
+        if (isCallerOnDifferentThread()) {
+            Message response = sendMessageSynchronously(REQ_GET_LINK_CAPABILITIES);
+            if ((response != null) && (response.what == RSP_GET_LINK_CAPABILITIES)) {
+                value = rspLinkCapabilities(response);
+            } else {
+                value = null;
+            }
         } else {
-            log("getLinkCapabilities error response=" + response);
-            return null;
+            value = mDc.getCopyLinkCapabilities();
         }
+        return value;
     }
 
     /**
@@ -416,118 +357,73 @@
     }
 
     /**
-     * Reset the connection and wait for it to complete.
+     * Bring up a connection to the apn and return an AsyncResult in onCompletedMsg.
+     * Used for cellular networks that use Acesss Point Names (APN) such
+     * as GSM networks.
+     *
+     * @param apnContext is the Access Point Name to bring up a connection to
+     * @param initialMaxRetry the number of retires for initial bringup.
+     * @param profileId for the conneciton
+     * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
+     *        With AsyncResult.userObj set to the original msg.obj,
+     *        AsyncResult.result = FailCause and AsyncResult.exception = Exception().
      */
-    public void resetSync() {
-        Message response = sendMessageSynchronously(REQ_RESET);
-        if ((response != null) && (response.what == RSP_RESET)) {
-            if (DBG) log("restSync ok");
-        } else {
-            log("restSync error response=" + response);
+    public void bringUp(ApnContext apnContext, int initialMaxRetry, int profileId,
+            Message onCompletedMsg) {
+        if (DBG) {
+            log("bringUp: apnContext=" + apnContext + " initialMaxRetry=" + initialMaxRetry
+                + " onCompletedMsg=" + onCompletedMsg);
         }
+        sendMessage(DataConnection.EVENT_CONNECT,
+                    new ConnectionParams(apnContext, initialMaxRetry, profileId, onCompletedMsg));
     }
 
     /**
-     * Request the ApnContext List associated with DC.
-     * Response RSP_GET_APNCONTEXT_LIST when complete.
-     */
-    public void reqGetApnList(ApnContext apnContext) {
-        Message response = sendMessageSynchronously(REQ_GET_APNCONTEXT_LIST);
-        if (DBG) log("reqGetApnList");
-    }
-
-    /**
-     * Retrieve Collection of ApnContext from the response message.
+     * Tear down the connection through the apn on the network.
      *
-     * @param response sent from DC in response to REQ_GET_APNCONTEXT_LIST.
-     * @return Collection of ApnContext
+     * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
+     *        With AsyncResult.userObj set to the original msg.obj.
      */
-    public Collection<ApnContext> rspApnList(Message response) {
-        Collection<ApnContext> retVal = (Collection<ApnContext>)response.obj;
-        if (retVal == null) retVal = new ArrayList<ApnContext>();
-        return retVal;
-    }
-
-    /**
-     * Retrieve collection of ApnContext currently associated with
-     * the DataConnectionA synchronously.
-     *
-     * @return Collection of ApnContext
-     */
-    public Collection<ApnContext> getApnListSync() {
-        Message response = sendMessageSynchronously(REQ_GET_APNCONTEXT_LIST);
-        if ((response != null) && (response.what == RSP_GET_APNCONTEXT_LIST)) {
-            if (DBG) log("getApnList ok");
-            return rspApnList(response);
-        } else {
-            log("getApnList error response=" + response);
-            // return dummy list with no entry
-            return new ArrayList<ApnContext>();
+    public void tearDown(ApnContext apnContext, String reason, Message onCompletedMsg) {
+        if (DBG) {
+            log("tearDown: apnContext=" + apnContext
+                    + " reason=" + reason + " onCompletedMsg=" + onCompletedMsg);
         }
+        sendMessage(DataConnection.EVENT_DISCONNECT,
+                        new DisconnectParams(apnContext, reason, onCompletedMsg));
     }
 
     /**
-     * Request to set Pending ReconnectIntent to DC.
-     * Response RSP_SET_RECONNECT_INTENT when complete.
-     */
-    public void reqSetReconnectIntent(PendingIntent intent) {
-        Message response = sendMessageSynchronously(REQ_SET_RECONNECT_INTENT, intent);
-        if (DBG) log("reqSetReconnectIntent");
-    }
-
-    /**
-     * Set pending reconnect intent to DC synchronously.
+     * Tear down the connection through the apn on the network.  Ignores refcount and
+     * and always tears down.
      *
-     * @param intent to set.
+     * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
+     *        With AsyncResult.userObj set to the original msg.obj.
      */
-    public void setReconnectIntentSync(PendingIntent intent) {
-        Message response = sendMessageSynchronously(REQ_SET_RECONNECT_INTENT, intent);
-        if ((response != null) && (response.what == RSP_SET_RECONNECT_INTENT)) {
-            if (DBG) log("setReconnectIntent ok");
-        } else {
-            log("setReconnectIntent error response=" + response);
-        }
+    public void tearDownAll(String reason, Message onCompletedMsg) {
+        if (DBG) log("tearDownAll: reason=" + reason + " onCompletedMsg=" + onCompletedMsg);
+        sendMessage(DataConnection.EVENT_DISCONNECT_ALL,
+                new DisconnectParams(null, reason, onCompletedMsg));
     }
 
     /**
-     * Request to get Pending ReconnectIntent to DC.
-     * Response RSP_GET_RECONNECT_INTENT when complete.
+     * @return connection id
      */
-    public void reqGetReconnectIntent() {
-        Message response = sendMessageSynchronously(REQ_GET_RECONNECT_INTENT);
-        if (DBG) log("reqGetReconnectIntent");
-    }
-
-    /**
-     * Retrieve reconnect intent from response message from DC.
-     *
-     * @param response which contains the reconnect intent.
-     * @return PendingIntent from the response.
-     */
-    public PendingIntent rspReconnectIntent(Message response) {
-        PendingIntent retVal = (PendingIntent) response.obj;
-        return retVal;
-    }
-
-    /**
-     * Retrieve reconnect intent currently set in DC synchronously.
-     *
-     * @return PendingIntent reconnect intent current ly set in DC
-     */
-    public PendingIntent getReconnectIntentSync() {
-        Message response = sendMessageSynchronously(REQ_GET_RECONNECT_INTENT);
-        if ((response != null) && (response.what == RSP_GET_RECONNECT_INTENT)) {
-            if (DBG) log("getReconnectIntent ok");
-            return rspReconnectIntent(response);
-        } else {
-            log("getReconnectIntent error response=" + response);
-            return null;
-        }
+    public int getDataConnectionIdSync() {
+        // Safe because this is owned by the caller.
+        return mDc.getDataConnectionId();
     }
 
     @Override
     public String toString() {
-        return dataConnection.getName();
+        return mDc.getName();
+    }
+
+    private boolean isCallerOnDifferentThread() {
+        long curThreadId = Thread.currentThread().getId();
+        boolean value = mDcThreadId != curThreadId;
+        if (DBG) log("isCallerOnDifferentThread: " + value);
+        return value;
     }
 
     private void log(String s) {
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataConnectionBase.java b/src/java/com/android/internal/telephony/dataconnection/DataConnectionBase.java
deleted file mode 100644
index f0d1e09..0000000
--- a/src/java/com/android/internal/telephony/dataconnection/DataConnectionBase.java
+++ /dev/null
@@ -1,1520 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony.dataconnection;
-
-
-import com.android.internal.telephony.CommandException;
-import com.android.internal.telephony.DataCallState;
-import com.android.internal.telephony.DctConstants;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.PhoneBase;
-import com.android.internal.telephony.RILConstants;
-import com.android.internal.telephony.RetryManager;
-import com.android.internal.util.AsyncChannel;
-import com.android.internal.util.Protocol;
-import com.android.internal.util.State;
-import com.android.internal.util.StateMachine;
-
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.LinkCapabilities;
-import android.net.LinkProperties;
-import android.net.ProxyProperties;
-import android.os.AsyncResult;
-import android.os.Message;
-import android.os.SystemProperties;
-import android.text.TextUtils;
-import android.telephony.Rlog;
-import android.util.TimeUtils;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * {@hide}
- *
- * DataConnectionBase StateMachine.
- *
- * This is an abstract base class for representing a single data connection.
- * Instances of this class such represent a connection via the cellular network.
- * There may be multiple data connections and all of them are managed by the
- * <code>DataConnectionTracker</code>.
- *
- * Instances are asynchronous state machines and have two primary entry points
- * <code>connect()</code> and <code>disconnect</code>. The message a parameter will be returned
- * hen the operation completes. The <code>msg.obj</code> will contain an AsyncResult
- * object and <code>AsyncResult.userObj</code> is the original <code>msg.obj</code>. if successful
- * with the <code>AsyncResult.result == null</code> and <code>AsyncResult.exception == null</code>.
- * If an error <code>AsyncResult.result = FailCause</code> and
- * <code>AsyncResult.exception = new Exception()</code>.
- *
- * The other public methods are provided for debugging.
- */
-public abstract class DataConnectionBase extends StateMachine {
-    protected static final String LOG_TAG = "DCBase";
-    protected static final boolean DBG = true;
-    protected static final boolean VDBG = true;
-    protected static final boolean DBG_FAILURE = SystemProperties.getInt("ro.debuggable", 0) == 1;
-
-    protected static AtomicInteger mCount = new AtomicInteger(0);
-    protected AsyncChannel mAc;
-
-    protected List<ApnContext> mApnList = null;
-    PendingIntent mReconnectIntent = null;
-
-    private DataConnectionTrackerBase mDataConnectionTracker = null;
-
-    /**
-     * Used internally for saving connecting parameters.
-     */
-    protected static class ConnectionParams {
-        ConnectionParams(ApnContext apnContext, Message onCompletedMsg) {
-            mApnContext = apnContext;
-            mOnCompletedMsg = onCompletedMsg;
-        }
-
-        int mTheTag;
-        ApnContext mApnContext;
-        Message mOnCompletedMsg;
-    }
-
-    /**
-     * Used internally for saving disconnecting parameters.
-     */
-    protected static class DisconnectParams {
-        DisconnectParams(ApnContext apnContext, String reason, Message onCompletedMsg) {
-            mApnContext = apnContext;
-            mReason = reason;
-            mOnCompletedMsg = onCompletedMsg;
-        }
-
-        int mTheTag;
-        ApnContext mApnContext;
-        String mReason;
-        Message mOnCompletedMsg;
-    }
-
-    /**
-     * Returned as the reason for a connection failure as defined
-     * by RIL_DataCallFailCause in ril.h and some local errors.
-     */
-    public enum FailCause {
-        NONE(0),
-
-        // This series of errors as specified by the standards
-        // specified in ril.h
-        OPERATOR_BARRED(0x08),
-        INSUFFICIENT_RESOURCES(0x1A),
-        MISSING_UNKNOWN_APN(0x1B),
-        UNKNOWN_PDP_ADDRESS_TYPE(0x1C),
-        USER_AUTHENTICATION(0x1D),
-        ACTIVATION_REJECT_GGSN(0x1E),
-        ACTIVATION_REJECT_UNSPECIFIED(0x1F),
-        SERVICE_OPTION_NOT_SUPPORTED(0x20),
-        SERVICE_OPTION_NOT_SUBSCRIBED(0x21),
-        SERVICE_OPTION_OUT_OF_ORDER(0x22),
-        NSAPI_IN_USE(0x23),
-        ONLY_IPV4_ALLOWED(0x32),
-        ONLY_IPV6_ALLOWED(0x33),
-        ONLY_SINGLE_BEARER_ALLOWED(0x34),
-        PROTOCOL_ERRORS(0x6F),
-
-        // Local errors generated by Vendor RIL
-        // specified in ril.h
-        REGISTRATION_FAIL(-1),
-        GPRS_REGISTRATION_FAIL(-2),
-        SIGNAL_LOST(-3),
-        PREF_RADIO_TECH_CHANGED(-4),
-        RADIO_POWER_OFF(-5),
-        TETHERED_CALL_ACTIVE(-6),
-        ERROR_UNSPECIFIED(0xFFFF),
-
-        // Errors generated by the Framework
-        // specified here
-        UNKNOWN(0x10000),
-        RADIO_NOT_AVAILABLE(0x10001),
-        UNACCEPTABLE_NETWORK_PARAMETER(0x10002),
-        CONNECTION_TO_DATACONNECTIONAC_BROKEN(0x10003);
-
-        private final int mErrorCode;
-        private static final HashMap<Integer, FailCause> sErrorCodeToFailCauseMap;
-        static {
-            sErrorCodeToFailCauseMap = new HashMap<Integer, FailCause>();
-            for (FailCause fc : values()) {
-                sErrorCodeToFailCauseMap.put(fc.getErrorCode(), fc);
-            }
-        }
-
-        FailCause(int errorCode) {
-            mErrorCode = errorCode;
-        }
-
-        public int getErrorCode() {
-            return mErrorCode;
-        }
-
-        public boolean isPermanentFail() {
-            return (this == OPERATOR_BARRED) || (this == MISSING_UNKNOWN_APN) ||
-                   (this == UNKNOWN_PDP_ADDRESS_TYPE) || (this == USER_AUTHENTICATION) ||
-                   (this == ACTIVATION_REJECT_GGSN) || (this == SERVICE_OPTION_NOT_SUPPORTED) ||
-                   (this == SERVICE_OPTION_NOT_SUBSCRIBED) || (this == NSAPI_IN_USE) ||
-                   (this == ONLY_IPV4_ALLOWED) || (this == ONLY_IPV6_ALLOWED) ||
-                   (this == PROTOCOL_ERRORS) || (this == SIGNAL_LOST) ||
-                   (this == RADIO_POWER_OFF) || (this == TETHERED_CALL_ACTIVE);
-        }
-
-        public boolean isEventLoggable() {
-            return (this == OPERATOR_BARRED) || (this == INSUFFICIENT_RESOURCES) ||
-                    (this == UNKNOWN_PDP_ADDRESS_TYPE) || (this == USER_AUTHENTICATION) ||
-                    (this == ACTIVATION_REJECT_GGSN) || (this == ACTIVATION_REJECT_UNSPECIFIED) ||
-                    (this == SERVICE_OPTION_NOT_SUBSCRIBED) ||
-                    (this == SERVICE_OPTION_NOT_SUPPORTED) ||
-                    (this == SERVICE_OPTION_OUT_OF_ORDER) || (this == NSAPI_IN_USE) ||
-                    (this == ONLY_IPV4_ALLOWED) || (this == ONLY_IPV6_ALLOWED) ||
-                    (this == PROTOCOL_ERRORS) || (this == SIGNAL_LOST) ||
-                    (this == RADIO_POWER_OFF) || (this == TETHERED_CALL_ACTIVE) ||
-                    (this == UNACCEPTABLE_NETWORK_PARAMETER);
-        }
-
-        public static FailCause fromInt(int errorCode) {
-            FailCause fc = sErrorCodeToFailCauseMap.get(errorCode);
-            if (fc == null) {
-                fc = UNKNOWN;
-            }
-            return fc;
-        }
-    }
-
-    /**
-     * Static logging for DataConnection
-     */
-    private static void sDcLog(String s) {
-        Rlog.d(LOG_TAG, "[DC] " + s);
-    }
-
-    // Debugging INTENT with are two targets, com.android.internal.telephony.DC which
-    // is for all DataConnections and com.android.internal.telephony.<NameDC-X> where
-    // NameDc-X is a particular DC such as GsmDC-1.
-    protected static final String INTENT_BASE = DataConnectionBase.class.getPackage().getName();
-    protected static String sActionFailBringUp;
-    protected String mActionFailBringUp;
-
-    // The FailBringUp class
-    public static class FailBringUp {
-        protected static final String ACTION_FAIL_BRINGUP = "action_fail_bringup";
-
-        // counter with its --ei option name and default value
-        public static final String COUNTER = "counter";
-        public static final int DEFAULT_COUNTER = 1;
-        public int counter;
-
-        // failCause with its --ei option name and default value
-        public static final String FAIL_CAUSE = "fail_cause";
-        public static final FailCause DEFAULT_FAIL_CAUSE = FailCause.ERROR_UNSPECIFIED;
-        public FailCause failCause;
-
-        // suggestedRetryTime with its --ei option name and default value
-        public static final String SUGGESTED_RETRY_TIME = "suggested_retry_time";
-        public static final int DEFAULT_SUGGESTED_RETRY_TIME = -1;
-        public int suggestedRetryTime;
-
-        // Get the Extra Intent parameters
-        public void getEiParameters(Intent intent, String s) {
-            if (DBG) sDcLog(s + ".getEiParameters: action=" + intent.getAction());
-            counter = intent.getIntExtra(FailBringUp.COUNTER,
-                    FailBringUp.DEFAULT_COUNTER);
-            failCause = FailCause.fromInt(
-                    intent.getIntExtra(FailBringUp.FAIL_CAUSE,
-                            FailBringUp.DEFAULT_FAIL_CAUSE.getErrorCode()));
-            suggestedRetryTime =
-                    intent.getIntExtra(FailBringUp.SUGGESTED_RETRY_TIME,
-                            FailBringUp.DEFAULT_SUGGESTED_RETRY_TIME);
-            if (DBG) {
-                sDcLog(s + ".getEiParameters: " + this);
-            }
-        }
-
-        @Override
-        public String toString() {
-            return "{counter=" + counter +
-                    " failCause=" + failCause +
-                    " suggestedRetryTime=" + suggestedRetryTime + "}";
-
-        }
-    }
-
-    // This is the static FailBringUp used to cause all DC's to "fail" a bringUp.
-    // Here is an example that sets counter to 2 and cause to -3 for all instances:
-    //
-    // adb shell am broadcast \
-    //  -a com.android.internal.telephony.DC.action_fail_bringup \
-    //  --ei counter 2 --ei fail_cause -3
-    //
-    // Also you can add a suggested retry time if desired:
-    //  --ei suggested_retry_time 5000
-    protected static FailBringUp sFailBringUp = new FailBringUp();
-
-    // The static intent receiver one for all instances.
-    protected static BroadcastReceiver sIntentReceiver = new BroadcastReceiver ()
-    {
-        @Override
-        public void onReceive(Context context, Intent intent)
-        {
-            String action = intent.getAction();
-            if (DBG) sDcLog("sIntentReceiver.onReceive: action=" + action);
-            if (action.equals(sActionFailBringUp)) {
-                sFailBringUp.getEiParameters(intent, "sFailBringUp");
-            } else {
-                if (DBG) sDcLog("onReceive: unknown action=" + action);
-            }
-        }
-    };
-
-    // This is the per instance FailBringUP used to cause one DC to "fail" a bringUp.
-    // Here is an example that sets counter to 2 and cause to -3 for GsmDC-2:
-    //
-    // adb shell am broadcast \
-    //  -a com.android.internal.telephony.GsmDC-2.action_fail_bringup \
-    //  --ei counter 2 --ei fail_cause -3
-    //
-    // Also you can add a suggested retry time if desired:
-    //  --ei suggested_retry_time 5000
-    protected FailBringUp mFailBringUp = new FailBringUp();
-
-    protected BroadcastReceiver mIntentReceiver = new BroadcastReceiver ()
-    {
-        @Override
-        public void onReceive(Context context, Intent intent)
-        {
-            String action = intent.getAction();
-            if (DBG) log("mIntentReceiver.onReceive: action=" + action);
-            if (DBG_FAILURE && action.equals(mActionFailBringUp)) {
-                mFailBringUp.getEiParameters(intent, "mFailBringUp");
-            } else {
-                if (DBG) log("onReceive: unknown action=" + action);
-            }
-        }
-    };
-
-    /**
-     * Do the on connect or fake it if an error
-     */
-    protected void doOnConnect(ConnectionParams cp) {
-        // Check if we should fake an error.
-        if (sFailBringUp.counter  > 0) {
-            DataCallState response = new DataCallState();
-            response.version = mPhone.mCi.getRilVersion();
-            response.status = sFailBringUp.failCause.getErrorCode();
-            response.cid = 0;
-            response.active = 0;
-            response.type = "";
-            response.ifname = "";
-            response.addresses = new String[0];
-            response.dnses = new String[0];
-            response.gateways = new String[0];
-            response.suggestedRetryTime = sFailBringUp.suggestedRetryTime;
-
-            Message msg = obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE, cp);
-            AsyncResult.forMessage(msg, response, null);
-            sendMessage(msg);
-            if (DBG) {
-                log("doOnConnect: sFailBringUp.counter=" + sFailBringUp.counter +
-                        " send error response=" + response);
-            }
-            sFailBringUp.counter -= 1;
-            return;
-        }
-        if (mFailBringUp.counter > 0) {
-            DataCallState response = new DataCallState();
-            response.version = mPhone.mCi.getRilVersion();
-            response.status = mFailBringUp.failCause.getErrorCode();
-            response.cid = 0;
-            response.active = 0;
-            response.type = "";
-            response.ifname = "";
-            response.addresses = new String[0];
-            response.dnses = new String[0];
-            response.gateways = new String[0];
-            response.suggestedRetryTime = mFailBringUp.suggestedRetryTime;
-
-            Message msg = obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE, cp);
-            AsyncResult.forMessage(msg, response, null);
-            sendMessage(msg);
-            if (DBG) {
-                log("doOnConnect: mFailBringUp.counter=" + mFailBringUp.counter +
-                        " send error response=" + response);
-            }
-            mFailBringUp.counter -= 1;
-            return;
-        }
-
-        // Else do the normal onConnection
-        onConnect(cp);
-    }
-
-    public static class CallSetupException extends Exception {
-        private int mRetryOverride = -1;
-
-        CallSetupException (int retryOverride) {
-            mRetryOverride = retryOverride;
-        }
-
-        public int getRetryOverride() {
-            return mRetryOverride;
-        }
-    }
-
-    // ***** Event codes for driving the state machine
-    protected static final int BASE = Protocol.BASE_DATA_CONNECTION;
-    protected static final int EVENT_CONNECT = BASE + 0;
-    protected static final int EVENT_SETUP_DATA_CONNECTION_DONE = BASE + 1;
-    protected static final int EVENT_GET_LAST_FAIL_DONE = BASE + 2;
-    protected static final int EVENT_DEACTIVATE_DONE = BASE + 3;
-    protected static final int EVENT_DISCONNECT = BASE + 4;
-    protected static final int EVENT_RIL_CONNECTED = BASE + 5;
-    protected static final int EVENT_DISCONNECT_ALL = BASE + 6;
-
-    private static final int CMD_TO_STRING_COUNT = EVENT_DISCONNECT_ALL - BASE + 1;
-    private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT];
-    static {
-        sCmdToString[EVENT_CONNECT - BASE] = "EVENT_CONNECT";
-        sCmdToString[EVENT_SETUP_DATA_CONNECTION_DONE - BASE] =
-                "EVENT_SETUP_DATA_CONNECTION_DONE";
-        sCmdToString[EVENT_GET_LAST_FAIL_DONE - BASE] = "EVENT_GET_LAST_FAIL_DONE";
-        sCmdToString[EVENT_DEACTIVATE_DONE - BASE] = "EVENT_DEACTIVATE_DONE";
-        sCmdToString[EVENT_DISCONNECT - BASE] = "EVENT_DISCONNECT";
-        sCmdToString[EVENT_RIL_CONNECTED - BASE] = "EVENT_RIL_CONNECTED";
-        sCmdToString[EVENT_DISCONNECT_ALL - BASE] = "EVENT_DISCONNECT_ALL";
-    }
-    protected static String cmdToString(int cmd) {
-        cmd -= BASE;
-        if ((cmd >= 0) && (cmd < sCmdToString.length)) {
-            return sCmdToString[cmd];
-        } else {
-            return null;
-        }
-    }
-
-    //***** Tag IDs for EventLog
-    protected static final int EVENT_LOG_BAD_DNS_ADDRESS = 50100;
-
-    //***** Member Variables
-    protected ApnSetting mApn;
-    protected int mTag;
-    protected PhoneBase mPhone;
-    protected int mRilVersion = -1;
-    protected int mCid;
-    protected LinkProperties mLinkProperties = new LinkProperties();
-    protected LinkCapabilities mCapabilities = new LinkCapabilities();
-    protected long mCreateTime;
-    protected long mLastFailTime;
-    protected FailCause mLastFailCause;
-    protected int mRetryOverride = -1;
-    protected static final String NULL_IP = "0.0.0.0";
-    Object mUserData;
-
-    //***** Abstract methods
-    @Override
-    public abstract String toString();
-
-    // A Non recursive toString
-    public String toStringSimple() {
-        return toString();
-    }
-
-    protected abstract void onConnect(ConnectionParams cp);
-
-    protected abstract boolean isDnsOk(String[] domainNameServers);
-
-   //***** Constructor
-    protected DataConnectionBase(PhoneBase phone, String name, int id, RetryManager rm,
-            DataConnectionTrackerBase dct) {
-        super(name);
-        setLogRecSize(300);
-        setLogOnlyTransitions(true);
-        if (DBG) log("DataConnectionBase constructor E");
-        mPhone = phone;
-        mDataConnectionTracker = dct;
-        mId = id;
-        mRetryMgr = rm;
-        mCid = -1;
-
-        if (DBG_FAILURE) {
-            IntentFilter filter;
-
-            synchronized (DataConnectionBase.class) {
-                // Register the static Intent receiver once
-                if (sActionFailBringUp == null) {
-                    sActionFailBringUp = INTENT_BASE + ".DC." +
-                            FailBringUp.ACTION_FAIL_BRINGUP;
-
-                    filter = new IntentFilter();
-                    filter.addAction(sActionFailBringUp);
-                    phone.getContext().registerReceiver(sIntentReceiver, filter, null, phone);
-                    log("DataConnectionBase: register sActionFailBringUp=" + sActionFailBringUp);
-                }
-            }
-
-            // Register the per instance Intent receiver
-            mActionFailBringUp = INTENT_BASE + "." + getName() + "." +
-                    FailBringUp.ACTION_FAIL_BRINGUP;
-            filter = new IntentFilter();
-            filter.addAction(mActionFailBringUp);
-            phone.getContext().registerReceiver(mIntentReceiver, filter, null, phone);
-            log("DataConnectionBase: register mActionFailBringUp=" + mActionFailBringUp);
-        }
-
-        addState(mDefaultState);
-            addState(mInactiveState, mDefaultState);
-            addState(mActivatingState, mDefaultState);
-            addState(mActiveState, mDefaultState);
-            addState(mDisconnectingState, mDefaultState);
-            addState(mDisconnectingErrorCreatingConnection, mDefaultState);
-        setInitialState(mInactiveState);
-
-        mApnList = new ArrayList<ApnContext>();
-        if (DBG) log("DataConnectionBase constructor X");
-    }
-
-    /**
-     * Shut down this instance and its state machine.
-     */
-    private void shutDown() {
-        if (DBG) log("shutDown");
-
-        if (mAc != null) {
-            mAc.disconnected();
-            mAc = null;
-        }
-        mApnList = null;
-        mReconnectIntent = null;
-        mDataConnectionTracker = null;
-        mApn = null;
-        mPhone = null;
-        mLinkProperties = null;
-        mCapabilities = null;
-        mLastFailCause = null;
-        mUserData = null;
-    }
-
-    /**
-     * TearDown the data connection.
-     *
-     * @param o will be returned in AsyncResult.userObj
-     *          and is either a DisconnectParams or ConnectionParams.
-     */
-    private void tearDownData(Object o) {
-        int discReason = RILConstants.DEACTIVATE_REASON_NONE;
-        if ((o != null) && (o instanceof DisconnectParams)) {
-            DisconnectParams dp = (DisconnectParams)o;
-            Message m = dp.mOnCompletedMsg;
-            if (TextUtils.equals(dp.mReason, Phone.REASON_RADIO_TURNED_OFF)) {
-                discReason = RILConstants.DEACTIVATE_REASON_RADIO_OFF;
-            } else if (TextUtils.equals(dp.mReason, Phone.REASON_PDP_RESET)) {
-                discReason = RILConstants.DEACTIVATE_REASON_PDP_RESET;
-            }
-        }
-        if (mPhone.mCi.getRadioState().isOn()) {
-            if (DBG) log("tearDownData radio is on, call deactivateDataCall");
-            mPhone.mCi.deactivateDataCall(mCid, discReason, obtainMessage(EVENT_DEACTIVATE_DONE, o));
-        } else {
-            if (DBG) log("tearDownData radio is off sendMessage EVENT_DEACTIVATE_DONE immediately");
-            AsyncResult ar = new AsyncResult(o, null, null);
-            sendMessage(obtainMessage(EVENT_DEACTIVATE_DONE, ar));
-        }
-    }
-
-    /**
-     * Send the connectionCompletedMsg.
-     *
-     * @param cp is the ConnectionParams
-     * @param cause
-     */
-    private void notifyConnectCompleted(ConnectionParams cp, FailCause cause) {
-        Message connectionCompletedMsg = cp.mOnCompletedMsg;
-        if (connectionCompletedMsg == null) {
-            return;
-        }
-
-        long timeStamp = System.currentTimeMillis();
-        connectionCompletedMsg.arg1 = mCid;
-
-        if (cause == FailCause.NONE) {
-            mCreateTime = timeStamp;
-            AsyncResult.forMessage(connectionCompletedMsg);
-        } else {
-            mLastFailCause = cause;
-            mLastFailTime = timeStamp;
-            AsyncResult.forMessage(connectionCompletedMsg, cause,
-                                   new CallSetupException(mRetryOverride));
-        }
-        if (DBG) log("notifyConnectionCompleted at " + timeStamp + " cause=" + cause);
-
-        connectionCompletedMsg.sendToTarget();
-    }
-
-    /**
-     * Send ar.userObj if its a message, which is should be back to originator.
-     *
-     * @param dp is the DisconnectParams.
-     */
-    private void notifyDisconnectCompleted(DisconnectParams dp, boolean sendAll) {
-        if (VDBG) log("NotifyDisconnectCompleted");
-
-        ApnContext alreadySent = null;
-        String reason = null;
-
-        if (dp.mOnCompletedMsg != null) {
-            // Get ApnContext, but only valid on GSM devices this is a string on CDMA devices.
-            Message msg = dp.mOnCompletedMsg;
-            if (msg.obj instanceof ApnContext) {
-                alreadySent = (ApnContext)msg.obj;
-            }
-            reason = dp.mReason;
-            if (VDBG) {
-                log(String.format("msg=%s msg.obj=%s", msg.toString(),
-                    ((msg.obj instanceof String) ? (String) msg.obj : "<no-reason>")));
-            }
-            AsyncResult.forMessage(msg);
-            msg.sendToTarget();
-        }
-        if (sendAll) {
-            for (ApnContext a : mApnList) {
-                if (a == alreadySent) continue;
-                if (reason != null) a.setReason(reason);
-                Message msg = mDataConnectionTracker.obtainMessage(
-                        DctConstants.EVENT_DISCONNECT_DONE, a);
-                AsyncResult.forMessage(msg);
-                msg.sendToTarget();
-            }
-        }
-
-        if (DBG) log("NotifyDisconnectCompleted DisconnectParams=" + dp);
-    }
-
-    protected int getRilRadioTechnology() {
-        int rilRadioTechnology;
-        if (mApn.bearer > 0) {
-            rilRadioTechnology = mApn.bearer + 2;
-        } else {
-            rilRadioTechnology = mPhone.getServiceState().getRilDataRadioTechnology() + 2;
-        }
-        return rilRadioTechnology;
-    }
-
-    /*
-     * **************************************************************************
-     * Begin Members and methods owned by DataConnectionTracker but stored
-     * in a DataConnectionBase because there is one per connection.
-     * **************************************************************************
-     */
-
-    /*
-     * The id is owned by DataConnectionTracker.
-     */
-    private int mId;
-
-    /**
-     * Get the DataConnection ID
-     */
-    public int getDataConnectionId() {
-        return mId;
-    }
-
-    /*
-     * The retry manager is currently owned by the DataConnectionTracker but is stored
-     * in the DataConnection because there is one per connection. These methods
-     * should only be used by the DataConnectionTracker although someday the retrying
-     * maybe managed by the DataConnection itself and these methods could disappear.
-     */
-    private RetryManager mRetryMgr;
-
-    /**
-     * @return retry manager retryCount
-     */
-    public int getRetryCount() {
-        return mRetryMgr.getRetryCount();
-    }
-
-    /**
-     * set retry manager retryCount
-     */
-    public void setRetryCount(int retryCount) {
-        if (DBG) log("setRetryCount: " + retryCount);
-        mRetryMgr.setRetryCount(retryCount);
-    }
-
-    /**
-     * @return retry manager retryTimer
-     */
-    public int getRetryTimer() {
-        return mRetryMgr.getRetryTimer();
-    }
-
-    /**
-     * increaseRetryCount of retry manager
-     */
-    public void increaseRetryCount() {
-        mRetryMgr.increaseRetryCount();
-    }
-
-    /**
-     * @return retry manager isRetryNeeded
-     */
-    public boolean isRetryNeeded() {
-        return mRetryMgr.isRetryNeeded();
-    }
-
-    /**
-     * resetRetryCount of retry manager
-     */
-    public void resetRetryCount() {
-        mRetryMgr.resetRetryCount();
-    }
-
-    /**
-     * set retryForeverUsingLasttimeout of retry manager
-     */
-    public void retryForeverUsingLastTimeout() {
-        mRetryMgr.retryForeverUsingLastTimeout();
-    }
-
-    /**
-     * @return retry manager isRetryForever
-     */
-    public boolean isRetryForever() {
-        return mRetryMgr.isRetryForever();
-    }
-
-    /**
-     * @return whether the retry config is set successfully or not
-     */
-    public boolean configureRetry(int maxRetryCount, int retryTime, int randomizationTime) {
-        return mRetryMgr.configure(maxRetryCount, retryTime, randomizationTime);
-    }
-
-    /**
-     * @return whether the retry config is set successfully or not
-     */
-    public boolean configureRetry(String configStr) {
-        return mRetryMgr.configure(configStr);
-    }
-
-    /*
-     * **************************************************************************
-     * End members owned by DataConnectionTracker
-     * **************************************************************************
-     */
-
-    /**
-     * Clear all settings called when entering mInactiveState.
-     */
-    protected void clearSettings() {
-        if (DBG) log("clearSettings");
-
-        mCreateTime = -1;
-        mLastFailTime = -1;
-        mLastFailCause = FailCause.NONE;
-        mRetryOverride = -1;
-        mCid = -1;
-
-        mLinkProperties = new LinkProperties();
-        mApnList.clear();
-        mApn = null;
-    }
-
-    /**
-     * Process setup completion.
-     *
-     * @param ar is the result
-     * @return SetupResult.
-     */
-    private DataCallState.SetupResult onSetupConnectionCompleted(AsyncResult ar) {
-        DataCallState response = (DataCallState) ar.result;
-        ConnectionParams cp = (ConnectionParams) ar.userObj;
-        DataCallState.SetupResult result;
-
-        if (ar.exception != null) {
-            if (DBG) {
-                log("onSetupConnectionCompleted failed, ar.exception=" + ar.exception +
-                    " response=" + response);
-            }
-
-            if (ar.exception instanceof CommandException
-                    && ((CommandException) (ar.exception)).getCommandError()
-                    == CommandException.Error.RADIO_NOT_AVAILABLE) {
-                result = DataCallState.SetupResult.ERR_BadCommand;
-                result.mFailCause = FailCause.RADIO_NOT_AVAILABLE;
-            } else if ((response == null) || (response.version < 4)) {
-                result = DataCallState.SetupResult.ERR_GetLastErrorFromRil;
-            } else {
-                result = DataCallState.SetupResult.ERR_RilError;
-                result.mFailCause = FailCause.fromInt(response.status);
-            }
-        } else if (cp.mTheTag != mTag) {
-            if (DBG) {
-                log("BUG: onSetupConnectionCompleted is stale cp.tag=" + cp.mTheTag + ", mtag=" + mTag);
-            }
-            result = DataCallState.SetupResult.ERR_Stale;
-        } else if (response.status != 0) {
-            result = DataCallState.SetupResult.ERR_RilError;
-            result.mFailCause = FailCause.fromInt(response.status);
-        } else {
-            if (DBG) log("onSetupConnectionCompleted received DataCallState: " + response);
-            mCid = response.cid;
-            result = updateLinkProperty(response).setupResult;
-        }
-
-        return result;
-    }
-
-    private int getSuggestedRetryTime(AsyncResult ar) {
-        int retry = -1;
-        if (ar.exception == null) {
-            DataCallState response = (DataCallState) ar.result;
-            retry =  response.suggestedRetryTime;
-        }
-        return retry;
-    }
-
-    private DataCallState.SetupResult setLinkProperties(DataCallState response,
-            LinkProperties lp) {
-        // Check if system property dns usable
-        boolean okToUseSystemPropertyDns = false;
-        String propertyPrefix = "net." + response.ifname + ".";
-        String dnsServers[] = new String[2];
-        dnsServers[0] = SystemProperties.get(propertyPrefix + "dns1");
-        dnsServers[1] = SystemProperties.get(propertyPrefix + "dns2");
-        okToUseSystemPropertyDns = isDnsOk(dnsServers);
-
-        // set link properties based on data call response
-        return response.setLinkProperties(lp, okToUseSystemPropertyDns);
-    }
-
-    public static class UpdateLinkPropertyResult {
-        public DataCallState.SetupResult setupResult = DataCallState.SetupResult.SUCCESS;
-        public LinkProperties oldLp;
-        public LinkProperties newLp;
-        public UpdateLinkPropertyResult(LinkProperties curLp) {
-            oldLp = curLp;
-            newLp = curLp;
-        }
-    }
-
-    private UpdateLinkPropertyResult updateLinkProperty(DataCallState newState) {
-        UpdateLinkPropertyResult result = new UpdateLinkPropertyResult(mLinkProperties);
-
-        if (newState == null) return result;
-
-        DataCallState.SetupResult setupResult;
-        result.newLp = new LinkProperties();
-
-        // set link properties based on data call response
-        result.setupResult = setLinkProperties(newState, result.newLp);
-        if (result.setupResult != DataCallState.SetupResult.SUCCESS) {
-            if (DBG) log("updateLinkProperty failed : " + result.setupResult);
-            return result;
-        }
-        // copy HTTP proxy as it is not part DataCallState.
-        result.newLp.setHttpProxy(mLinkProperties.getHttpProxy());
-
-        if (DBG && (! result.oldLp.equals(result.newLp))) {
-            log("updateLinkProperty old LP=" + result.oldLp);
-            log("updateLinkProperty new LP=" + result.newLp);
-        }
-        mLinkProperties = result.newLp;
-
-        return result;
-    }
-
-    /**
-     * The parent state for all other states.
-     */
-    private class DcDefaultState extends State {
-        @Override
-        public void enter() {
-            mPhone.mCi.registerForRilConnected(getHandler(), EVENT_RIL_CONNECTED, null);
-        }
-        @Override
-        public void exit() {
-            mPhone.mCi.unregisterForRilConnected(getHandler());
-            shutDown();
-        }
-        @Override
-        public boolean processMessage(Message msg) {
-            boolean retVal = HANDLED;
-            AsyncResult ar;
-
-            if (VDBG) {
-                log("DcDefault msg=0x" + Integer.toHexString(msg.what)
-                        + " RefCount=" + mApnList.size());
-            }
-            switch (msg.what) {
-                case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
-                    if (mAc != null) {
-                        if (VDBG) log("Disconnecting to previous connection mAc=" + mAc);
-                        mAc.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
-                                AsyncChannel.STATUS_FULL_CONNECTION_REFUSED_ALREADY_CONNECTED);
-                    } else {
-                        mAc = new AsyncChannel();
-                        mAc.connected(null, getHandler(), msg.replyTo);
-                        if (VDBG) log("DcDefaultState: FULL_CONNECTION reply connected");
-                        mAc.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
-                                AsyncChannel.STATUS_SUCCESSFUL, mId, "hi");
-                    }
-                    break;
-                }
-                case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
-                    if (VDBG) log("CMD_CHANNEL_DISCONNECTED");
-                    quit();
-                    break;
-                }
-                case DataConnectionAc.REQ_IS_INACTIVE: {
-                    boolean val = getCurrentState() == mInactiveState;
-                    if (VDBG) log("REQ_IS_INACTIVE  isInactive=" + val);
-                    mAc.replyToMessage(msg, DataConnectionAc.RSP_IS_INACTIVE, val ? 1 : 0);
-                    break;
-                }
-                case DataConnectionAc.REQ_GET_CID: {
-                    if (VDBG) log("REQ_GET_CID  cid=" + mCid);
-                    mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_CID, mCid);
-                    break;
-                }
-                case DataConnectionAc.REQ_GET_APNSETTING: {
-                    if (VDBG) log("REQ_GET_APNSETTING  apnSetting=" + mApn);
-                    mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_APNSETTING, mApn);
-                    break;
-                }
-                case DataConnectionAc.REQ_GET_LINK_PROPERTIES: {
-                    LinkProperties lp = new LinkProperties(mLinkProperties);
-                    if (VDBG) log("REQ_GET_LINK_PROPERTIES linkProperties" + lp);
-                    mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_LINK_PROPERTIES, lp);
-                    break;
-                }
-                case DataConnectionAc.REQ_SET_LINK_PROPERTIES_HTTP_PROXY: {
-                    ProxyProperties proxy = (ProxyProperties) msg.obj;
-                    if (VDBG) log("REQ_SET_LINK_PROPERTIES_HTTP_PROXY proxy=" + proxy);
-                    mLinkProperties.setHttpProxy(proxy);
-                    mAc.replyToMessage(msg, DataConnectionAc.RSP_SET_LINK_PROPERTIES_HTTP_PROXY);
-                    break;
-                }
-                case DataConnectionAc.REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE: {
-                    DataCallState newState = (DataCallState) msg.obj;
-                    UpdateLinkPropertyResult result =
-                                             updateLinkProperty(newState);
-                    if (VDBG) {
-                        log("REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE result="
-                            + result + " newState=" + newState);
-                    }
-                    mAc.replyToMessage(msg,
-                                   DataConnectionAc.RSP_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE,
-                                   result);
-                    break;
-                }
-                case DataConnectionAc.REQ_GET_LINK_CAPABILITIES: {
-                    LinkCapabilities lc = new LinkCapabilities(mCapabilities);
-                    if (VDBG) log("REQ_GET_LINK_CAPABILITIES linkCapabilities" + lc);
-                    mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_LINK_CAPABILITIES, lc);
-                    break;
-                }
-                case DataConnectionAc.REQ_RESET:
-                    if (VDBG) log("DcDefaultState: msg.what=REQ_RESET");
-                    mAc.replyToMessage(msg, DataConnectionAc.RSP_RESET);
-                    transitionTo(mInactiveState);
-                    break;
-                case DataConnectionAc.REQ_GET_REFCOUNT: {
-                    if (VDBG) log("REQ_GET_REFCOUNT  RefCount=" + mApnList.size());
-                    mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_REFCOUNT, mApnList.size());
-                    break;
-                }
-                case DataConnectionAc.REQ_GET_APNCONTEXT_LIST: {
-                    if (VDBG) log("REQ_GET_APNCONTEXT_LIST num in list=" + mApnList.size());
-                    mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_APNCONTEXT_LIST,
-                                       new ArrayList<ApnContext>(mApnList));
-                    break;
-                }
-                case DataConnectionAc.REQ_SET_RECONNECT_INTENT: {
-                    PendingIntent intent = (PendingIntent) msg.obj;
-                    if (VDBG) log("REQ_SET_RECONNECT_INTENT");
-                    mReconnectIntent = intent;
-                    mAc.replyToMessage(msg, DataConnectionAc.RSP_SET_RECONNECT_INTENT);
-                    break;
-                }
-                case DataConnectionAc.REQ_GET_RECONNECT_INTENT: {
-                    if (VDBG) log("REQ_GET_RECONNECT_INTENT");
-                    mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_RECONNECT_INTENT,
-                                       mReconnectIntent);
-                    break;
-                }
-                case EVENT_CONNECT:
-                    if (DBG) log("DcDefaultState: msg.what=EVENT_CONNECT, fail not expected");
-                    ConnectionParams cp = (ConnectionParams) msg.obj;
-                    notifyConnectCompleted(cp, FailCause.UNKNOWN);
-                    break;
-
-                case EVENT_DISCONNECT:
-                    if (DBG) {
-                        log("DcDefaultState deferring msg.what=EVENT_DISCONNECT RefCount="
-                                + mApnList.size());
-                    }
-                    deferMessage(msg);
-                    break;
-
-                case EVENT_DISCONNECT_ALL:
-                    if (DBG) {
-                        log("DcDefaultState deferring msg.what=EVENT_DISCONNECT_ALL RefCount="
-                                + mApnList.size());
-                    }
-                    deferMessage(msg);
-                    break;
-
-                case EVENT_RIL_CONNECTED:
-                    ar = (AsyncResult)msg.obj;
-                    if (ar.exception == null) {
-                        mRilVersion = (Integer)ar.result;
-                        if (DBG) {
-                            log("DcDefaultState: msg.what=EVENT_RIL_CONNECTED mRilVersion=" +
-                                mRilVersion);
-                        }
-                    } else {
-                        log("Unexpected exception on EVENT_RIL_CONNECTED");
-                        mRilVersion = -1;
-                    }
-                    break;
-
-                default:
-                    if (DBG) {
-                        log("DcDefaultState: shouldn't happen but ignore msg.what=0x" +
-                                Integer.toHexString(msg.what));
-                    }
-                    break;
-            }
-
-            return retVal;
-        }
-    }
-    private DcDefaultState mDefaultState = new DcDefaultState();
-
-    /**
-     * The state machine is inactive and expects a EVENT_CONNECT.
-     */
-    private class DcInactiveState extends State {
-        private ConnectionParams mConnectionParams = null;
-        private FailCause mFailCause = null;
-        private DisconnectParams mDisconnectParams = null;
-
-        public void setEnterNotificationParams(ConnectionParams cp, FailCause cause,
-                                               int retryOverride) {
-            if (VDBG) log("DcInactiveState: setEnterNoticationParams cp,cause");
-            mConnectionParams = cp;
-            mFailCause = cause;
-            mRetryOverride = retryOverride;
-        }
-
-        public void setEnterNotificationParams(DisconnectParams dp) {
-            if (VDBG) log("DcInactiveState: setEnterNoticationParams dp");
-            mDisconnectParams = dp;
-        }
-
-        @Override
-        public void enter() {
-            mTag += 1;
-
-            /**
-             * Now that we've transitioned to Inactive state we
-             * can send notifications. Previously we sent the
-             * notifications in the processMessage handler but
-             * that caused a race condition because the synchronous
-             * call to isInactive.
-             */
-            if ((mConnectionParams != null) && (mFailCause != null)) {
-                if (VDBG) log("DcInactiveState: enter notifyConnectCompleted");
-                notifyConnectCompleted(mConnectionParams, mFailCause);
-            }
-            if (mDisconnectParams != null) {
-                if (VDBG) log("DcInactiveState: enter notifyDisconnectCompleted");
-                notifyDisconnectCompleted(mDisconnectParams, true);
-            }
-            clearSettings();
-        }
-
-        @Override
-        public void exit() {
-            // clear notifications
-            mConnectionParams = null;
-            mFailCause = null;
-            mDisconnectParams = null;
-        }
-
-        @Override
-        public boolean processMessage(Message msg) {
-            boolean retVal;
-
-            switch (msg.what) {
-                case DataConnectionAc.REQ_RESET:
-                    if (DBG) {
-                        log("DcInactiveState: msg.what=RSP_RESET, ignore we're already reset");
-                    }
-                    mAc.replyToMessage(msg, DataConnectionAc.RSP_RESET);
-                    retVal = HANDLED;
-                    break;
-
-                case EVENT_CONNECT:
-                    ConnectionParams cp = (ConnectionParams) msg.obj;
-                    mApnList.add(cp.mApnContext);
-                    cp.mTheTag = mTag;
-                    if (DBG) {
-                        log("DcInactiveState msg.what=EVENT_CONNECT " + "RefCount="
-                                + mApnList.size());
-                    }
-                    doOnConnect(cp);
-                    transitionTo(mActivatingState);
-                    retVal = HANDLED;
-                    break;
-
-                case EVENT_DISCONNECT:
-                    if (DBG) log("DcInactiveState: msg.what=EVENT_DISCONNECT");
-                    notifyDisconnectCompleted((DisconnectParams)msg.obj, false);
-                    retVal = HANDLED;
-                    break;
-
-                case EVENT_DISCONNECT_ALL:
-                    if (DBG) log("DcInactiveState: msg.what=EVENT_DISCONNECT_ALL");
-                    notifyDisconnectCompleted((DisconnectParams)msg.obj, false);
-                    retVal = HANDLED;
-                    break;
-
-                default:
-                    if (VDBG) {
-                        log("DcInactiveState nothandled msg.what=0x" +
-                                Integer.toHexString(msg.what));
-                    }
-                    retVal = NOT_HANDLED;
-                    break;
-            }
-            return retVal;
-        }
-    }
-    private DcInactiveState mInactiveState = new DcInactiveState();
-
-    /**
-     * The state machine is activating a connection.
-     */
-    private class DcActivatingState extends State {
-        @Override
-        public boolean processMessage(Message msg) {
-            boolean retVal;
-            AsyncResult ar;
-            ConnectionParams cp;
-
-            switch (msg.what) {
-                case EVENT_CONNECT:
-                    if (DBG) {
-                        log("DcActivatingState deferring msg.what=EVENT_CONNECT RefCount="
-                                + mApnList.size());
-                    }
-                    deferMessage(msg);
-                    retVal = HANDLED;
-                    break;
-
-                case EVENT_SETUP_DATA_CONNECTION_DONE:
-                    if (DBG) {
-                        log("DcActivatingState msg.what=EVENT_SETUP_DATA_CONNECTION_DONE"
-                                + " RefCount=" + mApnList.size());
-                    }
-
-                    ar = (AsyncResult) msg.obj;
-                    cp = (ConnectionParams) ar.userObj;
-
-                    DataCallState.SetupResult result = onSetupConnectionCompleted(ar);
-                    if (DBG) log("DcActivatingState onSetupConnectionCompleted result=" + result);
-                    switch (result) {
-                        case SUCCESS:
-                            // All is well
-                            mActiveState.setEnterNotificationParams(cp, FailCause.NONE);
-                            transitionTo(mActiveState);
-                            break;
-                        case ERR_BadCommand:
-                            // Vendor ril rejected the command and didn't connect.
-                            // Transition to inactive but send notifications after
-                            // we've entered the mInactive state.
-                            mInactiveState.setEnterNotificationParams(cp, result.mFailCause, -1);
-                            transitionTo(mInactiveState);
-                            break;
-                        case ERR_UnacceptableParameter:
-                            // The addresses given from the RIL are bad
-                            tearDownData(cp);
-                            transitionTo(mDisconnectingErrorCreatingConnection);
-                            break;
-                        case ERR_GetLastErrorFromRil:
-                            // Request failed and this is an old RIL
-                            mPhone.mCi.getLastDataCallFailCause(
-                                    obtainMessage(EVENT_GET_LAST_FAIL_DONE, cp));
-                            break;
-                        case ERR_RilError:
-                            // Request failed and mFailCause has the reason
-                            mInactiveState.setEnterNotificationParams(cp, result.mFailCause,
-                                                                      getSuggestedRetryTime(ar));
-                            transitionTo(mInactiveState);
-                            break;
-                        case ERR_Stale:
-                            // Request is stale, ignore.
-                            break;
-                        default:
-                            throw new RuntimeException("Unknown SetupResult, should not happen");
-                    }
-                    retVal = HANDLED;
-                    break;
-
-                case EVENT_GET_LAST_FAIL_DONE:
-                    ar = (AsyncResult) msg.obj;
-                    cp = (ConnectionParams) ar.userObj;
-                    FailCause cause = FailCause.UNKNOWN;
-
-                    if (cp.mTheTag == mTag) {
-                        if (DBG) {
-                            log("DcActivatingState msg.what=EVENT_GET_LAST_FAIL_DONE"
-                                    + " RefCount=" + mApnList.size());
-                        }
-                        if (ar.exception == null) {
-                            int rilFailCause = ((int[]) (ar.result))[0];
-                            cause = FailCause.fromInt(rilFailCause);
-                        }
-                        // Transition to inactive but send notifications after
-                        // we've entered the mInactive state.
-                        mInactiveState.setEnterNotificationParams(cp, cause, -1);
-                        transitionTo(mInactiveState);
-                    } else {
-                        if (DBG) {
-                            log("DcActivatingState EVENT_GET_LAST_FAIL_DONE is stale cp.tag="
-                                + cp.mTheTag + ", mTag=" + mTag + " RefCount=" + mApnList.size());
-                        }
-                    }
-
-                    retVal = HANDLED;
-                    break;
-
-                default:
-                    if (VDBG) {
-                        log("DcActivatingState not handled msg.what=0x" +
-                                Integer.toHexString(msg.what) + " RefCount=" + mApnList.size());
-                    }
-                    retVal = NOT_HANDLED;
-                    break;
-            }
-            return retVal;
-        }
-    }
-    private DcActivatingState mActivatingState = new DcActivatingState();
-
-    /**
-     * The state machine is connected, expecting an EVENT_DISCONNECT.
-     */
-    private class DcActiveState extends State {
-        private ConnectionParams mConnectionParams = null;
-        private FailCause mFailCause = null;
-
-        public void setEnterNotificationParams(ConnectionParams cp, FailCause cause) {
-            if (VDBG) log("DcInactiveState: setEnterNoticationParams cp,cause");
-            mConnectionParams = cp;
-            mFailCause = cause;
-        }
-
-        @Override public void enter() {
-            /**
-             * Now that we've transitioned to Active state we
-             * can send notifications. Previously we sent the
-             * notifications in the processMessage handler but
-             * that caused a race condition because the synchronous
-             * call to isActive.
-             */
-            if ((mConnectionParams != null) && (mFailCause != null)) {
-                if (VDBG) log("DcActiveState: enter notifyConnectCompleted");
-                notifyConnectCompleted(mConnectionParams, mFailCause);
-            }
-        }
-
-        @Override
-        public void exit() {
-            // clear notifications
-            mConnectionParams = null;
-            mFailCause = null;
-        }
-
-        @Override
-        public boolean processMessage(Message msg) {
-            boolean retVal;
-
-            switch (msg.what) {
-                case EVENT_CONNECT: {
-                    ConnectionParams cp = (ConnectionParams) msg.obj;
-                    if (mApnList.contains(cp.mApnContext)) {
-                        log("DcActiveState ERROR already added apnContext=" + cp.mApnContext
-                                    + " to this DC=" + this);
-                    } else {
-                        mApnList.add(cp.mApnContext);
-                        if (DBG) {
-                            log("DcActiveState msg.what=EVENT_CONNECT RefCount=" + mApnList.size());
-                        }
-                    }
-                    notifyConnectCompleted(cp, FailCause.NONE);
-                    retVal = HANDLED;
-                    break;
-                }
-                case EVENT_DISCONNECT: {
-                    DisconnectParams dp = (DisconnectParams) msg.obj;
-                    if (mApnList.contains(dp.mApnContext)) {
-                        if (DBG) {
-                            log("DcActiveState msg.what=EVENT_DISCONNECT RefCount="
-                                    + mApnList.size());
-                        }
-
-                        if (mApnList.size() == 1) {
-                            mApnList.clear();
-                            dp.mTheTag = mTag;
-                            tearDownData(dp);
-                            transitionTo(mDisconnectingState);
-                        } else {
-                            mApnList.remove(dp.mApnContext);
-                            notifyDisconnectCompleted(dp, false);
-                        }
-                    } else {
-                        log("DcActiveState ERROR no such apnContext=" + dp.mApnContext
-                                + " in this DC=" + this);
-                        notifyDisconnectCompleted(dp, false);
-                    }
-                    retVal = HANDLED;
-                    break;
-                }
-                case EVENT_DISCONNECT_ALL: {
-                    if (DBG) {
-                        log("DcActiveState msg.what=EVENT_DISCONNECT_ALL RefCount="
-                                + mApnList.size() + " clearing apn contexts");
-                    }
-                    mApnList.clear();
-                    DisconnectParams dp = (DisconnectParams) msg.obj;
-                    dp.mTheTag = mTag;
-                    tearDownData(dp);
-                    transitionTo(mDisconnectingState);
-                    retVal = HANDLED;
-                    break;
-                }
-                default:
-                    if (VDBG) {
-                        log("DcActiveState not handled msg.what=0x" +
-                                Integer.toHexString(msg.what));
-                    }
-                    retVal = NOT_HANDLED;
-                    break;
-            }
-            return retVal;
-        }
-    }
-    private DcActiveState mActiveState = new DcActiveState();
-
-    /**
-     * The state machine is disconnecting.
-     */
-    private class DcDisconnectingState extends State {
-        @Override
-        public boolean processMessage(Message msg) {
-            boolean retVal;
-
-            switch (msg.what) {
-                case EVENT_CONNECT:
-                    if (DBG) log("DcDisconnectingState msg.what=EVENT_CONNECT. Defer. RefCount = "
-                            + mApnList.size());
-                    deferMessage(msg);
-                    retVal = HANDLED;
-                    break;
-
-                case EVENT_DEACTIVATE_DONE:
-                    if (DBG) log("DcDisconnectingState msg.what=EVENT_DEACTIVATE_DONE RefCount="
-                            + mApnList.size());
-                    AsyncResult ar = (AsyncResult) msg.obj;
-                    DisconnectParams dp = (DisconnectParams) ar.userObj;
-                    if (dp.mTheTag == mTag) {
-                        // Transition to inactive but send notifications after
-                        // we've entered the mInactive state.
-                        mInactiveState.setEnterNotificationParams((DisconnectParams) ar.userObj);
-                        transitionTo(mInactiveState);
-                    } else {
-                        if (DBG) log("DcDisconnectState EVENT_DEACTIVATE_DONE stale dp.tag="
-                                + dp.mTheTag + " mTag=" + mTag);
-                    }
-                    retVal = HANDLED;
-                    break;
-
-                default:
-                    if (VDBG) {
-                        log("DcDisconnectingState not handled msg.what=0x" +
-                                Integer.toHexString(msg.what));
-                    }
-                    retVal = NOT_HANDLED;
-                    break;
-            }
-            return retVal;
-        }
-    }
-    private DcDisconnectingState mDisconnectingState = new DcDisconnectingState();
-
-    /**
-     * The state machine is disconnecting after an creating a connection.
-     */
-    private class DcDisconnectionErrorCreatingConnection extends State {
-        @Override
-        public boolean processMessage(Message msg) {
-            boolean retVal;
-
-            switch (msg.what) {
-                case EVENT_DEACTIVATE_DONE:
-                    AsyncResult ar = (AsyncResult) msg.obj;
-                    ConnectionParams cp = (ConnectionParams) ar.userObj;
-                    if (cp.mTheTag == mTag) {
-                        if (DBG) {
-                            log("DcDisconnectionErrorCreatingConnection" +
-                                " msg.what=EVENT_DEACTIVATE_DONE");
-                        }
-
-                        // Transition to inactive but send notifications after
-                        // we've entered the mInactive state.
-                        mInactiveState.setEnterNotificationParams(cp,
-                                FailCause.UNACCEPTABLE_NETWORK_PARAMETER, -1);
-                        transitionTo(mInactiveState);
-                    } else {
-                        if (DBG) {
-                            log("DcDisconnectionErrorCreatingConnection EVENT_DEACTIVATE_DONE" +
-                                    " stale dp.tag=" + cp.mTheTag + ", mTag=" + mTag);
-                        }
-                    }
-                    retVal = HANDLED;
-                    break;
-
-                default:
-                    if (VDBG) {
-                        log("DcDisconnectionErrorCreatingConnection not handled msg.what=0x"
-                                + Integer.toHexString(msg.what));
-                    }
-                    retVal = NOT_HANDLED;
-                    break;
-            }
-            return retVal;
-        }
-    }
-    private DcDisconnectionErrorCreatingConnection mDisconnectingErrorCreatingConnection =
-                new DcDisconnectionErrorCreatingConnection();
-
-    // ******* public interface
-
-    /**
-     * Bring up a connection to the apn and return an AsyncResult in onCompletedMsg.
-     * Used for cellular networks that use Acesss Point Names (APN) such
-     * as GSM networks.
-     *
-     * @param apnContext is the Access Point Name to bring up a connection to
-     * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
-     *        With AsyncResult.userObj set to the original msg.obj,
-     *        AsyncResult.result = FailCause and AsyncResult.exception = Exception().
-     */
-    public void bringUp(ApnContext apnContext, Message onCompletedMsg) {
-        if (DBG) log("bringUp: apnContext=" + apnContext + " onCompletedMsg=" + onCompletedMsg);
-        sendMessage(obtainMessage(EVENT_CONNECT, new ConnectionParams(apnContext, onCompletedMsg)));
-    }
-
-    /**
-     * Tear down the connection through the apn on the network.
-     *
-     * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
-     *        With AsyncResult.userObj set to the original msg.obj.
-     */
-    public void tearDown(ApnContext apnContext, String reason, Message onCompletedMsg) {
-        if (DBG) {
-            log("tearDown: apnContext=" + apnContext
-                    + " reason=" + reason + " onCompletedMsg=" + onCompletedMsg);
-        }
-        sendMessage(obtainMessage(EVENT_DISCONNECT,
-                        new DisconnectParams(apnContext, reason, onCompletedMsg)));
-    }
-
-    /**
-     * Tear down the connection through the apn on the network.  Ignores refcount and
-     * and always tears down.
-     *
-     * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
-     *        With AsyncResult.userObj set to the original msg.obj.
-     */
-    public void tearDownAll(String reason, Message onCompletedMsg) {
-        if (DBG) log("tearDownAll: reason=" + reason + " onCompletedMsg=" + onCompletedMsg);
-        sendMessage(obtainMessage(EVENT_DISCONNECT_ALL,
-                new DisconnectParams(null, reason, onCompletedMsg)));
-    }
-
-    /**
-     * @return the string for msg.what as our info.
-     */
-    @Override
-    protected String getWhatToString(int what) {
-        String info = null;
-        info = cmdToString(what);
-        if (info == null) {
-            info = DataConnectionAc.cmdToString(what);
-        }
-        return info;
-    }
-
-    /**
-     * Dump the current state.
-     *
-     * @param fd
-     * @param pw
-     * @param args
-     */
-    @Override
-    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        pw.print("DataConnectionBase ");
-        super.dump(fd, pw, args);
-        pw.println(" mApnContexts.size=" + mApnList.size());
-        pw.println(" mApnContexts=" + mApnList);
-        pw.flush();
-        pw.println(" mDataConnectionTracker=" + mDataConnectionTracker);
-        pw.println(" mApn=" + mApn);
-        pw.println(" mTag=" + mTag);
-        pw.flush();
-        pw.println(" mPhone=" + mPhone);
-        pw.println(" mRilVersion=" + mRilVersion);
-        pw.println(" mCid=" + mCid);
-        pw.flush();
-        pw.println(" mLinkProperties=" + mLinkProperties);
-        pw.flush();
-        pw.println(" mCapabilities=" + mCapabilities);
-        pw.println(" mCreateTime=" + TimeUtils.logTimeOfDay(mCreateTime));
-        pw.println(" mLastFailTime=" + TimeUtils.logTimeOfDay(mLastFailTime));
-        pw.println(" mLastFailCause=" + mLastFailCause);
-        pw.flush();
-        pw.println(" mRetryOverride=" + mRetryOverride);
-        pw.println(" mUserData=" + mUserData);
-        if (mRetryMgr != null) pw.println(" " + mRetryMgr);
-        pw.flush();
-    }
-}
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataConnectionTracker.java b/src/java/com/android/internal/telephony/dataconnection/DataConnectionTracker.java
index d9a7bf4..2730706 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataConnectionTracker.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataConnectionTracker.java
@@ -27,10 +27,8 @@
 import android.database.ContentObserver;
 import android.database.Cursor;
 import android.net.ConnectivityManager;
-import android.net.LinkAddress;
 import android.net.LinkCapabilities;
 import android.net.LinkProperties;
-import android.net.LinkProperties.CompareResult;
 import android.net.NetworkConfig;
 import android.net.NetworkUtils;
 import android.net.ProxyProperties;
@@ -52,20 +50,11 @@
 
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneBase;
-import com.android.internal.telephony.dataconnection.ApnContext;
-import com.android.internal.telephony.dataconnection.ApnSetting;
-import com.android.internal.telephony.DataCallState;
-import com.android.internal.telephony.dataconnection.DataConnectionBase;
-import com.android.internal.telephony.dataconnection.DataConnectionBase.FailCause;
-import com.android.internal.telephony.dataconnection.DataConnectionBase.UpdateLinkPropertyResult;
-import com.android.internal.telephony.dataconnection.DataConnectionAc;
-import com.android.internal.telephony.dataconnection.DataConnectionTrackerBase;
 import com.android.internal.telephony.DctConstants;
 import com.android.internal.telephony.EventLogTags;
 import com.android.internal.telephony.gsm.GSMPhone;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.RILConstants;
-import com.android.internal.telephony.RetryManager;
 import com.android.internal.telephony.uicc.IccRecords;
 import com.android.internal.telephony.uicc.UiccController;
 import com.android.internal.util.AsyncChannel;
@@ -73,9 +62,7 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.HashMap;
-import java.util.List;
 
 /**
  * {@hide}
@@ -104,69 +91,17 @@
 
     //***** Constants
 
+    // Used by puppetmaster/*/radio_stress.py
+    private static final String PUPPET_MASTER_RADIO_STRESS_TEST = "gsm.defaultpdpcontext.active";
+
     private static final int POLL_PDP_MILLIS = 5 * 1000;
 
-    private static final String INTENT_RECONNECT_ALARM =
-        "com.android.internal.telephony.gprs-reconnect";
-    private static final String INTENT_RECONNECT_ALARM_EXTRA_TYPE = "reconnect_alarm_extra_type";
-    private static final String INTENT_RECONNECT_ALARM_EXTRA_RETRY_COUNT =
-        "reconnect_alaram_extra_retry_count";
-
-    private static final String INTENT_DATA_STALL_ALARM =
-        "com.android.internal.telephony.gprs-data-stall";
-
     static final Uri PREFERAPN_NO_UPDATE_URI =
                         Uri.parse("content://telephony/carriers/preferapn_no_update");
     static final String APN_ID = "apn_id";
+
     private boolean mCanSetPreferApn = false;
 
-    @Override
-    protected void onActionIntentReconnectAlarm(Intent intent) {
-        String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON);
-        String apnType = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE);
-        int retryCount = intent.getIntExtra(INTENT_RECONNECT_ALARM_EXTRA_RETRY_COUNT, 0);
-
-        ApnContext apnContext = mApnContexts.get(apnType);
-
-        if (DBG) {
-            log("onActionIntentReconnectAlarm: mState=" + mState + " reason=" + reason +
-                    " retryCount=" + retryCount +
-                    " apnType=" + apnType + " apnContext=" + apnContext +
-                    " mDataConnectionAsyncChannels=" + mDataConnectionAsyncChannels);
-        }
-
-        if ((apnContext != null) && (apnContext.isEnabled())) {
-            apnContext.setReason(reason);
-            apnContext.setRetryCount(retryCount);
-            DctConstants.State apnContextState = apnContext.getState();
-            if (DBG) {
-                log("onActionIntentReconnectAlarm: apnContext state=" + apnContextState);
-            }
-            if ((apnContextState == DctConstants.State.FAILED)
-                    || (apnContextState == DctConstants.State.IDLE)) {
-                if (DBG) {
-                    log("onActionIntentReconnectAlarm: state is FAILED|IDLE, disassociate");
-                }
-                apnContext.setDataConnectionAc(null);
-                apnContext.setDataConnection(null);
-                apnContext.setState(DctConstants.State.IDLE);
-            } else {
-                if (DBG) log("onActionIntentReconnectAlarm: keep associated");
-            }
-            // TODO: IF already associated should we send the EVENT_TRY_SETUP_DATA???
-            sendMessage(obtainMessage(DctConstants.EVENT_TRY_SETUP_DATA, apnContext));
-
-            DataConnectionAc dcac = apnContext.getDataConnectionAc();
-            if (dcac != null) {
-                Collection<ApnContext> apnList = dcac.getApnListSync();
-                log("onActionIntentReconnectAlarm: dcac.getApnListSync()=" + apnList);
-                // Alarm had expired. Clear pending intent recorded on the DataConnection.
-                // TODO: Maybe store in apnContext????
-                dcac.setReconnectIntentSync(null);
-            }
-        }
-    }
-
     /** Watches for changes to the APN db. */
     private ApnChangeObserver mApnObserver;
 
@@ -239,7 +174,7 @@
         ApnContext apnContext = mApnContexts.get(type);
         if (apnContext == null) return false;
 
-        return (apnContext.getDataConnection() != null);
+        return (apnContext.getDcAc() != null);
     }
 
     @Override
@@ -255,7 +190,7 @@
         boolean dataAllowed = isDataAllowed();
         boolean possible = dataAllowed && apnTypePossible;
 
-        if (DBG) {
+        if (VDBG) {
             log(String.format("isDataPossible(%s): possible=%b isDataAllowed=%b " +
                     "apnTypePossible=%b apnContextisEnabled=%b apnContextState()=%s",
                     apnType, possible, dataAllowed, apnTypePossible,
@@ -269,16 +204,6 @@
         if(DBG) log("finalize");
     }
 
-    @Override
-    protected String getActionIntentReconnectAlarm() {
-        return INTENT_RECONNECT_ALARM;
-    }
-
-    @Override
-    protected String getActionIntentDataStallAlarm() {
-        return INTENT_DATA_STALL_ALARM;
-    }
-
     private ApnContext addApnContext(String type) {
         ApnContext apnContext = new ApnContext(type, LOG_TAG);
         apnContext.setDependencyMet(false);
@@ -343,7 +268,7 @@
     public LinkProperties getLinkProperties(String apnType) {
         ApnContext apnContext = mApnContexts.get(apnType);
         if (apnContext != null) {
-            DataConnectionAc dcac = apnContext.getDataConnectionAc();
+            DataConnectionAc dcac = apnContext.getDcAc();
             if (dcac != null) {
                 if (DBG) log("return link properites for " + apnType);
                 return dcac.getLinkPropertiesSync();
@@ -357,7 +282,7 @@
     public LinkCapabilities getLinkCapabilities(String apnType) {
         ApnContext apnContext = mApnContexts.get(apnType);
         if (apnContext!=null) {
-            DataConnectionAc dataConnectionAc = apnContext.getDataConnectionAc();
+            DataConnectionAc dataConnectionAc = apnContext.getDcAc();
             if (dataConnectionAc != null) {
                 if (DBG) log("get active pdp is not null, return link Capabilities for " + apnType);
                 return dataConnectionAc.getLinkCapabilitiesSync();
@@ -385,7 +310,7 @@
     @Override
     // Return active apn of specific apn type
     public String getActiveApnString(String apnType) {
-        if (DBG) log( "get active apn string for type:" + apnType);
+        if (VDBG) log( "get active apn string for type:" + apnType);
         ApnContext apnContext = mApnContexts.get(apnType);
         if (apnContext != null) {
             ApnSetting apnSetting = apnContext.getApnSetting();
@@ -435,6 +360,7 @@
                 case DISCONNECTING:
                     if (DBG) log("overall state is CONNECTED");
                     return DctConstants.State.CONNECTED;
+                case RETRYING:
                 case CONNECTING:
                     isConnecting = true;
                     isFailed = false;
@@ -529,8 +455,8 @@
             return true;
         }
 
-        if (mAllApns != null) {
-            for (ApnSetting apn : mAllApns) {
+        if (mAllApnSettings != null) {
+            for (ApnSetting apn : mAllApnSettings) {
                 if (apn.canHandleType(type)) {
                     return true;
                 }
@@ -591,7 +517,7 @@
             notifyOffApnsOfAvailability(Phone.REASON_DATA_ATTACHED);
         }
         mAutoAttachOnCreation = true;
-        setupDataOnReadyApns(Phone.REASON_DATA_ATTACHED);
+        setupDataOnConnectableApns(Phone.REASON_DATA_ATTACHED);
     }
 
     @Override
@@ -637,49 +563,15 @@
         return allowed;
     }
 
-    private void setupDataOnReadyApns(String reason) {
-        // Stop reconnect alarms on all data connections pending
-        // retry. Reset ApnContext state to IDLE.
-        for (DataConnectionAc dcac : mDataConnectionAsyncChannels.values()) {
-            if (dcac.getReconnectIntentSync() != null) {
-                cancelReconnectAlarm(dcac);
-            }
-            // update retry config for existing calls to match up
-            // ones for the new RAT.
-            if (dcac.dataConnection != null) {
-                Collection<ApnContext> apns = dcac.getApnListSync();
-
-                boolean hasDefault = false;
-                for (ApnContext apnContext : apns) {
-                    if (apnContext.getApnType().equals(PhoneConstants.APN_TYPE_DEFAULT)) {
-                        hasDefault = true;
-                        break;
-                    }
-                }
-                configureRetry(dcac.dataConnection, hasDefault, 0);
-            }
-        }
-
-        // Be sure retry counts for Apncontexts and DC's are sync'd.
-        // When DCT/ApnContexts are refactored and we cleanup retrying
-        // this won't be needed.
-        resetAllRetryCounts();
-
-        // Only check for default APN state
+    private void setupDataOnConnectableApns(String reason) {
         for (ApnContext apnContext : mApnContexts.values()) {
             if (apnContext.getState() == DctConstants.State.FAILED) {
-                // By this time, alarms for all failed Apns
-                // should be stopped if any.
-                // Make sure to set the state back to IDLE
-                // so that setup data can happen.
                 apnContext.setState(DctConstants.State.IDLE);
             }
-            if (apnContext.isReady()) {
-                if (apnContext.getState() == DctConstants.State.IDLE ||
-                        apnContext.getState() == DctConstants.State.SCANNING) {
-                    apnContext.setReason(reason);
-                    trySetupData(apnContext);
-                }
+            if (apnContext.isConnectable()) {
+                log("setupDataOnConnectableApns: isConnectable() call trySetupData");
+                apnContext.setReason(reason);
+                trySetupData(apnContext);
             }
         }
     }
@@ -725,21 +617,24 @@
 
         boolean desiredPowerState = mPhone.getServiceStateTracker().getDesiredPowerState();
 
-        if ((apnContext.getState() == DctConstants.State.IDLE ||
-                    apnContext.getState() == DctConstants.State.SCANNING) &&
+        if (apnContext.isConnectable() &&
                 isDataAllowed(apnContext) && getAnyDataEnabled() && !isEmergency()) {
-
+            if (apnContext.getState() == DctConstants.State.FAILED) {
+                if (DBG) log("trySetupData: make a FAILED ApnContext IDLE so its reusable");
+                apnContext.setState(DctConstants.State.IDLE);
+            }
             if (apnContext.getState() == DctConstants.State.IDLE) {
                 ArrayList<ApnSetting> waitingApns = buildWaitingApns(apnContext.getApnType());
                 if (waitingApns.isEmpty()) {
-                    notifyNoData(DataConnectionBase.FailCause.MISSING_UNKNOWN_APN, apnContext);
+                    notifyNoData(DcFailCause.MISSING_UNKNOWN_APN, apnContext);
                     notifyOffApnsOfAvailability(apnContext.getReason());
                     if (DBG) log("trySetupData: X No APN found retValue=false");
                     return false;
                 } else {
                     apnContext.setWaitingApns(waitingApns);
                     if (DBG) {
-                        log ("trySetupData: Create from mAllApns : " + apnListToString(mAllApns));
+                        log ("trySetupData: Create from mAllApnSettings : "
+                                    + apnListToString(mAllApnSettings));
                     }
                 }
             }
@@ -748,18 +643,16 @@
                 log("trySetupData: call setupData, waitingApns : "
                         + apnListToString(apnContext.getWaitingApns()));
             }
-            // apnContext.setReason(apnContext.getReason());
             boolean retValue = setupData(apnContext);
             notifyOffApnsOfAvailability(apnContext.getReason());
 
             if (DBG) log("trySetupData: X retValue=" + retValue);
             return retValue;
         } else {
-            // TODO: check the condition.
             if (!apnContext.getApnType().equals(PhoneConstants.APN_TYPE_DEFAULT)
-                && (apnContext.getState() == DctConstants.State.IDLE
-                    || apnContext.getState() == DctConstants.State.SCANNING))
+                    && apnContext.isConnectable()) {
                 mPhone.notifyDataConnectionFailed(apnContext.getReason(), apnContext.getApnType());
+            }
             notifyOffApnsOfAvailability(apnContext.getReason());
             if (DBG) log ("trySetupData: X apnContext not 'ready' retValue=false");
             return false;
@@ -771,12 +664,12 @@
     protected void notifyOffApnsOfAvailability(String reason) {
         for (ApnContext apnContext : mApnContexts.values()) {
             if (!apnContext.isReady()) {
-                if (DBG) log("notifyOffApnOfAvailability type:" + apnContext.getApnType());
+                if (VDBG) log("notifyOffApnOfAvailability type:" + apnContext.getApnType());
                 mPhone.notifyDataConnection(reason != null ? reason : apnContext.getReason(),
                                             apnContext.getApnType(),
                                             PhoneConstants.DataState.DISCONNECTED);
             } else {
-                if (DBG) {
+                if (VDBG) {
                     log("notifyOffApnsOfAvailability skipped apn due to isReady==true: " +
                             apnContext.toString());
                 }
@@ -830,7 +723,7 @@
             return;
         }
 
-        DataConnectionAc dcac = apnContext.getDataConnectionAc();
+        DataConnectionAc dcac = apnContext.getDcAc();
         if (DBG) {
             log("cleanUpConnection: E tearDown=" + tearDown + " reason=" + apnContext.getReason() +
                     " apnContext=" + apnContext);
@@ -841,7 +734,6 @@
                 // If apnContext is not enabled anymore, break the linkage to the DCAC/DC.
                 apnContext.setState(DctConstants.State.IDLE);
                 if (!apnContext.isReady()) {
-                    apnContext.setDataConnection(null);
                     apnContext.setDataConnectionAc(null);
                 }
             } else {
@@ -866,9 +758,9 @@
                         }
                         Message msg = obtainMessage(DctConstants.EVENT_DISCONNECT_DONE, apnContext);
                         if (disconnectAll) {
-                            apnContext.getDataConnection().tearDownAll(apnContext.getReason(), msg);
+                            apnContext.getDcAc().tearDownAll(apnContext.getReason(), msg);
                         } else {
-                            apnContext.getDataConnection()
+                            apnContext.getDcAc()
                                 .tearDown(apnContext, apnContext.getReason(), msg);
                         }
                         apnContext.setState(DctConstants.State.DISCONNECTING);
@@ -883,42 +775,38 @@
             }
         } else {
             // force clean up the data connection.
-            if (dcac != null) dcac.resetSync();
+            if (dcac != null) dcac.reqReset();
             apnContext.setState(DctConstants.State.IDLE);
             mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
-            apnContext.setDataConnection(null);
             apnContext.setDataConnectionAc(null);
         }
 
-        // make sure reconnection alarm is cleaned up if there is no ApnContext
+        // Make sure reconnection alarm is cleaned up if there is no ApnContext
         // associated to the connection.
         if (dcac != null) {
-            Collection<ApnContext> apnList = dcac.getApnListSync();
-            if (apnList.isEmpty()) {
-                cancelReconnectAlarm(dcac);
-            }
+            cancelReconnectAlarm(apnContext);
         }
         if (DBG) {
             log("cleanUpConnection: X tearDown=" + tearDown + " reason=" + apnContext.getReason() +
-                    " apnContext=" + apnContext + " dc=" + apnContext.getDataConnection());
+                    " apnContext=" + apnContext + " dcac=" + apnContext.getDcAc());
         }
     }
 
     /**
-     * Cancels the alarm associated with DCAC.
+     * Cancels the alarm associated with apnContext.
      *
-     * @param dcac on which the alarm should be stopped.
+     * @param apnContext on which the alarm should be stopped.
      */
-    private void cancelReconnectAlarm(DataConnectionAc dcac) {
-        if (dcac == null) return;
+    private void cancelReconnectAlarm(ApnContext apnContext) {
+        if (apnContext == null) return;
 
-        PendingIntent intent = dcac.getReconnectIntentSync();
+        PendingIntent intent = apnContext.getReconnectIntent();
 
         if (intent != null) {
                 AlarmManager am =
                     (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
                 am.cancel(intent);
-                dcac.setReconnectIntentSync(null);
+                apnContext.setReconnectIntent(null);
         }
     }
 
@@ -1054,9 +942,9 @@
     }
 
     private boolean dataConnectionNotInUse(DataConnectionAc dcac) {
-        if (DBG) log("dataConnectionNotInUse: check if dcac is inuse dc=" + dcac.dataConnection);
+        if (DBG) log("dataConnectionNotInUse: check if dcac is inuse dcac=" + dcac);
         for (ApnContext apnContext : mApnContexts.values()) {
-            if (apnContext.getDataConnectionAc() == dcac) {
+            if (apnContext.getDcAc() == dcac) {
                 if (DBG) log("dataConnectionNotInUse: in use by apnContext=" + apnContext);
                 return false;
             }
@@ -1065,20 +953,19 @@
         // Probably move retry handling into DataConnections and reduce complexity
         // of DCT.
         if (DBG) log("dataConnectionNotInUse: tearDownAll");
-        dcac.dataConnection.tearDownAll("No connection", null);
+        dcac.tearDownAll("No connection", null);
         if (DBG) log("dataConnectionNotInUse: not in use return true");
         return true;
     }
 
-    private DataConnection findFreeDataConnection() {
-        for (DataConnectionAc dcac : mDataConnectionAsyncChannels.values()) {
+    private DataConnectionAc findFreeDataConnection() {
+        for (DataConnectionAc dcac : mDataConnectionAcHashMap.values()) {
             if (dcac.isInactiveSync() && dataConnectionNotInUse(dcac)) {
-                DataConnectionBase dc = dcac.dataConnection;
                 if (DBG) {
                     log("findFreeDataConnection: found free DataConnection=" +
-                        " dcac=" + dcac + " dc=" + dc);
+                        " dcac=" + dcac);
                 }
-                return (DataConnection) dc;
+                return dcac;
             }
         }
         log("findFreeDataConnection: NO free DataConnection");
@@ -1087,66 +974,48 @@
 
     private boolean setupData(ApnContext apnContext) {
         if (DBG) log("setupData: apnContext=" + apnContext);
-        ApnSetting apn;
-        DataConnection dc;
+        ApnSetting apnSetting;
+        DataConnectionAc dcac;
 
         int profileId = getApnProfileID(apnContext.getApnType());
-        apn = apnContext.getNextWaitingApn();
-        if (apn == null) {
+        apnSetting = apnContext.getNextWaitingApn();
+        if (apnSetting == null) {
             if (DBG) log("setupData: return for no apn found!");
             return false;
         }
 
+        dcac = checkForCompatibleConnectedApnContext(apnContext);
+        if (dcac != null) {
+            // Get the dcacApnSetting for the connection we want to share.
+            ApnSetting dcacApnSetting = dcac.getApnSettingSync();
+            if (dcacApnSetting != null) {
+                // Setting is good, so use it.
+                apnSetting = dcacApnSetting;
+            }
+        }
+        if (dcac == null) {
+            dcac = findFreeDataConnection();
 
-        dc = (DataConnection) checkForConnectionForApnContext(apnContext);
-
-        if (dc == null) {
-            // TODO: When allocating you are mapping type to id. If more than 1 free,
-            // then could findFreeDataConnection get the wrong one??
-            dc = findFreeDataConnection();
-
-            if (dc == null) {
-                dc = createDataConnection();
+            if (dcac == null) {
+                dcac = createDataConnection();
             }
 
-            if (dc == null) {
-                if (DBG) log("setupData: No free DataConnection found!");
+            if (dcac == null) {
+                if (DBG) log("setupData: No free DataConnection and couldn't create one, WEIRD");
                 return false;
             }
-        } else {
-            apn = mDataConnectionAsyncChannels.get(dc.getDataConnectionId()).getApnSettingSync();
         }
+        if (DBG) log("setupData: dcac=" + dcac + " apnSetting=" + apnSetting);
 
-        DataConnectionAc dcac = mDataConnectionAsyncChannels.get(dc.getDataConnectionId());
-        dc.setProfileId( profileId );  //  assumed no connection sharing on profiled types
-
-        int refCount = dcac.getRefCountSync();
-        if (DBG) log("setupData: init dc and apnContext RefCount=" + refCount);
-
-        // configure retry count if no other Apn is using the same connection.
-        if (refCount == 0) {
-            configureRetry(dc, apn.canHandleType(PhoneConstants.APN_TYPE_DEFAULT),
-                    apnContext.getRetryCount());
-        }
         apnContext.setDataConnectionAc(dcac);
-        apnContext.setDataConnection(dc);
-
-        apnContext.setApnSetting(apn);
+        apnContext.setApnSetting(apnSetting);
         apnContext.setState(DctConstants.State.CONNECTING);
         mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
-        // If reconnect alarm is active on this DataConnection, wait for the alarm being
-        // fired so that we don't disrupt data retry pattern engaged.
-        if (apnContext.getDataConnectionAc().getReconnectIntentSync() != null) {
-            if (DBG) log("setupData: data reconnection pending");
-            apnContext.setState(DctConstants.State.FAILED);
-            mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
-            return true;
-        }
 
         Message msg = obtainMessage();
         msg.what = DctConstants.EVENT_DATA_SETUP_COMPLETE;
         msg.obj = apnContext;
-        dc.bringUp(apnContext, msg);
+        dcac.bringUp(apnContext, getInitialMaxRetry(), profileId, msg);
 
         if (DBG) log("setupData: initing!");
         return true;
@@ -1171,7 +1040,7 @@
         createAllApnList();
         cleanUpAllConnections(!isDisconnected, Phone.REASON_APN_CHANGED);
         if (isDisconnected) {
-            setupDataOnReadyApns(Phone.REASON_APN_CHANGED);
+            setupDataOnConnectableApns(Phone.REASON_APN_CHANGED);
         }
     }
 
@@ -1180,7 +1049,7 @@
      * @return DataConnectionAc associated with specified cid.
      */
     private DataConnectionAc findDataConnectionAcByCid(int cid) {
-        for (DataConnectionAc dcac : mDataConnectionAsyncChannels.values()) {
+        for (DataConnectionAc dcac : mDataConnectionAcHashMap.values()) {
             if (dcac.getCidSync() == cid) {
                 return dcac;
             }
@@ -1189,52 +1058,14 @@
     }
 
     /**
-     * @param dcacs Collection of DataConnectionAc reported from RIL.
-     * @return List of ApnContext which is connected, but is not present in
-     *         data connection list reported from RIL.
-     */
-    private List<ApnContext> findApnContextToClean(Collection<DataConnectionAc> dcacs) {
-        if (dcacs == null) return null;
-
-        if (DBG) log("findApnContextToClean(ar): E dcacs=" + dcacs);
-
-        ArrayList<ApnContext> list = new ArrayList<ApnContext>();
-        for (ApnContext apnContext : mApnContexts.values()) {
-            if (apnContext.getState() == DctConstants.State.CONNECTED) {
-                boolean found = false;
-                for (DataConnectionAc dcac : dcacs) {
-                    if (dcac == apnContext.getDataConnectionAc()) {
-                        // ApnContext holds the ref to dcac present in data call list.
-                        found = true;
-                        break;
-                    }
-                }
-                if (!found) {
-                    // ApnContext does not have dcac reported in data call list.
-                    // Fetch all the ApnContexts that map to this dcac.
-                    if (DBG) log("findApnContextToClean(ar): Connected apn not found in the list (" +
-                                 apnContext.toString() + ")");
-                    if (apnContext.getDataConnectionAc() != null) {
-                        list.addAll(apnContext.getDataConnectionAc().getApnListSync());
-                    } else {
-                        list.add(apnContext);
-                    }
-                }
-            }
-        }
-        if (DBG) log("findApnContextToClean(ar): X list=" + list);
-        return list;
-    }
-
-    /**
      * @param ar is the result of RIL_REQUEST_DATA_CALL_LIST
      * or RIL_UNSOL_DATA_CALL_LIST_CHANGED
      */
     private void onDataStateChanged (AsyncResult ar) {
-        ArrayList<DataCallState> dataCallStates;
+        ArrayList<DataCallResponse> dataCallStates;
 
         if (DBG) log("onDataStateChanged(ar): E");
-        dataCallStates = (ArrayList<DataCallState>)(ar.result);
+        dataCallStates = (ArrayList<DataCallResponse>)(ar.result);
 
         if (ar.exception != null) {
             // This is probably "radio not available" or something
@@ -1243,117 +1074,24 @@
             if (DBG) log("onDataStateChanged(ar): exception; likely radio not available, ignore");
             return;
         }
-        if (DBG) log("onDataStateChanged(ar): DataCallState size=" + dataCallStates.size());
-
-        boolean isAnyDataCallDormant = false;
-        boolean isAnyDataCallActive = false;
+        if (DBG) log("onDataStateChanged(ar): DataCallResponse size=" + dataCallStates.size());
 
         // Create a hash map to store the dataCallState of each DataConnectionAc
-        HashMap<DataCallState, DataConnectionAc> dataCallStateToDcac;
-        dataCallStateToDcac = new HashMap<DataCallState, DataConnectionAc>();
-        for (DataCallState dataCallState : dataCallStates) {
+        HashMap<DataCallResponse, DataConnectionAc> dataCallStateToDcac;
+        dataCallStateToDcac = new HashMap<DataCallResponse, DataConnectionAc>();
+        for (DataCallResponse dataCallState : dataCallStates) {
             DataConnectionAc dcac = findDataConnectionAcByCid(dataCallState.cid);
 
             if (dcac != null) dataCallStateToDcac.put(dataCallState, dcac);
         }
 
-        // A list of apns to cleanup, those that aren't in the list we know we have to cleanup
-        List<ApnContext> apnsToCleanup = findApnContextToClean(dataCallStateToDcac.values());
-
-        // Find which connections have changed state and send a notification or cleanup
-        for (DataCallState newState : dataCallStates) {
-            DataConnectionAc dcac = dataCallStateToDcac.get(newState);
-
-            if (dcac == null) {
-                loge("onDataStateChanged(ar): No associated DataConnection ignore");
-                continue;
-            }
-
+        // Check if we should start or stop polling, by looking
+        // for dormant and active connections.
+        boolean isAnyDataCallDormant = false;
+        boolean isAnyDataCallActive = false;
+        for (DataCallResponse newState : dataCallStates) {
             if (newState.active == DATA_CONNECTION_ACTIVE_PH_LINK_UP) isAnyDataCallActive = true;
             if (newState.active == DATA_CONNECTION_ACTIVE_PH_LINK_DOWN) isAnyDataCallDormant = true;
-
-            // The list of apn's associated with this DataConnection
-            Collection<ApnContext> apns = dcac.getApnListSync();
-
-            // Find which ApnContexts of this DC are in the "Connected/Connecting" state.
-            ArrayList<ApnContext> connectedApns = new ArrayList<ApnContext>();
-            for (ApnContext apnContext : apns) {
-                if (apnContext.getState() == DctConstants.State.CONNECTED ||
-                       apnContext.getState() == DctConstants.State.CONNECTING) {
-                    connectedApns.add(apnContext);
-                }
-            }
-            if (connectedApns.size() == 0) {
-                if (DBG) log("onDataStateChanged(ar): no connected apns");
-            } else {
-                // Determine if the connection/apnContext should be cleaned up
-                // or just a notification should be sent out.
-                if (DBG) log("onDataStateChanged(ar): Found ConnId=" + newState.cid
-                        + " newState=" + newState.toString());
-                if (newState.active == 0) {
-                    if (DBG) {
-                        log("onDataStateChanged(ar): inactive, cleanup apns=" + connectedApns);
-                    }
-                    apnsToCleanup.addAll(connectedApns);
-                } else {
-                    // Its active so update the DataConnections link properties
-                    UpdateLinkPropertyResult result =
-                        dcac.updateLinkPropertiesDataCallStateSync(newState);
-                    if (result.oldLp.equals(result.newLp)) {
-                        if (DBG) log("onDataStateChanged(ar): no change");
-                    } else {
-                        if (result.oldLp.isIdenticalInterfaceName(result.newLp)) {
-                            if (! result.oldLp.isIdenticalDnses(result.newLp) ||
-                                    ! result.oldLp.isIdenticalRoutes(result.newLp) ||
-                                    ! result.oldLp.isIdenticalHttpProxy(result.newLp) ||
-                                    ! result.oldLp.isIdenticalAddresses(result.newLp)) {
-                                // If the same address type was removed and added we need to cleanup
-                                CompareResult<LinkAddress> car =
-                                    result.oldLp.compareAddresses(result.newLp);
-                                if (DBG) {
-                                    log("onDataStateChanged: oldLp=" + result.oldLp +
-                                            " newLp=" + result.newLp + " car=" + car);
-                                }
-                                boolean needToClean = false;
-                                for (LinkAddress added : car.added) {
-                                    for (LinkAddress removed : car.removed) {
-                                        if (NetworkUtils.addressTypeMatches(removed.getAddress(),
-                                                added.getAddress())) {
-                                            needToClean = true;
-                                            break;
-                                        }
-                                    }
-                                }
-                                if (needToClean) {
-                                    if (DBG) {
-                                        log("onDataStateChanged(ar): addr change, cleanup apns=" +
-                                                connectedApns + " oldLp=" + result.oldLp +
-                                                " newLp=" + result.newLp);
-                                    }
-                                    apnsToCleanup.addAll(connectedApns);
-                                } else {
-                                    if (DBG) log("onDataStateChanged(ar): simple change");
-                                    for (ApnContext apnContext : connectedApns) {
-                                         mPhone.notifyDataConnection(
-                                                 PhoneConstants.REASON_LINK_PROPERTIES_CHANGED,
-                                                 apnContext.getApnType());
-                                    }
-                                }
-                            } else {
-                                if (DBG) {
-                                    log("onDataStateChanged(ar): no changes");
-                                }
-                            }
-                        } else {
-                            if (DBG) {
-                                log("onDataStateChanged(ar): interface change, cleanup apns="
-                                        + connectedApns);
-                            }
-                            apnsToCleanup.addAll(connectedApns);
-                        }
-                    }
-                }
-            }
         }
 
         if (isAnyDataCallDormant && !isAnyDataCallActive) {
@@ -1376,20 +1114,6 @@
             }
             if (isAnyDataCallActive) startNetStatPoll();
         }
-        mPhone.notifyDataActivity();
-
-        if (apnsToCleanup.size() != 0) {
-            // Add an event log when the network drops PDP
-            int cid = getCellLocationId();
-            EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP, cid,
-                                TelephonyManager.getDefault().getNetworkType());
-        }
-
-        // Cleanup those dropped connections
-        if (DBG) log("onDataStateChange(ar): apnsToCleanup=" + apnsToCleanup);
-        for (ApnContext apnContext : apnsToCleanup) {
-            cleanUpConnection(true, apnContext);
-        }
 
         if (DBG) log("onDataStateChanged(ar): X");
     }
@@ -1404,8 +1128,6 @@
         mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
         startNetStatPoll();
         startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
-        // reset reconnect timer
-        apnContext.setRetryCount(0);
     }
 
     // TODO: For multiple Active APNs not exactly sure how to do this.
@@ -1434,15 +1156,6 @@
     }
 
     /**
-     * Returns true if the last fail cause is something that
-     * seems like it deserves an error notification.
-     * Transient errors are ignored
-     */
-    private boolean shouldPostNotification(DataConnection.FailCause  cause) {
-        return (cause != DataConnection.FailCause.UNKNOWN);
-    }
-
-    /**
      * Return true if data connection need to be setup after disconnected due to
      * reason.
      *
@@ -1458,107 +1171,42 @@
         return retry;
     }
 
-    private void reconnectAfterFail(FailCause lastFailCauseCode,
-                                    ApnContext apnContext, int retryOverride) {
-        if (apnContext == null) {
-            loge("reconnectAfterFail: apnContext == null, impossible");
-            return;
-        }
-        if (DBG) {
-            log("reconnectAfterFail: lastFailCause=" + lastFailCauseCode +
-                    " retryOverride=" + retryOverride + " apnContext=" + apnContext);
-        }
-        if ((apnContext.getState() == DctConstants.State.FAILED) &&
-            (apnContext.getDataConnection() != null)) {
-            if (!apnContext.getDataConnection().isRetryNeeded()) {
-                if (!apnContext.getApnType().equals(PhoneConstants.APN_TYPE_DEFAULT)) {
-                    mPhone.notifyDataConnection(Phone.REASON_APN_FAILED, apnContext.getApnType());
-                    return;
-                }
-                if (mReregisterOnReconnectFailure) {
-                    // We've re-registerd once now just retry forever.
-                    apnContext.getDataConnection().retryForeverUsingLastTimeout();
-                } else {
-                    // Try to Re-register to the network.
-                    if (DBG) log("reconnectAfterFail: activate failed, Reregistering to network");
-                    mReregisterOnReconnectFailure = true;
-                    mPhone.getServiceStateTracker().reRegisterNetwork(null);
-                    apnContext.setRetryCount(0);
-                    return;
-                }
-            }
-
-            // If retry needs to be backed off for specific case (determined by RIL/Modem)
-            // use the specified timer instead of pre-configured retry pattern.
-            int nextReconnectDelay = retryOverride;
-            if (nextReconnectDelay < 0) {
-                nextReconnectDelay = apnContext.getDataConnection().getRetryTimer();
-                apnContext.getDataConnection().increaseRetryCount();
-                if (DBG) {
-                    log("reconnectAfterFail: increaseRetryCount=" +
-                            apnContext.getDataConnection().getRetryCount() +
-                            " nextReconnectDelay=" + nextReconnectDelay);
-                }
-            }
-            startAlarmForReconnect(nextReconnectDelay, apnContext);
-
-            if (!shouldPostNotification(lastFailCauseCode)) {
-                if (DBG) {
-                    log("reconnectAfterFail: NOT Posting GPRS Unavailable notification "
-                                + "-- likely transient error");
-                }
-            } else {
-                apnContext.setState(DctConstants.State.FAILED);
-                notifyNoData(lastFailCauseCode, apnContext);
-            }
-        }
-    }
-
     private void startAlarmForReconnect(int delay, ApnContext apnContext) {
+        DataConnectionAc dcac = apnContext.getDcAc();
 
-        DataConnectionAc dcac = apnContext.getDataConnectionAc();
-
-        if ((dcac == null) || (dcac.dataConnection == null)) {
+        if (dcac == null) {
             // should not happen, but just in case.
             loge("startAlarmForReconnect: null dcac or dc.");
             return;
         }
 
-        AlarmManager am =
-            (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
-
         Intent intent = new Intent(INTENT_RECONNECT_ALARM + '.' +
-                                   dcac.dataConnection.getDataConnectionId());
+                                   dcac.getDataConnectionIdSync());
         String reason = apnContext.getReason();
         intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON, reason);
         String apnType = apnContext.getApnType();
         intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE, apnType);
 
-        // TODO: Until a real fix is created, which probably entails pushing
-        // retires into the DC itself, this fix gets the retry count and
-        // puts it in the reconnect alarm. When the reconnect alarm fires
-        // onActionIntentReconnectAlarm is called which will use the value saved
-        // here and save it in the ApnContext and send the EVENT_CONNECT message
-        // which invokes setupData. Then setupData will use the value in the ApnContext
-        // and to tell the DC to set the retry count in the retry manager.
-        int retryCount = dcac.dataConnection.getRetryCount();
-        intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_RETRY_COUNT, retryCount);
+        PendingIntent alarmIntent = PendingIntent.getBroadcast (mPhone.getContext(), 0,
+                                        intent, PendingIntent.FLAG_UPDATE_CURRENT);
+        apnContext.setReconnectIntent(alarmIntent);
+        mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+                SystemClock.elapsedRealtime() + delay, alarmIntent);
+    }
 
-        if (DBG) {
-            log("startAlarmForReconnect: next attempt in " + (delay / 1000) + "s" +
-                    " reason='" + reason + "' apnType=" + apnType +
-                    " retryCount=" + retryCount);
-        }
+    private void startAlarmForRestartTrySetup(int delay, ApnContext apnContext) {
+        Intent intent = new Intent(INTENT_RESTART_TRYSETUP_ALARM);
+        String apnType = apnContext.getApnType();
+        intent.putExtra(INTENT_RESTART_TRYSETUP_ALARM_EXTRA_TYPE, apnType);
 
         PendingIntent alarmIntent = PendingIntent.getBroadcast (mPhone.getContext(), 0,
                                         intent, PendingIntent.FLAG_UPDATE_CURRENT);
-        dcac.setReconnectIntentSync(alarmIntent);
-        am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+        apnContext.setReconnectIntent(alarmIntent);
+        mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                 SystemClock.elapsedRealtime() + delay, alarmIntent);
-
     }
 
-    private void notifyNoData(DataConnectionBase.FailCause lastFailCauseCode,
+    private void notifyNoData(DcFailCause lastFailCauseCode,
                               ApnContext apnContext) {
         if (DBG) log( "notifyNoData: type=" + apnContext.getApnType());
         if (lastFailCauseCode.isPermanentFail()
@@ -1574,7 +1222,7 @@
             if (DBG) log("onRecordsLoaded: notifying data availability");
             notifyOffApnsOfAvailability(Phone.REASON_SIM_LOADED);
         }
-        setupDataOnReadyApns(Phone.REASON_SIM_LOADED);
+        setupDataOnConnectableApns(Phone.REASON_SIM_LOADED);
     }
 
     @Override
@@ -1631,62 +1279,75 @@
         if (trySetup) trySetupData(apnContext);
     }
 
-    private DataConnectionBase checkForConnectionForApnContext(ApnContext apnContext) {
-        // Loop through all apnContexts looking for one with a conn that satisfies this apnType
+    private DataConnectionAc checkForCompatibleConnectedApnContext(ApnContext apnContext) {
         String apnType = apnContext.getApnType();
         ApnSetting dunSetting = null;
 
         if (PhoneConstants.APN_TYPE_DUN.equals(apnType)) {
             dunSetting = fetchDunApn();
         }
+        if (DBG) {
+            log("checkForCompatibleConnectedApnContext: apnContext=" + apnContext );
+        }
 
-        DataConnectionBase potential = null;
-        for (ApnContext c : mApnContexts.values()) {
-            DataConnectionBase conn = c.getDataConnection();
-            if (conn != null) {
-                ApnSetting apnSetting = c.getApnSetting();
+        DataConnectionAc potentialDcac = null;
+        ApnContext potentialApnCtx = null;
+        for (ApnContext curApnCtx : mApnContexts.values()) {
+            DataConnectionAc curDcac = curApnCtx.getDcAc();
+            if (curDcac != null) {
+                ApnSetting apnSetting = curApnCtx.getApnSetting();
                 if (dunSetting != null) {
                     if (dunSetting.equals(apnSetting)) {
-                        switch (c.getState()) {
+                        switch (curApnCtx.getState()) {
                             case CONNECTED:
                                 if (DBG) {
-                                    log("checkForConnectionForApnContext: apnContext=" +
-                                            apnContext + " found conn=" + conn);
+                                    log("checkForCompatibleConnectedApnContext:"
+                                            + " found dun conn=" + curDcac
+                                            + " curApnCtx=" + curApnCtx);
                                 }
-                                return conn;
+                                return curDcac;
+                            case RETRYING:
                             case CONNECTING:
-                                potential = conn;
+                                potentialDcac = curDcac;
+                                potentialApnCtx = curApnCtx;
                             default:
                                 // Not connected, potential unchanged
                                 break;
                         }
                     }
                 } else if (apnSetting != null && apnSetting.canHandleType(apnType)) {
-                    switch (c.getState()) {
+                    switch (curApnCtx.getState()) {
                         case CONNECTED:
                             if (DBG) {
-                                log("checkForConnectionForApnContext: apnContext=" + apnContext +
-                                        " found conn=" + conn);
+                                log("checkForCompatibleConnectedApnContext:"
+                                        + " found canHandle conn=" + curDcac
+                                        + " curApnCtx=" + curApnCtx);
                             }
-                            return conn;
+                            return curDcac;
+                        case RETRYING:
                         case CONNECTING:
-                            potential = conn;
+                            potentialDcac = curDcac;
+                            potentialApnCtx = curApnCtx;
                         default:
                             // Not connected, potential unchanged
                             break;
                     }
                 }
+            } else {
+                if (VDBG) {
+                    log("checkForCompatibleConnectedApnContext: not conn curApnCtx=" + curApnCtx);
+                }
             }
         }
-        if (potential != null) {
+        if (potentialDcac != null) {
             if (DBG) {
-                log("checkForConnectionForApnContext: apnContext=" + apnContext +
-                    " found conn=" + potential);
+                log("checkForCompatibleConnectedApnContext: found potential conn=" + potentialDcac
+                        + " curApnCtx=" + potentialApnCtx);
             }
-            return potential;
+            return potentialDcac;
         }
 
-        if (DBG) log("checkForConnectionForApnContext: apnContext=" + apnContext + " NO conn");
+        if (DBG) log("checkForCompatibleConnectedApnContext: NO conn apnContext=" + apnContext);
         return null;
     }
 
@@ -1706,7 +1367,7 @@
     // TODO: We shouldnt need this.
     protected boolean onTrySetupData(String reason) {
         if (DBG) log("onTrySetupData: reason=" + reason);
-        setupDataOnReadyApns(reason);
+        setupDataOnConnectableApns(reason);
         return true;
     }
 
@@ -1723,7 +1384,7 @@
 
         if (getDataOnRoamingEnabled() == false) {
             notifyOffApnsOfAvailability(Phone.REASON_ROAMING_OFF);
-            setupDataOnReadyApns(Phone.REASON_ROAMING_OFF);
+            setupDataOnConnectableApns(Phone.REASON_ROAMING_OFF);
         } else {
             notifyDataConnection(Phone.REASON_ROAMING_OFF);
         }
@@ -1735,7 +1396,7 @@
 
         if (getDataOnRoamingEnabled()) {
             if (DBG) log("onRoamingOn: setup data on roaming");
-            setupDataOnReadyApns(Phone.REASON_ROAMING_ON);
+            setupDataOnConnectableApns(Phone.REASON_ROAMING_ON);
             notifyDataConnection(Phone.REASON_ROAMING_ON);
         } else {
             if (DBG) log("onRoamingOn: Tear down data connection on roaming.");
@@ -1771,7 +1432,6 @@
         // Make sure our reconnect delay starts at the initial value
         // next time the radio comes on
 
-        resetAllRetryCounts();
         mReregisterOnReconnectFailure = false;
 
         if (mPhone.getSimulatedRadioControl() != null) {
@@ -1785,10 +1445,14 @@
         notifyOffApnsOfAvailability(null);
     }
 
+    /**
+     * A SETUP (aka bringUp) has completed, possibly with an error. If
+     * there is an error this method will call {@link #onDataSetupCompleteError}.
+     */
     @Override
     protected void onDataSetupComplete(AsyncResult ar) {
 
-        DataConnectionBase.FailCause cause = DataConnectionBase.FailCause.UNKNOWN;
+        DcFailCause cause = DcFailCause.UNKNOWN;
         boolean handleError = false;
         ApnContext apnContext = null;
 
@@ -1799,14 +1463,14 @@
         }
 
         if (ar.exception == null) {
-            DataConnectionAc dcac = apnContext.getDataConnectionAc();
+            DataConnectionAc dcac = apnContext.getDcAc();
 
             if (RADIO_TESTS) {
                 // Note: To change radio.test.onDSC.null.dcac from command line you need to
                 // adb root and adb remount and from the command line you can only change the
                 // value to 1 once. To change it a second time you can reboot or execute
                 // adb shell stop and then adb shell start. The command line to set the value is:
-                //   adb shell sqlite3 /data/data/com.android.providers.settings/databases/settings.db "insert into system (name,value) values ('radio.test.onDSC.null.dcac', '1');"
+                // adb shell sqlite3 /data/data/com.android.providers.settings/databases/settings.db "insert into system (name,value) values ('radio.test.onDSC.null.dcac', '1');"
                 ContentResolver cr = mPhone.getContext().getContentResolver();
                 String radioTestProperty = "radio.test.onDSC.null.dcac";
                 if (Settings.System.getInt(cr, radioTestProperty, 0) == 1) {
@@ -1821,10 +1485,9 @@
             }
             if (dcac == null) {
                 log("onDataSetupComplete: no connection to DC, handle as error");
-                cause = DataConnectionBase.FailCause.CONNECTION_TO_DATACONNECTIONAC_BROKEN;
+                cause = DcFailCause.CONNECTION_TO_DATACONNECTIONAC_BROKEN;
                 handleError = true;
             } else {
-                DataConnectionBase dc = apnContext.getDataConnection();
                 ApnSetting apn = apnContext.getApnSetting();
                 if (DBG) {
                     log("onDataSetupComplete: success apn=" + (apn == null ? "unknown" : apn.apn));
@@ -1844,7 +1507,7 @@
 
                 // everything is setup
                 if(TextUtils.equals(apnContext.getApnType(),PhoneConstants.APN_TYPE_DEFAULT)) {
-                    SystemProperties.set("gsm.defaultpdpcontext.active", "true");
+                    SystemProperties.set(PUPPET_MASTER_RADIO_STRESS_TEST, "true");
                     if (mCanSetPreferApn && mPreferredApn == null) {
                         if (DBG) log("onDataSetupComplete: PREFERED APN is null");
                         mPreferredApn = apn;
@@ -1853,12 +1516,12 @@
                         }
                     }
                 } else {
-                    SystemProperties.set("gsm.defaultpdpcontext.active", "false");
+                    SystemProperties.set(PUPPET_MASTER_RADIO_STRESS_TEST, "false");
                 }
                 notifyDefaultData(apnContext);
             }
         } else {
-            cause = (DataConnectionBase.FailCause) (ar.result);
+            cause = (DcFailCause) (ar.result);
             if (DBG) {
                 ApnSetting apn = apnContext.getApnSetting();
                 log(String.format("onDataSetupComplete: error apn=%s cause=%s",
@@ -1885,38 +1548,50 @@
         }
 
         if (handleError) {
-            // See if there are more APN's to try
-            if (apnContext.getWaitingApns().isEmpty()) {
-                if (apnContext.getWaitingApnsPermFailCount() == 0) {
-                    if (DBG) {
-                        log("onDataSetupComplete: All APN's had permanent failures, stop retrying");
-                    }
-                    apnContext.setState(DctConstants.State.FAILED);
-                    mPhone.notifyDataConnection(Phone.REASON_APN_FAILED, apnContext.getApnType());
+            onDataSetupCompleteError(ar);
+        }
+    }
 
-                    apnContext.setDataConnection(null);
-                    apnContext.setDataConnectionAc(null);
-                } else {
-                    if (DBG) log("onDataSetupComplete: Not all permanent failures, retry");
-                    // check to see if retry should be overridden for this failure.
-                    int retryOverride = -1;
-                    if (ar.exception instanceof DataConnectionBase.CallSetupException) {
-                        retryOverride =
-                            ((DataConnectionBase.CallSetupException)ar.exception).getRetryOverride();
-                    }
-                    if (retryOverride == RILConstants.MAX_INT) {
-                        if (DBG) log("No retry is suggested.");
-                    } else {
-                        startDelayedRetry(cause, apnContext, retryOverride);
-                    }
+    /**
+     * 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}.
+     */
+    @Override
+    protected void onDataSetupCompleteError(AsyncResult ar) {
+        String reason = "";
+        ApnContext apnContext = null;
+
+        if(ar.userObj instanceof ApnContext){
+            apnContext = (ApnContext)ar.userObj;
+        } else {
+            throw new RuntimeException("onDataSetupCompleteError: No apnContext");
+        }
+
+        // See if there are more APN's to try
+        if (apnContext.getWaitingApns().isEmpty()) {
+            apnContext.setState(DctConstants.State.FAILED);
+            mPhone.notifyDataConnection(Phone.REASON_APN_FAILED, apnContext.getApnType());
+
+            apnContext.setDataConnectionAc(null);
+
+            if (apnContext.getWaitingApnsPermFailCount() == 0) {
+                if (DBG) {
+                    log("onDataSetupComplete: All APN's had permanent failures, stop retrying");
                 }
             } 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);
+                if (DBG) {
+                    log("onDataSetupComplete: Not all APN's had permanent failures, retry");
+                }
+                startAlarmForRestartTrySetup(APN_DELAY_MILLIS, 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);
         }
     }
 
@@ -1945,7 +1620,6 @@
             if (mPhone.getServiceStateTracker().processPendingRadioPowerOffAfterDataOff()) {
                 // Radio will be turned off. No need to retry data setup
                 apnContext.setApnSetting(null);
-                apnContext.setDataConnection(null);
                 apnContext.setDataConnectionAc(null);
                 return;
             }
@@ -1953,18 +1627,38 @@
 
         // If APN is still enabled, try to bring it back up automatically
         if (apnContext.isReady() && retryAfterDisconnected(apnContext.getReason())) {
-            SystemProperties.set("gsm.defaultpdpcontext.active", "false");  // TODO - what the heck?  This shoudld go
+            SystemProperties.set(PUPPET_MASTER_RADIO_STRESS_TEST, "false");
             // 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);
         } else {
             apnContext.setApnSetting(null);
-            apnContext.setDataConnection(null);
             apnContext.setDataConnectionAc(null);
         }
     }
 
+    /**
+     * Called when EVENT_DISCONNECT_DC_RETRYING is received.
+     */
+    @Override
+    protected void onDisconnectDcRetrying(int connId, AsyncResult ar) {
+        // We could just do this in DC!!!
+        ApnContext apnContext = null;
+
+        if (ar.userObj instanceof ApnContext) {
+            apnContext = (ApnContext) ar.userObj;
+        } else {
+            loge("onDisconnectDcRetrying: Invalid ar in onDisconnectDone, ignore");
+            return;
+        }
+
+        apnContext.setState(DctConstants.State.RETRYING);
+        if(DBG) log("onDisconnectDcRetrying: apnContext=" + apnContext);
+
+        mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
+    }
+
     protected void onPollPdp() {
         if (getOverallState() == DctConstants.State.CONNECTED) {
             // only poll when connected
@@ -1998,7 +1692,7 @@
             }
         }
         // reset reconnect timer
-        setupDataOnReadyApns(Phone.REASON_VOICE_CALL_ENDED);
+        setupDataOnConnectableApns(Phone.REASON_VOICE_CALL_ENDED);
     }
 
     @Override
@@ -2014,7 +1708,7 @@
     @Override
     protected boolean isConnected() {
         for (ApnContext apnContext : mApnContexts.values()) {
-            if (apnContext.getState() ==DctConstants.State.CONNECTED) {
+            if (apnContext.getState() == DctConstants.State.CONNECTED) {
                 // At least one context is connected, return true
                 return true;
             }
@@ -2053,7 +1747,7 @@
      * Data Connections and setup the preferredApn.
      */
     private void createAllApnList() {
-        mAllApns = new ArrayList<ApnSetting>();
+        mAllApnSettings = new ArrayList<ApnSetting>();
         IccRecords r = mIccRecords.get();
         String operator = (r != null) ? r.getOperatorNumeric() : "";
         if (operator != null) {
@@ -2068,16 +1762,16 @@
 
             if (cursor != null) {
                 if (cursor.getCount() > 0) {
-                    mAllApns = createApnList(cursor);
+                    mAllApnSettings = createApnList(cursor);
                 }
                 cursor.close();
             }
         }
 
-        if (mAllApns.isEmpty()) {
+        if (mAllApnSettings.isEmpty()) {
             if (DBG) log("createAllApnList: No APN found for carrier: " + operator);
             mPreferredApn = null;
-            // TODO: What is the right behaviour?
+            // TODO: What is the right behavior?
             //notifyNoData(DataConnection.FailCause.MISSING_UNKNOWN_APN);
         } else {
             mPreferredApn = getPreferredApn();
@@ -2087,60 +1781,33 @@
             }
             if (DBG) log("createAllApnList: mPreferredApn=" + mPreferredApn);
         }
-        if (DBG) log("createAllApnList: X mAllApns=" + mAllApns);
+        if (DBG) log("createAllApnList: X mAllApnSettings=" + mAllApnSettings);
     }
 
-    /** Return the id for a new data connection */
-    private DataConnection createDataConnection() {
+    /** Return the DC AsyncChannel for the new data connection */
+    private DataConnectionAc createDataConnection() {
         if (DBG) log("createDataConnection E");
 
-        RetryManager rm = new RetryManager();
         int id = mUniqueIdGenerator.getAndIncrement();
-        DataConnection conn = DataConnection.makeDataConnection(mPhone, id, rm, this);
+        DataConnection conn = DataConnection.makeDataConnection(mPhone, id,
+                                                this, mDcTesterFailBringUpAll, mDcc);
         mDataConnections.put(id, conn);
         DataConnectionAc dcac = new DataConnectionAc(conn, LOG_TAG);
         int status = dcac.fullyConnectSync(mPhone.getContext(), this, conn.getHandler());
         if (status == AsyncChannel.STATUS_SUCCESSFUL) {
-            mDataConnectionAsyncChannels.put(dcac.dataConnection.getDataConnectionId(), dcac);
+            mDataConnectionAcHashMap.put(dcac.getDataConnectionIdSync(), dcac);
         } else {
-            loge("createDataConnection: Could not connect to dcac.mDc=" + dcac.dataConnection +
-                    " status=" + status);
+            loge("createDataConnection: Could not connect to dcac=" + dcac + " status=" + status);
         }
 
         // install reconnect intent filter for this data connection.
         IntentFilter filter = new IntentFilter();
         filter.addAction(INTENT_RECONNECT_ALARM + '.' + id);
+        filter.addAction(INTENT_RESTART_TRYSETUP_ALARM);
         mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone);
 
         if (DBG) log("createDataConnection() X id=" + id + " dc=" + conn);
-        return conn;
-    }
-
-    private void configureRetry(DataConnectionBase dc, boolean forDefault, int retryCount) {
-        if (DBG) {
-            log("configureRetry: forDefault=" + forDefault + " retryCount=" + retryCount +
-                    " dc=" + dc);
-        }
-        if (dc == null) return;
-
-        if (!dc.configureRetry(getReryConfig(forDefault))) {
-            if (forDefault) {
-                if (!dc.configureRetry(DEFAULT_DATA_RETRY_CONFIG)) {
-                    // Should never happen, log an error and default to a simple linear sequence.
-                    loge("configureRetry: Could not configure using " +
-                            "DEFAULT_DATA_RETRY_CONFIG=" + DEFAULT_DATA_RETRY_CONFIG);
-                    dc.configureRetry(20, 2000, 1000);
-                }
-            } else {
-                if (!dc.configureRetry(SECONDARY_DATA_RETRY_CONFIG)) {
-                    // Should never happen, log an error and default to a simple sequence.
-                    loge("configureRetry: Could note configure using " +
-                            "SECONDARY_DATA_RETRY_CONFIG=" + SECONDARY_DATA_RETRY_CONFIG);
-                    dc.configureRetry("max_retries=3, 333, 333, 333");
-                }
-            }
-        }
-        dc.setRetryCount(retryCount);
+        return dcac;
     }
 
     private void destroyDataConnections() {
@@ -2219,9 +1886,9 @@
                 mPreferredApn = null;
             }
         }
-        if (mAllApns != null) {
-            if (DBG) log("buildWaitingApns: mAllApns=" + mAllApns);
-            for (ApnSetting apn : mAllApns) {
+        if (mAllApnSettings != null) {
+            if (DBG) log("buildWaitingApns: mAllApnSettings=" + mAllApnSettings);
+            for (ApnSetting apn : mAllApnSettings) {
                 if (DBG) log("buildWaitingApns: apn=" + apn);
                 if (apn.canHandleType(requestedApnType)) {
                     if (apn.bearer == 0 || apn.bearer == radioTech) {
@@ -2241,7 +1908,7 @@
             }
             }
         } else {
-            loge("mAllApns is empty!");
+            loge("mAllApnSettings is empty!");
         }
         if (DBG) log("buildWaitingApns: X apnList=" + apnList);
         return apnList;
@@ -2257,13 +1924,6 @@
         return result.toString();
     }
 
-    private void startDelayedRetry(DataConnection.FailCause cause,
-                                   ApnContext apnContext, int retryOverride) {
-        apnContext.setState(DctConstants.State.FAILED);
-        notifyNoData(cause, apnContext);
-        reconnectAfterFail(cause, apnContext, retryOverride);
-    }
-
     private void setPreferredApn(int pos) {
         if (!mCanSetPreferApn) {
             log("setPreferredApn: X !canSEtPreferApn");
@@ -2283,8 +1943,8 @@
     }
 
     private ApnSetting getPreferredApn() {
-        if (mAllApns.isEmpty()) {
-            log("getPreferredApn: X not found mAllApns.isEmpty");
+        if (mAllApnSettings.isEmpty()) {
+            log("getPreferredApn: X not found mAllApnSettings.isEmpty");
             return null;
         }
 
@@ -2304,7 +1964,7 @@
             int pos;
             cursor.moveToFirst();
             pos = cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID));
-            for(ApnSetting p:mAllApns) {
+            for(ApnSetting p : mAllApnSettings) {
                 log("getPreferredApn: apnSetting=" + p);
                 if (p.id == pos && p.canHandleType(mRequestedApnType)) {
                     log("getPreferredApn: X found apnSetting" + p);
@@ -2385,14 +2045,14 @@
                     startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
                 } else {
                     // TODO: Should all PDN states be checked to fail?
-                    if (mState ==DctConstants.State.FAILED) {
+                    if (mState == DctConstants.State.FAILED) {
                         cleanUpAllConnections(false, Phone.REASON_PS_RESTRICT_ENABLED);
-                        resetAllRetryCounts();
                         mReregisterOnReconnectFailure = false;
                     }
                     trySetupData(Phone.REASON_PS_RESTRICT_ENABLED, PhoneConstants.APN_TYPE_DEFAULT);
                 }
                 break;
+
             case DctConstants.EVENT_TRY_SETUP_DATA:
                 if (msg.obj instanceof ApnContext) {
                     onTrySetupData((ApnContext)msg.obj);
@@ -2409,9 +2069,11 @@
                 if (msg.obj instanceof ApnContext) {
                     cleanUpConnection(tearDown, (ApnContext)msg.obj);
                 } else {
-                    loge("EVENT_CLEAN_UP_CONNECTION request w/o apn context");
+                    loge("EVENT_CLEAN_UP_CONNECTION request w/o apn context, call super");
+                    super.handleMessage(msg);
                 }
                 break;
+
             default:
                 // handle the message in the super class DataConnectionTracker
                 super.handleMessage(msg);
@@ -2471,12 +2133,12 @@
 
     @Override
     protected void log(String s) {
-        Rlog.d(LOG_TAG, "[GsmDCT] "+ s);
+        Rlog.d(LOG_TAG, s);
     }
 
     @Override
     protected void loge(String s) {
-        Rlog.e(LOG_TAG, "[GsmDCT] " + s);
+        Rlog.e(LOG_TAG, s);
     }
 
     @Override
@@ -2487,6 +2149,6 @@
         pw.println(" canSetPreferApn=" + mCanSetPreferApn);
         pw.println(" mApnObserver=" + mApnObserver);
         pw.println(" getOverallState=" + getOverallState());
-        pw.println(" mDataConnectionAsyncChannels=%s\n" + mDataConnectionAsyncChannels);
+        pw.println(" mDataConnectionAsyncChannels=%s\n" + mDataConnectionAcHashMap);
     }
 }
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataConnectionTrackerBase.java b/src/java/com/android/internal/telephony/dataconnection/DataConnectionTrackerBase.java
index 66eb400..b302930 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataConnectionTrackerBase.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataConnectionTrackerBase.java
@@ -33,6 +33,7 @@
 import android.os.AsyncResult;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.HandlerThread;
 import android.os.Message;
 import android.os.Messenger;
 import android.os.SystemClock;
@@ -70,7 +71,8 @@
  */
 public abstract class DataConnectionTrackerBase extends Handler {
     protected static final boolean DBG = true;
-    protected static final boolean VDBG = false;
+    protected static final boolean VDBG = false; // STOPSHIP if true
+    protected static final boolean VDBG_STALL = true; // STOPSHIP if true
     protected static final boolean RADIO_TESTS = false;
 
     /**
@@ -86,6 +88,8 @@
     protected static final int APN_DELAY_MILLIS =
                                 SystemProperties.getInt("persist.radio.apn_delay", 5000);
 
+    AlarmManager mAlarmManager;
+
     protected Object mDataEnabledLock = new Object();
 
     // responds to the setInternalDataEnabled call - used internally to turn off data
@@ -155,17 +159,27 @@
 
     protected String RADIO_RESET_PROPERTY = "gsm.radioreset";
 
-
-    // TODO: See if we can remove INTENT_RECONNECT_ALARM
-    //       having to have different values for GSM and
-    //       CDMA. If so we can then remove the need for
-    //       getActionIntentReconnectAlarm.
+    protected static final String INTENT_RECONNECT_ALARM =
+            "com.android.internal.telephony.data-reconnect";
+    protected static final String INTENT_RECONNECT_ALARM_EXTRA_TYPE = "reconnect_alarm_extra_type";
     protected static final String INTENT_RECONNECT_ALARM_EXTRA_REASON =
-        "reconnect_alarm_extra_reason";
+            "reconnect_alarm_extra_reason";
+
+    protected static final String INTENT_RESTART_TRYSETUP_ALARM =
+            "com.android.internal.telephony.data-restart-trysetup";
+    protected static final String INTENT_RESTART_TRYSETUP_ALARM_EXTRA_TYPE =
+            "restart_trysetup_alarm_extra_type";
+
+    protected static final String INTENT_DATA_STALL_ALARM =
+            "com.android.internal.telephony.data-stall";
+
 
 
     protected static final String DEFALUT_DATA_ON_BOOT_PROP = "net.def_data_on_boot";
 
+    protected DcTesterFailBringUpAll mDcTesterFailBringUpAll;
+    protected DcController mDcc;
+
     // member variables
     protected PhoneBase mPhone;
     protected UiccController mUiccController;
@@ -210,11 +224,11 @@
     protected AtomicInteger mUniqueIdGenerator = new AtomicInteger(0);
 
     /** The data connections. */
-    protected HashMap<Integer, DataConnectionBase> mDataConnections =
-        new HashMap<Integer, DataConnectionBase>();
+    protected HashMap<Integer, DataConnection> mDataConnections =
+        new HashMap<Integer, DataConnection>();
 
     /** The data connection async channels */
-    protected HashMap<Integer, DataConnectionAc> mDataConnectionAsyncChannels =
+    protected HashMap<Integer, DataConnectionAc> mDataConnectionAcHashMap =
         new HashMap<Integer, DataConnectionAc>();
 
     /** Convert an ApnType string to Id (TODO: Use "enumeration" instead of String for ApnType) */
@@ -229,7 +243,7 @@
     protected ApnSetting mActiveApn;
 
     /** allApns holds all apns */
-    protected ArrayList<ApnSetting> mAllApns = null;
+    protected ArrayList<ApnSetting> mAllApnSettings = null;
 
     /** preferred apn */
     protected ApnSetting mPreferredApn = null;
@@ -259,10 +273,13 @@
                 stopNetStatPoll();
                 startNetStatPoll();
                 restartDataStallAlarm();
-            } else if (action.startsWith(getActionIntentReconnectAlarm())) {
+            } else if (action.startsWith(INTENT_RECONNECT_ALARM)) {
                 if (DBG) log("Reconnect alarm. Previous state was " + mState);
                 onActionIntentReconnectAlarm(intent);
-            } else if (action.equals(getActionIntentDataStallAlarm())) {
+            } else if (action.startsWith(INTENT_RESTART_TRYSETUP_ALARM)) {
+                if (DBG) log("Restart trySetup alarm");
+                onActionIntentRestartTrySetupAlarm(intent);
+            } else if (action.equals(INTENT_DATA_STALL_ALARM)) {
                 onActionIntentDataStallAlarm(intent);
             } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
                 final android.net.NetworkInfo networkInfo = (NetworkInfo)
@@ -284,7 +301,6 @@
         }
     };
 
-    private final DataRoamingSettingObserver mDataRoamingSettingObserver;
     private Runnable mPollNetStat = new Runnable()
     {
         @Override
@@ -307,32 +323,52 @@
     };
 
     private class DataRoamingSettingObserver extends ContentObserver {
-        public DataRoamingSettingObserver(Handler handler) {
+
+        public DataRoamingSettingObserver(Handler handler, Context context) {
             super(handler);
+            mResolver = context.getContentResolver();
         }
 
-        public void register(Context context) {
-            final ContentResolver resolver = context.getContentResolver();
-            resolver.registerContentObserver(
+        public void register() {
+            mResolver.registerContentObserver(
                     Settings.Global.getUriFor(Settings.Global.DATA_ROAMING), false, this);
         }
 
-        public void unregister(Context context) {
-            final ContentResolver resolver = context.getContentResolver();
-            resolver.unregisterContentObserver(this);
+        public void unregister() {
+            mResolver.unregisterContentObserver(this);
         }
 
         @Override
         public void onChange(boolean selfChange) {
             // already running on mPhone handler thread
-            handleDataOnRoamingChange();
+            if (mPhone.getServiceState().getRoaming()) {
+                sendMessage(obtainMessage(DctConstants.EVENT_ROAMING_ON));
+            }
         }
     }
+    private final DataRoamingSettingObserver mDataRoamingSettingObserver;
+
+    /**
+     * The Initial MaxRetry sent to a DataConnection as a parameter
+     * to DataConnectionAc.bringUp. This value can be defined at compile
+     * time using the SystemProperty Settings.Global.DCT_INITIAL_MAX_RETRY
+     * and at runtime using gservices to change Settings.Global.DCT_INITIAL_MAX_RETRY.
+     */
+    private static final int DEFAULT_MDC_INITIAL_RETRY = 1;
+    protected int getInitialMaxRetry() {
+        // 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);
+
+        // Check if its been overridden
+        return Settings.Global.getInt(mResolver,
+                Settings.Global.MDC_INITIAL_MAX_RETRY, value);
+    }
 
     /**
-     * Maintian the sum of transmit and receive packets.
+     * Maintain the sum of transmit and receive packets.
      *
-     * The packet counts are initizlied and reset to -1 and
+     * The packet counts are initialized and reset to -1 and
      * remain -1 until they can be updated.
      */
     public class TxRxSum {
@@ -371,18 +407,47 @@
 
     protected void onActionIntentReconnectAlarm(Intent intent) {
         String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON);
-        if (mState == DctConstants.State.FAILED) {
-            Message msg = obtainMessage(DctConstants.EVENT_CLEAN_UP_CONNECTION);
-            msg.arg1 = 0; // tearDown is false
-            msg.arg2 = 0;
-            msg.obj = reason;
-            sendMessage(msg);
+        String apnType = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE);
+
+        ApnContext apnContext = mApnContexts.get(apnType);
+
+        if (DBG) {
+            log("onActionIntentReconnectAlarm: mState=" + mState + " reason=" + reason +
+                    " apnType=" + apnType + " apnContext=" + apnContext +
+                    " mDataConnectionAsyncChannels=" + mDataConnectionAcHashMap);
         }
-        sendMessage(obtainMessage(DctConstants.EVENT_TRY_SETUP_DATA));
+
+        if ((apnContext != null) && (apnContext.isEnabled())) {
+            apnContext.setReason(reason);
+            DctConstants.State apnContextState = apnContext.getState();
+            if (DBG) {
+                log("onActionIntentReconnectAlarm: apnContext state=" + apnContextState);
+            }
+            if ((apnContextState == DctConstants.State.FAILED)
+                    || (apnContextState == DctConstants.State.IDLE)) {
+                if (DBG) {
+                    log("onActionIntentReconnectAlarm: state is FAILED|IDLE, disassociate");
+                }
+                apnContext.setDataConnectionAc(null);
+                apnContext.setState(DctConstants.State.IDLE);
+            } else {
+                if (DBG) log("onActionIntentReconnectAlarm: keep associated");
+            }
+            // TODO: IF already associated should we send the EVENT_TRY_SETUP_DATA???
+            sendMessage(obtainMessage(DctConstants.EVENT_TRY_SETUP_DATA, apnContext));
+
+            apnContext.setReconnectIntent(null);
+        }
+    }
+
+    protected void onActionIntentRestartTrySetupAlarm(Intent intent) {
+        String apnType = intent.getStringExtra(INTENT_RESTART_TRYSETUP_ALARM_EXTRA_TYPE);
+        ApnContext apnContext = mApnContexts.get(apnType);
+        sendMessage(obtainMessage(DctConstants.EVENT_TRY_SETUP_DATA, apnContext));
     }
 
     protected void onActionIntentDataStallAlarm(Intent intent) {
-        if (VDBG) log("onActionIntentDataStallAlarm: action=" + intent.getAction());
+        if (VDBG_STALL) log("onActionIntentDataStallAlarm: action=" + intent.getAction());
         Message msg = obtainMessage(DctConstants.EVENT_DATA_STALL_ALARM,
                 intent.getAction());
         msg.arg1 = intent.getIntExtra(DATA_STALL_ALARM_TAG_EXTRA, 0);
@@ -396,22 +461,24 @@
         super();
         if (DBG) log("DCT.constructor");
         mPhone = phone;
+        mResolver = mPhone.getContext().getContentResolver();
         mUiccController = UiccController.getInstance();
         mUiccController.registerForIccChanged(this, DctConstants.EVENT_ICC_CHANGED, null);
+        mAlarmManager =
+                (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
+
 
         IntentFilter filter = new IntentFilter();
-        filter.addAction(getActionIntentReconnectAlarm());
+        filter.addAction(INTENT_RECONNECT_ALARM);
         filter.addAction(Intent.ACTION_SCREEN_ON);
         filter.addAction(Intent.ACTION_SCREEN_OFF);
         filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
         filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
-        filter.addAction(getActionIntentDataStallAlarm());
+        filter.addAction(INTENT_DATA_STALL_ALARM);
 
         mUserDataEnabled = Settings.Global.getInt(
                 mPhone.getContext().getContentResolver(), Settings.Global.MOBILE_DATA, 1) == 1;
 
-        // TODO: Why is this registering the phone as the receiver of the intent
-        //       and not its own handler?
         mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone);
 
         // This preference tells us 1) initial condition for "dataEnabled",
@@ -426,23 +493,29 @@
         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mPhone.getContext());
         mAutoAttachOnCreation = sp.getBoolean(PhoneBase.DATA_DISABLED_ON_BOOT_KEY, false);
 
-        // watch for changes to Settings.Global.DATA_ROAMING
-        mDataRoamingSettingObserver = new DataRoamingSettingObserver(mPhone);
-        mDataRoamingSettingObserver.register(mPhone.getContext());
+        // Watch for changes to Settings.Global.DATA_ROAMING
+        mDataRoamingSettingObserver = new DataRoamingSettingObserver(mPhone, mPhone.getContext());
+        mDataRoamingSettingObserver.register();
 
-        mResolver = mPhone.getContext().getContentResolver();
+        HandlerThread dcHandlerThread = new HandlerThread("DcHandlerThread");
+        dcHandlerThread.start();
+        Handler dcHandler = new Handler(dcHandlerThread.getLooper());
+        mDcc = DcController.makeDcc(mPhone, this, dcHandler);
+        mDcTesterFailBringUpAll = new DcTesterFailBringUpAll(mPhone, dcHandler);
     }
 
     public void dispose() {
         if (DBG) log("DCT.dispose");
-        for (DataConnectionAc dcac : mDataConnectionAsyncChannels.values()) {
+        for (DataConnectionAc dcac : mDataConnectionAcHashMap.values()) {
             dcac.disconnect();
         }
-        mDataConnectionAsyncChannels.clear();
+        mDataConnectionAcHashMap.clear();
         mIsDisposed = true;
         mPhone.getContext().unregisterReceiver(mIntentReceiver);
-        mDataRoamingSettingObserver.unregister(mPhone.getContext());
         mUiccController.unregisterForIccChanged(this);
+        mDataRoamingSettingObserver.unregister();
+        mDcc.dispose();
+        mDcTesterFailBringUpAll.dispose();
     }
 
     protected void broadcastMessenger() {
@@ -529,18 +602,7 @@
         }
     }
 
-    private void handleDataOnRoamingChange() {
-        if (mPhone.getServiceState().getRoaming()) {
-            if (getDataOnRoamingEnabled()) {
-                resetAllRetryCounts();
-            }
-            sendMessage(obtainMessage(DctConstants.EVENT_ROAMING_ON));
-        }
-    }
-
     // abstract methods
-    protected abstract String getActionIntentReconnectAlarm();
-    protected abstract String getActionIntentDataStallAlarm();
     protected abstract void restartRadio();
     protected abstract void log(String s);
     protected abstract void loge(String s);
@@ -556,7 +618,9 @@
     protected abstract void onRadioAvailable();
     protected abstract void onRadioOffOrNotAvailable();
     protected abstract void onDataSetupComplete(AsyncResult ar);
+    protected abstract void onDataSetupCompleteError(AsyncResult ar);
     protected abstract void onDisconnectDone(int connId, AsyncResult ar);
+    protected abstract void onDisconnectDcRetrying(int connId, AsyncResult ar);
     protected abstract void onVoiceCallStarted();
     protected abstract void onVoiceCallEnded();
     protected abstract void onCleanUpConnection(boolean tearDown, int apnId, String reason);
@@ -570,7 +634,7 @@
             case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
                 log("DISCONNECTED_CONNECTED: msg=" + msg);
                 DataConnectionAc dcac = (DataConnectionAc) msg.obj;
-                mDataConnectionAsyncChannels.remove(dcac.dataConnection.getDataConnectionId());
+                mDataConnectionAcHashMap.remove(dcac.getDataConnectionIdSync());
                 dcac.disconnected();
                 break;
             }
@@ -591,9 +655,6 @@
                 break;
 
             case DctConstants.EVENT_ROAMING_OFF:
-                if (getDataOnRoamingEnabled() == false) {
-                    resetAllRetryCounts();
-                }
                 onRoamingOff();
                 break;
 
@@ -614,11 +675,20 @@
                 onDataSetupComplete((AsyncResult) msg.obj);
                 break;
 
+            case DctConstants.EVENT_DATA_SETUP_COMPLETE_ERROR:
+                onDataSetupCompleteError((AsyncResult) msg.obj);
+                break;
+
             case DctConstants.EVENT_DISCONNECT_DONE:
                 log("DataConnectoinTracker.handleMessage: EVENT_DISCONNECT_DONE msg=" + msg);
                 onDisconnectDone(msg.arg1, (AsyncResult) msg.obj);
                 break;
 
+            case DctConstants.EVENT_DISCONNECT_DC_RETRYING:
+                log("DataConnectoinTracker.handleMessage: EVENT_DISCONNECT_DC_RETRYING msg=" + msg);
+                onDisconnectDcRetrying(msg.arg1, (AsyncResult) msg.obj);
+                break;
+
             case DctConstants.EVENT_VOICE_CALL_STARTED:
                 onVoiceCallStarted();
                 break;
@@ -669,10 +739,10 @@
                 onSetPolicyDataEnabled(enabled);
                 break;
             }
-            case DctConstants.EVENT_ICC_CHANGED:
+            case DctConstants.EVENT_ICC_CHANGED: {
                 onUpdateIcc();
                 break;
-
+            }
             default:
                 Rlog.e("DATA", "Unidentified event msg=" + msg);
                 break;
@@ -754,8 +824,7 @@
         int id = apnTypeToId(apnType);
 
         if (isApnIdEnabled(id)) {
-            // TODO - remove this cdma-only hack and support multiple DCs.
-            DataConnectionAc dcac = mDataConnectionAsyncChannels.get(0);
+            DataConnectionAc dcac = mDataConnectionAcHashMap.get(0);
             return dcac.getLinkPropertiesSync();
         } else {
             return new LinkProperties();
@@ -765,8 +834,7 @@
     public LinkCapabilities getLinkCapabilities(String apnType) {
         int id = apnTypeToId(apnType);
         if (isApnIdEnabled(id)) {
-            // TODO - remove this cdma-only hack and support multiple DCs.
-            DataConnectionAc dcac = mDataConnectionAsyncChannels.get(0);
+            DataConnectionAc dcac = mDataConnectionAcHashMap.get(0);
             return dcac.getLinkCapabilitiesSync();
         } else {
             return new LinkCapabilities();
@@ -789,6 +857,7 @@
         switch (mState) {
             case IDLE:
                 break;
+            case RETRYING:
             case CONNECTING:
             case SCANNING:
                 mPhone.notifyDataConnection(reason, apnIdToType(apnId),
@@ -802,7 +871,7 @@
                         PhoneConstants.DataState.CONNECTED);
                 break;
             default:
-                // Ingore
+                // Ignore
                 break;
         }
     }
@@ -1021,7 +1090,6 @@
             mInternalDataEnabled = enabled;
             if (enabled) {
                 log("onSetInternalDataEnabled: changed to enabled, try to setup data call");
-                resetAllRetryCounts();
                 onTrySetupData(Phone.REASON_DATA_ENABLED);
             } else {
                 log("onSetInternalDataEnabled: changed to disabled, cleanUpAllConnections");
@@ -1055,7 +1123,6 @@
                 }
                 if (prevEnabled != getAnyDataEnabled()) {
                     if (!prevEnabled) {
-                        resetAllRetryCounts();
                         onTrySetupData(Phone.REASON_DATA_ENABLED);
                     } else {
                         onCleanUpAllConnections(Phone.REASON_DATA_DISABLED);
@@ -1075,7 +1142,6 @@
                 sPolicyDataEnabled = enabled;
                 if (prevEnabled != getAnyDataEnabled()) {
                     if (!prevEnabled) {
-                        resetAllRetryCounts();
                         onTrySetupData(Phone.REASON_DATA_ENABLED);
                     } else {
                         onCleanUpAllConnections(Phone.REASON_DATA_DISABLED);
@@ -1106,15 +1172,6 @@
         }
     }
 
-    protected void resetAllRetryCounts() {
-        for (ApnContext ac : mApnContexts.values()) {
-            ac.setRetryCount(0);
-        }
-        for (DataConnectionBase dc : mDataConnections.values()) {
-            dc.resetRetryCount();
-        }
-    }
-
     protected void resetPollStats() {
         mTxPkts = -1;
         mRxPkts = -1;
@@ -1198,13 +1255,13 @@
     public int getRecoveryAction() {
         int action = Settings.System.getInt(mPhone.getContext().getContentResolver(),
                 "radio.data.stall.recovery.action", RecoveryAction.GET_DATA_CALL_LIST);
-        if (VDBG) log("getRecoveryAction: " + action);
+        if (VDBG_STALL) log("getRecoveryAction: " + action);
         return action;
     }
     public void putRecoveryAction(int action) {
         Settings.System.putInt(mPhone.getContext().getContentResolver(),
                 "radio.data.stall.recovery.action", action);
-        if (VDBG) log("putRecoveryAction: " + action);
+        if (VDBG_STALL) log("putRecoveryAction: " + action);
     }
 
     protected boolean isConnected() {
@@ -1274,7 +1331,7 @@
         TxRxSum preTxRxSum = new TxRxSum(mDataStallTxRxSum);
         mDataStallTxRxSum.updateTxRxSum();
 
-        if (VDBG) {
+        if (VDBG_STALL) {
             log("updateDataStallInfo: mDataStallTxRxSum=" + mDataStallTxRxSum +
                     " preTxRxSum=" + preTxRxSum);
         }
@@ -1289,7 +1346,7 @@
             }
         }
         if ( sent > 0 && received > 0 ) {
-            if (VDBG) log("updateDataStallInfo: IN/OUT");
+            if (VDBG_STALL) log("updateDataStallInfo: IN/OUT");
             mSentSinceLastRecv = 0;
             putRecoveryAction(RecoveryAction.GET_DATA_CALL_LIST);
         } else if (sent > 0 && received == 0) {
@@ -1303,11 +1360,11 @@
                         " mSentSinceLastRecv=" + mSentSinceLastRecv);
             }
         } else if (sent == 0 && received > 0) {
-            if (VDBG) log("updateDataStallInfo: IN");
+            if (VDBG_STALL) log("updateDataStallInfo: IN");
             mSentSinceLastRecv = 0;
             putRecoveryAction(RecoveryAction.GET_DATA_CALL_LIST);
         } else {
-            if (VDBG) log("updateDataStallInfo: NONE");
+            if (VDBG_STALL) log("updateDataStallInfo: NONE");
         }
     }
 
@@ -1332,7 +1389,7 @@
             suspectedStall = DATA_STALL_SUSPECTED;
             sendMessage(obtainMessage(DctConstants.EVENT_DO_RECOVERY));
         } else {
-            if (VDBG) {
+            if (VDBG_STALL) {
                 log("onDataStallAlarm: tag=" + tag + " Sent " + String.valueOf(mSentSinceLastRecv) +
                     " pkts since last received, < watchdogTrigger=" + hangWatchdogTrigger);
             }
@@ -1358,33 +1415,31 @@
             }
 
             mDataStallAlarmTag += 1;
-            if (VDBG) {
+            if (VDBG_STALL) {
                 log("startDataStallAlarm: tag=" + mDataStallAlarmTag +
                         " delay=" + (delayInMs / 1000) + "s");
             }
-            AlarmManager am =
-                    (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
-
-            Intent intent = new Intent(getActionIntentDataStallAlarm());
+            Intent intent = new Intent(INTENT_DATA_STALL_ALARM);
             intent.putExtra(DATA_STALL_ALARM_TAG_EXTRA, mDataStallAlarmTag);
             mDataStallAlarmIntent = PendingIntent.getBroadcast(mPhone.getContext(), 0, intent,
                     PendingIntent.FLAG_UPDATE_CURRENT);
-            am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+            mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                     SystemClock.elapsedRealtime() + delayInMs, mDataStallAlarmIntent);
+        } else {
+            if (VDBG_STALL) {
+                log("startDataStallAlarm: NOT started, no connection tag=" + mDataStallAlarmTag);
+            }
         }
     }
 
     protected void stopDataStallAlarm() {
-        AlarmManager am =
-            (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
-
-        if (VDBG) {
+        if (VDBG_STALL) {
             log("stopDataStallAlarm: current tag=" + mDataStallAlarmTag +
                     " mDataStallAlarmIntent=" + mDataStallAlarmIntent);
         }
         mDataStallAlarmTag += 1;
         if (mDataStallAlarmIntent != null) {
-            am.cancel(mDataStallAlarmIntent);
+            mAlarmManager.cancel(mDataStallAlarmIntent);
             mDataStallAlarmIntent = null;
         }
     }
@@ -1396,13 +1451,23 @@
         int nextAction = getRecoveryAction();
 
         if (RecoveryAction.isAggressiveRecovery(nextAction)) {
-            if (DBG) log("data stall recovery action is pending. not resetting the alarm.");
+            if (DBG) log("restartDataStallAlarm: action is pending. not resetting the alarm.");
             return;
         }
+        if (VDBG_STALL) log("restartDataStallAlarm: stop then start.");
         stopDataStallAlarm();
         startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
     }
 
+    void sendCleanUpConnection(boolean tearDown, ApnContext apnContext) {
+        if (DBG)log("sendCleanUpConnection: tearDown=" + tearDown + " apnContext=" + apnContext);
+        Message msg = obtainMessage(DctConstants.EVENT_CLEAN_UP_CONNECTION);
+        msg.arg1 = tearDown ? 1 : 0;
+        msg.arg2 = 0;
+        msg.obj = apnContext;
+        sendMessage(msg);
+    }
+
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("DataConnectionTrackerBase:");
         pw.println(" RADIO_TESTS=" + RADIO_TESTS);
@@ -1436,25 +1501,43 @@
         pw.println(" mUniqueIdGenerator=" + mUniqueIdGenerator);
         pw.flush();
         pw.println(" ***************************************");
-        Set<Entry<Integer, DataConnectionBase> > mDcSet = mDataConnections.entrySet();
-        pw.println(" mDataConnections: count=" + mDcSet.size());
-        for (Entry<Integer, DataConnectionBase> entry : mDcSet) {
-            pw.printf(" *** mDataConnection[%d] \n", entry.getKey());
-            entry.getValue().dump(fd, pw, args);
+        DcController dcc = mDcc;
+        if (dcc != null) {
+            dcc.dump(fd, pw, args);
+        } else {
+            pw.println(" mDcc=null");
+        }
+        pw.println(" ***************************************");
+        HashMap<Integer, DataConnection> dcs = mDataConnections;
+        if (dcs != null) {
+            Set<Entry<Integer, DataConnection> > mDcSet = mDataConnections.entrySet();
+            pw.println(" mDataConnections: count=" + mDcSet.size());
+            for (Entry<Integer, DataConnection> entry : mDcSet) {
+                pw.printf(" *** mDataConnection[%d] \n", entry.getKey());
+                entry.getValue().dump(fd, pw, args);
+            }
+        } else {
+            pw.println("mDataConnections=null");
         }
         pw.println(" ***************************************");
         pw.flush();
-        Set<Entry<String, Integer>> mApnToDcIdSet = mApnToDataConnectionId.entrySet();
-        pw.println(" mApnToDataConnectonId size=" + mApnToDcIdSet.size());
-        for (Entry<String, Integer> entry : mApnToDcIdSet) {
-            pw.printf(" mApnToDataConnectonId[%s]=%d\n", entry.getKey(), entry.getValue());
+        HashMap<String, Integer> apnToDcId = mApnToDataConnectionId;
+        if (apnToDcId != null) {
+            Set<Entry<String, Integer>> apnToDcIdSet = apnToDcId.entrySet();
+            pw.println(" mApnToDataConnectonId size=" + apnToDcIdSet.size());
+            for (Entry<String, Integer> entry : apnToDcIdSet) {
+                pw.printf(" mApnToDataConnectonId[%s]=%d\n", entry.getKey(), entry.getValue());
+            }
+        } else {
+            pw.println("mApnToDataConnectionId=null");
         }
         pw.println(" ***************************************");
         pw.flush();
-        if (mApnContexts != null) {
-            Set<Entry<String, ApnContext>> mApnContextsSet = mApnContexts.entrySet();
-            pw.println(" mApnContexts size=" + mApnContextsSet.size());
-            for (Entry<String, ApnContext> entry : mApnContextsSet) {
+        ConcurrentHashMap<String, ApnContext> apnCtxs = mApnContexts;
+        if (apnCtxs != null) {
+            Set<Entry<String, ApnContext>> apnCtxsSet = apnCtxs.entrySet();
+            pw.println(" mApnContexts size=" + apnCtxsSet.size());
+            for (Entry<String, ApnContext> entry : apnCtxsSet) {
                 entry.getValue().dump(fd, pw, args);
             }
             pw.println(" ***************************************");
@@ -1463,14 +1546,15 @@
         }
         pw.flush();
         pw.println(" mActiveApn=" + mActiveApn);
-        if (mAllApns != null) {
-            pw.println(" mAllApns size=" + mAllApns.size());
-            for (int i=0; i < mAllApns.size(); i++) {
-                pw.printf(" mAllApns[%d]: %s\n", i, mAllApns.get(i));
+        ArrayList<ApnSetting> apnSettings = mAllApnSettings;
+        if (apnSettings != null) {
+            pw.println(" mAllApnSettings size=" + apnSettings.size());
+            for (int i=0; i < apnSettings.size(); i++) {
+                pw.printf(" mAllApnSettings[%d]: %s\n", i, apnSettings.get(i));
             }
             pw.flush();
         } else {
-            pw.println(" mAllApns=null");
+            pw.println(" mAllApnSettings=null");
         }
         pw.println(" mPreferredApn=" + mPreferredApn);
         pw.println(" mIsPsRestricted=" + mIsPsRestricted);
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcController.java b/src/java/com/android/internal/telephony/dataconnection/DcController.java
new file mode 100644
index 0000000..8ffd54c
--- /dev/null
+++ b/src/java/com/android/internal/telephony/dataconnection/DcController.java
@@ -0,0 +1,357 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.dataconnection;
+
+import android.net.LinkAddress;
+import android.net.NetworkUtils;
+import android.net.LinkProperties.CompareResult;
+import android.os.AsyncResult;
+import android.os.Handler;
+import android.os.Message;
+import android.os.SystemProperties;
+import android.telephony.Rlog;
+import com.android.internal.telephony.PhoneBase;
+import com.android.internal.telephony.PhoneConstants;
+import com.android.internal.telephony.dataconnection.DataConnection.UpdateLinkPropertyResult;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * Data Connection Controller which is a package visible class and controls
+ * multiple data connections. For instance listening for unsolicited messages
+ * and then demultiplexing them to the appropriate DC.
+ */
+class DcController extends StateMachine {
+    private static final boolean DBG = true;
+    private static final boolean VDBG = false;
+    protected static final boolean DEBUGGABLE = SystemProperties.getInt("ro.debuggable", 0) == 1;
+
+    private PhoneBase mPhone;
+    private DataConnectionTrackerBase mDct;
+    private DcTesterDeactivateAll mDcTesterDeactivateAll;
+
+    // package as its used by Testing code
+    ArrayList<DataConnection> mDcListAll = new ArrayList<DataConnection>();
+    private HashMap<Integer, DataConnection> mDcListActiveByCid =
+            new HashMap<Integer, DataConnection>();
+
+    /**
+     * Constants for the data connection activity:
+     * physical link down/up
+     *
+     * TODO: Move to RILConstants.java
+     */
+    static final int DATA_CONNECTION_ACTIVE_PH_LINK_INACTIVE = 0;
+    static final int DATA_CONNECTION_ACTIVE_PH_LINK_DORMANT = 1;
+    static final int DATA_CONNECTION_ACTIVE_PH_LINK_UP = 2;
+
+    private DccDefaultState mDccDefaultState = new DccDefaultState();
+
+    /**
+     * Constructor.
+     *
+     * @param name to be used for the Controller
+     * @param phone the phone associated with Dcc and Dct
+     * @param dct the DataConnectionTracker associated with Dcc
+     * @param handler defines the thread/looper to be used with Dcc
+     */
+    private DcController(String name, PhoneBase phone, DataConnectionTrackerBase dct,
+            Handler handler) {
+        super(name, handler);
+        setLogRecSize(300);
+        log("E ctor");
+        mPhone = phone;
+        mDct = dct;
+        addState(mDccDefaultState);
+        setInitialState(mDccDefaultState);
+        log("X ctor");
+    }
+
+    static DcController makeDcc(PhoneBase phone, DataConnectionTrackerBase dct, Handler handler) {
+        DcController dcc = new DcController("Dcc", phone, dct, handler);
+        dcc.start();
+        return dcc;
+    }
+
+    void dispose() {
+        log("dispose: call quiteNow()");
+        quitNow();
+    }
+
+    void addDc(DataConnection dc) {
+        mDcListAll.add(dc);
+    }
+
+    void removeDc(DataConnection dc) {
+        mDcListActiveByCid.remove(dc.mCid);
+        mDcListAll.remove(dc);
+    }
+
+    void addActiveDcByCid(DataConnection dc) {
+        if (DBG && dc.mCid < 0) {
+            log("addActiveDcByCid dc.mCid < 0 dc=" + dc);
+        }
+        mDcListActiveByCid.put(dc.mCid, dc);
+    }
+
+    void removeActiveDcByCid(DataConnection dc) {
+        DataConnection removedDc = mDcListActiveByCid.remove(dc.mCid);
+        if (DBG && removedDc == null) {
+            log("removeActiveDcByCid removedDc=null dc=" + dc);
+        }
+    }
+
+    private class DccDefaultState extends State {
+        @Override
+        public void enter() {
+            mPhone.mCi.registerForRilConnected(getHandler(),
+                    DataConnection.EVENT_RIL_CONNECTED, null);
+            mPhone.mCi.registerForDataNetworkStateChanged(getHandler(),
+                    DataConnection.EVENT_DATA_STATE_CHANGED, null);
+            if (DEBUGGABLE) {
+                mDcTesterDeactivateAll =
+                        new DcTesterDeactivateAll(mPhone, DcController.this, getHandler());
+            }
+        }
+
+        @Override
+        public void exit() {
+            if (mPhone != null) {
+                mPhone.mCi.unregisterForRilConnected(getHandler());
+                mPhone.mCi.unregisterForDataNetworkStateChanged(getHandler());
+            }
+            if (mDcTesterDeactivateAll != null) {
+                mDcTesterDeactivateAll.dispose();
+            }
+        }
+
+        @Override
+        public boolean processMessage(Message msg) {
+            AsyncResult ar;
+
+            switch (msg.what) {
+                case DataConnection.EVENT_RIL_CONNECTED:
+                    ar = (AsyncResult)msg.obj;
+                    if (ar.exception == null) {
+                        if (DBG) {
+                            log("DccDefaultState: msg.what=EVENT_RIL_CONNECTED mRilVersion=" +
+                                ar.result);
+                        }
+                    } else {
+                        log("DccDefaultState: Unexpected exception on EVENT_RIL_CONNECTED");
+                    }
+                    break;
+
+                case DataConnection.EVENT_DATA_STATE_CHANGED:
+                    ar = (AsyncResult)msg.obj;
+                    if (ar.exception == null) {
+                        onDataStateChanged((ArrayList<DataCallResponse>)ar.result);
+                    } else {
+                        log("DccDefaultState: EVENT_DATA_STATE_CHANGED:" +
+                                    " exception; likely radio not available, ignore");
+                    }
+                    break;
+            }
+            return HANDLED;
+        }
+
+        /**
+         * Process the new list of "known" Data Calls
+         * @param dcsList as sent by RIL_UNSOL_DATA_CALL_LIST_CHANGED
+         */
+        private void onDataStateChanged(ArrayList<DataCallResponse> dcsList) {
+            if (DBG) {
+                lr("onDataStateChanged: dcsList=" + dcsList
+                        + " mDcListActiveByCid=" + mDcListActiveByCid);
+            }
+            if (VDBG) {
+                log("onDataStateChanged: mDcListAll=" + mDcListAll);
+            }
+
+            // Create hashmap of cid to DataCallResponse
+            HashMap<Integer, DataCallResponse> dataCallResponseListByCid =
+                    new HashMap<Integer, DataCallResponse>();
+            for (DataCallResponse dcs : dcsList) {
+                dataCallResponseListByCid.put(dcs.cid, dcs);
+            }
+
+            // Add a DC that is active but not in the
+            // dcsList to the list of DC's to retry
+            ArrayList<DataConnection> dcsToRetry = new ArrayList<DataConnection>();
+            for (DataConnection dc : mDcListActiveByCid.values()) {
+                if (dataCallResponseListByCid.get(dc.mCid) == null) {
+                    if (DBG) log("onDataStateChanged: add to retry dc=" + dc);
+                    dcsToRetry.add(dc);
+                }
+            }
+            if (DBG) log("onDataStateChanged: dcsToRetry=" + dcsToRetry);
+
+            // Find which connections have changed state and send a notification or cleanup
+            // and any that are in active need to be retried.
+            ArrayList<ApnContext> apnsToCleanup = new ArrayList<ApnContext>();
+
+            for (DataCallResponse newState : dcsList) {
+                DataConnection dc = mDcListActiveByCid.get(newState.cid);
+                if (dc == null) {
+                    // UNSOL_DATA_CALL_LIST_CHANGED arrived before SETUP_DATA_CALL completed.
+                    loge("onDataStateChanged: no associated DC yet, ignore");
+                    continue;
+                }
+
+                if (dc.mApnContexts.size() == 0) {
+                    if (DBG) loge("onDataStateChanged: no connected apns, ignore");
+                } else {
+                    // Determine if the connection/apnContext should be cleaned up
+                    // or just a notification should be sent out.
+                    if (DBG) log("onDataStateChanged: Found ConnId=" + newState.cid
+                            + " newState=" + newState.toString());
+                    if (newState.active == DATA_CONNECTION_ACTIVE_PH_LINK_INACTIVE) {
+                        if (DBG) log("onDataStateChanged: inactive, add to retry list");
+                        dcsToRetry.add(dc);
+                    } else {
+                        // Its active so update the DataConnections link properties
+                        UpdateLinkPropertyResult result = dc.updateLinkProperty(newState);
+                        if (result.oldLp.equals(result.newLp)) {
+                            if (DBG) log("onDataStateChanged: no change");
+                        } else {
+                            if (result.oldLp.isIdenticalInterfaceName(result.newLp)) {
+                                if (! result.oldLp.isIdenticalDnses(result.newLp) ||
+                                        ! result.oldLp.isIdenticalRoutes(result.newLp) ||
+                                        ! result.oldLp.isIdenticalHttpProxy(result.newLp) ||
+                                        ! result.oldLp.isIdenticalAddresses(result.newLp)) {
+                                    // If the same address type was removed and
+                                    // added we need to cleanup
+                                    CompareResult<LinkAddress> car =
+                                        result.oldLp.compareAddresses(result.newLp);
+                                    if (DBG) {
+                                        log("onDataStateChanged: oldLp=" + result.oldLp +
+                                                " newLp=" + result.newLp + " car=" + car);
+                                    }
+                                    boolean needToClean = false;
+                                    for (LinkAddress added : car.added) {
+                                        for (LinkAddress removed : car.removed) {
+                                            if (NetworkUtils.addressTypeMatches(
+                                                    removed.getAddress(),
+                                                    added.getAddress())) {
+                                                needToClean = true;
+                                                break;
+                                            }
+                                        }
+                                    }
+                                    if (needToClean) {
+                                        if (DBG) {
+                                            log("onDataStateChanged: addr change," +
+                                                    " cleanup apns=" + dc.mApnContexts +
+                                                    " oldLp=" + result.oldLp +
+                                                    " newLp=" + result.newLp);
+                                        }
+                                        apnsToCleanup.addAll(dc.mApnContexts);
+                                    } else {
+                                        if (DBG) log("onDataStateChanged: simple change");
+                                        for (ApnContext apnContext : dc.mApnContexts) {
+                                             mPhone.notifyDataConnection(
+                                                 PhoneConstants.REASON_LINK_PROPERTIES_CHANGED,
+                                                 apnContext.getApnType());
+                                        }
+                                    }
+                                } else {
+                                    if (DBG) {
+                                        log("onDataStateChanged: no changes");
+                                    }
+                                }
+                            } else {
+                                apnsToCleanup.addAll(dc.mApnContexts);
+                                if (DBG) {
+                                    log("onDataStateChanged: interface change, cleanup apns="
+                                            + dc.mApnContexts);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            mPhone.notifyDataActivity();
+
+            if (DBG) {
+                lr("onDataStateChanged: dcsToRetry=" + dcsToRetry
+                        + " apnsToCleanup=" + apnsToCleanup);
+            }
+
+            // Cleanup connections that have changed
+            for (ApnContext apnContext : apnsToCleanup) {
+               mDct.sendCleanUpConnection(true, apnContext);
+            }
+
+            // Retry connections that have disappeared
+            for (DataConnection dc : dcsToRetry) {
+                if (DBG) log("onDataStateChanged: send EVENT_LOST_CONNECTION dc.mTag=" + dc.mTag);
+                dc.sendMessage(DataConnection.EVENT_LOST_CONNECTION, dc.mTag);
+            }
+
+            if (DBG) log("onDataStateChanged: X");
+        }
+    }
+
+    /**
+     * lr is short name for logAndAddLogRec
+     * @param s
+     */
+    private void lr(String s) {
+        logAndAddLogRec(s);
+    }
+
+    @Override
+    protected void log(String s) {
+        Rlog.d(getName(), s);
+    }
+
+    @Override
+    protected void loge(String s) {
+        Rlog.e(getName(), s);
+    }
+
+    /**
+     * @return the string for msg.what as our info.
+     */
+    @Override
+    protected String getWhatToString(int what) {
+        String info = null;
+        info = DataConnection.cmdToString(what);
+        if (info == null) {
+            info = DataConnectionAc.cmdToString(what);
+        }
+        return info;
+    }
+
+    @Override
+    public String toString() {
+        return "mDcListAll=" + mDcListAll + " mDcListActiveByCid=" + mDcListActiveByCid;
+    }
+
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        super.dump(fd, pw, args);
+        pw.println(" mPhone=" + mPhone);
+        pw.println(" mDcListAll=" + mDcListAll);
+        pw.println(" mDcListActiveByCid=" + mDcListActiveByCid);
+    }
+}
\ No newline at end of file
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcFailBringUp.java b/src/java/com/android/internal/telephony/dataconnection/DcFailBringUp.java
new file mode 100644
index 0000000..c891817
--- /dev/null
+++ b/src/java/com/android/internal/telephony/dataconnection/DcFailBringUp.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.dataconnection;
+
+import android.content.Intent;
+import android.telephony.Rlog;
+
+/**
+ * A package visible class for supporting testing failing bringUp commands. This
+ * saves the parameters from a action_fail_bringup intent. See
+ * {@link DataConnection#doOnConnect} and {@see DcTesterFailBringUpAll} for more info.
+ */
+class DcFailBringUp {
+    private static final String LOG_TAG = "DcFailBringUp";
+    private static final boolean DBG = true;
+
+    static final String INTENT_BASE = DataConnection.class.getPackage().getName();
+
+    static final String ACTION_FAIL_BRINGUP = "action_fail_bringup";
+
+    // counter with its --ei option name and default value
+    static final String COUNTER = "counter";
+    static final int DEFAULT_COUNTER = 1;
+    int mCounter;
+
+    // failCause with its --ei option name and default value
+    static final String FAIL_CAUSE = "fail_cause";
+    static final DcFailCause DEFAULT_FAIL_CAUSE = DcFailCause.ERROR_UNSPECIFIED;
+    DcFailCause mFailCause;
+
+    // suggestedRetryTime with its --ei option name and default value
+    static final String SUGGESTED_RETRY_TIME = "suggested_retry_time";
+    static final int DEFAULT_SUGGESTED_RETRY_TIME = -1;
+    int mSuggestedRetryTime;
+
+    // Get the Extra Intent parameters
+    void saveParameters(Intent intent, String s) {
+        if (DBG) log(s + ".saveParameters: action=" + intent.getAction());
+        mCounter = intent.getIntExtra(COUNTER, DEFAULT_COUNTER);
+        mFailCause = DcFailCause.fromInt(
+                intent.getIntExtra(FAIL_CAUSE, DEFAULT_FAIL_CAUSE.getErrorCode()));
+        mSuggestedRetryTime =
+                intent.getIntExtra(SUGGESTED_RETRY_TIME, DEFAULT_SUGGESTED_RETRY_TIME);
+        if (DBG) {
+            log(s + ".saveParameters: " + this);
+        }
+    }
+
+    void saveParameters(int counter, int failCause, int suggestedRetryTime) {
+        mCounter = counter;
+        mFailCause = DcFailCause.fromInt(failCause);
+        mSuggestedRetryTime = suggestedRetryTime;
+    }
+
+    @Override
+    public String toString() {
+        return "{mCounter=" + mCounter +
+                " mFailCause=" + mFailCause +
+                " mSuggestedRetryTime=" + mSuggestedRetryTime + "}";
+
+    }
+
+    private static void log(String s) {
+        Rlog.d(LOG_TAG, s);
+    }
+}
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcFailCause.java b/src/java/com/android/internal/telephony/dataconnection/DcFailCause.java
new file mode 100644
index 0000000..a535e09
--- /dev/null
+++ b/src/java/com/android/internal/telephony/dataconnection/DcFailCause.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.telephony.dataconnection;
+
+import java.util.HashMap;
+
+/**
+ * Returned as the reason for a connection failure as defined
+ * by RIL_DataCallFailCause in ril.h and some local errors.
+ */
+public enum DcFailCause {
+    NONE(0),
+
+    // This series of errors as specified by the standards
+    // specified in ril.h
+    OPERATOR_BARRED(0x08),
+    INSUFFICIENT_RESOURCES(0x1A),
+    MISSING_UNKNOWN_APN(0x1B),
+    UNKNOWN_PDP_ADDRESS_TYPE(0x1C),
+    USER_AUTHENTICATION(0x1D),
+    ACTIVATION_REJECT_GGSN(0x1E),
+    ACTIVATION_REJECT_UNSPECIFIED(0x1F),
+    SERVICE_OPTION_NOT_SUPPORTED(0x20),
+    SERVICE_OPTION_NOT_SUBSCRIBED(0x21),
+    SERVICE_OPTION_OUT_OF_ORDER(0x22),
+    NSAPI_IN_USE(0x23),
+    ONLY_IPV4_ALLOWED(0x32),
+    ONLY_IPV6_ALLOWED(0x33),
+    ONLY_SINGLE_BEARER_ALLOWED(0x34),
+    PROTOCOL_ERRORS(0x6F),
+
+    // Local errors generated by Vendor RIL
+    // specified in ril.h
+    REGISTRATION_FAIL(-1),
+    GPRS_REGISTRATION_FAIL(-2),
+    SIGNAL_LOST(-3),
+    PREF_RADIO_TECH_CHANGED(-4),
+    RADIO_POWER_OFF(-5),
+    TETHERED_CALL_ACTIVE(-6),
+    ERROR_UNSPECIFIED(0xFFFF),
+
+    // Errors generated by the Framework
+    // specified here
+    UNKNOWN(0x10000),
+    RADIO_NOT_AVAILABLE(0x10001),
+    UNACCEPTABLE_NETWORK_PARAMETER(0x10002),
+    CONNECTION_TO_DATACONNECTIONAC_BROKEN(0x10003),
+    LOST_CONNECTION(0x10004),
+    RESET_BY_FRAMEWORK(0x10005);
+
+    private final int mErrorCode;
+    private static final HashMap<Integer, DcFailCause> sErrorCodeToFailCauseMap;
+    static {
+        sErrorCodeToFailCauseMap = new HashMap<Integer, DcFailCause>();
+        for (DcFailCause fc : values()) {
+            sErrorCodeToFailCauseMap.put(fc.getErrorCode(), fc);
+        }
+    }
+
+    DcFailCause(int errorCode) {
+        mErrorCode = errorCode;
+    }
+
+    public int getErrorCode() {
+        return mErrorCode;
+    }
+
+    public boolean isPermanentFail() {
+        return (this == OPERATOR_BARRED) || (this == MISSING_UNKNOWN_APN) ||
+               (this == UNKNOWN_PDP_ADDRESS_TYPE) || (this == USER_AUTHENTICATION) ||
+               (this == ACTIVATION_REJECT_GGSN) || (this == SERVICE_OPTION_NOT_SUPPORTED) ||
+               (this == SERVICE_OPTION_NOT_SUBSCRIBED) || (this == NSAPI_IN_USE) ||
+               (this == ONLY_IPV4_ALLOWED) || (this == ONLY_IPV6_ALLOWED) ||
+               (this == PROTOCOL_ERRORS) || (this == SIGNAL_LOST) ||
+               (this == RADIO_POWER_OFF) || (this == TETHERED_CALL_ACTIVE);
+    }
+
+    public boolean isEventLoggable() {
+        return (this == OPERATOR_BARRED) || (this == INSUFFICIENT_RESOURCES) ||
+                (this == UNKNOWN_PDP_ADDRESS_TYPE) || (this == USER_AUTHENTICATION) ||
+                (this == ACTIVATION_REJECT_GGSN) || (this == ACTIVATION_REJECT_UNSPECIFIED) ||
+                (this == SERVICE_OPTION_NOT_SUBSCRIBED) ||
+                (this == SERVICE_OPTION_NOT_SUPPORTED) ||
+                (this == SERVICE_OPTION_OUT_OF_ORDER) || (this == NSAPI_IN_USE) ||
+                (this == ONLY_IPV4_ALLOWED) || (this == ONLY_IPV6_ALLOWED) ||
+                (this == PROTOCOL_ERRORS) || (this == SIGNAL_LOST) ||
+                (this == RADIO_POWER_OFF) || (this == TETHERED_CALL_ACTIVE) ||
+                (this == UNACCEPTABLE_NETWORK_PARAMETER);
+    }
+
+    public static DcFailCause fromInt(int errorCode) {
+        DcFailCause fc = sErrorCodeToFailCauseMap.get(errorCode);
+        if (fc == null) {
+            fc = UNKNOWN;
+        }
+        return fc;
+    }
+}
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcRetryAlarmController.java b/src/java/com/android/internal/telephony/dataconnection/DcRetryAlarmController.java
new file mode 100644
index 0000000..be5d300
--- /dev/null
+++ b/src/java/com/android/internal/telephony/dataconnection/DcRetryAlarmController.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.telephony.dataconnection;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.AsyncResult;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.telephony.Rlog;
+import android.text.TextUtils;
+
+import com.android.internal.telephony.PhoneBase;
+import com.android.internal.telephony.RILConstants;
+
+/**
+ * The Data Connection Retry Alarm Controller.
+ */
+public class DcRetryAlarmController {
+    private String mLogTag = "DcRac";
+    private static final boolean DBG = true;
+    protected static final boolean DEBUGGABLE = SystemProperties.getInt("ro.debuggable", 0) == 1;
+
+    private PhoneBase mPhone;
+    private DataConnection mDc;
+    private AlarmManager mAlarmManager;
+
+    // The Intent action for retrying and its two extra's
+    private String mActionRetry;
+    private static final String INTENT_RETRY_ALARM_WHAT = "what";
+    private static final String INTENT_RETRY_ALARM_TAG = "tag";
+
+    private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+            @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (TextUtils.isEmpty(action)) {
+                // Our mActionXxxx's could be null when disposed this could match an empty action.
+                log("onReceive: ignore empty action='" + action + "'");
+                return;
+            }
+            if (TextUtils.equals(action, mActionRetry)) {
+                if (!intent.hasExtra(INTENT_RETRY_ALARM_WHAT)) {
+                    throw new RuntimeException(mActionRetry + " has no INTENT_RETRY_ALRAM_WHAT");
+                }
+                if (!intent.hasExtra(INTENT_RETRY_ALARM_TAG)) {
+                    throw new RuntimeException(mActionRetry + " has no INTENT_RETRY_ALRAM_TAG");
+                }
+                int what = intent.getIntExtra(INTENT_RETRY_ALARM_WHAT, Integer.MAX_VALUE);
+                int tag = intent.getIntExtra(INTENT_RETRY_ALARM_TAG, Integer.MAX_VALUE);
+                if (DBG) {
+                    log("onReceive: action=" + action
+                            + " sendMessage(what:" + mDc.getWhatToString(what)
+                            + ", tag:" + tag + ")");
+                }
+                mDc.sendMessage(mDc.obtainMessage(what, tag, 0));
+            } else {
+                if (DBG) log("onReceive: unknown action=" + action);
+            }
+        }
+    };
+
+    DcRetryAlarmController(PhoneBase phone, DataConnection dc) {
+        mLogTag = dc.getName();
+        mPhone = phone;
+        mDc = dc;
+        mAlarmManager = (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
+        mActionRetry = mDc.getClass().getCanonicalName() + "." + mDc.getName() + ".action_retry";
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(mActionRetry);
+        log("DcRetryAlarmController: register for intent action=" + mActionRetry);
+
+        mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mDc.getHandler());
+    }
+
+    /**
+     * Dispose of resources when shutting down
+     */
+    void dispose() {
+        if (DBG) log("dispose");
+        mPhone.getContext().unregisterReceiver(mIntentReceiver);
+        mPhone = null;
+        mDc = null;
+        mAlarmManager = null;
+        mActionRetry = null;
+    }
+
+    /**
+     * Using dc.mRetryManager and the result of the SETUP_DATA_CALL determine
+     * the retry delay.
+     *
+     * @param dc is the DataConnection
+     * @param ar is the result from SETUP_DATA_CALL
+     * @return < 0 if no retry is needed otherwise the delay to the next SETUP_DATA_CALL
+     */
+    int getSuggestedRetryTime(DataConnection dc, AsyncResult ar) {
+        int retryDelay;
+
+        DataCallResponse response = (DataCallResponse) ar.result;
+        retryDelay = response.suggestedRetryTime;
+        if (retryDelay == RILConstants.MAX_INT) {
+            if (DBG) log("getSuggestedRetryTime: suggestedRetryTime is MAX_INT, retry NOT needed");
+            retryDelay = -1;
+        } else if (retryDelay >= 0) {
+            if (DBG) log("getSuggestedRetryTime: suggestedRetryTime is >= 0 use it");
+        } else if (dc.mRetryManager.isRetryNeeded()) {
+            retryDelay = dc.mRetryManager.getRetryTimer();
+            if (retryDelay < 0) {
+                retryDelay = 0;
+            }
+            if (DBG) log("getSuggestedRetryTime: retry is needed");
+        } else {
+            if (DBG) log("getSuggestedRetryTime: retry is NOT needed");
+            retryDelay = -1;
+        }
+
+        if (DBG) {
+            log("getSuggestedRetryTime: " + retryDelay + " response=" + response + " dc=" + dc);
+        }
+        return retryDelay;
+    }
+
+    public void startRetryAlarm(int what, int tag, int delay) {
+        Intent intent = new Intent(mActionRetry);
+        intent.putExtra(INTENT_RETRY_ALARM_WHAT, what);
+        intent.putExtra(INTENT_RETRY_ALARM_TAG, tag);
+
+        if (DBG) {
+            log("startRetryAlarm: next attempt in " + (delay / 1000) + "s" +
+                    " what=" + what + " tag=" + tag);
+        }
+
+        PendingIntent retryIntent = PendingIntent.getBroadcast (mPhone.getContext(), 0,
+                                        intent, PendingIntent.FLAG_UPDATE_CURRENT);
+        mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+                SystemClock.elapsedRealtime() + delay, retryIntent);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(mLogTag).append(" [dcRac] ");
+        sb.append(" mPhone=").append(mPhone);
+        sb.append(" mDc=").append(mDc);
+        sb.append(" mAlaramManager=").append(mAlarmManager);
+        sb.append(" mActionRetry=").append(mActionRetry);
+        return sb.toString();
+    }
+
+    private void log(String s) {
+        Rlog.d(mLogTag, "[dcRac] " + s);
+    }
+}
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTesterDeactivateAll.java b/src/java/com/android/internal/telephony/dataconnection/DcTesterDeactivateAll.java
new file mode 100644
index 0000000..87f9d93
--- /dev/null
+++ b/src/java/com/android/internal/telephony/dataconnection/DcTesterDeactivateAll.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.dataconnection;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Handler;
+import android.os.SystemProperties;
+import android.telephony.Rlog;
+
+import com.android.internal.telephony.PhoneBase;
+
+/**
+ * To bring down all DC's send the following intent:
+ *
+ * adb shell am broadcast -a com.android.internal.telephony.dataconnection.action_deactivate_all
+ */
+public class DcTesterDeactivateAll {
+    private static final String LOG_TAG = "DcTesterDeacativeAll";
+    private static final boolean DBG = true;
+    private static final boolean DEBUGGABLE = SystemProperties.getInt("ro.debuggable", 0) == 1;
+
+    private PhoneBase mPhone;
+    private DcController mDcc;
+
+    public static String sActionDcTesterDeactivateAll =
+            "com.android.internal.telephony.dataconnection.action_deactivate_all";
+
+
+    // The static intent receiver one for all instances and we assume this
+    // is running on the same thread as Dcc.
+    protected BroadcastReceiver sIntentReceiver = new BroadcastReceiver() {
+            @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (DBG) log("sIntentReceiver.onReceive: action=" + action);
+            if (action.equals(sActionDcTesterDeactivateAll)
+                    || action.equals(mPhone.getActionDetached())) {
+                log("Send DEACTIVATE to all Dcc's");
+                if (mDcc != null) {
+                    for (DataConnection dc : mDcc.mDcListAll) {
+                        dc.tearDownNow();
+                    }
+                } else {
+                    if (DBG) log("onReceive: mDcc is null, ignoring");
+                }
+            } else {
+                if (DBG) log("onReceive: unknown action=" + action);
+            }
+        }
+    };
+
+    DcTesterDeactivateAll(PhoneBase phone, DcController dcc, Handler handler) {
+        mPhone = phone;
+        mDcc = dcc;
+
+        if (DEBUGGABLE) {
+            IntentFilter filter = new IntentFilter();
+
+            filter.addAction(sActionDcTesterDeactivateAll);
+            log("register for intent action=" + sActionDcTesterDeactivateAll);
+
+            filter.addAction(mPhone.getActionDetached());
+            log("register for intent action=" + mPhone.getActionDetached());
+
+            phone.getContext().registerReceiver(sIntentReceiver, filter, null, handler);
+        }
+    }
+
+    void dispose() {
+        mPhone.getContext().unregisterReceiver(sIntentReceiver);
+    }
+
+    private static void log(String s) {
+        Rlog.d(LOG_TAG, s);
+    }
+}
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTesterFailBringUpAll.java b/src/java/com/android/internal/telephony/dataconnection/DcTesterFailBringUpAll.java
new file mode 100644
index 0000000..0c86e1c
--- /dev/null
+++ b/src/java/com/android/internal/telephony/dataconnection/DcTesterFailBringUpAll.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.dataconnection;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Handler;
+import android.os.SystemProperties;
+import android.telephony.Rlog;
+
+import com.android.internal.telephony.PhoneBase;
+
+/**
+ * A package level call that causes all DataConnection bringUp calls to fail a specific
+ * number of times. Here is an example that sets counter to 2 and cause to -3 for all instances:
+ *    adb shell am broadcast -a com.android.internal.telephony.dataconnection.action_fail_bringup \
+ *     --ei counter 2 --ei fail_cause -3
+ *
+ * Also you can add a suggested retry time if desired:
+ *     --ei suggested_retry_time 5000
+ *
+ * There is also a per DC command implemented in {@link DcRetryAlarmController#mFailBringUp} the intent is
+ * the same as above except the action has a "DC-x" before the action_fail_bringup so for
+ * DC-1 the action action is:
+ *    adb shell am broadcast \
+ *      -a com.android.internal.telephony.dataconnection.DC-1.action_fail_bringup \
+ *      --ei counter 2 --ei fail_cause -3
+ *
+ * The fail_cause is one of {@link DcFailCause}
+ */
+public class DcTesterFailBringUpAll {
+    private static final String LOG_TAG = "DcTesterFailBrinupAll";
+    private static final boolean DBG = true;
+    private static final boolean DEBUGGABLE = SystemProperties.getInt("ro.debuggable", 0) == 1;
+
+    private PhoneBase mPhone;
+
+    private String mActionFailBringUp = DcFailBringUp.INTENT_BASE + "."
+            + DcFailBringUp.ACTION_FAIL_BRINGUP;
+
+    // The saved FailBringUp data from the intent
+    private DcFailBringUp mFailBringUp = new DcFailBringUp();
+
+    // The static intent receiver one for all instances.
+    private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+            @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (DBG) log("sIntentReceiver.onReceive: action=" + action);
+            if (action.equals(mActionFailBringUp)) {
+                mFailBringUp.saveParameters(intent, "sFailBringUp");
+            } else if (action.equals(mPhone.getActionDetached())) {
+                // Counter is MAX, bringUp/retry will always fail
+                log("simulate detaching");
+                mFailBringUp.saveParameters(Integer.MAX_VALUE,
+                        DcFailCause.LOST_CONNECTION.getErrorCode(),
+                        DcFailBringUp.DEFAULT_SUGGESTED_RETRY_TIME);
+            } else if (action.equals(mPhone.getActionAttached())) {
+                // Counter is 0 next bringUp/retry will succeed
+                log("simulate attaching");
+                mFailBringUp.saveParameters(0, DcFailCause.NONE.getErrorCode(),
+                        DcFailBringUp.DEFAULT_SUGGESTED_RETRY_TIME);
+            } else {
+                if (DBG) log("onReceive: unknown action=" + action);
+            }
+        }
+    };
+
+    DcTesterFailBringUpAll(PhoneBase phone, Handler handler) {
+        mPhone = phone;
+        if (DEBUGGABLE) {
+            IntentFilter filter = new IntentFilter();
+
+            filter.addAction(mActionFailBringUp);
+            log("register for intent action=" + mActionFailBringUp);
+
+            filter.addAction(mPhone.getActionDetached());
+            log("register for intent action=" + mPhone.getActionDetached());
+
+            filter.addAction(mPhone.getActionAttached());
+            log("register for intent action=" + mPhone.getActionAttached());
+
+            phone.getContext().registerReceiver(mIntentReceiver, filter, null, handler);
+        }
+    }
+
+    void dispose() {
+        mPhone.getContext().unregisterReceiver(mIntentReceiver);
+    }
+
+    DcFailBringUp getDcFailBringUp() {
+        return mFailBringUp;
+    }
+
+    private void log(String s) {
+        Rlog.d(LOG_TAG, s);
+    }
+}
diff --git a/src/java/com/android/internal/telephony/gsm/GSMPhone.java b/src/java/com/android/internal/telephony/gsm/GSMPhone.java
index 32e5a80..23967e8 100644
--- a/src/java/com/android/internal/telephony/gsm/GSMPhone.java
+++ b/src/java/com/android/internal/telephony/gsm/GSMPhone.java
@@ -132,7 +132,7 @@
 
     public
     GSMPhone (Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode) {
-        super(notifier, context, ci, unitTestMode);
+        super("GSM", notifier, context, ci, unitTestMode);
 
         if (ci instanceof SimulatedRadioControl) {
             mSimulatedRadioControl = (SimulatedRadioControl) ci;
@@ -258,11 +258,6 @@
     }
 
     @Override
-    public String getPhoneName() {
-        return "GSM";
-    }
-
-    @Override
     public int getPhoneType() {
         return PhoneConstants.PHONE_TYPE_GSM;
     }
@@ -320,6 +315,7 @@
                     }
                 break;
 
+                case RETRYING:
                 case CONNECTING:
                 case SCANNING:
                     ret = PhoneConstants.DataState.CONNECTING;
diff --git a/src/java/com/android/internal/telephony/sip/SipConnectionBase.java b/src/java/com/android/internal/telephony/sip/SipConnectionBase.java
index 19d217f..c3f39de 100644
--- a/src/java/com/android/internal/telephony/sip/SipConnectionBase.java
+++ b/src/java/com/android/internal/telephony/sip/SipConnectionBase.java
@@ -29,7 +29,7 @@
 abstract class SipConnectionBase extends Connection {
     private static final String LOG_TAG = "SipConnBase";
     private static final boolean DBG = true;
-    private static final boolean VDBG = true; // STOPSHIP if true
+    private static final boolean VDBG = false; // STOPSHIP if true
 
     private String mPostDialString;      // outgoing calls only
     private int mNextPostDialChar;       // index into postDialString
diff --git a/src/java/com/android/internal/telephony/sip/SipPhone.java b/src/java/com/android/internal/telephony/sip/SipPhone.java
index 764c7ef..878fe3f 100644
--- a/src/java/com/android/internal/telephony/sip/SipPhone.java
+++ b/src/java/com/android/internal/telephony/sip/SipPhone.java
@@ -49,7 +49,7 @@
 public class SipPhone extends SipPhoneBase {
     private static final String LOG_TAG = "SipPhone";
     private static final boolean DBG = true;
-    private static final boolean VDBG = true; // STOPSHIP if true
+    private static final boolean VDBG = false; // STOPSHIP if true
     private static final int TIMEOUT_MAKE_CALL = 15; // in seconds
     private static final int TIMEOUT_ANSWER_CALL = 8; // in seconds
     private static final int TIMEOUT_HOLD_CALL = 15; // in seconds
@@ -63,7 +63,7 @@
     private SipProfile mProfile;
 
     SipPhone (Context context, PhoneNotifier notifier, SipProfile profile) {
-        super(context, notifier);
+        super("SIP:" + profile.getUriString(), context, notifier);
 
         if (DBG) log("new SipPhone: " + profile.getUriString());
         mRingingCall = new SipCall();
@@ -81,11 +81,6 @@
         return mProfile.getUriString().equals(that.mProfile.getUriString());
     }
 
-    @Override
-    public String getPhoneName() {
-        return "SIP:" + getUriString(mProfile);
-    }
-
     public String getSipUri() {
         return mProfile.getUriString();
     }
diff --git a/src/java/com/android/internal/telephony/sip/SipPhoneBase.java b/src/java/com/android/internal/telephony/sip/SipPhoneBase.java
index 49ca7c6..b749542 100755
--- a/src/java/com/android/internal/telephony/sip/SipPhoneBase.java
+++ b/src/java/com/android/internal/telephony/sip/SipPhoneBase.java
@@ -33,7 +33,7 @@
 import com.android.internal.telephony.Call;
 import com.android.internal.telephony.CallStateException;
 import com.android.internal.telephony.Connection;
-import com.android.internal.telephony.dataconnection.DataConnectionBase;
+import com.android.internal.telephony.dataconnection.DataConnection;
 import com.android.internal.telephony.IccCard;
 import com.android.internal.telephony.IccPhoneBookInterfaceManager;
 import com.android.internal.telephony.IccSmsInterfaceManager;
@@ -56,8 +56,8 @@
     private RegistrantList mRingbackRegistrants = new RegistrantList();
     private PhoneConstants.State mState = PhoneConstants.State.IDLE;
 
-    public SipPhoneBase(Context context, PhoneNotifier notifier) {
-        super(notifier, context, new SipCommandInterface(context), false);
+    public SipPhoneBase(String name, Context context, PhoneNotifier notifier) {
+        super(name, notifier, context, new SipCommandInterface(context), false);
     }
 
     @Override
@@ -424,7 +424,7 @@
     public void getDataCallList(Message response) {
     }
 
-    public List<DataConnectionBase> getCurrentDataConnectionList () {
+    public List<DataConnection> getCurrentDataConnectionList () {
         return null;
     }
 
diff --git a/src/java/com/android/internal/telephony/test/SimulatedCommands.java b/src/java/com/android/internal/telephony/test/SimulatedCommands.java
index 883e11c..23c09ee 100644
--- a/src/java/com/android/internal/telephony/test/SimulatedCommands.java
+++ b/src/java/com/android/internal/telephony/test/SimulatedCommands.java
@@ -25,10 +25,10 @@
 import com.android.internal.telephony.BaseCommands;
 import com.android.internal.telephony.CommandException;
 import com.android.internal.telephony.CommandsInterface;
-import com.android.internal.telephony.DataCallState;
+import com.android.internal.telephony.cdma.CdmaSmsBroadcastConfigInfo;
+import com.android.internal.telephony.dataconnection.DataCallResponse;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.UUSInfo;
-import com.android.internal.telephony.cdma.CdmaSmsBroadcastConfigInfo;
 import com.android.internal.telephony.gsm.CallFailCause;
 import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo;
 import com.android.internal.telephony.gsm.SuppServiceNotification;
@@ -478,11 +478,11 @@
      *  retMsg.obj = AsyncResult ar
      *  ar.exception carries exception on failure
      *  ar.userObject contains the original value of result.obj
-     *  ar.result contains a List of DataCallState
+     *  ar.result contains a List of DataCallResponse
      */
     @Override
     public void getDataCallList(Message result) {
-        resultSuccess(result, new ArrayList<DataCallState>(0));
+        resultSuccess(result, new ArrayList<DataCallResponse>(0));
     }
 
     /**