Update LinkProperties treatment of gateways

A link can have multiple gateways (think ipv4/ipv6 for a trivial example).
.

bug:3438810
Change-Id: I28c90a6947cd50b82e5ca9a0113148f98b3f4dd8
diff --git a/core/java/android/net/DhcpInfoInternal.java b/core/java/android/net/DhcpInfoInternal.java
index 6e981df..7396669 100644
--- a/core/java/android/net/DhcpInfoInternal.java
+++ b/core/java/android/net/DhcpInfoInternal.java
@@ -44,12 +44,14 @@
     }
 
     private int convertToInt(String addr) {
-        try {
-            InetAddress inetAddress = NetworkUtils.numericToInetAddress(addr);
-            if (inetAddress instanceof Inet4Address) {
-                return NetworkUtils.inetAddressToInt(inetAddress);
-            }
-        } catch (IllegalArgumentException e) {}
+        if (addr != null) {
+            try {
+                InetAddress inetAddress = NetworkUtils.numericToInetAddress(addr);
+                if (inetAddress instanceof Inet4Address) {
+                    return NetworkUtils.inetAddressToInt(inetAddress);
+                }
+            } catch (IllegalArgumentException e) {}
+        }
         return 0;
     }
 
@@ -80,19 +82,17 @@
         LinkProperties p = new LinkProperties();
         p.addLinkAddress(makeLinkAddress());
         if (TextUtils.isEmpty(gateway) == false) {
-            p.setGateway(NetworkUtils.numericToInetAddress(gateway));
-        } else {
-            Log.e(TAG, "makeLinkProperties with empty gateway!");
+            p.addGateway(NetworkUtils.numericToInetAddress(gateway));
         }
         if (TextUtils.isEmpty(dns1) == false) {
             p.addDns(NetworkUtils.numericToInetAddress(dns1));
         } else {
-            Log.e(TAG, "makeLinkProperties with empty dns1!");
+            Log.d(TAG, "makeLinkProperties with empty dns1!");
         }
         if (TextUtils.isEmpty(dns2) == false) {
             p.addDns(NetworkUtils.numericToInetAddress(dns2));
         } else {
-            Log.e(TAG, "makeLinkProperties with empty dns2!");
+            Log.d(TAG, "makeLinkProperties with empty dns2!");
         }
         return p;
     }
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index f1545ea..b6e9751 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -31,7 +31,24 @@
 
 /**
  * Describes the properties of a network link.
- * TODO - consider adding optional fields like Apn and ApnType
+ *
+ * A link represents a connection to a network.
+ * It may have multiple addresses and multiple gateways,
+ * multiple dns servers but only one http proxy.
+ *
+ * Because it's a single network, the dns's
+ * are interchangeable and don't need associating with
+ * particular addresses.  The gateways similarly don't
+ * need associating with particular addresses.
+ *
+ * A dual stack interface works fine in this model:
+ * each address has it's own prefix length to describe
+ * the local network.  The dns servers all return
+ * both v4 addresses and v6 addresses regardless of the
+ * address family of the server itself (rfc4213) and we
+ * don't care which is used.  The gateways will be
+ * selected based on the destination address and the
+ * source address has no relavence.
  * @hide
  */
 public class LinkProperties implements Parcelable {
@@ -39,7 +56,7 @@
     String mIfaceName;
     private Collection<LinkAddress> mLinkAddresses;
     private Collection<InetAddress> mDnses;
-    private InetAddress mGateway;
+    private Collection<InetAddress> mGateways;
     private ProxyProperties mHttpProxy;
 
     public LinkProperties() {
@@ -52,7 +69,7 @@
             mIfaceName = source.getInterfaceName();
             mLinkAddresses = source.getLinkAddresses();
             mDnses = source.getDnses();
-            mGateway = source.getGateway();
+            mGateways = source.getGateways();
             mHttpProxy = new ProxyProperties(source.getHttpProxy());
         }
     }
@@ -89,11 +106,11 @@
         return Collections.unmodifiableCollection(mDnses);
     }
 
