From 0a46db5d88461d9a6c85bb2e95982ac4c511d57e Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Thu, 14 Jul 2011 14:28:05 -0700 Subject: [PATCH] Apply the dns and route diff which we get a change bug:5008973 Change-Id: Ib99e43d9d852452cc1f2aea6bef07bbd194f28cc --- core/java/android/net/LinkProperties.java | 90 ++++++- core/java/android/net/RouteInfo.java | 11 + .../com/android/server/ConnectivityService.java | 297 +++++++++------------ .../android/internal/telephony/DataConnection.java | 1 - .../internal/telephony/DataConnectionAc.java | 1 - .../telephony/gsm/GsmDataConnectionTracker.java | 4 +- 6 files changed, 223 insertions(+), 181 deletions(-) diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index f2f0e825c007..9826becf3180 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -57,16 +57,16 @@ public class LinkProperties implements Parcelable { private Collection mRoutes = new ArrayList(); private ProxyProperties mHttpProxy; - public static class CompareAddressesResult { - public ArrayList removed = new ArrayList(); - public ArrayList added = new ArrayList(); + public static class CompareResult { + public ArrayList removed = new ArrayList(); + public ArrayList added = new ArrayList(); @Override public String toString() { - String retVal = "removedAddresses=["; - for (LinkAddress addr : removed) retVal += addr.toString() + ","; - retVal += "] addedAddresses=["; - for (LinkAddress addr : added) retVal += addr.toString() + ","; + String retVal = "removed=["; + for (T addr : removed) retVal += addr.toString() + ","; + retVal += "] added=["; + for (T addr : added) retVal += addr.toString() + ","; retVal += "]"; return retVal; } @@ -263,10 +263,10 @@ public class LinkProperties implements Parcelable { * mLinkAddress which would then result in target and mLinkAddresses * being the same list. * - * @param target is a new list of addresses + * @param target is a LinkProperties with the new list of addresses * @return the removed and added lists. */ - public CompareAddressesResult compareAddresses(LinkProperties target) { + public CompareResult compareAddresses(LinkProperties target) { /* * Duplicate the LinkAddresses into removed, we will be removing * address which are common between mLinkAddresses and target @@ -274,17 +274,81 @@ public class LinkProperties implements Parcelable { * are in target but not in mLinkAddresses are placed in the * addedAddresses. */ - CompareAddressesResult result = new CompareAddressesResult(); + CompareResult result = new CompareResult(); result.removed = new ArrayList(mLinkAddresses); result.added.clear(); - for (LinkAddress newAddress : target.getLinkAddresses()) { - if (! result.removed.remove(newAddress)) { - result.added.add(newAddress); + if (target != null) { + for (LinkAddress newAddress : target.getLinkAddresses()) { + if (! result.removed.remove(newAddress)) { + result.added.add(newAddress); + } + } + } + return result; + } + + /** + * Return two lists, a list of dns addresses that would be removed from + * mDnses and a list of addresses that would be added to + * mDnses which would then result in target and mDnses + * being the same list. + * + * @param target is a LinkProperties with the new list of dns addresses + * @return the removed and added lists. + */ + public CompareResult compareDnses(LinkProperties target) { + /* + * Duplicate the InetAddresses into removed, we will be removing + * dns address which are common between mDnses and target + * leaving the addresses that are different. And dns address which + * are in target but not in mDnses are placed in the + * addedAddresses. + */ + CompareResult result = new CompareResult(); + + result.removed = new ArrayList(mDnses); + result.added.clear(); + if (target != null) { + for (InetAddress newAddress : target.getDnses()) { + if (! result.removed.remove(newAddress)) { + result.added.add(newAddress); + } } } return result; } + /** + * Return two lists, a list of routes that would be removed from + * mRoutes and a list of routes that would be added to + * mRoutes which would then result in target and mRoutes + * being the same list. + * + * @param target is a LinkProperties with the new list of routes + * @return the removed and added lists. + */ + public CompareResult compareRoutes(LinkProperties target) { + /* + * Duplicate the RouteInfos into removed, we will be removing + * routes which are common between mDnses and target + * leaving the routes that are different. And route address which + * are in target but not in mRoutes are placed in added. + */ + CompareResult result = new CompareResult(); + + result.removed = new ArrayList(mRoutes); + result.added.clear(); + if (target != null) { + for (RouteInfo r : target.getRoutes()) { + if (! result.removed.remove(r)) { + result.added.add(r); + } + } + } + return result; + } + + @Override /** * generate hashcode based on significant fields diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java index 8e5ddda4a6bc..275f32a48559 100644 --- a/core/java/android/net/RouteInfo.java +++ b/core/java/android/net/RouteInfo.java @@ -43,6 +43,7 @@ public class RouteInfo implements Parcelable { private final InetAddress mGateway; private final boolean mIsDefault; + private final boolean mIsHost; public RouteInfo(LinkAddress destination, InetAddress gateway) { if (destination == null) { @@ -68,6 +69,7 @@ public class RouteInfo implements Parcelable { destination.getNetworkPrefixLength()), destination.getNetworkPrefixLength()); mGateway = gateway; mIsDefault = isDefault(); + mIsHost = isHost(); } public RouteInfo(InetAddress gateway) { @@ -88,6 +90,10 @@ public class RouteInfo implements Parcelable { } } + private boolean isHost() { + return (mGateway.equals(Inet4Address.ANY) || mGateway.equals(Inet6Address.ANY)); + } + private boolean isDefault() { boolean val = false; if (mGateway != null) { @@ -100,6 +106,7 @@ public class RouteInfo implements Parcelable { return val; } + public LinkAddress getDestination() { return mDestination; } @@ -112,6 +119,10 @@ public class RouteInfo implements Parcelable { return mIsDefault; } + public boolean isHostRoute() { + return mIsHost; + } + public String toString() { String val = ""; if (mDestination != null) val = mDestination.toString(); diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 812c1eb1d547..edf190708862 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -28,7 +28,7 @@ import android.net.EthernetDataTracker; import android.net.IConnectivityManager; import android.net.LinkAddress; import android.net.LinkProperties; -import android.net.LinkProperties.CompareAddressesResult; +import android.net.LinkProperties.CompareResult; import android.net.MobileDataStateTracker; import android.net.NetworkConfig; import android.net.NetworkInfo; @@ -232,6 +232,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { private InetAddress mDefaultDns; + // this collection is used to refcount the added routes - if there are none left + // it's time to remove the route from the route table + private Collection mAddedRoutes = new ArrayList(); + // used in DBG mode to track inet condition reports private static final int INET_CONDITION_LOG_MAX_SIZE = 15; private ArrayList mInetLog; @@ -451,7 +455,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { mNetConfigs[netType].radio); continue; } - mCurrentLinkProperties[netType] = mNetTrackers[netType].getLinkProperties(); + mCurrentLinkProperties[netType] = null; } mTethering = new Tethering(mContext, mHandler.getLooper()); @@ -936,62 +940,68 @@ public class ConnectivityService extends IConnectivityManager.Stub { } try { InetAddress addr = InetAddress.getByAddress(hostAddress); - return addHostRoute(tracker, addr, 0); + LinkProperties lp = tracker.getLinkProperties(); + return addRoute(lp, RouteInfo.makeHostRoute(addr)); } catch (UnknownHostException e) {} return false; } - /** - * Ensure that a network route exists to deliver traffic to the specified - * host via the mobile data network. - * @param hostAddress the IP address of the host to which the route is desired, - * in network byte order. - * TODO - deprecate - * @return {@code true} on success, {@code false} on failure - */ - private boolean addHostRoute(NetworkStateTracker nt, InetAddress hostAddress, int cycleCount) { - LinkProperties lp = nt.getLinkProperties(); - if ((lp == null) || (hostAddress == null)) return false; + private boolean addRoute(LinkProperties p, RouteInfo r) { + return modifyRoute(p.getInterfaceName(), p, r, 0, true); + } - String interfaceName = lp.getInterfaceName(); - if (DBG) { - log("Requested host route to " + hostAddress + "(" + interfaceName + "), cycleCount=" + - cycleCount); - } - if (interfaceName == null) { - if (DBG) loge("addHostRoute failed due to null interface name"); + private boolean removeRoute(LinkProperties p, RouteInfo r) { + return modifyRoute(p.getInterfaceName(), p, r, 0, false); + } + + private boolean modifyRoute(String ifaceName, LinkProperties lp, RouteInfo r, int cycleCount, + boolean doAdd) { + if ((ifaceName == null) || (lp == null) || (r == null)) return false; + + if (cycleCount > MAX_HOSTROUTE_CYCLE_COUNT) { + loge("Error adding route - too much recursion"); return false; } - RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getRoutes(), hostAddress); - InetAddress gatewayAddress = null; - if (bestRoute != null) { - gatewayAddress = bestRoute.getGateway(); - // if the best route is ourself, don't relf-reference, just add the host route - if (hostAddress.equals(gatewayAddress)) gatewayAddress = null; + if (r.isHostRoute() == false) { + RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getRoutes(), r.getGateway()); + if (bestRoute != null) { + if (bestRoute.getGateway().equals(r.getGateway()) == false) { + bestRoute = RouteInfo.makeHostRoute(r.getGateway(), bestRoute.getGateway()); + } else { + bestRoute = RouteInfo.makeHostRoute(r.getGateway()); + } + if (!modifyRoute(ifaceName, lp, bestRoute, cycleCount+1, doAdd)) return false; + } } - if (gatewayAddress != null) { - if (cycleCount > MAX_HOSTROUTE_CYCLE_COUNT) { - loge("Error adding hostroute - too much recursion"); + if (doAdd) { + if (DBG) log("Adding " + r + " for interface " + ifaceName); + mAddedRoutes.add(r); + try { + mNetd.addRoute(ifaceName, r); + } catch (Exception e) { + // never crash - catch them all + loge("Exception trying to add a route: " + e); return false; } - if (!addHostRoute(nt, gatewayAddress, cycleCount+1)) return false; - } - - RouteInfo route = RouteInfo.makeHostRoute(hostAddress, gatewayAddress); - - try { - mNetd.addRoute(interfaceName, route); - return true; - } catch (Exception ex) { - return false; + } else { + // if we remove this one and there are no more like it, then refcount==0 and + // we can remove it from the table + mAddedRoutes.remove(r); + if (mAddedRoutes.contains(r) == false) { + if (DBG) log("Removing " + r + " for interface " + ifaceName); + try { + mNetd.removeRoute(ifaceName, r); + } catch (Exception e) { + // never crash - catch them all + loge("Exception trying to remove a route: " + e); + return false; + } + } else { + if (DBG) log("not removing " + r + " as it's still in use"); + } } - } - - // TODO support the removal of single host routes. Keep a ref count of them so we - // aren't over-zealous - private boolean removeHostRoute(NetworkStateTracker nt, InetAddress hostAddress) { - return false; + return true; } /** @@ -1427,10 +1437,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ handleDnsConfigurationChange(netType); + LinkProperties curLp = mCurrentLinkProperties[netType]; + LinkProperties newLp = null; + if (mNetTrackers[netType].getNetworkInfo().isConnected()) { - LinkProperties newLp = mNetTrackers[netType].getLinkProperties(); - LinkProperties curLp = mCurrentLinkProperties[netType]; - mCurrentLinkProperties[netType] = newLp; + newLp = mNetTrackers[netType].getLinkProperties(); if (VDBG) { log("handleConnectivityChange: changed linkProperty[" + netType + "]:" + " doReset=" + doReset + " resetMask=" + resetMask + @@ -1438,48 +1449,50 @@ public class ConnectivityService extends IConnectivityManager.Stub { "\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 (curLp != null) { + if (curLp.isIdenticalInterfaceName(newLp)) { + CompareResult 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 (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); } - } - 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); - } + resetMask = NetworkUtils.RESET_ALL_ADDRESSES; + log("handleConnectivityChange: interface not not equivalent reset both" + + " 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()) { handleApplyDefaultProxy(netType); - addDefaultRoute(mNetTrackers[netType]); - } else { - addPrivateDnsRoutes(mNetTrackers[netType]); } } else { - if (mNetConfigs[netType].isDefault()) { - removeDefaultRoute(mNetTrackers[netType]); - } else { - removePrivateDnsRoutes(mNetTrackers[netType]); + if (VDBG) { + log("handleConnectivityChange: changed linkProperty[" + netType + "]:" + + " doReset=" + doReset + " resetMask=" + resetMask + + "\n curLp=" + curLp + + "\n newLp= null"); } } + mCurrentLinkProperties[netType] = newLp; + updateRoutes(newLp, curLp, mNetConfigs[netType].isDefault()); if (doReset || resetMask != 0) { LinkProperties linkProperties = mNetTrackers[netType].getLinkProperties(); @@ -1503,108 +1516,64 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - private void addPrivateDnsRoutes(NetworkStateTracker nt) { - boolean privateDnsRouteSet = nt.isPrivateDnsRouteSet(); - LinkProperties p = nt.getLinkProperties(); - if (p == null) return; - String interfaceName = p.getInterfaceName(); - - if (DBG) { - log("addPrivateDnsRoutes for " + nt + - "(" + interfaceName + ") - mPrivateDnsRouteSet = " + privateDnsRouteSet); - } - if (interfaceName != null && !privateDnsRouteSet) { - Collection dnsList = p.getDnses(); - for (InetAddress dns : dnsList) { - addHostRoute(nt, dns, 0); + /** + * Add and remove routes using the old properties (null if not previously connected), + * new properties (null if becoming disconnected). May even be double null, which + * is a noop. + * Uses isLinkDefault to determine if default routes should be set or conversely if + * host routes should be set to the dns servers + */ + private void updateRoutes(LinkProperties newLp, LinkProperties curLp, boolean isLinkDefault) { + Collection routesToAdd = null; + CompareResult dnsDiff = null; + + if (curLp != null) { + // check for the delta between the current set and the new + CompareResult routeDiff = curLp.compareRoutes(newLp); + dnsDiff = curLp.compareDnses(newLp); + + for (RouteInfo r : routeDiff.removed) { + if (isLinkDefault || ! r.isDefaultRoute()) { + removeRoute(curLp, r); + } } - nt.privateDnsRouteSet(true); + routesToAdd = routeDiff.added; } - } - private void removePrivateDnsRoutes(NetworkStateTracker nt) { - LinkProperties p = nt.getLinkProperties(); - if (p == null) return; - String interfaceName = p.getInterfaceName(); - boolean privateDnsRouteSet = nt.isPrivateDnsRouteSet(); - if (interfaceName != null && privateDnsRouteSet) { - if (DBG) { - log("removePrivateDnsRoutes for " + nt.getNetworkInfo().getTypeName() + - " (" + interfaceName + ")"); + if (newLp != null) { + // if we didn't get a diff from cur -> new, then just use the new + if (routesToAdd == null) { + routesToAdd = newLp.getRoutes(); } - Collection dnsList = p.getDnses(); - for (InetAddress dns : dnsList) { - if (DBG) log(" removing " + dns); - RouteInfo route = RouteInfo.makeHostRoute(dns); - try { - mNetd.removeRoute(interfaceName, route); - } catch (Exception ex) { - loge("error (" + ex + ") removing dns route " + route); + for (RouteInfo r : routesToAdd) { + if (isLinkDefault || ! r.isDefaultRoute()) { + addRoute(newLp, r); } } - nt.privateDnsRouteSet(false); } - } - - - private void addDefaultRoute(NetworkStateTracker nt) { - LinkProperties p = nt.getLinkProperties(); - if (p == null) return; - String interfaceName = p.getInterfaceName(); - if (TextUtils.isEmpty(interfaceName)) return; - for (RouteInfo route : p.getRoutes()) { - //TODO - handle non-default routes - if (route.isDefaultRoute()) { - if (DBG) log("adding default route " + route); - InetAddress gateway = route.getGateway(); - if (addHostRoute(nt, gateway, 0)) { - try { - mNetd.addRoute(interfaceName, route); - } catch (Exception e) { - loge("error adding default route " + route); - continue; - } - if (DBG) { - NetworkInfo networkInfo = nt.getNetworkInfo(); - log("addDefaultRoute for " + networkInfo.getTypeName() + - " (" + interfaceName + "), GatewayAddr=" + - gateway.getHostAddress()); - } - } else { - loge("error adding host route for default route " + route); + if (!isLinkDefault) { + // handle DNS routes + Collection dnsToAdd = null; + if (dnsDiff != null) { + dnsToAdd = dnsDiff.added; + for (InetAddress dnsAddress : dnsDiff.removed) { + removeRoute(curLp, RouteInfo.makeHostRoute(dnsAddress)); } } - } - } - - - public void removeDefaultRoute(NetworkStateTracker nt) { - LinkProperties p = nt.getLinkProperties(); - if (p == null) return; - String interfaceName = p.getInterfaceName(); - - if (interfaceName == null) return; - - for (RouteInfo route : p.getRoutes()) { - //TODO - handle non-default routes - if (route.isDefaultRoute()) { - try { - mNetd.removeRoute(interfaceName, route); - } catch (Exception ex) { - loge("error (" + ex + ") removing default route " + route); - continue; + if (newLp != null) { + if (dnsToAdd == null) { + dnsToAdd = newLp.getDnses(); } - if (DBG) { - NetworkInfo networkInfo = nt.getNetworkInfo(); - log("removeDefaultRoute for " + networkInfo.getTypeName() + " (" + - interfaceName + ")"); + for(InetAddress dnsAddress : dnsToAdd) { + addRoute(newLp, RouteInfo.makeHostRoute(dnsAddress)); } } } } + /** * Reads the network specific TCP buffer sizes from SystemProperties * net.tcp.buffersize.[default|wifi|umts|edge|gprs] and set them for system diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java index 1bba8e3a99c5..8978f1d1417a 100644 --- a/telephony/java/com/android/internal/telephony/DataConnection.java +++ b/telephony/java/com/android/internal/telephony/DataConnection.java @@ -26,7 +26,6 @@ import com.android.internal.util.StateMachine; import android.app.PendingIntent; import android.net.LinkCapabilities; import android.net.LinkProperties; -import android.net.LinkProperties.CompareAddressesResult; import android.net.ProxyProperties; import android.os.AsyncResult; import android.os.Message; diff --git a/telephony/java/com/android/internal/telephony/DataConnectionAc.java b/telephony/java/com/android/internal/telephony/DataConnectionAc.java index 9e185e50ec63..a9f2cd1b090d 100644 --- a/telephony/java/com/android/internal/telephony/DataConnectionAc.java +++ b/telephony/java/com/android/internal/telephony/DataConnectionAc.java @@ -23,7 +23,6 @@ import com.android.internal.util.Protocol; import android.app.PendingIntent; import android.net.LinkCapabilities; import android.net.LinkProperties; -import android.net.LinkProperties.CompareAddressesResult; import android.net.ProxyProperties; import android.os.Message; diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java index bf964b7befe7..ccdb0bf69a5b 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java @@ -27,7 +27,7 @@ import android.database.ContentObserver; import android.database.Cursor; import android.net.ConnectivityManager; import android.net.LinkAddress; -import android.net.LinkProperties.CompareAddressesResult; +import android.net.LinkProperties.CompareResult; import android.net.NetworkUtils; import android.net.ProxyProperties; import android.net.TrafficStats; @@ -1152,7 +1152,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { ! 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 = + CompareResult car = result.oldLp.compareAddresses(result.newLp); boolean needToClean = false; for (LinkAddress added : car.added) { -- 2.11.0