Ignore obsolete disconnect_completed msgs.
Msg passing meant the disconnect_completed was getting processed after
a new connect request was received and acted on, so the disc_completed
would causes us to mark the state incorrectly and we'd get in trouble.
bug:22776917
Change-Id: I781c0619dade00554d368a649c3e43a32cf511dc
diff --git a/src/java/com/android/internal/telephony/dataconnection/ApnContext.java b/src/java/com/android/internal/telephony/dataconnection/ApnContext.java
index 081e9b7..afc8ed6 100644
--- a/src/java/com/android/internal/telephony/dataconnection/ApnContext.java
+++ b/src/java/com/android/internal/telephony/dataconnection/ApnContext.java
@@ -93,6 +93,12 @@
*/
private boolean mConcurrentVoiceAndDataAllowed;
+ /**
+ * used to track a single connection request so disconnects can get ignored if
+ * obsolete.
+ */
+ private final AtomicInteger mConnectionGeneration = new AtomicInteger(0);
+
public ApnContext(Context context, String apnType, String logTag, NetworkConfig config,
DcTrackerBase tracker) {
mContext = context;
@@ -392,6 +398,14 @@
return result;
}
+ public int incAndGetConnectionGeneration() {
+ return mConnectionGeneration.incrementAndGet();
+ }
+
+ public int getConnectionGeneration() {
+ return mConnectionGeneration.get();
+ }
+
@Override
public synchronized String toString() {
// We don't print mDataConnection because its recursive.
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
index 8877bf5..2f31246 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
@@ -65,6 +65,7 @@
import java.util.concurrent.atomic.AtomicInteger;
import java.net.InetAddress;
import java.util.Collection;
+import java.util.HashMap;
/**
* {@hide}
@@ -127,15 +128,18 @@
int mRilRat;
boolean mRetryWhenSSChange;
Message mOnCompletedMsg;
+ final int mConnectionGeneration;
ConnectionParams(ApnContext apnContext, int initialMaxRetry, int profileId,
- int rilRadioTechnology, boolean retryWhenSSChange, Message onCompletedMsg) {
+ int rilRadioTechnology, boolean retryWhenSSChange, Message onCompletedMsg,
+ int connectionGeneration) {
mApnContext = apnContext;
mInitialMaxRetry = initialMaxRetry;
mProfileId = profileId;
mRilRat = rilRadioTechnology;
mRetryWhenSSChange = retryWhenSSChange;
mOnCompletedMsg = onCompletedMsg;
+ mConnectionGeneration = connectionGeneration;
}
@Override
@@ -190,7 +194,7 @@
//***** Package visible variables
int mTag;
int mCid;
- List<ApnContext> mApnContexts = null;
+ HashMap<ApnContext, ConnectionParams> mApnContexts = null;
PendingIntent mReconnectIntent = null;
RetryManager mRetryManager = new RetryManager();
@@ -448,7 +452,7 @@
addState(mDisconnectingErrorCreatingConnection, mDefaultState);
setInitialState(mInactiveState);
- mApnContexts = new ArrayList<ApnContext>();
+ mApnContexts = new HashMap<ApnContext, ConnectionParams>();
if (DBG) log("DataConnection constructor X");
}
@@ -614,10 +618,13 @@
private void notifyAllWithEvent(ApnContext alreadySent, int event, String reason) {
mNetworkInfo.setDetailedState(mNetworkInfo.getDetailedState(), reason,
mNetworkInfo.getExtraInfo());
- for (ApnContext apnContext : mApnContexts) {
+ for (ConnectionParams cp : mApnContexts.values()) {
+ ApnContext apnContext = cp.mApnContext;
if (apnContext == alreadySent) continue;
if (reason != null) apnContext.setReason(reason);
- Message msg = mDct.obtainMessage(event, apnContext);
+ Pair<ApnContext, Integer> pair =
+ new Pair<ApnContext, Integer>(apnContext, cp.mConnectionGeneration);
+ Message msg = mDct.obtainMessage(event, pair);
AsyncResult.forMessage(msg);
msg.sendToTarget();
}
@@ -1038,8 +1045,8 @@
mConnectionParams = cp;
mConnectionParams.mTag = mTag;
- if (!mApnContexts.contains(apnContext)) {
- mApnContexts.add(apnContext);
+ if (!mApnContexts.containsKey(apnContext)) {
+ mApnContexts.put(apnContext, cp);
}
configureRetry(mApnSetting.canHandleType(PhoneConstants.APN_TYPE_DEFAULT));
mRetryManager.setRetryCount(0);
@@ -1541,7 +1548,8 @@
case EVENT_DISCONNECT: {
DisconnectParams dp = (DisconnectParams) msg.obj;
- if (mApnContexts.remove(dp.mApnContext) && mApnContexts.size() == 0) {
+ if ((mApnContexts.remove(dp.mApnContext) != null) &&
+ (mApnContexts.size() == 0)) {
if (DBG) {
log("DcRetryingState msg.what=EVENT_DISCONNECT " + " RefCount="
+ mApnContexts.size() + " dp=" + dp);
@@ -1839,10 +1847,10 @@
if (DBG) {
log("DcActiveState: EVENT_CONNECT cp=" + cp + " dc=" + DataConnection.this);
}
- if (mApnContexts.contains(cp.mApnContext)) {
+ if (mApnContexts.containsKey(cp.mApnContext)) {
log("DcActiveState ERROR already added apnContext=" + cp.mApnContext);
} else {
- mApnContexts.add(cp.mApnContext);
+ mApnContexts.put(cp.mApnContext, cp);
if (DBG) {
log("DcActiveState msg.what=EVENT_CONNECT RefCount="
+ mApnContexts.size());
@@ -1858,7 +1866,7 @@
log("DcActiveState: EVENT_DISCONNECT dp=" + dp
+ " dc=" + DataConnection.this);
}
- if (mApnContexts.contains(dp.mApnContext)) {
+ if (mApnContexts.containsKey(dp.mApnContext)) {
if (DBG) {
log("DcActiveState msg.what=EVENT_DISCONNECT RefCount="
+ mApnContexts.size());
@@ -2085,7 +2093,7 @@
}
// this can only happen if our exit has been called - we're already disconnected
if (mApnContexts == null) return;
- for (ApnContext apnContext : mApnContexts) {
+ for (ApnContext apnContext : mApnContexts.keySet()) {
log("DcNetworkAgent: [unwanted]: disconnect apnContext=" + apnContext);
Message msg = mDct.obtainMessage(DctConstants.EVENT_DISCONNECT_DONE, apnContext);
DisconnectParams dp = new DisconnectParams(apnContext, apnContext.getReason(), msg);
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcAsyncChannel.java b/src/java/com/android/internal/telephony/dataconnection/DcAsyncChannel.java
index b503a0d..d46646b 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcAsyncChannel.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcAsyncChannel.java
@@ -368,14 +368,16 @@
* AsyncResult.result = FailCause and AsyncResult.exception = Exception().
*/
public void bringUp(ApnContext apnContext, int initialMaxRetry, int profileId,
- int rilRadioTechnology, boolean retryWhenSSChange, Message onCompletedMsg) {
+ int rilRadioTechnology, boolean retryWhenSSChange, Message onCompletedMsg,
+ int connectionGeneration) {
if (DBG) {
log("bringUp: apnContext=" + apnContext + " initialMaxRetry=" + initialMaxRetry
+ " onCompletedMsg=" + onCompletedMsg);
}
sendMessage(DataConnection.EVENT_CONNECT,
new ConnectionParams(apnContext, initialMaxRetry, profileId,
- rilRadioTechnology, retryWhenSSChange, onCompletedMsg));
+ rilRadioTechnology, retryWhenSSChange, onCompletedMsg,
+ connectionGeneration));
}
/**
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcController.java b/src/java/com/android/internal/telephony/dataconnection/DcController.java
index 98d1c3b..61736ed 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcController.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcController.java
@@ -265,7 +265,7 @@
+ " newState=" + newState.toString());
if (newState.active == DATA_CONNECTION_ACTIVE_PH_LINK_INACTIVE) {
if (mDct.mIsCleanupRequired) {
- apnsToCleanup.addAll(dc.mApnContexts);
+ apnsToCleanup.addAll(dc.mApnContexts.keySet());
mDct.mIsCleanupRequired = false;
} else {
DcFailCause failCause = DcFailCause.fromInt(newState.status);
@@ -275,7 +275,7 @@
mDct.sendRestartRadio();
} else if (mDct.isPermanentFail(failCause)) {
if (DBG) log("onDataStateChanged: inactive, add to cleanup list");
- apnsToCleanup.addAll(dc.mApnContexts);
+ apnsToCleanup.addAll(dc.mApnContexts.keySet());
} else {
if (DBG) log("onDataStateChanged: inactive, add to retry list");
dcsToRetry.add(dc);
@@ -318,11 +318,11 @@
" oldLp=" + result.oldLp +
" newLp=" + result.newLp);
}
- apnsToCleanup.addAll(dc.mApnContexts);
+ apnsToCleanup.addAll(dc.mApnContexts.keySet());
} else {
if (DBG) log("onDataStateChanged: simple change");
- for (ApnContext apnContext : dc.mApnContexts) {
+ for (ApnContext apnContext : dc.mApnContexts.keySet()) {
mPhone.notifyDataConnection(
PhoneConstants.REASON_LINK_PROPERTIES_CHANGED,
apnContext.getApnType());
@@ -334,7 +334,7 @@
}
}
} else {
- apnsToCleanup.addAll(dc.mApnContexts);
+ apnsToCleanup.addAll(dc.mApnContexts.keySet());
if (DBG) {
log("onDataStateChanged: interface change, cleanup apns="
+ dc.mApnContexts);
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
index 0a453b0..de6517f 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
@@ -57,6 +57,7 @@
import android.text.TextUtils;
import android.util.EventLog;
import android.util.LocalLog;
+import android.util.Pair;
import android.view.WindowManager;
import android.telephony.Rlog;
@@ -1307,6 +1308,7 @@
apnContext.setDataConnectionAc(dcac);
apnContext.setApnSetting(apnSetting);
+ int connectionGeneration = apnContext.incAndGetConnectionGeneration();
apnContext.setState(DctConstants.State.CONNECTING);
mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
@@ -1314,7 +1316,7 @@
msg.what = DctConstants.EVENT_DATA_SETUP_COMPLETE;
msg.obj = apnContext;
dcac.bringUp(apnContext, getInitialMaxRetry(), profileId, radioTech,
- mAutoAttachOnCreation.get(), msg);
+ mAutoAttachOnCreation.get(), msg, connectionGeneration);
if (DBG) log("setupData: initing!");
return true;
@@ -1817,13 +1819,9 @@
DcFailCause cause = DcFailCause.UNKNOWN;
boolean handleError = false;
- ApnContext apnContext = null;
+ ApnContext apnContext = getValidApnContext(ar, "onDataSetupComplete");
- if(ar.userObj instanceof ApnContext){
- apnContext = (ApnContext)ar.userObj;
- } else {
- throw new RuntimeException("onDataSetupComplete: No apnContext");
- }
+ if (apnContext == null) return;
if (ar.exception == null) {
DcAsyncChannel dcac = apnContext.getDcAc();
@@ -2007,6 +2005,27 @@
}
/**
+ * check for obsolete messages. Return ApnContext if valid, null if not
+ */
+ private ApnContext getValidApnContext(AsyncResult ar, String logString) {
+ if (ar != null && ar.userObj instanceof Pair) {
+ Pair<ApnContext, Integer>pair = (Pair<ApnContext, Integer>)ar.userObj;
+ ApnContext apnContext = pair.first;
+ if (apnContext != null) {
+ if (apnContext.getConnectionGeneration() == pair.second) {
+ return apnContext;
+ } else {
+ log("ignoring obsolete " + logString);
+ return null;
+ }
+ }
+ }
+ throw new RuntimeException(logString + ": No apnContext");
+ }
+
+
+
+ /**
* 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
@@ -2015,13 +2034,9 @@
@Override
protected void onDataSetupCompleteError(AsyncResult ar) {
String reason = "";
- ApnContext apnContext = null;
+ ApnContext apnContext = getValidApnContext(ar, "onDataSetupCompleteError");
- if(ar.userObj instanceof ApnContext){
- apnContext = (ApnContext)ar.userObj;
- } else {
- throw new RuntimeException("onDataSetupCompleteError: No apnContext");
- }
+ if (apnContext == null) return;
// See if there are more APN's to try
if (apnContext.getWaitingApns().isEmpty()) {
@@ -2055,15 +2070,9 @@
* Called when EVENT_DISCONNECT_DONE is received.
*/
@Override
- protected void onDisconnectDone(int connId, AsyncResult ar) {
- ApnContext apnContext = null;
-
- if (ar.userObj instanceof ApnContext) {
- apnContext = (ApnContext) ar.userObj;
- } else {
- loge("onDisconnectDone: Invalid ar in onDisconnectDone, ignore");
- return;
- }
+ protected void onDisconnectDone(AsyncResult ar) {
+ ApnContext apnContext = getValidApnContext(ar, "onDisconnectDone");
+ if (apnContext == null) return;
if(DBG) log("onDisconnectDone: EVENT_DISCONNECT_DONE apnContext=" + apnContext);
apnContext.setState(DctConstants.State.IDLE);
@@ -2134,16 +2143,10 @@
* Called when EVENT_DISCONNECT_DC_RETRYING is received.
*/
@Override
- protected void onDisconnectDcRetrying(int connId, AsyncResult ar) {
+ protected void onDisconnectDcRetrying(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 apnContext = getValidApnContext(ar, "onDisconnectDcRetrying");
+ if (apnContext == null) return;
apnContext.setState(DctConstants.State.RETRYING);
if(DBG) log("onDisconnectDcRetrying: apnContext=" + apnContext);
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTrackerBase.java b/src/java/com/android/internal/telephony/dataconnection/DcTrackerBase.java
index 5c0226e..d2fc619 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcTrackerBase.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcTrackerBase.java
@@ -231,9 +231,6 @@
/** Intent sent when the reconnect alarm fires. */
protected PendingIntent mReconnectIntent = null;
- /** CID of active data connection */
- protected int mCidActive;
-
// When false we will not auto attach and manually attaching is required.
protected boolean mAutoAttachOnCreationConfig = false;
protected AtomicBoolean mAutoAttachOnCreation = new AtomicBoolean(false);
@@ -876,8 +873,8 @@
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 onDisconnectDone(AsyncResult ar);
+ protected abstract void onDisconnectDcRetrying(AsyncResult ar);
protected abstract void onVoiceCallStarted();
protected abstract void onVoiceCallEnded();
protected abstract void onCleanUpConnection(boolean tearDown, int apnId, String reason);
@@ -933,7 +930,6 @@
break;
case DctConstants.EVENT_DATA_SETUP_COMPLETE:
- mCidActive = msg.arg1;
onDataSetupComplete((AsyncResult) msg.obj);
break;
@@ -943,12 +939,12 @@
case DctConstants.EVENT_DISCONNECT_DONE:
log("DataConnectionTracker.handleMessage: EVENT_DISCONNECT_DONE msg=" + msg);
- onDisconnectDone(msg.arg1, (AsyncResult) msg.obj);
+ onDisconnectDone((AsyncResult) msg.obj);
break;
case DctConstants.EVENT_DISCONNECT_DC_RETRYING:
log("DataConnectionTracker.handleMessage: EVENT_DISCONNECT_DC_RETRYING msg=" + msg);
- onDisconnectDcRetrying(msg.arg1, (AsyncResult) msg.obj);
+ onDisconnectDcRetrying((AsyncResult) msg.obj);
break;
case DctConstants.EVENT_VOICE_CALL_STARTED:
@@ -1947,7 +1943,6 @@
pw.println(" mResolver=" + mResolver);
pw.println(" mIsWifiConnected=" + mIsWifiConnected);
pw.println(" mReconnectIntent=" + mReconnectIntent);
- pw.println(" mCidActive=" + mCidActive);
pw.println(" mAutoAttachOnCreation=" + mAutoAttachOnCreation.get());
pw.println(" mIsScreenOn=" + mIsScreenOn);
pw.println(" mUniqueIdGenerator=" + mUniqueIdGenerator);