OSDN Git Service

Data connection retry pattern could be broken by PDP sharing
authorKazuhiro Ondo <kazuhiro.ondo@motorola.com>
Wed, 22 Jun 2011 22:26:08 +0000 (17:26 -0500)
committerWink Saville <wink@google.com>
Mon, 27 Jun 2011 22:12:21 +0000 (15:12 -0700)
If a DataConnection is pending re-connect alarm, the new request
from another ApnContext sharing the same DC could disrupt
the re-connection pattern currently engaged.

This patch is to ensure the new request for PDP sharing
scenario will not trigger another SETUP_DATA request if
reconnection alarm is set in AlarmManager.

Bug: 4901019
Change-Id: I98b0d9af8b58fb880efdbc0246009de5cb116a54

telephony/java/com/android/internal/telephony/ApnContext.java
telephony/java/com/android/internal/telephony/DataConnection.java
telephony/java/com/android/internal/telephony/DataConnectionAc.java
telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java

index 5ec00e8..a52f1ca 100644 (file)
@@ -16,8 +16,6 @@
 
 package com.android.internal.telephony;
 
-import android.app.PendingIntent;
-
 import android.util.Log;
 import java.util.ArrayList;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -49,8 +47,6 @@ public class ApnContext {
 
     String mReason;
 
-    PendingIntent mReconnectIntent;
-
     /**
      * user/app requested connection on this APN
      */
@@ -90,9 +86,9 @@ public class ApnContext {
 
     public synchronized void setDataConnectionAc(DataConnectionAc dcac) {
         if (dcac != null) {
-            dcac.addApnContext(this);
+            dcac.addApnContextSync(this);
         } else {
-            if (mDataConnectionAc != null) mDataConnectionAc.removeApnContext(this);
+            if (mDataConnectionAc != null) mDataConnectionAc.removeApnContextSync(this);
         }
         mDataConnectionAc = dcac;
     }
@@ -169,16 +165,6 @@ public class ApnContext {
         return mReason;
     }
 
-    public synchronized void setReconnectIntent(PendingIntent intent) {
-        if (DBG)
-            log("set ReconnectIntent for type " + mApnType);
-        mReconnectIntent = intent;
-    }
-
-    public synchronized PendingIntent getReconnectIntent() {
-        return mReconnectIntent;
-    }
-
     public boolean isReady() {
         return mDataEnabled.get() && mDependencyMet.get();
     }
index cb8b0e5..5c84fdc 100644 (file)
@@ -22,6 +22,7 @@ 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.LinkAddress;
 import android.net.LinkCapabilities;
 import android.net.LinkProperties;
@@ -35,8 +36,10 @@ import android.os.Parcelable;
 import android.os.SystemProperties;
 import android.text.TextUtils;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
+import java.util.List;
 import java.util.concurrent.atomic.AtomicInteger;
 
 /**
@@ -68,6 +71,8 @@ public abstract class DataConnection extends StateMachine {
     protected static int mCount;
     protected AsyncChannel mAc;
 
+    private List<ApnContext> mApnList = null;
+    PendingIntent mReconnectIntent = null;
 
     /**
      * Used internally for saving connecting parameters.
@@ -250,6 +255,8 @@ public abstract class DataConnection extends StateMachine {
             addState(mDisconnectingState, mDefaultState);
             addState(mDisconnectingErrorCreatingConnection, mDefaultState);
         setInitialState(mInactiveState);
+
+        mApnList = new ArrayList<ApnContext>();
         if (DBG) log("DataConnection constructor X");
     }
 
@@ -662,7 +669,41 @@ public abstract class DataConnection extends StateMachine {
                     mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_REFCOUNT, mRefCount);
                     break;
                 }
-
+                case DataConnectionAc.REQ_ADD_APNCONTEXT: {
+                    ApnContext apnContext = (ApnContext) msg.obj;
+                    if (VDBG) log("REQ_ADD_APNCONTEXT apn=" + apnContext.getApnType());
+                    if (!mApnList.contains(apnContext)) {
+                        mApnList.add(apnContext);
+                    }
+                    mAc.replyToMessage(msg, DataConnectionAc.RSP_ADD_APNCONTEXT);
+                    break;
+                }
+                case DataConnectionAc.REQ_REMOVE_APNCONTEXT: {
+                    ApnContext apnContext = (ApnContext) msg.obj;
+                    if (VDBG) log("REQ_REMOVE_APNCONTEXT apn=" + apnContext.getApnType());
+                    mApnList.remove(apnContext);
+                    mAc.replyToMessage(msg, DataConnectionAc.RSP_REMOVE_APNCONTEXT);
+                    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(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;
index e23f1cc..309dbed 100644 (file)
@@ -19,6 +19,7 @@ package com.android.internal.telephony;
 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;
@@ -26,8 +27,6 @@ import android.os.Message;
 
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
 
 /**
  * AsyncChannel to a DataConnection
@@ -35,7 +34,6 @@ import java.util.List;
 public class DataConnectionAc extends AsyncChannel {
     private static final boolean DBG = false;
     private String mLogTag;
-    private List<ApnContext> mApnList = null;
 
     public DataConnection dataConnection;
 
@@ -68,6 +66,21 @@ public class DataConnectionAc extends AsyncChannel {
     public static final int REQ_GET_REFCOUNT = BASE + 16;
     public static final int RSP_GET_REFCOUNT = BASE + 17;
 
+    public static final int REQ_ADD_APNCONTEXT = BASE + 18;
+    public static final int RSP_ADD_APNCONTEXT = BASE + 19;
+
+    public static final int REQ_REMOVE_APNCONTEXT = BASE + 20;
+    public static final int RSP_REMOVE_APNCONTEXT = BASE + 21;
+
+    public static final int REQ_GET_APNCONTEXT_LIST = BASE + 22;
+    public static final int RSP_GET_APNCONTEXT_LIST = BASE + 23;
+
+    public static final int REQ_SET_RECONNECT_INTENT = BASE + 24;
+    public static final int RSP_SET_RECONNECT_INTENT = BASE + 25;
+
+    public static final int REQ_GET_RECONNECT_INTENT = BASE + 26;
+    public static final int RSP_GET_RECONNECT_INTENT = BASE + 27;
+
     /**
      * enum used to notify action taken or necessary to be
      * taken after the link property is changed.
@@ -91,7 +104,6 @@ public class DataConnectionAc extends AsyncChannel {
     public DataConnectionAc(DataConnection dc, String logTag) {
         dataConnection = dc;
         mLogTag = logTag;
-        mApnList = Collections.synchronizedList(new ArrayList<ApnContext>());
     }
 
     /**
@@ -379,32 +391,147 @@ public class DataConnectionAc extends AsyncChannel {
     }
 
     /**
-     * Add ApnContext association.
+     * Request to add ApnContext association.
+     * Response RSP_ADD_APNCONTEXT when complete.
+     */
+    public void reqAddApnContext(ApnContext apnContext) {
+        Message response = sendMessageSynchronously(REQ_ADD_APNCONTEXT, apnContext);
+        if (DBG) log("reqAddApnContext");
+    }
+
+    /**
+     * Add ApnContext association synchronoulsy.
      *
      * @param ApnContext to associate
      */
-    public void addApnContext(ApnContext apnContext) {
-        if (!mApnList.contains(apnContext)) {
-            mApnList.add(apnContext);
+    public void addApnContextSync(ApnContext apnContext) {
+        Message response = sendMessageSynchronously(REQ_ADD_APNCONTEXT, apnContext);
+        if ((response != null) && (response.what == RSP_ADD_APNCONTEXT)) {
+            if (DBG) log("addApnContext ok");
+        } else {
+            log("addApnContext error response=" + response);
         }
     }
 
     /**
+     * Request to remove ApnContext association.
+     * Response RSP_REMOVE_APNCONTEXT when complete.
+     */
+    public void reqRemomveApnContext(ApnContext apnContext) {
+        Message response = sendMessageSynchronously(REQ_REMOVE_APNCONTEXT, apnContext);
+        if (DBG) log("reqRemomveApnContext");
+    }
+
+    /**
      * Remove ApnContext associateion.
      *
      * @param ApnContext to dissociate
      */
-    public void removeApnContext(ApnContext apnContext) {
-        mApnList.remove(apnContext);
+    public void removeApnContextSync(ApnContext apnContext) {
+        Message response = sendMessageSynchronously(REQ_REMOVE_APNCONTEXT, apnContext);
+        if ((response != null) && (response.what == RSP_REMOVE_APNCONTEXT)) {
+            if (DBG) log("removeApnContext ok");
+        } else {
+            log("removeApnContext error response=" + response);
+        }
+    }
+
+    /**
+     * Request to retrive 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.
+     *
+     * @param Message sent from DC in response to REQ_GET_APNCONTEXT_LIST.
+     * @return Collection of ApnContext
+     */
+    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 DataConnectionAc.
+     * Retrieve collection of ApnContext currently associated with
+     * the DataConnectionA synchronously.
      *
      * @return Collection of ApnContext
      */
-    public Collection<ApnContext> getApnList() {
-        return mApnList;
+    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>();
+        }
+    }
+
+    /**
+     * 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.
+     *
+     * @param PendingIntent to set.
+     */
+    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);
+        }
+    }
+
+    /**
+     * Request to get Pending ReconnectIntent to DC.
+     * Response RSP_GET_RECONNECT_INTENT when complete.
+     */
+    public void reqGetReconnectIntent() {
+        Message response = sendMessageSynchronously(REQ_GET_RECONNECT_INTENT);
+        if (DBG) log("reqGetReconnectIntent");
+    }
+
+    /**
+     * Retrieve reconnect intent from response message from DC.
+     *
+     * @param Message 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;
+        }
     }
 
     private void log(String s) {
index 1ac012f..5fc0bf9 100644 (file)
@@ -125,14 +125,20 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
         if (DBG) log("GPRS reconnect alarm. Previous state was " + mState);
 
         String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON);
-        String type = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE);
-        ApnContext apnContext = mApnContexts.get(type);
-        if (apnContext != null) {
-            apnContext.setReason(reason);
-            if (apnContext.getState() == State.FAILED) {
-                apnContext.setState(State.IDLE);
+        int connectionId = intent.getIntExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE, -1);
+
+        DataConnectionAc dcac= mDataConnectionAsyncChannels.get(connectionId);
+
+        if (dcac != null) {
+            for (ApnContext apnContext : dcac.getApnListSync()) {
+                apnContext.setReason(reason);
+                if (apnContext.getState() == State.FAILED) {
+                    apnContext.setState(State.IDLE);
+                }
+                sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA, apnContext));
             }
-            sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA, apnContext));
+            // Alram had expired. Clear pending intent recorded on the DataConnection.
+            dcac.setReconnectIntentSync(null);
         }
     }
 
@@ -591,17 +597,25 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
     }
 
     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);
+                if (dcac.dataConnection != null) {
+                    dcac.dataConnection.resetRetryCount();
+                }
+
+                Collection<ApnContext> apnList = dcac.getApnListSync();
+                for (ApnContext apnContext : apnList) {
+                    apnContext.setState(State.IDLE);
+                }
+            }
+        }
+
         // Only check for default APN state
         for (ApnContext apnContext : mApnContexts.values()) {
             if (apnContext.isReady()) {
-                if (apnContext.getState() == State.FAILED) {
-                    cleanApnContextBeforeRestart(apnContext);
-                    if (apnContext.getDataConnection() != null) {
-                        apnContext.getDataConnection().resetRetryCount();
-                    }
-                }
-                // Do not start ApnContext in SCANNING state
-                // FAILED state must be reset to IDLE by now
                 if (apnContext.getState() == State.IDLE) {
                     apnContext.setReason(reason);
                     trySetupData(apnContext);
@@ -751,53 +765,70 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
         if (DBG) {
             log("cleanUpConnection: tearDown=" + tearDown + " reason=" + apnContext.getReason());
         }
-        if (tearDown && cleanApnContextBeforeRestart(apnContext)) {
-            // if the request is tearDown and ApnContext does not hold an active connection,
-            // we're ok to return here.
-            return;
-        }
-
         DataConnectionAc dcac = apnContext.getDataConnectionAc();
-        if (tearDown && (dcac != null)) {
-            if (DBG) log("cleanUpConnection: tearing down");
-            Message msg = obtainMessage(EVENT_DISCONNECT_DONE, apnContext);
-            apnContext.getDataConnection().tearDown(apnContext.getReason(), msg);
-            apnContext.setState(State.DISCONNECTING);
+        if (tearDown) {
+            boolean isConnected = (apnContext.getState() != State.IDLE
+                                   && apnContext.getState() != State.FAILED);
+            if (!isConnected) {
+                // The request is tearDown and but ApnContext is not connected.
+                // If apnContext is not enabled anymore, break the linkage to the DCAC/DC.
+                apnContext.setState(State.IDLE);
+                if (!apnContext.isReady()) {
+                    apnContext.setDataConnection(null);
+                    apnContext.setDataConnectionAc(null);
+                }
+            } else {
+                // Connection is still there. Try to clean up.
+                if (dcac != null) {
+                    if (apnContext.getState() != State.DISCONNECTING) {
+                        if (DBG) log("cleanUpConnection: tearing down");
+                        Message msg = obtainMessage(EVENT_DISCONNECT_DONE, apnContext);
+                        apnContext.getDataConnection().tearDown(apnContext.getReason(), msg);
+                        apnContext.setState(State.DISCONNECTING);
+                    } else {
+                        // apn is connected but no reference to dcac.
+                        // Should not be happen, but reset the state in case.
+                        apnContext.setState(State.IDLE);
+                        mPhone.notifyDataConnection(apnContext.getReason(),
+                                                    apnContext.getApnType());
+                    }
+                }
+            }
         } else {
+            // force clean up the data connection.
             if (dcac != null) dcac.resetSync();
             apnContext.setState(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
+        // associated to the connection.
+        if (dcac != null) {
+            Collection<ApnContext> apnList = dcac.getApnListSync();
+            if (apnList.isEmpty()) {
+                cancelReconnectAlarm(dcac);
+            }
+        }
     }
 
     /**
-     * @param APNContext to clean
-     * @return true if ApnContext is not connected anymore.
-     *         false if ApnContext still holds a connection.
+     * Cancels the alarm associated with DCAC.
+     *
+     * @param DataConnectionAc on which the alarm should be stopped.
      */
-    private boolean cleanApnContextBeforeRestart(ApnContext apnContext) {
-        if (apnContext == null) return true;
+    private void cancelReconnectAlarm(DataConnectionAc dcac) {
+        if (dcac == null) return;
 
-        // Clear the reconnect alarm, if set.
-        if (apnContext.getReconnectIntent() != null) {
-            AlarmManager am =
-                (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
-            am.cancel(apnContext.getReconnectIntent());
-            apnContext.setReconnectIntent(null);
-        }
+        PendingIntent intent = dcac.getReconnectIntentSync();
 
-        if (apnContext.getState() == State.IDLE || apnContext.getState() == State.DISCONNECTING) {
-            if (DBG) log("cleanUpConnection: state= " + apnContext.getState());
-            return true;
-        }
-
-        if (apnContext.getState() == State.FAILED) {
-            apnContext.setState(State.IDLE);
-            return true;
+        if (intent != null) {
+                AlarmManager am =
+                    (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
+                am.cancel(intent);
+                dcac.setReconnectIntentSync(null);
         }
-        return false;
     }
 
     /**
@@ -936,17 +967,26 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
                 configureRetry(dc, apnContext.getApnType());
             }
             apnContext.setDataConnectionAc(dcac);
-            apnContext.setApnSetting(apn);
             apnContext.setDataConnection(dc);
         }
 
+        apnContext.setApnSetting(apn);
+        apnContext.setState(State.INITING);
+        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 disruppt data retry pattern engaged.
+        if (apnContext.getDataConnectionAc().getReconnectIntentSync() != null) {
+            if (DBG) log("setupData: data reconnection pending");
+            apnContext.setState(State.FAILED);
+            mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
+            return true;
+        }
+
         Message msg = obtainMessage();
         msg.what = EVENT_DATA_SETUP_COMPLETE;
         msg.obj = apnContext;
         dc.bringUp(msg, apn);
 
-        apnContext.setState(State.INITING);
-        mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
         if (DBG) log("setupData: initing!");
         return true;
     }
@@ -1063,13 +1103,12 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
             // no associated DataConnection found. Ignore.
             if (dcac == null) continue;
 
-            Collection<ApnContext> apns = dcac.getApnList();
+            Collection<ApnContext> apns = dcac.getApnListSync();
 
             // filter out ApnContext with "Connected" state.
             ArrayList<ApnContext> connectedApns = new ArrayList<ApnContext>();
             for (ApnContext apnContext : apns) {
-                if ((apnContext != null) &&
-                    (apnContext.getState() == State.CONNECTED)) {
+                if (apnContext.getState() == State.CONNECTED) {
                     connectedApns.add(apnContext);
                 }
             }
@@ -1449,21 +1488,28 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
                 + (delay / 1000) + "s");
         }
 
+        DataConnectionAc dcac = apnContext.getDataConnectionAc();
+
+        if ((dcac == null) || (dcac.dataConnection == null)) {
+            // should not happen, but just in case.
+            loge("null dcac or dc.");
+            return;
+        }
+
         AlarmManager am =
             (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
 
-        // TODO : Register the receiver only once maybe in baseclass.
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(INTENT_RECONNECT_ALARM + '.'+apnContext.getApnType());
-        mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone);
-
-        Intent intent = new Intent(INTENT_RECONNECT_ALARM + '.' + apnContext.getApnType());
+        Intent intent = new Intent(INTENT_RECONNECT_ALARM + '.' +
+                                   dcac.dataConnection.getDataConnectionId());
         intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON, apnContext.getReason());
-        intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE, apnContext.getApnType());
-        apnContext.setReconnectIntent(PendingIntent.getBroadcast (
-                mPhone.getContext(), 0, intent, 0));
+        intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE,
+                        dcac.dataConnection.getDataConnectionId());
+
+        PendingIntent alarmIntent = PendingIntent.getBroadcast (mPhone.getContext(), 0,
+                                                                intent, 0);
+        dcac.setReconnectIntentSync(alarmIntent);
         am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
-                SystemClock.elapsedRealtime() + delay, apnContext.getReconnectIntent());
+                SystemClock.elapsedRealtime() + delay, alarmIntent);
 
     }
 
@@ -1768,9 +1814,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
         }
 
         apnContext.setState(State.IDLE);
-        apnContext.setApnSetting(null);
-        apnContext.setDataConnection(null);
-        apnContext.setDataConnectionAc(null);
 
         mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
 
@@ -1779,6 +1822,9 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
         if (!isConnected()) {
             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;
             }
         }
@@ -1790,6 +1836,10 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
             // 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);
         }
     }
 
@@ -1915,6 +1965,11 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
                     " status=" + status);
         }
 
+        // install reconnect intent filter for this data connection.
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(INTENT_RECONNECT_ALARM + '.' + id);
+        mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone);
+
         if (DBG) log("createDataConnection() X id=" + id);
         return conn;
     }