Merge "Let DnsManager fill in LinkProperties for private DNSes"
am: 59e139a767

Change-Id: Icd79a15c573a3bc2f371d724081e296eca2b236f
diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java
index 7aaac06..d51a196 100644
--- a/services/core/java/com/android/server/connectivity/DnsManager.java
+++ b/services/core/java/com/android/server/connectivity/DnsManager.java
@@ -49,6 +49,7 @@
 import java.net.UnknownHostException;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -211,6 +212,8 @@
         }
 
         // Validation statuses of <hostname, ipAddress> pairs for a single netId
+        // Caution : not thread-safe. As mentioned in the top file comment, all
+        // methods of this class must only be called on ConnectivityService's thread.
         private Map<Pair<String, InetAddress>, ValidationStatus> mValidationMap;
 
         private PrivateDnsValidationStatuses() {
@@ -262,6 +265,16 @@
                 mValidationMap.put(p, ValidationStatus.FAILED);
             }
         }
+
+        private LinkProperties fillInValidatedPrivateDns(LinkProperties lp) {
+            lp.setValidatedPrivateDnsServers(Collections.EMPTY_LIST);
+            mValidationMap.forEach((key, value) -> {
+                    if (value == ValidationStatus.SUCCEEDED) {
+                        lp.addValidatedPrivateDnsServer(key.second);
+                    }
+                });
+            return lp;
+        }
     }
 
     private final Context mContext;
@@ -315,23 +328,19 @@
                 PRIVATE_DNS_OFF);
 
         final boolean useTls = privateDnsCfg.useTls;
+        final PrivateDnsValidationStatuses statuses =
+                useTls ? mPrivateDnsValidationMap.get(netId) : null;
+        final boolean validated = (null != statuses) && statuses.hasValidatedServer();
         final boolean strictMode = privateDnsCfg.inStrictMode();
-        final String tlsHostname = strictMode ? privateDnsCfg.hostname : "";
+        final String tlsHostname = strictMode ? privateDnsCfg.hostname : null;
+        final boolean usingPrivateDns = strictMode || validated;
 
-        if (strictMode) {
-            lp.setUsePrivateDns(true);
-            lp.setPrivateDnsServerName(tlsHostname);
-        } else if (useTls) {
-            // We are in opportunistic mode. Private DNS should be used if there
-            // is a known DNS-over-TLS validated server.
-            boolean validated = mPrivateDnsValidationMap.containsKey(netId) &&
-                    mPrivateDnsValidationMap.get(netId).hasValidatedServer();
-            lp.setUsePrivateDns(validated);
-            lp.setPrivateDnsServerName(null);
+        lp.setUsePrivateDns(usingPrivateDns);
+        lp.setPrivateDnsServerName(tlsHostname);
+        if (usingPrivateDns && null != statuses) {
+            statuses.fillInValidatedPrivateDns(lp);
         } else {
-            // Private DNS is disabled.
-            lp.setUsePrivateDns(false);
-            lp.setPrivateDnsServerName(null);
+            lp.setValidatedPrivateDnsServers(Collections.EMPTY_LIST);
         }
     }
 
diff --git a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
index bcd8bf3..1ec4eec 100644
--- a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
+++ b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
@@ -28,8 +28,11 @@
 
 import android.content.ContentResolver;
 import android.content.Context;
+import android.net.IpPrefix;
+import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.Network;
+import android.net.RouteInfo;
 import android.os.INetworkManagementService;
 import android.provider.Settings;
 import android.support.test.filters.SmallTest;
@@ -40,6 +43,7 @@
 import com.android.server.connectivity.MockableSystemProperties;
 
 import java.net.InetAddress;
+import java.util.Arrays;
 
 import org.junit.runner.RunWith;
 import org.junit.Before;