-    public void setGateway(InetAddress gateway) {
-        mGateway = gateway;
+    public void addGateway(InetAddress gateway) {
+        mGateways.add(gateway);
     }
-    public InetAddress getGateway() {
-        return mGateway;
+    public Collection<InetAddress> getGateways() {
+        return Collections.unmodifiableCollection(mGateways);
     }
 
     public void setHttpProxy(ProxyProperties proxy) {
@@ -107,7 +124,7 @@
         mIfaceName = null;
         mLinkAddresses = new ArrayList<LinkAddress>();
         mDnses = new ArrayList<InetAddress>();
-        mGateway = null;
+        mGateways = new ArrayList<InetAddress>();
         mHttpProxy = null;
     }
 
@@ -131,10 +148,12 @@
         for (InetAddress addr : mDnses) dns += addr.getHostAddress() + ",";
         dns += "] ";
 
+        String gateways = "Gateways: [";
+        for (InetAddress gw : mGateways) gateways += gw.getHostAddress() + ",";
+        gateways += "] ";
         String proxy = (mHttpProxy == null ? "" : "HttpProxy: " + mHttpProxy.toString() + " ");
-        String gateway = (mGateway == null ? "" : "Gateway: " + mGateway.getHostAddress() + " ");
 
-        return ifaceName + linkAddresses + gateway + dns + proxy;
+        return ifaceName + linkAddresses + gateways + dns + proxy;
     }
 
     /**
@@ -152,12 +171,12 @@
         for(InetAddress d : mDnses) {
             dest.writeByteArray(d.getAddress());
         }
-        if (mGateway != null) {
-            dest.writeByte((byte)1);
-            dest.writeByteArray(mGateway.getAddress());
-        } else {
-            dest.writeByte((byte)0);
+
+        dest.writeInt(mGateways.size());
+        for(InetAddress gw : mGateways) {
+            dest.writeByteArray(gw.getAddress());
         }
+
         if (mHttpProxy != null) {
             dest.writeByte((byte)1);
             dest.writeParcelable(mHttpProxy, flags);
@@ -192,10 +211,11 @@
                         netProp.addDns(InetAddress.getByAddress(in.createByteArray()));
                     } catch (UnknownHostException e) { }
                 }
-                if (in.readByte() == 1) {
+                addressCount = in.readInt();
+                for (int i=0; i<addressCount; i++) {
                     try {
-                        netProp.setGateway(InetAddress.getByAddress(in.createByteArray()));
-                    } catch (UnknownHostException e) {}
+                        netProp.addGateway(InetAddress.getByAddress(in.createByteArray()));
+                    } catch (UnknownHostException e) { }
                 }
                 if (in.readByte() == 1) {
                     netProp.setHttpProxy((ProxyProperties)in.readParcelable(null));
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
index 21f1bfc..1ecf103 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
@@ -303,7 +303,7 @@
                     if (!InetAddress.isNumeric(gwAddr)) {
                         throw new SAXException();
                     }
-                    mLinkProperties.setGateway(InetAddress.getByName(gwAddr));
+                    mLinkProperties.addGateway(InetAddress.getByName(gwAddr));
                 } catch (UnknownHostException e) {
                     throw new SAXException();
                 }
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 26397bb..8e39a63 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -1414,13 +1414,13 @@
         LinkProperties p = nt.getLinkProperties();
         if (p == null) return;
         String interfaceName = p.getInterfaceName();
-        InetAddress defaultGatewayAddr = p.getGateway();
+        if (TextUtils.isEmpty(interfaceName)) return;
+        for (InetAddress gateway : p.getGateways()) {
 
-        if ((interfaceName != null) && (defaultGatewayAddr != null )) {
-            if (!NetworkUtils.addDefaultRoute(interfaceName, defaultGatewayAddr) && DBG) {
+            if (!NetworkUtils.addDefaultRoute(interfaceName, gateway) && DBG) {
                 NetworkInfo networkInfo = nt.getNetworkInfo();
                 log("addDefaultRoute for " + networkInfo.getTypeName() +
-                        " (" + interfaceName + "), GatewayAddr=" + defaultGatewayAddr);
+                        " (" + interfaceName + "), GatewayAddr=" + gateway.getHostAddress());
             }
         }
     }
diff --git a/wifi/java/android/net/wifi/WifiConfigStore.java b/wifi/java/android/net/wifi/WifiConfigStore.java
index 55d1844..d411715 100644
--- a/wifi/java/android/net/wifi/WifiConfigStore.java
+++ b/wifi/java/android/net/wifi/WifiConfigStore.java
@@ -445,7 +445,10 @@
             if (iter.hasNext()) {
                 LinkAddress linkAddress = iter.next();
                 dhcpInfoInternal.ipAddress = linkAddress.getAddress().getHostAddress();
-                dhcpInfoInternal.gateway = linkProperties.getGateway().getHostAddress();
+                Iterator<InetAddress>gateways = linkProperties.getGateways().iterator();
+                if (gateways.hasNext()) {
+                    dhcpInfoInternal.gateway = gateways.next().getHostAddress();
+                }
                 dhcpInfoInternal.prefixLength = linkAddress.getNetworkPrefixLength();
                 Iterator<InetAddress> dnsIterator = linkProperties.getDnses().iterator();
                 dhcpInfoInternal.dns1 = dnsIterator.next().getHostAddress();
@@ -582,8 +585,7 @@
                                     out.writeUTF(linkAddr.getAddress().getHostAddress());
                                     out.writeInt(linkAddr.getNetworkPrefixLength());
                                 }
-                                InetAddress gateway = linkProperties.getGateway();
-                                if (gateway != null) {
+                                for (InetAddress gateway : linkProperties.getGateways()) {
                                     out.writeUTF(GATEWAY_KEY);
                                     out.writeUTF(gateway.getHostAddress());
                                 }
@@ -688,7 +690,7 @@
                                     in.readUTF()), in.readInt());
                             linkProperties.addLinkAddress(linkAddr);
                         } else if (key.equals(GATEWAY_KEY)) {
-                            linkProperties.setGateway(InetAddress.getByName(in.readUTF()));
+                            linkProperties.addGateway(InetAddress.getByName(in.readUTF()));
                         } else if (key.equals(DNS_KEY)) {
                             linkProperties.addDns(InetAddress.getByName(in.readUTF()));
                         } else if (key.equals(PROXY_SETTINGS_KEY)) {
@@ -999,15 +1001,17 @@
                         .getLinkAddresses();
                 Collection<InetAddress> currentDnses = currentConfig.linkProperties.getDnses();
                 Collection<InetAddress> newDnses = newConfig.linkProperties.getDnses();
-                InetAddress currentGateway = currentConfig.linkProperties.getGateway();
-                InetAddress newGateway = newConfig.linkProperties.getGateway();
+                Collection<InetAddress> currentGateways =
+                        currentConfig.linkProperties.getGateways();
+                Collection<InetAddress> newGateways = newConfig.linkProperties.getGateways();
 
-                boolean linkAddressesDiffer = !currentLinkAddresses.containsAll(newLinkAddresses) ||
-                        (currentLinkAddresses.size() != newLinkAddresses.size());
-                boolean dnsesDiffer = !currentDnses.containsAll(newDnses) ||
-                        (currentDnses.size() != newDnses.size());
-                boolean gatewaysDiffer = (currentGateway == null) ||
-                        !currentGateway.equals(newGateway);
+                boolean linkAddressesDiffer =
+                        (currentLinkAddresses.size() != newLinkAddresses.size()) ||
+                        !currentLinkAddresses.containsAll(newLinkAddresses);
+                boolean dnsesDiffer = (currentDnses.size() != newDnses.size()) ||
+                        !currentDnses.containsAll(newDnses);
+                boolean gatewaysDiffer = (currentGateways.size() != newGateways.size()) ||
+                        !currentGateways.containsAll(newGateways);
 
                 if ((currentConfig.ipAssignment != newConfig.ipAssignment) ||
                         linkAddressesDiffer ||
@@ -1087,7 +1091,9 @@
         for (LinkAddress linkAddr : config.linkProperties.getLinkAddresses()) {
             linkProperties.addLinkAddress(linkAddr);
         }
-        linkProperties.setGateway(config.linkProperties.getGateway());
+        for (InetAddress gateway : config.linkProperties.getGateways()) {
+            linkProperties.addGateway(gateway);
+        }
         for (InetAddress dns : config.linkProperties.getDnses()) {
             linkProperties.addDns(dns);
         }