diff options
author | Wink Saville <wink@google.com> | 2011-06-21 19:35:22 -0700 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2011-06-21 19:35:22 -0700 |
commit | 66c37f5df2b4cf469e90a0e9f7e0b336f56e8433 (patch) | |
tree | e6bcb8332b95634a4c225b9c6bd3b297c8dea107 /telephony/java/com | |
parent | 47e319247e89ab4ba30f58e5f532454ef21d15e6 (diff) | |
parent | 64a09341d8a16212855b7cdd16fe079e25d45838 (diff) | |
download | frameworks_base-66c37f5df2b4cf469e90a0e9f7e0b336f56e8433.zip frameworks_base-66c37f5df2b4cf469e90a0e9f7e0b336f56e8433.tar.gz frameworks_base-66c37f5df2b4cf469e90a0e9f7e0b336f56e8433.tar.bz2 |
am 64a09341: Merge "Fix handling of unsol_data_state_change with PDP sharing scenario" into honeycomb-LTE
* commit '64a09341d8a16212855b7cdd16fe079e25d45838':
Fix handling of unsol_data_state_change with PDP sharing scenario
Diffstat (limited to 'telephony/java/com')
3 files changed, 165 insertions, 67 deletions
diff --git a/telephony/java/com/android/internal/telephony/ApnContext.java b/telephony/java/com/android/internal/telephony/ApnContext.java index 496c43c..5ec00e8 100644 --- a/telephony/java/com/android/internal/telephony/ApnContext.java +++ b/telephony/java/com/android/internal/telephony/ApnContext.java @@ -89,6 +89,11 @@ public class ApnContext { } public synchronized void setDataConnectionAc(DataConnectionAc dcac) { + if (dcac != null) { + dcac.addApnContext(this); + } else { + if (mDataConnectionAc != null) mDataConnectionAc.removeApnContext(this); + } mDataConnectionAc = dcac; } diff --git a/telephony/java/com/android/internal/telephony/DataConnectionAc.java b/telephony/java/com/android/internal/telephony/DataConnectionAc.java index 62b90ae..e23f1cc 100644 --- a/telephony/java/com/android/internal/telephony/DataConnectionAc.java +++ b/telephony/java/com/android/internal/telephony/DataConnectionAc.java @@ -24,12 +24,18 @@ import android.net.LinkProperties; import android.net.ProxyProperties; import android.os.Message; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + /** * AsyncChannel to a DataConnection */ public class DataConnectionAc extends AsyncChannel { private static final boolean DBG = false; private String mLogTag; + private List<ApnContext> mApnList = null; public DataConnection dataConnection; @@ -85,6 +91,7 @@ public class DataConnectionAc extends AsyncChannel { public DataConnectionAc(DataConnection dc, String logTag) { dataConnection = dc; mLogTag = logTag; + mApnList = Collections.synchronizedList(new ArrayList<ApnContext>()); } /** @@ -371,6 +378,35 @@ public class DataConnectionAc extends AsyncChannel { } } + /** + * Add ApnContext association. + * + * @param ApnContext to associate + */ + public void addApnContext(ApnContext apnContext) { + if (!mApnList.contains(apnContext)) { + mApnList.add(apnContext); + } + } + + /** + * Remove ApnContext associateion. + * + * @param ApnContext to dissociate + */ + public void removeApnContext(ApnContext apnContext) { + mApnList.remove(apnContext); + } + + /** + * Retrieve collection of ApnContext currently associated with the DataConnectionAc. + * + * @return Collection of ApnContext + */ + public Collection<ApnContext> getApnList() { + return mApnList; + } + private void log(String s) { android.util.Log.d(mLogTag, "DataConnectionAc " + s); } diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java index 2118095..6ab217b 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java @@ -68,7 +68,9 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.util.ArrayList; +import java.util.Collection; import java.util.concurrent.ConcurrentHashMap; +import java.util.List; import java.util.Map; import java.util.HashMap; @@ -969,6 +971,49 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } /** + * @param cid Connection id provided from RIL. + * @return DataConnectionAc associated with specified cid. + */ + private DataConnectionAc findDataConnectionAcByCid(int cid) { + for (DataConnectionAc dcac : mDataConnectionAsyncChannels.values()) { + if (dcac.getCidSync() == cid) { + return dcac; + } + } + return null; + } + + /** + * @param dcacs Collection of DataConnectionAc reported from RIL. + * @return List of ApnContext whihc is connected, but does not present in + * data connection list reported from RIL. + */ + private List<ApnContext> findApnContextToClean(Collection<DataConnectionAc> dcacs) { + if (dcacs == null) return null; + + ArrayList<ApnContext> list = new ArrayList<ApnContext>(); + for (ApnContext apnContext : mApnContexts.values()) { + if (apnContext.getState() == 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 dcan reorted in data call list. + if (DBG) log("onDataStateChanged(ar): Connected apn not found in the list (" + + apnContext.toString() + ")"); + list.add(apnContext); + } + } + } + return list; + } + + /** * @param ar is the result of RIL_REQUEST_DATA_CALL_LIST * or RIL_UNSOL_DATA_CALL_LIST_CHANGED */ @@ -985,91 +1030,103 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { if (DBG) log("onDataStateChanged(ar): exception; likely radio not available, ignore"); return; } + if (DBG) log("onDataStateChanged(ar): DataCallState size=" + dataCallStates.size()); - // Create a hash map to store the dataCallState of each call id + // Create a hash map to store the dataCallState of each DataConnectionAc // TODO: Depends on how frequent the DATA_CALL_LIST got updated, // may cache response to reduce comparison. - HashMap<Integer, DataCallState> response; - response = new HashMap<Integer, DataCallState>(); - if (DBG) log("onDataStateChanged(ar): DataCallState size=" + dataCallStates.size()); - for (DataCallState dc : dataCallStates) { - response.put(dc.cid, dc); - if (DBG) log("onDataStateChanged(ar): " + dc.cid + ": " + dc.toString()); + HashMap<DataCallState, DataConnectionAc> response; + response = new HashMap<DataCallState, DataConnectionAc>(); + for (DataCallState dataCallState : dataCallStates) { + DataConnectionAc dcac = findDataConnectionAcByCid(dataCallState.cid); + + if (dcac != null) response.put(dataCallState, dcac); } - // For each connected apn, check if there is a matched active - // data call state, which has the same link properties. - if (DBG) log(" ApnContext size=" + mApnContexts.values().size()); - for (ApnContext apnContext : mApnContexts.values()) { - if (DBG){ - log("onDataStateChanged(ar): " + apnContext.toString()); - if (apnContext.getDataConnection() != null) { - log("onDataStateChanged(ar): " + apnContext.getDataConnection().toString()); + // step1: Find a list of "connected" APN which does not have reference to + // calls listed in the Data Call List. + List<ApnContext> apnsToClear = findApnContextToClean(response.values()); + + // step2: Check status of each calls in Data Call List. + // Collect list of ApnContext associated with the data call if the link + // has to be cleared. + for (DataCallState newState : dataCallStates) { + DataConnectionAc dcac = response.get(newState); + + // no associated DataConnection found. Ignore. + if (dcac == null) continue; + + Collection<ApnContext> apns = dcac.getApnList(); + + // filter out ApnContext with "Connected" state. + ArrayList<ApnContext> connectedApns = new ArrayList<ApnContext>(); + for (ApnContext apnContext : apns) { + if ((apnContext != null) && + (apnContext.getState() == State.CONNECTED)) { + connectedApns.add(apnContext); } } - DataConnectionAc dcac = apnContext.getDataConnectionAc(); - if (dcac == null) { + + // No "Connected" ApnContext associated with this CID. Ignore. + if (connectedApns.isEmpty()) { continue; } - int connectionId = dcac.getCidSync(); - if (apnContext.getState() == State.CONNECTED) { - // The way things are supposed to work, the PDP list - // should not contain the CID after it disconnects. - // However, the way things really work, sometimes the PDP - // context is still listed with active = false, which - // makes it hard to distinguish an activating context from - // an activated-and-then de-activated one. - if (response.containsKey(connectionId)) { - DataCallState newState = response.get(connectionId); - if (DBG) log("onDataStateChanged(ar): Found ConnId=" + connectionId + if (DBG) log("onDataStateChanged(ar): Found ConnId=" + newState.cid + " newState=" + newState.toString()); - if (newState.active != 0) { - boolean resetConnection; - switch (dcac.updateLinkPropertiesDataCallStateSync(newState)) { - case NONE: - if (DBG) log("onDataStateChanged(ar): Found but no change, skip"); - resetConnection = false; - break; - case CHANGED: - if (DBG) log("onDataStateChanged(ar): Found and changed, notify"); - mPhone.notifyDataConnection(Phone.REASON_LINK_PROPERTIES_CHANGED, - apnContext.getApnType()); - // Temporary hack, at this time a transition from CDMA -> Global - // fails so we'll hope for the best and not reset the connection. - // @see bug/4455071 - if (SystemProperties.getBoolean("telephony.ignore-state-changes", - true)) { - log("onDataStateChanged(ar): STOPSHIP don't reset, continue"); - resetConnection = false; - } else { - // Things changed so reset connection, when hack is removed - // this is the normal path. - log("onDataStateChanged(ar): changed so resetting connection"); - resetConnection = true; - } - break; - case RESET: - default: - if (DBG) log("onDataStateChanged(ar): an error, reset connection"); - resetConnection = true; - break; - } - if (resetConnection == false) continue; + if (newState.active != 0) { + boolean resetConnection; + switch (dcac.updateLinkPropertiesDataCallStateSync(newState)) { + case NONE: + if (DBG) log("onDataStateChanged(ar): Found but no change, skip"); + resetConnection = false; + break; + case CHANGED: + for (ApnContext apnContext : connectedApns) { + if (DBG) log("onDataStateChanged(ar): Found and changed, notify (" + + apnContext.toString() + ")"); + mPhone.notifyDataConnection(Phone.REASON_LINK_PROPERTIES_CHANGED, + apnContext.getApnType()); } + // Temporary hack, at this time a transition from CDMA -> Global + // fails so we'll hope for the best and not reset the connection. + // @see bug/4455071 + if (SystemProperties.getBoolean("telephony.ignore-state-changes", + true)) { + log("onDataStateChanged(ar): STOPSHIP don't reset, continue"); + resetConnection = false; + } else { + // Things changed so reset connection, when hack is removed + // this is the normal path. + log("onDataStateChanged(ar): changed so resetting connection"); + resetConnection = true; + } + break; + case RESET: + default: + if (DBG) log("onDataStateChanged(ar): an error, reset connection"); + resetConnection = true; + break; } + if (resetConnection == false) continue; + } - if (DBG) log("onDataStateChanged(ar): reset connection."); + if (DBG) log("onDataStateChanged(ar): reset connection."); - // Add an event log when the network drops PDP - int cid = getCellLocationId(); - EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP, cid, - TelephonyManager.getDefault().getNetworkType()); + apnsToClear.addAll(connectedApns); + } - cleanUpConnection(true, apnContext); - } + // step3: Clear apn connection if applicable. + if (!apnsToClear.isEmpty()) { + // Add an event log when the network drops PDP + int cid = getCellLocationId(); + EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP, cid, + TelephonyManager.getDefault().getNetworkType()); } + for (ApnContext apnContext : apnsToClear) { + cleanUpConnection(true, apnContext); + } if (DBG) log("onDataStateChanged(ar): X"); } |