@@ -56,6 +60,7 @@
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class DnsManagerTest {
+    static final String TEST_IFACENAME = "test_wlan0";
     static final int TEST_NETID = 100;
     static final int TEST_NETID_ALTERNATE = 101;
     static final int TEST_NETID_UNTRACKED = 102;
@@ -92,6 +97,7 @@
         mDnsManager.updatePrivateDns(new Network(TEST_NETID_ALTERNATE),
                 mDnsManager.getPrivateDnsConfig());
         LinkProperties lp = new LinkProperties();
+        lp.setInterfaceName(TEST_IFACENAME);
         lp.addDnsServer(InetAddress.getByName("3.3.3.3"));
         lp.addDnsServer(InetAddress.getByName("4.4.4.4"));
 
@@ -109,21 +115,51 @@
         mDnsManager.updatePrivateDnsStatus(TEST_NETID_ALTERNATE, fixedLp);
         assertTrue(fixedLp.isPrivateDnsActive());
         assertNull(fixedLp.getPrivateDnsServerName());
+        assertEquals(Arrays.asList(InetAddress.getByName("4.4.4.4")),
+                fixedLp.getValidatedPrivateDnsServers());
 
-        // Switch to strict mode
+        // Set up addresses for strict mode and switch to it.
+        lp.addLinkAddress(new LinkAddress("192.0.2.4/24"));
+        lp.addRoute(new RouteInfo((IpPrefix) null, InetAddress.getByName("192.0.2.4"),
+                TEST_IFACENAME));
+        lp.addLinkAddress(new LinkAddress("2001:db8:1::1/64"));
+        lp.addRoute(new RouteInfo((IpPrefix) null, InetAddress.getByName("2001:db8:1::1"),
+                TEST_IFACENAME));
+
         Settings.Global.putString(mContentResolver,
-                Settings.Global.PRIVATE_DNS_MODE,
-                PRIVATE_DNS_MODE_PROVIDER_HOSTNAME);
+                Settings.Global.PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_PROVIDER_HOSTNAME);
         Settings.Global.putString(mContentResolver,
                 Settings.Global.PRIVATE_DNS_SPECIFIER, "strictmode.com");
         mDnsManager.updatePrivateDns(new Network(TEST_NETID),
-                mDnsManager.getPrivateDnsConfig());
+                new DnsManager.PrivateDnsConfig("strictmode.com", new InetAddress[] {
+                    InetAddress.parseNumericAddress("6.6.6.6"),
+                    InetAddress.parseNumericAddress("2001:db8:66:66::1")
+                    }));
         mDnsManager.setDnsConfigurationForNetwork(TEST_NETID, lp, IS_DEFAULT);
         fixedLp = new LinkProperties(lp);
         mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp);
         assertTrue(fixedLp.isPrivateDnsActive());
         assertEquals("strictmode.com", fixedLp.getPrivateDnsServerName());
+        // No validation events yet.
+        assertEquals(Arrays.asList(new InetAddress[0]), fixedLp.getValidatedPrivateDnsServers());
+        // Validate one.
+        mDnsManager.updatePrivateDnsValidation(
+                new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
+                InetAddress.parseNumericAddress("6.6.6.6"), "strictmode.com", true));
         fixedLp = new LinkProperties(lp);
+        mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp);
+        assertEquals(Arrays.asList(InetAddress.parseNumericAddress("6.6.6.6")),
+                fixedLp.getValidatedPrivateDnsServers());
+        // Validate the 2nd one.
+        mDnsManager.updatePrivateDnsValidation(
+                new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
+                InetAddress.parseNumericAddress("2001:db8:66:66::1"), "strictmode.com", true));
+        fixedLp = new LinkProperties(lp);
+        mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp);
+        assertEquals(Arrays.asList(
+                        InetAddress.parseNumericAddress("2001:db8:66:66::1"),
+                        InetAddress.parseNumericAddress("6.6.6.6")),
+                fixedLp.getValidatedPrivateDnsServers());
     }
 
     @Test