Merge "Remove STOPSHIP but allow seamless Handoff when possible." into honeycomb-LTE

This commit is contained in:
Wink Saville
2011-07-13 14:15:19 -07:00
committed by Android (Google) Code Review
6 changed files with 291 additions and 148 deletions

View File

@@ -52,11 +52,26 @@ import java.util.Collections;
public class LinkProperties implements Parcelable { public class LinkProperties implements Parcelable {
String mIfaceName; String mIfaceName;
private Collection<LinkAddress> mLinkAddresses; private Collection<LinkAddress> mLinkAddresses = new ArrayList<LinkAddress>();
private Collection<InetAddress> mDnses; private Collection<InetAddress> mDnses = new ArrayList<InetAddress>();
private Collection<RouteInfo> mRoutes; private Collection<RouteInfo> mRoutes = new ArrayList<RouteInfo>();
private ProxyProperties mHttpProxy; private ProxyProperties mHttpProxy;
public static class CompareAddressesResult {
public ArrayList<LinkAddress> removed = new ArrayList<LinkAddress>();
public ArrayList<LinkAddress> added = new ArrayList<LinkAddress>();
@Override
public String toString() {
String retVal = "removedAddresses=[";
for (LinkAddress addr : removed) retVal += addr.toString() + ",";
retVal += "] addedAddresses=[";
for (LinkAddress addr : added) retVal += addr.toString() + ",";
retVal += "]";
return retVal;
}
}
public LinkProperties() { public LinkProperties() {
clear(); clear();
} }
@@ -121,9 +136,9 @@ public class LinkProperties implements Parcelable {
public void clear() { public void clear() {
mIfaceName = null; mIfaceName = null;
mLinkAddresses = new ArrayList<LinkAddress>(); mLinkAddresses.clear();
mDnses = new ArrayList<InetAddress>(); mDnses.clear();
mRoutes = new ArrayList<RouteInfo>(); mRoutes.clear();
mHttpProxy = null; mHttpProxy = null;
} }
@@ -155,6 +170,63 @@ public class LinkProperties implements Parcelable {
return ifaceName + linkAddresses + routes + dns + proxy; return ifaceName + linkAddresses + routes + dns + proxy;
} }
/**
* Compares this {@code LinkProperties} interface name against the target
*
* @param target LinkProperties to compare.
* @return {@code true} if both are identical, {@code false} otherwise.
*/
public boolean isIdenticalInterfaceName(LinkProperties target) {
return TextUtils.equals(getInterfaceName(), target.getInterfaceName());
}
/**
* Compares this {@code LinkProperties} interface name against the target
*
* @param target LinkProperties to compare.
* @return {@code true} if both are identical, {@code false} otherwise.
*/
public boolean isIdenticalAddresses(LinkProperties target) {
Collection<InetAddress> targetAddresses = target.getAddresses();
Collection<InetAddress> sourceAddresses = getAddresses();
return (sourceAddresses.size() == targetAddresses.size()) ?
sourceAddresses.containsAll(targetAddresses) : false;
}
/**
* Compares this {@code LinkProperties} DNS addresses against the target
*
* @param target LinkProperties to compare.
* @return {@code true} if both are identical, {@code false} otherwise.
*/
public boolean isIdenticalDnses(LinkProperties target) {
Collection<InetAddress> targetDnses = target.getDnses();
return (mDnses.size() == targetDnses.size()) ?
mDnses.containsAll(targetDnses) : false;
}
/**
* Compares this {@code LinkProperties} Routes against the target
*
* @param target LinkProperties to compare.
* @return {@code true} if both are identical, {@code false} otherwise.
*/
public boolean isIdenticalRoutes(LinkProperties target) {
Collection<RouteInfo> targetRoutes = target.getRoutes();
return (mRoutes.size() == targetRoutes.size()) ?
mRoutes.containsAll(targetRoutes) : false;
}
/**
* Compares this {@code LinkProperties} HttpProxy against the target
*
* @param target LinkProperties to compare.
* @return {@code true} if both are identical, {@code false} otherwise.
*/
public boolean isIdenticalHttpProxy(LinkProperties target) {
return getHttpProxy() == null ? target.getHttpProxy() == null :
getHttpProxy().equals(target.getHttpProxy());
}
@Override @Override
/** /**
@@ -176,30 +248,41 @@ public class LinkProperties implements Parcelable {
if (!(obj instanceof LinkProperties)) return false; if (!(obj instanceof LinkProperties)) return false;
boolean sameAddresses;
boolean sameDnses;
boolean sameRoutes;
LinkProperties target = (LinkProperties) obj; LinkProperties target = (LinkProperties) obj;
Collection<InetAddress> targetAddresses = target.getAddresses(); return isIdenticalInterfaceName(target) &&
Collection<InetAddress> sourceAddresses = getAddresses(); isIdenticalAddresses(target) &&
sameAddresses = (sourceAddresses.size() == targetAddresses.size()) ? isIdenticalDnses(target) &&
sourceAddresses.containsAll(targetAddresses) : false; isIdenticalRoutes(target) &&
isIdenticalHttpProxy(target);
}
Collection<InetAddress> targetDnses = target.getDnses(); /**
sameDnses = (mDnses.size() == targetDnses.size()) ? * Return two lists, a list of addresses that would be removed from
mDnses.containsAll(targetDnses) : false; * mLinkAddresses and a list of addresses that would be added to
* mLinkAddress which would then result in target and mLinkAddresses
Collection<RouteInfo> targetRoutes = target.getRoutes(); * being the same list.
sameRoutes = (mRoutes.size() == targetRoutes.size()) ? *
mRoutes.containsAll(targetRoutes) : false; * @param target is a new list of addresses
* @return the removed and added lists.
return */
sameAddresses && sameDnses && sameRoutes public CompareAddressesResult compareAddresses(LinkProperties target) {
&& TextUtils.equals(getInterfaceName(), target.getInterfaceName()) /*
&& (getHttpProxy() == null ? target.getHttpProxy() == null : * Duplicate the LinkAddresses into removed, we will be removing
getHttpProxy().equals(target.getHttpProxy())); * address which are common between mLinkAddresses and target
* leaving the addresses that are different. And address which
* are in target but not in mLinkAddresses are placed in the
* addedAddresses.
*/
CompareAddressesResult result = new CompareAddressesResult();
result.removed = new ArrayList<LinkAddress>(mLinkAddresses);
result.added.clear();
for (LinkAddress newAddress : target.getLinkAddresses()) {
if (! result.removed.remove(newAddress)) {
result.added.add(newAddress);
}
}
return result;
} }
@Override @Override

View File

@@ -28,6 +28,7 @@ import android.net.EthernetDataTracker;
import android.net.IConnectivityManager; import android.net.IConnectivityManager;
import android.net.LinkAddress; import android.net.LinkAddress;
import android.net.LinkProperties; import android.net.LinkProperties;
import android.net.LinkProperties.CompareAddressesResult;
import android.net.MobileDataStateTracker; import android.net.MobileDataStateTracker;
import android.net.NetworkConfig; import android.net.NetworkConfig;
import android.net.NetworkInfo; import android.net.NetworkInfo;
@@ -61,6 +62,7 @@ import java.io.FileDescriptor;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.net.Inet6Address;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.Inet4Address; import java.net.Inet4Address;
import java.net.UnknownHostException; import java.net.UnknownHostException;
@@ -76,6 +78,7 @@ import java.util.List;
public class ConnectivityService extends IConnectivityManager.Stub { public class ConnectivityService extends IConnectivityManager.Stub {
private static final boolean DBG = true; private static final boolean DBG = true;
private static final boolean VDBG = true;
private static final String TAG = "ConnectivityService"; private static final String TAG = "ConnectivityService";
// how long to wait before switching back to a radio's default network // how long to wait before switching back to a radio's default network
@@ -98,6 +101,11 @@ public class ConnectivityService extends IConnectivityManager.Stub {
*/ */
private NetworkStateTracker mNetTrackers[]; private NetworkStateTracker mNetTrackers[];
/**
* The link properties that define the current links
*/
private LinkProperties mCurrentLinkProperties[];
/** /**
* A per Net list of the PID's that requested access to the net * A per Net list of the PID's that requested access to the net
* used both as a refcount and for per-PID DNS selection * used both as a refcount and for per-PID DNS selection
@@ -302,6 +310,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
mNetTrackers = new NetworkStateTracker[ mNetTrackers = new NetworkStateTracker[
ConnectivityManager.MAX_NETWORK_TYPE+1]; ConnectivityManager.MAX_NETWORK_TYPE+1];
mCurrentLinkProperties = new LinkProperties[ConnectivityManager.MAX_NETWORK_TYPE+1];
mNetworkPreference = getPersistedNetworkPreference(); mNetworkPreference = getPersistedNetworkPreference();
@@ -442,6 +451,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
mNetConfigs[netType].radio); mNetConfigs[netType].radio);
continue; continue;
} }
mCurrentLinkProperties[netType] = mNetTrackers[netType].getLinkProperties();
} }
mTethering = new Tethering(mContext, mHandler.getLooper()); mTethering = new Tethering(mContext, mHandler.getLooper());
@@ -1409,6 +1419,8 @@ public class ConnectivityService extends IConnectivityManager.Stub {
* right routing table entries exist. * right routing table entries exist.
*/ */
private void handleConnectivityChange(int netType, boolean doReset) { private void handleConnectivityChange(int netType, boolean doReset) {
int resetMask = doReset ? NetworkUtils.RESET_ALL_ADDRESSES : 0;
/* /*
* If a non-default network is enabled, add the host routes that * If a non-default network is enabled, add the host routes that
* will allow it's DNS servers to be accessed. * will allow it's DNS servers to be accessed.
@@ -1416,6 +1428,45 @@ public class ConnectivityService extends IConnectivityManager.Stub {
handleDnsConfigurationChange(netType); handleDnsConfigurationChange(netType);
if (mNetTrackers[netType].getNetworkInfo().isConnected()) { if (mNetTrackers[netType].getNetworkInfo().isConnected()) {
LinkProperties newLp = mNetTrackers[netType].getLinkProperties();
LinkProperties curLp = mCurrentLinkProperties[netType];
mCurrentLinkProperties[netType] = newLp;
if (VDBG) {
log("handleConnectivityChange: changed linkProperty[" + netType + "]:" +
" doReset=" + doReset + " resetMask=" + resetMask +
"\n curLp=" + curLp +
"\n newLp=" + newLp);
}
if (curLp.isIdenticalInterfaceName(newLp)) {
CompareAddressesResult car = curLp.compareAddresses(newLp);
if ((car.removed.size() != 0) || (car.added.size() != 0)) {
for (LinkAddress linkAddr : car.removed) {
if (linkAddr.getAddress() instanceof Inet4Address) {
resetMask |= NetworkUtils.RESET_IPV4_ADDRESSES;
}
if (linkAddr.getAddress() instanceof Inet6Address) {
resetMask |= NetworkUtils.RESET_IPV6_ADDRESSES;
}
}
if (DBG) {
log("handleConnectivityChange: addresses changed" +
" linkProperty[" + netType + "]:" + " resetMask=" + resetMask +
"\n car=" + car);
}
} else {
if (DBG) {
log("handleConnectivityChange: address are the same reset per doReset" +
" linkProperty[" + netType + "]:" +
" resetMask=" + resetMask);
}
}
} else {
resetMask = NetworkUtils.RESET_ALL_ADDRESSES;
log("handleConnectivityChange: interface not not equivalent reset both" +
" linkProperty[" + netType + "]:" +
" resetMask=" + resetMask);
}
if (mNetConfigs[netType].isDefault()) { if (mNetConfigs[netType].isDefault()) {
handleApplyDefaultProxy(netType); handleApplyDefaultProxy(netType);
addDefaultRoute(mNetTrackers[netType]); addDefaultRoute(mNetTrackers[netType]);
@@ -1430,15 +1481,13 @@ public class ConnectivityService extends IConnectivityManager.Stub {
} }
} }
if (doReset) { if (doReset || resetMask != 0) {
LinkProperties linkProperties = mNetTrackers[netType].getLinkProperties(); LinkProperties linkProperties = mNetTrackers[netType].getLinkProperties();
if (linkProperties != null) { if (linkProperties != null) {
String iface = linkProperties.getInterfaceName(); String iface = linkProperties.getInterfaceName();
if (TextUtils.isEmpty(iface) == false) { if (TextUtils.isEmpty(iface) == false) {
if (DBG) { if (DBG) log("resetConnections(" + iface + ", " + resetMask + ")");
log("resetConnections(" + iface + ", NetworkUtils.RESET_ALL_ADDRESSES)"); NetworkUtils.resetConnections(iface, resetMask);
}
NetworkUtils.resetConnections(iface, NetworkUtils.RESET_ALL_ADDRESSES);
} }
} }
} }

View File

@@ -52,7 +52,7 @@ public class DataCallState {
/** /**
* Class returned by onSetupConnectionCompleted. * Class returned by onSetupConnectionCompleted.
*/ */
protected enum SetupResult { public enum SetupResult {
SUCCESS, SUCCESS,
ERR_BadCommand, ERR_BadCommand,
ERR_UnacceptableParameter, ERR_UnacceptableParameter,

View File

@@ -17,30 +17,25 @@
package com.android.internal.telephony; package com.android.internal.telephony;
import com.android.internal.telephony.DataCallState.SetupResult;
import com.android.internal.util.AsyncChannel; import com.android.internal.util.AsyncChannel;
import com.android.internal.util.Protocol; import com.android.internal.util.Protocol;
import com.android.internal.util.State; import com.android.internal.util.State;
import com.android.internal.util.StateMachine; import com.android.internal.util.StateMachine;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.net.LinkAddress;
import android.net.LinkCapabilities; import android.net.LinkCapabilities;
import android.net.LinkProperties; import android.net.LinkProperties;
import android.net.NetworkUtils; import android.net.LinkProperties.CompareAddressesResult;
import android.net.ProxyProperties; import android.net.ProxyProperties;
import android.os.AsyncResult; import android.os.AsyncResult;
import android.os.Bundle;
import android.os.Message; import android.os.Message;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemProperties; import android.os.SystemProperties;
import android.text.TextUtils; import android.text.TextUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
/** /**
* {@hide} * {@hide}
@@ -497,8 +492,7 @@ public abstract class DataConnection extends StateMachine {
} else { } else {
if (DBG) log("onSetupConnectionCompleted received DataCallState: " + response); if (DBG) log("onSetupConnectionCompleted received DataCallState: " + response);
cid = response.cid; cid = response.cid;
// set link properties based on data call response result = updateLinkProperty(response).setupResult;
result = setLinkProperties(response, mLinkProperties);
} }
return result; return result;
@@ -527,48 +521,41 @@ public abstract class DataConnection extends StateMachine {
return response.setLinkProperties(lp, okToUseSystemPropertyDns); return response.setLinkProperties(lp, okToUseSystemPropertyDns);
} }
private DataConnectionAc.LinkPropertyChangeAction updateLinkProperty( public static class UpdateLinkPropertyResult {
DataCallState newState) { public DataCallState.SetupResult setupResult = DataCallState.SetupResult.SUCCESS;
DataConnectionAc.LinkPropertyChangeAction changed = public LinkProperties oldLp;
DataConnectionAc.LinkPropertyChangeAction.NONE; public LinkProperties newLp;
public UpdateLinkPropertyResult(LinkProperties curLp) {
oldLp = curLp;
newLp = curLp;
}
}
if (newState == null) return changed; private UpdateLinkPropertyResult updateLinkProperty(DataCallState newState) {
UpdateLinkPropertyResult result = new UpdateLinkPropertyResult(mLinkProperties);
DataCallState.SetupResult result; if (newState == null) return result;
LinkProperties newLp = new LinkProperties();
DataCallState.SetupResult setupResult;
result.newLp = new LinkProperties();
// set link properties based on data call response // set link properties based on data call response
result = setLinkProperties(newState, newLp); result.setupResult = setLinkProperties(newState, result.newLp);
if (result != DataCallState.SetupResult.SUCCESS) { if (result.setupResult != DataCallState.SetupResult.SUCCESS) {
if (DBG) log("UpdateLinkProperty failed : " + result); if (DBG) log("updateLinkProperty failed : " + result.setupResult);
return changed; return result;
} }
// copy HTTP proxy as it is not part DataCallState. // copy HTTP proxy as it is not part DataCallState.
newLp.setHttpProxy(mLinkProperties.getHttpProxy()); result.newLp.setHttpProxy(mLinkProperties.getHttpProxy());
if (DBG) log("old LP=" + mLinkProperties); if (DBG && (! result.oldLp.equals(result.newLp))) {
if (DBG) log("new LP=" + newLp); if (DBG) log("updateLinkProperty old != new");
if (VDBG) log("updateLinkProperty old LP=" + result.oldLp);
// Check consistency of link address. Currently we expect if (VDBG) log("updateLinkProperty new LP=" + result.newLp);
// only one "global" address is assigned per each IP type.
Collection<LinkAddress> oLinks = mLinkProperties.getLinkAddresses();
Collection<LinkAddress> nLinks = newLp.getLinkAddresses();
for (LinkAddress oldLink : oLinks) {
for (LinkAddress newLink : nLinks) {
if ((NetworkUtils.addressTypeMatches(oldLink.getAddress(),
newLink.getAddress())) &&
(oldLink.equals(newLink) == false)) {
return DataConnectionAc.LinkPropertyChangeAction.RESET;
}
}
} }
mLinkProperties = result.newLp;
if (mLinkProperties == null || !mLinkProperties.equals(newLp)) { return result;
mLinkProperties = newLp;
changed = DataConnectionAc.LinkPropertyChangeAction.CHANGED;
}
return changed;
} }
/** /**
@@ -643,14 +630,15 @@ public abstract class DataConnection extends StateMachine {
} }
case DataConnectionAc.REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE: { case DataConnectionAc.REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE: {
DataCallState newState = (DataCallState) msg.obj; DataCallState newState = (DataCallState) msg.obj;
DataConnectionAc.LinkPropertyChangeAction action = updateLinkProperty(newState); UpdateLinkPropertyResult result =
updateLinkProperty(newState);
if (VDBG) { if (VDBG) {
log("REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE action=" log("REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE result="
+ action + " newState=" + newState); + result + " newState=" + newState);
} }
mAc.replyToMessage(msg, mAc.replyToMessage(msg,
DataConnectionAc.RSP_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE, DataConnectionAc.RSP_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE,
action.ordinal()); result);
break; break;
} }
case DataConnectionAc.REQ_GET_LINK_CAPABILITIES: { case DataConnectionAc.REQ_GET_LINK_CAPABILITIES: {
@@ -688,7 +676,7 @@ public abstract class DataConnection extends StateMachine {
case DataConnectionAc.REQ_GET_APNCONTEXT_LIST: { case DataConnectionAc.REQ_GET_APNCONTEXT_LIST: {
if (VDBG) log("REQ_GET_APNCONTEXT_LIST num in list=" + mApnList.size()); if (VDBG) log("REQ_GET_APNCONTEXT_LIST num in list=" + mApnList.size());
mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_APNCONTEXT_LIST, mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_APNCONTEXT_LIST,
new ArrayList(mApnList)); new ArrayList<ApnContext>(mApnList));
break; break;
} }
case DataConnectionAc.REQ_SET_RECONNECT_INTENT: { case DataConnectionAc.REQ_SET_RECONNECT_INTENT: {

View File

@@ -16,12 +16,14 @@
package com.android.internal.telephony; package com.android.internal.telephony;
import com.android.internal.telephony.DataConnection.UpdateLinkPropertyResult;
import com.android.internal.util.AsyncChannel; import com.android.internal.util.AsyncChannel;
import com.android.internal.util.Protocol; import com.android.internal.util.Protocol;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.net.LinkCapabilities; import android.net.LinkCapabilities;
import android.net.LinkProperties; import android.net.LinkProperties;
import android.net.LinkProperties.CompareAddressesResult;
import android.net.ProxyProperties; import android.net.ProxyProperties;
import android.os.Message; import android.os.Message;
@@ -310,18 +312,18 @@ public class DataConnectionAc extends AsyncChannel {
if (DBG) log("reqUpdateLinkPropertiesDataCallState"); if (DBG) log("reqUpdateLinkPropertiesDataCallState");
} }
public LinkPropertyChangeAction rspUpdateLinkPropertiesDataCallState(Message response) { public UpdateLinkPropertyResult rspUpdateLinkPropertiesDataCallState(Message response) {
LinkPropertyChangeAction retVal = LinkPropertyChangeAction.fromInt(response.arg1); UpdateLinkPropertyResult retVal = (UpdateLinkPropertyResult)response.obj;
if (DBG) log("rspUpdateLinkPropertiesState=" + retVal); if (DBG) log("rspUpdateLinkPropertiesState: retVal=" + retVal);
return retVal; return retVal;
} }
/** /**
* Update link properties in the data connection * Update link properties in the data connection
* *
* @return true if link property has been updated. false otherwise. * @return the removed and added addresses.
*/ */
public LinkPropertyChangeAction updateLinkPropertiesDataCallStateSync(DataCallState newState) { public UpdateLinkPropertyResult updateLinkPropertiesDataCallStateSync(DataCallState newState) {
Message response = Message response =
sendMessageSynchronously(REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE, newState); sendMessageSynchronously(REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE, newState);
if ((response != null) && if ((response != null) &&
@@ -329,7 +331,7 @@ public class DataConnectionAc extends AsyncChannel {
return rspUpdateLinkPropertiesDataCallState(response); return rspUpdateLinkPropertiesDataCallState(response);
} else { } else {
log("getLinkProperties error response=" + response); log("getLinkProperties error response=" + response);
return LinkPropertyChangeAction.NONE; return new UpdateLinkPropertyResult(new LinkProperties());
} }
} }

View File

@@ -26,6 +26,9 @@ import android.content.IntentFilter;
import android.database.ContentObserver; import android.database.ContentObserver;
import android.database.Cursor; import android.database.Cursor;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.net.LinkAddress;
import android.net.LinkProperties.CompareAddressesResult;
import android.net.NetworkUtils;
import android.net.ProxyProperties; import android.net.ProxyProperties;
import android.net.TrafficStats; import android.net.TrafficStats;
import android.net.Uri; import android.net.Uri;
@@ -53,6 +56,7 @@ import com.android.internal.telephony.ApnContext;
import com.android.internal.telephony.ApnSetting; import com.android.internal.telephony.ApnSetting;
import com.android.internal.telephony.DataCallState; import com.android.internal.telephony.DataCallState;
import com.android.internal.telephony.DataConnection; import com.android.internal.telephony.DataConnection;
import com.android.internal.telephony.DataConnection.UpdateLinkPropertyResult;
import com.android.internal.telephony.DataConnectionAc; import com.android.internal.telephony.DataConnectionAc;
import com.android.internal.telephony.DataConnectionTracker; import com.android.internal.telephony.DataConnectionTracker;
import com.android.internal.telephony.Phone; import com.android.internal.telephony.Phone;
@@ -1037,7 +1041,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
/** /**
* @param dcacs Collection of DataConnectionAc reported from RIL. * @param dcacs Collection of DataConnectionAc reported from RIL.
* @return List of ApnContext whihc is connected, but does not present in * @return List of ApnContext which is connected, but is not present in
* data connection list reported from RIL. * data connection list reported from RIL.
*/ */
private List<ApnContext> findApnContextToClean(Collection<DataConnectionAc> dcacs) { private List<ApnContext> findApnContextToClean(Collection<DataConnectionAc> dcacs) {
@@ -1091,32 +1095,30 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
if (DBG) log("onDataStateChanged(ar): DataCallState size=" + dataCallStates.size()); if (DBG) log("onDataStateChanged(ar): DataCallState size=" + dataCallStates.size());
// Create a hash map to store the dataCallState of each DataConnectionAc // Create a hash map to store the dataCallState of each DataConnectionAc
// TODO: Depends on how frequent the DATA_CALL_LIST got updated, HashMap<DataCallState, DataConnectionAc> dataCallStateToDcac;
// may cache response to reduce comparison. dataCallStateToDcac = new HashMap<DataCallState, DataConnectionAc>();
HashMap<DataCallState, DataConnectionAc> response;
response = new HashMap<DataCallState, DataConnectionAc>();
for (DataCallState dataCallState : dataCallStates) { for (DataCallState dataCallState : dataCallStates) {
DataConnectionAc dcac = findDataConnectionAcByCid(dataCallState.cid); DataConnectionAc dcac = findDataConnectionAcByCid(dataCallState.cid);
if (dcac != null) response.put(dataCallState, dcac); if (dcac != null) dataCallStateToDcac.put(dataCallState, dcac);
} }
// step1: Find a list of "connected" APN which does not have reference to // A list of apns to cleanup, those that aren't in the list we know we have to cleanup
// calls listed in the Data Call List. List<ApnContext> apnsToCleanup = findApnContextToClean(dataCallStateToDcac.values());
List<ApnContext> apnsToClear = findApnContextToClean(response.values());
// step2: Check status of each calls in Data Call List. // Find which connections have changed state and send a notification or cleanup
// Collect list of ApnContext associated with the data call if the link
// has to be cleared.
for (DataCallState newState : dataCallStates) { for (DataCallState newState : dataCallStates) {
DataConnectionAc dcac = response.get(newState); DataConnectionAc dcac = dataCallStateToDcac.get(newState);
// no associated DataConnection found. Ignore. if (dcac == null) {
if (dcac == null) continue; loge("onDataStateChanged(ar): No associated DataConnection ignore");
continue;
}
// The list of apn's associated with this DataConnection
Collection<ApnContext> apns = dcac.getApnListSync(); Collection<ApnContext> apns = dcac.getApnListSync();
// filter out ApnContext with "Connected/Connecting" state. // Find which ApnContexts of this DC are in the "Connected/Connecting" state.
ArrayList<ApnContext> connectedApns = new ArrayList<ApnContext>(); ArrayList<ApnContext> connectedApns = new ArrayList<ApnContext>();
for (ApnContext apnContext : apns) { for (ApnContext apnContext : apns) {
if (apnContext.getState() == State.CONNECTED || if (apnContext.getState() == State.CONNECTED ||
@@ -1125,67 +1127,86 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
connectedApns.add(apnContext); connectedApns.add(apnContext);
} }
} }
if (connectedApns.size() == 0) {
// No "Connected" ApnContext associated with this CID. Ignore. if (DBG) log("onDataStateChanged(ar): no connected apns");
if (connectedApns.isEmpty()) { } else {
continue; // 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
if (DBG) log("onDataStateChanged(ar): Found ConnId=" + newState.cid + " newState=" + newState.toString());
+ " newState=" + newState.toString()); if (newState.active == 0) {
if (newState.active != 0) { if (DBG) {
boolean resetConnection; log("onDataStateChanged(ar): inactive, cleanup apns=" + connectedApns);
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 apnsToCleanup.addAll(connectedApns);
// fails so we'll hope for the best and not reset the connection. } else {
// @see bug/4455071 // Its active so update the DataConnections link properties
if (SystemProperties.getBoolean("telephony.ignore-state-changes", UpdateLinkPropertyResult result =
true)) { dcac.updateLinkPropertiesDataCallStateSync(newState);
log("onDataStateChanged(ar): STOPSHIP don't reset, continue"); if (result.oldLp.equals(result.newLp)) {
resetConnection = false; if (DBG) log("onDataStateChanged(ar): no change");
} else { } else {
// Things changed so reset connection, when hack is removed if (result.oldLp.isIdenticalInterfaceName(result.newLp)) {
// this is the normal path. if (! result.oldLp.isIdenticalDnses(result.newLp) ||
log("onDataStateChanged(ar): changed so resetting connection"); ! result.oldLp.isIdenticalRoutes(result.newLp) ||
resetConnection = true; ! result.oldLp.isIdenticalHttpProxy(result.newLp) ||
! result.oldLp.isIdenticalAddresses(result.newLp)) {
// If the same address type was removed and added we need to cleanup
CompareAddressesResult car =
result.oldLp.compareAddresses(result.newLp);
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);
}
apnsToCleanup.addAll(connectedApns);
} else {
if (DBG) log("onDataStateChanged(ar): simple change");
for (ApnContext apnContext : connectedApns) {
mPhone.notifyDataConnection(
Phone.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);
}
} }
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.");
apnsToClear.addAll(connectedApns);
} }
// step3: Clear apn connection if applicable. if (apnsToCleanup.size() != 0) {
if (!apnsToClear.isEmpty()) {
// Add an event log when the network drops PDP // Add an event log when the network drops PDP
int cid = getCellLocationId(); int cid = getCellLocationId();
EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP, cid, EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP, cid,
TelephonyManager.getDefault().getNetworkType()); TelephonyManager.getDefault().getNetworkType());
} }
for (ApnContext apnContext : apnsToClear) { // Cleanup those dropped connections
for (ApnContext apnContext : apnsToCleanup) {
cleanUpConnection(true, apnContext); cleanUpConnection(true, apnContext);
} }
if (DBG) log("onDataStateChanged(ar): X"); if (DBG) log("onDataStateChanged(ar): X");
} }