Snap for 6348162 from 0403636284fbd2d4c13098c2767e1a27c281d2b5 to sdk-release

Change-Id: I6f8dc7272709e7311a7e3a0943c9b2ef0e6b8b37
diff --git a/Android.bp b/Android.bp
index 43a61a5..ccd7d58 100644
--- a/Android.bp
+++ b/Android.bp
@@ -23,6 +23,11 @@
         "netd_event_listener_interface",
     ],
     backend: {
+        java: {
+            apex_available: [
+                "com.android.bluetooth.updatable",
+            ],
+        },
         ndk: {
             gen_log: true,
         },
@@ -34,6 +39,37 @@
     ],
 }
 
+cc_defaults {
+    name: "resolv_test_defaults",
+    // Note that, static link liblog and libbase is a hard requirement for resolv related tests
+    // because libbase is not compatible between Q and R for general platform build due
+    // to its log revelant functions changing. And most of resolv related tests must be able to run
+    // in Q.
+    static_libs: [
+        "libbase",
+        "liblog",
+    ],
+}
+
+cc_defaults {
+    // This is necessary to have the coverage tests run on cf_x86_phone.
+    // Because the test_suite target is 64 bit and the test infra is running the 64 bit test
+    // suite on cf_x86_phone (32-bit) for coverage.
+    // See b/147785146 for details.
+    // TODO: Remove this target after coverage test switched to 64-bit device.
+    name: "resolv_test_mts_coverage_defaults",
+    test_config_template: ":resolv_test_config_template",
+    compile_multilib: "both",
+    multilib: {
+        lib32: {
+            suffix: "32",
+        },
+        lib64: {
+            suffix: "64",
+        },
+    },
+}
+
 cc_library {
     name: "libnetd_resolv",
     version_script: "libnetd_resolv.map.txt",
@@ -175,14 +211,21 @@
     ],
 }
 
+filegroup {
+    name: "resolv_test_config_template",
+    srcs: [
+        "resolv_test_config_template.xml",
+    ],
+}
+
 // TODO: Move this test to tests/
 cc_test {
     name: "resolv_unit_test",
     test_suites: ["device-tests", "mts"],
     require_root: true,
-    test_config: "resolv_unit_test_config.xml",
-    //TODO:  drop root privileges and make it be an real unit test.
-    defaults: ["netd_defaults"],
+    // TODO: Drop root privileges and make it be an real unit test.
+    // TODO: Remove resolv_test_mts_coverage_defaults after mts coverage switched to 64-bit device.
+    defaults: ["netd_defaults", "resolv_test_defaults", "resolv_test_mts_coverage_defaults"],
     srcs: [
         "resolv_cache_unit_test.cpp",
         "resolv_callback_unit_test.cpp",
@@ -192,17 +235,15 @@
         "DnsQueryLogTest.cpp",
     ],
     shared_libs: [
-        "libbase",
         "libcrypto",
-        "libcutils",
-        "libssl",
         "libbinder_ndk",
+        "libssl",
     ],
     static_libs: [
         "dnsresolver_aidl_interface-unstable-ndk_platform",
         "netd_event_listener_interface-ndk_platform",
+        "libcutils",
         "libgmock",
-        "liblog",
         "libnetd_resolv",
         "libnetd_test_dnsresponder",
         "libnetd_test_resolv_utils",
@@ -216,13 +257,4 @@
         "server_configurable_flags",
         "stats_proto",
     ],
-    compile_multilib: "both",
-    multilib: {
-        lib32: {
-            suffix: "32",
-        },
-        lib64: {
-            suffix: "64",
-        },
-    },
 }
diff --git a/PrivateDnsConfiguration.cpp b/PrivateDnsConfiguration.cpp
index bfac68a..2263153 100644
--- a/PrivateDnsConfiguration.cpp
+++ b/PrivateDnsConfiguration.cpp
@@ -102,6 +102,10 @@
         mPrivateDnsTransports.erase(netId);
         resolv_stats_set_servers_for_dot(netId, {});
         mPrivateDnsValidateThreads.erase(netId);
+        // TODO: As mPrivateDnsValidateThreads is reset, validation threads which haven't yet
+        // finished are considered outdated. Consider signaling the outdated validation threads to
+        // stop them from updating the state of PrivateDnsConfiguration (possibly disallow them to
+        // report onPrivateDnsValidationEvent).
         return 0;
     }
 
diff --git a/ResolverController.cpp b/ResolverController.cpp
index c59676a..22878f3 100644
--- a/ResolverController.cpp
+++ b/ResolverController.cpp
@@ -281,7 +281,7 @@
 int ResolverController::getPrefix64(unsigned netId, netdutils::IPPrefix* prefix) {
     netdutils::IPPrefix p = mDns64Configuration.getPrefix64(netId);
     if (p.family() != AF_INET6 || p.length() == 0) {
-        LOG(ERROR) << "No valid NAT64 prefix (" << netId << ", " << p.toString().c_str() << ")";
+        LOG(INFO) << "No valid NAT64 prefix (" << netId << ", " << p.toString().c_str() << ")";
 
         return -ENOENT;
     }
diff --git a/aidl_api/dnsresolver_aidl_interface/1/.hash b/aidl_api/dnsresolver_aidl_interface/1/.hash
new file mode 100644
index 0000000..e529a3a
--- /dev/null
+++ b/aidl_api/dnsresolver_aidl_interface/1/.hash
@@ -0,0 +1 @@
+6476b2d86877b861449c4ba9a0898a0916223b3f
diff --git a/aidl_api/dnsresolver_aidl_interface/2/.hash b/aidl_api/dnsresolver_aidl_interface/2/.hash
new file mode 100644
index 0000000..03e0b39
--- /dev/null
+++ b/aidl_api/dnsresolver_aidl_interface/2/.hash
@@ -0,0 +1 @@
+3d9f8db62d1a79a247a9da91abce4bab41b90a99
diff --git a/aidl_api/dnsresolver_aidl_interface/3/.hash b/aidl_api/dnsresolver_aidl_interface/3/.hash
index c6a5015..b2560b2 100644
--- a/aidl_api/dnsresolver_aidl_interface/3/.hash
+++ b/aidl_api/dnsresolver_aidl_interface/3/.hash
@@ -1 +1 @@
-e3cbaaa75f8ec9ff0ee35c2fa9b928121aeb9956  -
+1271d6ab46cd0b0efb08890607738c1e44484d67
diff --git a/aidl_api/dnsresolver_aidl_interface/current/android/net/IDnsResolver.aidl b/aidl_api/dnsresolver_aidl_interface/current/android/net/IDnsResolver.aidl
new file mode 100644
index 0000000..0ebc44f
--- /dev/null
+++ b/aidl_api/dnsresolver_aidl_interface/current/android/net/IDnsResolver.aidl
@@ -0,0 +1,55 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+interface IDnsResolver {
+  boolean isAlive();
+  void registerEventListener(android.net.metrics.INetdEventListener listener);
+  void setResolverConfiguration(in android.net.ResolverParamsParcel resolverParams);
+  void getResolverInfo(int netId, out @utf8InCpp String[] servers, out @utf8InCpp String[] domains, out @utf8InCpp String[] tlsServers, out int[] params, out int[] stats, out int[] wait_for_pending_req_timeout_count);
+  void startPrefix64Discovery(int netId);
+  void stopPrefix64Discovery(int netId);
+  @utf8InCpp String getPrefix64(int netId);
+  void createNetworkCache(int netId);
+  void destroyNetworkCache(int netId);
+  void setLogSeverity(int logSeverity);
+  void flushNetworkCache(int netId);
+  const int RESOLVER_PARAMS_SAMPLE_VALIDITY = 0;
+  const int RESOLVER_PARAMS_SUCCESS_THRESHOLD = 1;
+  const int RESOLVER_PARAMS_MIN_SAMPLES = 2;
+  const int RESOLVER_PARAMS_MAX_SAMPLES = 3;
+  const int RESOLVER_PARAMS_BASE_TIMEOUT_MSEC = 4;
+  const int RESOLVER_PARAMS_RETRY_COUNT = 5;
+  const int RESOLVER_PARAMS_COUNT = 6;
+  const int RESOLVER_STATS_SUCCESSES = 0;
+  const int RESOLVER_STATS_ERRORS = 1;
+  const int RESOLVER_STATS_TIMEOUTS = 2;
+  const int RESOLVER_STATS_INTERNAL_ERRORS = 3;
+  const int RESOLVER_STATS_RTT_AVG = 4;
+  const int RESOLVER_STATS_LAST_SAMPLE_TIME = 5;
+  const int RESOLVER_STATS_USABLE = 6;
+  const int RESOLVER_STATS_COUNT = 7;
+  const int DNS_RESOLVER_LOG_VERBOSE = 0;
+  const int DNS_RESOLVER_LOG_DEBUG = 1;
+  const int DNS_RESOLVER_LOG_INFO = 2;
+  const int DNS_RESOLVER_LOG_WARNING = 3;
+  const int DNS_RESOLVER_LOG_ERROR = 4;
+  const int TC_MODE_DEFAULT = 0;
+  const int TC_MODE_UDP_TCP = 1;
+  const int TC_MODE_MAX = 2;
+}
diff --git a/aidl_api/dnsresolver_aidl_interface/current/android/net/ResolverExperimentalOptionsParcel.aidl b/aidl_api/dnsresolver_aidl_interface/current/android/net/ResolverExperimentalOptionsParcel.aidl
new file mode 100644
index 0000000..07a1143
--- /dev/null
+++ b/aidl_api/dnsresolver_aidl_interface/current/android/net/ResolverExperimentalOptionsParcel.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+parcelable ResolverExperimentalOptionsParcel {
+  android.net.ResolverHostsParcel[] hosts = {};
+  int tcMode = 0;
+}
diff --git a/aidl_api/dnsresolver_aidl_interface/current/android/net/ResolverHostsParcel.aidl b/aidl_api/dnsresolver_aidl_interface/current/android/net/ResolverHostsParcel.aidl
new file mode 100644
index 0000000..3ab0533
--- /dev/null
+++ b/aidl_api/dnsresolver_aidl_interface/current/android/net/ResolverHostsParcel.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+parcelable ResolverHostsParcel {
+  @utf8InCpp String ipAddr;
+  @utf8InCpp String hostName = "";
+}
diff --git a/aidl_api/dnsresolver_aidl_interface/current/android/net/ResolverParamsParcel.aidl b/aidl_api/dnsresolver_aidl_interface/current/android/net/ResolverParamsParcel.aidl
new file mode 100644
index 0000000..8d807be
--- /dev/null
+++ b/aidl_api/dnsresolver_aidl_interface/current/android/net/ResolverParamsParcel.aidl
@@ -0,0 +1,36 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+parcelable ResolverParamsParcel {
+  int netId;
+  int sampleValiditySeconds;
+  int successThreshold;
+  int minSamples;
+  int maxSamples;
+  int baseTimeoutMsec;
+  int retryCount;
+  @utf8InCpp String[] servers;
+  @utf8InCpp String[] domains;
+  @utf8InCpp String tlsName;
+  @utf8InCpp String[] tlsServers;
+  @utf8InCpp String[] tlsFingerprints = {};
+  @utf8InCpp String caCertificate = "";
+  int tlsConnectTimeoutMs = 0;
+  android.net.ResolverExperimentalOptionsParcel experimentalOptions;
+}
diff --git a/apex/Android.bp b/apex/Android.bp
index a7aca24..69df1ed 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -28,8 +28,14 @@
     // Use a custom AndroidManifest.xml used for API targeting.
     androidManifest: "AndroidManifest.xml",
 
+    // IMPORTANT: For the APEX to be installed on Android 10,
+    // min_sdk_version should be 29. This enables the build system to make
+    // sure the package compatible to Android 10 in two ways:
+    // - build the APEX package compatible to Android 10
+    //   so that the package can be installed.
+    // - build artifacts (lib/javalib/bin) against Android 10 SDK
+    //   so that the artifacts can run.
     min_sdk_version: "29",
-    legacy_android10_support: true,
 }
 
 apex_key {
diff --git a/resolv_unit_test_config.xml b/resolv_test_config_template.xml
similarity index 74%
rename from resolv_unit_test_config.xml
rename to resolv_test_config_template.xml
index feafea1..3caba2b 100644
--- a/resolv_unit_test_config.xml
+++ b/resolv_test_config_template.xml
@@ -13,17 +13,22 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<configuration description="Configuration for resolv unit tests">
+<!-- Workaround for MTS coverage because test infra is running the 64 bit
+     test suite on cf_x86_phone (32-bit). See b/147785146 for details.
+     We need to push the correct binary against the architecture of
+     test device with "append-bitness" option.
+-->
+<configuration description="Configuration for {MODULE} tests">
    <option name="test-suite-tag" value="mts" />
    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
        <option name="cleanup" value="true" />
-       <option name="push" value="resolv_unit_test->/data/local/tmp/resolv_unit_test" />
+       <option name="push" value="{MODULE}->/data/local/tmp/{MODULE}" />
        <option name="append-bitness" value="true" />
    </target_preparer>
    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
    <test class="com.android.tradefed.testtype.GTest" >
        <option name="native-test-device-path" value="/data/local/tmp" />
-       <option name="module-name" value="resolv_unit_test" />
+       <option name="module-name" value="{MODULE}" />
        <option name="runtime-hint" value="10m" />
        <!-- test-timeout unit is ms, value = 10 min -->
        <option name="native-test-timeout" value="600000" />
diff --git a/stats.proto b/stats.proto
index fe2dfa6..abca793 100644
--- a/stats.proto
+++ b/stats.proto
@@ -44,6 +44,7 @@
     RC_EAI_BADHINTS = 12;
     RC_EAI_PROTOCOL = 13;
     RC_EAI_OVERFLOW = 14;
+    RC_RESOLV_INTERNAL_ERROR = 254;
     RC_RESOLV_TIMEOUT = 255;
     RC_EAI_MAX = 256;
 }
@@ -198,6 +199,144 @@
     CS_SKIP = 3;
 }
 
+// The enum LinuxErrno is defined in the following 2 files.
+// 1. bionic/libc/kernel/uapi/asm-generic/errno-base.h
+// 2. bionic/libc/kernel/uapi/asm-generic/errno.h
+enum LinuxErrno {
+    SYS_UNKNOWN = 0;
+    SYS_EPERM = 1;              // Not super-user
+    SYS_ENOENT = 2;             // No such file or directory
+    SYS_ESRCH = 3;              // No such process
+    SYS_EINTR = 4;              // Interrupted system call
+    SYS_EIO = 5;                // I/O error
+    SYS_ENXIO = 6;              // No such device or address
+    SYS_E2BIG = 7;              // Arg list too long
+    SYS_ENOEXEC = 8;            // Exec format error
+    SYS_EBADF = 9;              // Bad file number
+    SYS_ECHILD = 10;            // No children
+    SYS_EAGAIN = 11;            // No more processes
+    SYS_ENOMEM = 12;            // Not enough core
+    SYS_EACCES = 13;            // Permission denied
+    SYS_EFAULT = 14;            // Bad address
+    SYS_ENOTBLK = 15;           // Block device required
+    SYS_EBUSY = 16;             // Mount device busy
+    SYS_EEXIST = 17;            // File exists
+    SYS_EXDEV = 18;             // Cross-device link
+    SYS_ENODEV = 19;            // No such device
+    SYS_ENOTDIR = 20;           // Not a directory
+    SYS_EISDIR = 21;            // Is a directory
+    SYS_EINVAL = 22;            // Invalid argument
+    SYS_ENFILE = 23;            // Too many open files in system
+    SYS_EMFILE = 24;            // Too many open files
+    SYS_ENOTTY = 25;            // Not a typewriter
+    SYS_ETXTBSY = 26;           // Text file busy
+    SYS_EFBIG = 27;             // File too large
+    SYS_ENOSPC = 28;            // No space left on device
+    SYS_ESPIPE = 29;            // Illegal seek
+    SYS_EROFS = 30;             // Read only file system
+    SYS_EMLINK = 31;            // Too many links
+    SYS_EPIPE = 32;             // Broken pipe
+    SYS_EDOM = 33;              // Math arg out of domain of func
+    SYS_ERANGE = 34;            // Math result not representable
+    SYS_EDEADLOCK = 35;         // File locking deadlock error
+    SYS_ENAMETOOLONG = 36;      // File or path name too long
+    SYS_ENOLCK = 37;            // No record locks available
+    SYS_ENOSYS = 38;            // Function not implemented
+    SYS_ENOTEMPTY = 39;         // Directory not empty
+    SYS_ELOOP = 40;             // Too many symbolic links
+    SYS_ENOMSG = 42;            // No message of desired type
+    SYS_EIDRM = 43;             // Identifier removed
+    SYS_ECHRNG = 44;            // Channel number out of range
+    SYS_EL2NSYNC = 45;          // Level 2 not synchronized
+    SYS_EL3HLT = 46;            // Level 3 halted
+    SYS_EL3RST = 47;            // Level 3 reset
+    SYS_ELNRNG = 48;            // Link number out of range
+    SYS_EUNATCH = 49;           // rotocol driver not attached
+    SYS_ENOCSI = 50;            // No CSI structure available
+    SYS_EL2HLT = 51;            // Level 2 halted
+    SYS_EBADE = 52;             // Invalid exchange
+    SYS_EBADR = 53;             // Invalid request descriptor
+    SYS_EXFULL = 54;            // Exchange full
+    SYS_ENOANO = 55;            // No anode
+    SYS_EBADRQC = 56;           // Invalid request code
+    SYS_EBADSLT = 57;           // Invalid slot
+    SYS_EBFONT = 59;            // Bad font file fmt
+    SYS_ENOSTR = 60;            // Device not a stream
+    SYS_ENODATA = 61;           // No data (for no delay io)
+    SYS_ETIME = 62;             // Timer expired
+    SYS_ENOSR = 63;             // Out of streams resources
+    SYS_ENONET = 64;            // Machine is not on the network
+    SYS_ENOPKG = 65;            // Package not installed
+    SYS_EREMOTE = 66;           // The object is remote
+    SYS_ENOLINK = 67;           // The link has been severed
+    SYS_EADV = 68;              // Advertise error
+    SYS_ESRMNT = 69;            // Srmount error
+    SYS_ECOMM = 70;             // Communication error on send
+    SYS_EPROTO = 71;            // Protocol error
+    SYS_EMULTIHOP = 72;         // Multihop attempted
+    SYS_EDOTDOT = 73;           // Cross mount point (not really error)
+    SYS_EBADMSG = 74;           // Trying to read unreadable message
+    SYS_EOVERFLOW = 75;         // Value too large for defined data type
+    SYS_ENOTUNIQ = 76;          // Given log. name not unique
+    SYS_EBADFD = 77;            // f.d. invalid for this operation
+    SYS_EREMCHG = 78;           // Remote address changed
+    SYS_ELIBACC = 79;           // Can't access a needed shared lib
+    SYS_ELIBBAD = 80;           // Accessing a corrupted shared lib
+    SYS_ELIBSCN = 81;           // .lib section in a.out corrupted
+    SYS_ELIBMAX = 82;           // Attempting to link in too many libs
+    SYS_ELIBEXEC = 83;          // Attempting to exec a shared library
+    SYS_EILSEQ = 84;
+    SYS_ERESTART = 85;
+    SYS_ESTRPIPE = 86;
+    SYS_EUSERS = 87;
+    SYS_ENOTSOCK = 88;          // Socket operation on non-socket
+    SYS_EDESTADDRREQ = 89;      // Destination address required
+    SYS_EMSGSIZE = 90;          // Message too long
+    SYS_EPROTOTYPE = 91;        // Protocol wrong type for socket
+    SYS_ENOPROTOOPT = 92;       // Protocol not available
+    SYS_EPROTONOSUPPORT = 93;   // Unknown protocol
+    SYS_ESOCKTNOSUPPORT = 94;   // Socket type not supported
+    SYS_EOPNOTSUPP = 95;        // Operation not supported on transport endpoint
+    SYS_EPFNOSUPPORT = 96;      // Protocol family not supported
+    SYS_EAFNOSUPPORT = 97;      // Address family not supported by protocol family
+    SYS_EADDRINUSE = 98;        // Address already in use
+    SYS_EADDRNOTAVAIL = 99;     // Address not available
+    SYS_ENETDOWN = 100;         // Network interface is not configured
+    SYS_ENETUNREACH = 101;      // Network is unreachable
+    SYS_ENETRESET = 102;
+    SYS_ECONNABORTED = 103;     // Connection aborted
+    SYS_ECONNRESET = 104;       // Connection reset by peer
+    SYS_ENOBUFS = 105;          // No buffer space available
+    SYS_EISCONN = 106;          // Socket is already connected
+    SYS_ENOTCONN = 107;         // Socket is not connected
+    SYS_ESHUTDOWN = 108;        // Can't send after socket shutdown
+    SYS_ETOOMANYREFS = 109;
+    SYS_ETIMEDOUT = 110;        // Connection timed out
+    SYS_ECONNREFUSED = 111;     // Connection refused
+    SYS_EHOSTDOWN = 112;        // Host is down
+    SYS_EHOSTUNREACH = 113;     // Host is unreachable
+    SYS_EALREADY = 114;         // Socket already connected
+    SYS_EINPROGRESS = 115;      // Connection already in progress
+    SYS_ESTALE = 116;
+    SYS_EUCLEAN = 117;
+    SYS_ENOTNAM = 118;
+    SYS_ENAVAIL = 119;
+    SYS_EISNAM = 120;
+    SYS_EREMOTEIO = 121;
+    SYS_EDQUOT = 122;
+    SYS_ENOMEDIUM = 123;        // No medium (in tape drive)
+    SYS_EMEDIUMTYPE = 124;
+    SYS_ECANCELED = 125;
+    SYS_ENOKEY = 126;
+    SYS_EKEYEXPIRED = 127;
+    SYS_EKEYREVOKED = 128;
+    SYS_EKEYREJECTED = 129;
+    SYS_EOWNERDEAD = 130;
+    SYS_ENOTRECOVERABLE = 131;
+    SYS_ERFKILL = 132;
+    SYS_EHWPOISON = 133;
+}
+
 message DnsQueryEvent {
     optional NsRcode rcode = 1;
 
@@ -219,6 +358,8 @@
     optional bool connected = 8;
 
     optional int32 latency_micros = 9;
+
+    optional LinuxErrno linux_errno = 10;
 }
 
 message DnsQueryEvents {
diff --git a/tests/Android.bp b/tests/Android.bp
index daeecd7..9952763 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -1,6 +1,6 @@
 cc_test_library {
     name: "libnetd_test_resolv_utils",
-    defaults: ["netd_defaults"],
+    defaults: ["netd_defaults", "resolv_test_defaults"],
     srcs: [
         "resolv_test_utils.cpp",
     ],
@@ -8,7 +8,6 @@
         "libnetd_resolv_headers",
     ],
     shared_libs: [
-        "libbase",
         "libutils",
     ],
     static_libs: [
@@ -17,6 +16,46 @@
     ],
 }
 
+cc_library_host_static {
+    name: "golddata_proto_host",
+    proto: {
+        export_proto_headers: true,
+        type: "full",
+    },
+    srcs: [
+        "golddata.proto",
+    ],
+}
+
+cc_binary_host {
+    name: "resolv_gold_test_pbtxt2pb_host",
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    srcs: ["pbtxt2pb_converter_host.cpp"],
+    static_libs: [
+        "golddata_proto_host",
+        "libc++fs",
+        "libprotobuf-cpp-full",
+    ],
+}
+
+genrule {
+    name: "resolv_gold_test_pbtxt2pb",
+    tools: [
+        "resolv_gold_test_pbtxt2pb_host",
+        "soong_zip",
+    ],
+    srcs: ["testdata/*.pbtxt"],
+    // convert .pbtxt to .pb files; zip them as a single pb.zip.
+    cmd: "mkdir $(genDir)/pb && for fname in $(in); " +
+         "do $(location resolv_gold_test_pbtxt2pb_host) --in_file=$$fname " +
+         "--out_dir=$(genDir)/pb; done && " +
+         "$(location soong_zip) -o $(out) -C $(genDir)/pb -D $(genDir)/pb",
+    out: ["testdata/pb.zip"],
+}
+
 cc_library_static {
     name: "golddata_proto",
     defaults: ["netd_defaults"],
@@ -33,8 +72,12 @@
     name: "resolv_gold_test",
     test_suites: ["device-tests", "mts"],
     require_root: true,
-    defaults: ["netd_defaults"],
-    data: ["testdata/pb/*.pb"],
+    // b/151392634, this is a workaround because MTS
+    // can not handle the test with testdata correctly.
+    // TODO: Remove the xml after MTS fixing the problem.
+    test_config: "resolv_gold_test_config.xml",
+    defaults: ["netd_defaults", "resolv_test_defaults"],
+    data: [":resolv_gold_test_pbtxt2pb"],
     srcs: [
         "resolv_gold_test.cpp",
     ],
@@ -42,16 +85,14 @@
         "libnetd_client_headers",
     ],
     shared_libs: [
-        "libbinder_ndk",
         "libcrypto",
+        "libbinder_ndk",
         "libssl",
     ],
     static_libs: [
         "dnsresolver_aidl_interface-unstable-ndk_platform",
         "golddata_proto",
-        "libbase",
         "libgmock",
-        "liblog",
         "libnetd_resolv",
         "libnetd_test_dnsresponder_ndk",
         "libnetd_test_resolv_utils",
@@ -62,7 +103,9 @@
         "server_configurable_flags",
         "stats_proto",
     ],
-    compile_multilib: "first",
+    // MTS test binary can't be built under compile_multilib = "both" and having test data.
+    // However, MTS coverage requires 32 bit test binary to run.
+    compile_multilib: "prefer32",
 }
 
 cc_test {
@@ -70,8 +113,8 @@
     test_suites: ["device-tests", "mts"],
     // This won't work with test_config
     // require_root: true,
-    test_config: "resolv_stress_test_config.xml",
-    defaults: ["netd_defaults"],
+    // TODO: Remove resolv_test_mts_coverage_defaults after mts coverage switched to 64-bit device.
+    defaults: ["netd_defaults", "resolv_test_defaults", "resolv_test_mts_coverage_defaults"],
     srcs: [
         "resolv_stress_test.cpp",
     ],
@@ -79,10 +122,8 @@
         "libnetd_resolv_headers",
     ],
     shared_libs: [
-        "libbase",
         "libbinder_ndk",
         "libnetd_client",
-        "libutils",
     ],
     static_libs: [
         "dnsresolver_aidl_interface-ndk_platform",
@@ -90,18 +131,18 @@
         "libnetd_test_dnsresponder_ndk",
         "libnetd_test_resolv_utils",
         "libnetdutils",
+        "libutils",
         "netd_event_listener_interface-ndk_platform",
         "netd_aidl_interface-ndk_platform",
     ],
-    compile_multilib: "first",
 }
 
 cc_test {
     name: "resolv_integration_test",
     test_suites: ["device-tests", "mts"],
     require_root: true,
-    test_config: "resolv_integration_test_config.xml",
-    defaults: ["netd_defaults"],
+    test_config_template: ":resolv_test_config_template",
+    defaults: ["netd_defaults", "resolv_test_defaults"],
     tidy: false, // cuts test build time by > 1m30s
     srcs: [
         "dns_responder/dns_responder.cpp",
@@ -119,11 +160,9 @@
     ],
     static_libs: [
         "dnsresolver_aidl_interface-unstable-ndk_platform",
-        "libbase",
         "libbpf_android",
         "libcrypto_static",
         "libgmock",
-        "liblog",
         "libnetd_test_dnsresponder_ndk",
         "libnetd_test_metrics_listener",
         "libnetd_test_resolv_utils",
@@ -135,6 +174,9 @@
         "netd_aidl_interface-ndk_platform",
         "netd_event_listener_interface-ndk_platform",
     ],
+    // This test talks to the DnsResolver module over a binary protocol on a socket, so keep it as
+    // multilib setting is worth because we might be able to get some coverage for the case where
+    // 32bit apps talk to 64bit resolvers.
     compile_multilib: "both",
     multilib: {
         lib32: {
@@ -151,12 +193,10 @@
     srcs: [
         "resolv_stats_test_utils.cpp"
     ],
-    defaults: ["netd_defaults"],
+    defaults: ["netd_defaults", "resolv_test_defaults"],
     export_include_dirs: ["."],
     static_libs: [
-        "libbase",
         "libgmock",
-        "liblog",
         "libnetdutils",
         "libprotobuf-cpp-lite",
         "stats_proto",
@@ -168,12 +208,10 @@
     srcs: [
         "resolv_stats_test_utils_test.cpp",
     ],
-    defaults: ["netd_defaults"],
+    defaults: ["netd_defaults", "resolv_test_defaults"],
     test_suites: ["device-tests"],
     static_libs: [
-        "libbase",
         "libgmock",
-        "liblog",
         "libprotobuf-cpp-lite",
         "resolv_stats_test_utils",
         "stats_proto",
diff --git a/tests/dns_metrics_listener/Android.bp b/tests/dns_metrics_listener/Android.bp
index 8a957d6..74c545e 100644
--- a/tests/dns_metrics_listener/Android.bp
+++ b/tests/dns_metrics_listener/Android.bp
@@ -1,6 +1,6 @@
 cc_test_library {
     name: "libnetd_test_metrics_listener",
-    defaults: ["netd_defaults"],
+    defaults: ["netd_defaults", "resolv_test_defaults"],
     srcs: [
         "base_metrics_listener.cpp",
         "dns_metrics_listener.cpp",
@@ -10,7 +10,6 @@
         "libbinder_ndk",
     ],
     static_libs: [
-        "libbase",
         "libutils",
         "netd_event_listener_interface-ndk_platform",
     ],
diff --git a/tests/dns_metrics_listener/base_metrics_listener.cpp b/tests/dns_metrics_listener/base_metrics_listener.cpp
index c46f093..acd7310 100644
--- a/tests/dns_metrics_listener/base_metrics_listener.cpp
+++ b/tests/dns_metrics_listener/base_metrics_listener.cpp
@@ -45,7 +45,7 @@
 
 ::ndk::ScopedAStatus BaseMetricsListener::onWakeupEvent(
         const std::string& /*prefix*/, int32_t /*uid*/, int32_t /*ethertype*/,
-        int32_t /*ipNextHeader*/, const std::vector<int8_t>& /*dstHw*/,
+        int32_t /*ipNextHeader*/, const std::vector<uint8_t>& /*dstHw*/,
         const std::string& /*srcIp*/, const std::string& /*dstIp*/, int32_t /*srcPort*/,
         int32_t /*dstPort*/, int64_t /*timestampNs*/) {
     // default no-op
diff --git a/tests/dns_metrics_listener/base_metrics_listener.h b/tests/dns_metrics_listener/base_metrics_listener.h
index d50997d..e0b403f 100644
--- a/tests/dns_metrics_listener/base_metrics_listener.h
+++ b/tests/dns_metrics_listener/base_metrics_listener.h
@@ -45,7 +45,7 @@
                                                 int32_t /*uid*/) override;
     virtual ::ndk::ScopedAStatus onWakeupEvent(const std::string& /*prefix*/, int32_t /*uid*/,
                                                int32_t /*ethertype*/, int32_t /*ipNextHeader*/,
-                                               const std::vector<int8_t>& /*dstHw*/,
+                                               const std::vector<uint8_t>& /*dstHw*/,
                                                const std::string& /*srcIp*/,
                                                const std::string& /*dstIp*/, int32_t /*srcPort*/,
                                                int32_t /*dstPort*/,
diff --git a/tests/dns_metrics_listener/dns_metrics_listener.h b/tests/dns_metrics_listener/dns_metrics_listener.h
index d6268e2..4322296 100644
--- a/tests/dns_metrics_listener/dns_metrics_listener.h
+++ b/tests/dns_metrics_listener/dns_metrics_listener.h
@@ -57,6 +57,13 @@
     // Wait for the expected private DNS validation result until timeout.
     bool waitForPrivateDnsValidation(const std::string& serverAddr, const bool validated);
 
+    // Return true if a validation result for |serverAddr| is found; otherwise, return false.
+    // Only exists for testing.
+    bool findValidationRecord(const std::string& serverAddr) const EXCLUDES(mMutex) {
+        std::lock_guard lock(mMutex);
+        return mValidationRecords.find({mNetId, serverAddr}) != mValidationRecords.end();
+    }
+
   private:
     typedef std::pair<int32_t, std::string> ServerKey;
 
diff --git a/tests/dns_responder/Android.bp b/tests/dns_responder/Android.bp
index c1e785f..b67bcee 100644
--- a/tests/dns_responder/Android.bp
+++ b/tests/dns_responder/Android.bp
@@ -1,10 +1,9 @@
 // TODO: Remove libnetd_test_dnsresponder after eliminating all users.
 cc_library_static {
     name: "libnetd_test_dnsresponder",
-    defaults: ["netd_defaults"],
+    defaults: ["netd_defaults", "resolv_test_defaults"],
     shared_libs: [
         "dnsresolver_aidl_interface-unstable-cpp",
-        "libbase",
         "libbinder",
         "libnetd_client",
         "libnetdutils",
@@ -21,7 +20,7 @@
 
 cc_library {
     name: "libnetd_test_dnsresponder_ndk",
-    defaults: ["netd_defaults"],
+    defaults: ["netd_defaults", "resolv_test_defaults"],
     shared_libs: [
         "libbinder_ndk",
         "libnetd_client",
@@ -35,9 +34,7 @@
     ],
     static_libs: [
         "dnsresolver_aidl_interface-unstable-ndk_platform",
-        "libbase",
         "libcrypto_static",
-        "liblog",
         "libnetdutils",
         "libssl",
         "netd_event_listener_interface-ndk_platform",
diff --git a/tests/dns_responder/dns_tls_frontend.cpp b/tests/dns_responder/dns_tls_frontend.cpp
index dfd4ec4..bf23dbc 100644
--- a/tests/dns_responder/dns_tls_frontend.cpp
+++ b/tests/dns_responder/dns_tls_frontend.cpp
@@ -200,6 +200,7 @@
                 break;
             }
 
+            accept_connection_count_++;
             if (hangOnHandshake_) {
                 LOG(DEBUG) << "TEST ONLY: unresponsive to SSL handshake";
 
diff --git a/tests/dns_responder/dns_tls_frontend.h b/tests/dns_responder/dns_tls_frontend.h
index 1b34607..386db6a 100644
--- a/tests/dns_responder/dns_tls_frontend.h
+++ b/tests/dns_responder/dns_tls_frontend.h
@@ -57,6 +57,7 @@
     int queries() const { return queries_; }
     void clearQueries() { queries_ = 0; }
     bool waitForQueries(int expected_count) const;
+    int acceptConnectionsCount() const { return accept_connection_count_; }
 
     void set_chain_length(int length) { chain_length_ = length; }
     void setHangOnHandshakeForTesting(bool hangOnHandshake) { hangOnHandshake_ = hangOnHandshake; }
@@ -88,6 +89,7 @@
     // Eventfd used to signal for the handler thread termination.
     android::base::unique_fd event_fd_;
     std::atomic<int> queries_ = 0;
+    std::atomic<int> accept_connection_count_ = 0;
     std::thread handler_thread_ GUARDED_BY(update_mutex_);
     std::mutex update_mutex_;
     int chain_length_ = 1;
diff --git a/tests/golddata.proto b/tests/golddata.proto
index 23a32d0..3a512b4 100644
--- a/tests/golddata.proto
+++ b/tests/golddata.proto
@@ -16,7 +16,6 @@
 
 syntax = "proto3";
 package android.net;
-option optimize_for = LITE_RUNTIME;
 
 // Used to indicate which call is invoked to send DNS lookups.
 enum CallType {
@@ -200,4 +199,4 @@
     // addMappingBinaryPacket() in
     // packages/modules/DnsResolver/tests/dns_responder/dns_responder.cpp.
     repeated PacketMapping packet_mapping = 3;
-}
\ No newline at end of file
+}
diff --git a/tests/pbtxt2pb_converter_host.cpp b/tests/pbtxt2pb_converter_host.cpp
new file mode 100644
index 0000000..90fe455
--- /dev/null
+++ b/tests/pbtxt2pb_converter_host.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <fcntl.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/text_format.h>
+
+#include <filesystem>
+
+#include "golddata.pb.h"
+
+using namespace std;
+
+bool ConvertPbtxtToPb(const filesystem::path& pbtxtFile, const filesystem::path& pbOutDir) {
+    // parse plain text from .pbtxt.
+    android::net::GoldTest goldTest;
+
+    int fd = open(pbtxtFile.c_str(), O_RDONLY);
+    if (fd < 0) {
+        cerr << "Failed to open " << pbtxtFile << ", " << strerror(errno) << endl;
+        return false;
+    }
+    {
+        google::protobuf::io::FileInputStream fileInput(fd);
+        fileInput.SetCloseOnDelete(true);
+        if (!google::protobuf::TextFormat::Parse(&fileInput, &goldTest)) {
+            cerr << "Failed to parse " << pbtxtFile << endl;
+            return false;
+        }
+    }
+
+    // write marshalled message into .pb file
+    filesystem::path pbFile = pbOutDir / pbtxtFile.filename();
+    pbFile.replace_extension(".pb");
+    fd = open(pbFile.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0660);
+    if (fd < 0) {
+        cerr << "Failed to open " << pbFile << ", " << strerror(errno) << endl;
+        return false;
+    }
+    {
+        google::protobuf::io::FileOutputStream fileOutputStream(fd);
+        fileOutputStream.SetCloseOnDelete(true);
+        if (!goldTest.SerializeToZeroCopyStream(&fileOutputStream)) {
+            cerr << "Failed to serialize " << pbFile << endl;
+            filesystem::remove(pbFile);
+            return false;
+        }
+    }
+
+    cout << "Generate " << pbFile << " successfully" << endl;
+    return true;
+}
+
+int main(int argc, char const* const* argv) {
+    filesystem::path pbtxtFile;
+    filesystem::path pbOutDir;
+    const string arg_in = "--in_file=";
+    const string arg_out = "--out_dir=";
+
+    for (int i = 1; i < argc; i++) {
+        std::string arg = argv[i];
+        if (arg.find(arg_in) == 0) {
+            pbtxtFile = filesystem::path(arg.substr(arg_in.size()));
+        } else if (arg.find(arg_out) == 0) {
+            pbOutDir = filesystem::path(arg.substr(arg_out.size()));
+        } else {
+            cerr << "Unknown argument: " << arg << endl;
+            exit(1);
+        }
+    }
+
+    if (pbtxtFile.empty() || pbOutDir.empty()) {
+        cerr << arg_in << " or " << arg_out << " is unassigned" << endl;
+        exit(1);
+    }
+    if (!ConvertPbtxtToPb(pbtxtFile, pbOutDir)) {
+        cerr << "Failed to convert " << pbtxtFile << endl;
+        exit(1);
+    }
+}
diff --git a/tests/resolv_gold_test.cpp b/tests/resolv_gold_test.cpp
index 99bcb92..d8e9a6c 100644
--- a/tests/resolv_gold_test.cpp
+++ b/tests/resolv_gold_test.cpp
@@ -20,6 +20,7 @@
 #include <Fwmark.h>
 #include <android-base/chrono_utils.h>
 #include <android-base/file.h>
+#include <android-base/logging.h>
 #include <android-base/result.h>
 #include <android-base/stringprintf.h>
 #include <gmock/gmock-matchers.h>
@@ -49,9 +50,8 @@
 // TODO: Consider moving to packages/modules/DnsResolver/tests/resolv_test_utils.h.
 constexpr unsigned int MAXPACKET = 8 * 1024;
 
-// The testdata/pb/*.pb are generated from testdata/*.pbtext.
-// TODO: Generate .pb files via precompiler.
-const std::string kTestDataPath = android::base::GetExecutableDirectory() + "/testdata/pb/";
+// The testdata/*.pb are generated from testdata/*.pbtext.
+const std::string kTestDataPath = android::base::GetExecutableDirectory() + "/testdata/";
 const std::vector<std::string> kGoldFilesGetAddrInfo = {
         "getaddrinfo.topsite.google.pb",    "getaddrinfo.topsite.youtube.pb",
         "getaddrinfo.topsite.amazon.pb",    "getaddrinfo.topsite.yahoo.pb",
@@ -66,6 +66,18 @@
 // Fixture test class definition.
 class TestBase : public ::testing::Test {
   protected:
+    static void SetUpTestSuite() {
+        // Unzip *.pb from pb.zip. The unzipped files get 777 permission by default. Remove execute
+        // permission so that Trade Federation test harness has no chance mis-executing on *.pb.
+        const std::string unzipCmd = "unzip -o " + kTestDataPath + "pb.zip -d " + kTestDataPath +
+                                     "&& chmod -R 666 " + kTestDataPath;
+        // NOLINTNEXTLINE(cert-env33-c)
+        if (W_EXITCODE(0, 0) != system(unzipCmd.c_str())) {
+            LOG(ERROR) << "fail to inflate .pb files";
+            GTEST_LOG_(FATAL) << "fail to inflate .pb files";
+        }
+    }
+
     void SetUp() override {
         // Create cache for test
         resolv_create_cache_for_net(TEST_NETID);
@@ -423,7 +435,7 @@
         tls.clearQueries();
     }
 
-    // Read test configuration from proto text file to proto.
+    // Read test configuration from serialized binary to proto.
     const Result<GoldTest> result = ToProto(file);
     ASSERT_TRUE(result.ok()) << result.error().message();
     const GoldTest& goldtest = result.value();
diff --git a/tests/resolv_integration_test_config.xml b/tests/resolv_gold_test_config.xml
similarity index 78%
rename from tests/resolv_integration_test_config.xml
rename to tests/resolv_gold_test_config.xml
index a25595f..e70a7e6 100644
--- a/tests/resolv_integration_test_config.xml
+++ b/tests/resolv_gold_test_config.xml
@@ -13,17 +13,18 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<configuration description="Configuration for resolv integration tests">
+<configuration description="Configuration for resolv gold tests">
    <option name="test-suite-tag" value="mts" />
    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
        <option name="cleanup" value="true" />
-       <option name="push" value="resolv_integration_test->/data/local/tmp/resolv_integration_test" />
-       <option name="append-bitness" value="true" />
+       <option name="push" value="resolv_gold_test->/data/local/tmp/resolv_gold_test" />
+       <!-- Temporary solotuon for b/151392634 -->
+       <option name="push" value="testdata->/data/local/tmp/testdata/" />
    </target_preparer>
    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
    <test class="com.android.tradefed.testtype.GTest" >
        <option name="native-test-device-path" value="/data/local/tmp" />
-       <option name="module-name" value="resolv_integration_test" />
+       <option name="module-name" value="resolv_gold_test" />
        <option name="runtime-hint" value="10m" />
        <!-- test-timeout unit is ms, value = 10 min -->
        <option name="native-test-timeout" value="600000" />
diff --git a/tests/resolv_integration_test.cpp b/tests/resolv_integration_test.cpp
index 72b85bb..9dda0f1 100644
--- a/tests/resolv_integration_test.cpp
+++ b/tests/resolv_integration_test.cpp
@@ -81,6 +81,8 @@
                                          const addrinfo* hints, unsigned netid, unsigned mark,
                                          struct addrinfo** result);
 
+using namespace std::chrono_literals;
+
 using aidl::android::net::IDnsResolver;
 using aidl::android::net::INetd;
 using aidl::android::net::ResolverParamsParcel;
@@ -115,11 +117,38 @@
     return {std::move(result), s.timeTakenUs() / 1000};
 }
 
+struct NameserverStats {
+    NameserverStats() = delete;
+    NameserverStats(const std::string server) : server(server) {}
+    NameserverStats& setSuccesses(int val) {
+        successes = val;
+        return *this;
+    }
+    NameserverStats& setErrors(int val) {
+        errors = val;
+        return *this;
+    }
+    NameserverStats& setTimeouts(int val) {
+        timeouts = val;
+        return *this;
+    }
+    NameserverStats& setInternalErrors(int val) {
+        internal_errors = val;
+        return *this;
+    }
+
+    const std::string server;
+    int successes = 0;
+    int errors = 0;
+    int timeouts = 0;
+    int internal_errors = 0;
+};
+
 }  // namespace
 
 class ResolverTest : public ::testing::Test {
   public:
-    static void SetUpTestCase() {
+    static void SetUpTestSuite() {
         // Get binder service.
         // Note that |mDnsClient| is not used for getting binder service in this static function.
         // The reason is that wants to keep |mDnsClient| as a non-static data member. |mDnsClient|
@@ -153,7 +182,7 @@
         // recipient.
         ABinderProcess_startThreadPool();
     }
-    static void TearDownTestCase() { AIBinder_DeathRecipient_delete(sResolvDeathRecipient); }
+    static void TearDownTestSuite() { AIBinder_DeathRecipient_delete(sResolvDeathRecipient); }
 
   protected:
     void SetUp() { mDnsClient.SetUp(); }
@@ -190,6 +219,69 @@
         return sDnsMetricsListener->waitForPrivateDnsValidation(serverAddr, validated);
     }
 
+    bool hasUncaughtPrivateDnsValidation(const std::string& serverAddr) {
+        return sDnsMetricsListener->findValidationRecord(serverAddr);
+    }
+
+    bool expectStatsFromGetResolverInfo(const std::vector<NameserverStats>& nameserversStats) {
+        std::vector<std::string> res_servers;
+        std::vector<std::string> res_domains;
+        std::vector<std::string> res_tls_servers;
+        res_params res_params;
+        std::vector<ResolverStats> res_stats;
+        int wait_for_pending_req_timeout_count;
+
+        if (!DnsResponderClient::GetResolverInfo(mDnsClient.resolvService(), TEST_NETID,
+                                                 &res_servers, &res_domains, &res_tls_servers,
+                                                 &res_params, &res_stats,
+                                                 &wait_for_pending_req_timeout_count)) {
+            ADD_FAILURE() << "GetResolverInfo failed";
+            return false;
+        }
+
+        if (res_servers.size() != res_stats.size()) {
+            ADD_FAILURE() << fmt::format("res_servers.size() != res_stats.size(): {} != {}",
+                                         res_servers.size(), res_stats.size());
+            return false;
+        }
+        if (res_servers.size() != nameserversStats.size()) {
+            ADD_FAILURE() << fmt::format("res_servers.size() != nameserversStats.size(): {} != {}",
+                                         res_servers.size(), nameserversStats.size());
+            return false;
+        }
+
+        for (const auto& stats : nameserversStats) {
+            SCOPED_TRACE(stats.server);
+            const auto it = std::find(res_servers.begin(), res_servers.end(), stats.server);
+            if (it == res_servers.end()) {
+                ADD_FAILURE() << fmt::format("nameserver {} not found in the list {{{}}}",
+                                             stats.server, fmt::join(res_servers, ", "));
+                return false;
+            }
+            const int index = std::distance(res_servers.begin(), it);
+
+            // The check excludes rtt_avg, last_sample_time, and usable since they will be obsolete
+            // after |res_stats| is retrieved from NetConfig.dnsStats rather than NetConfig.nsstats.
+            EXPECT_EQ(res_stats[index].successes, stats.successes);
+            EXPECT_EQ(res_stats[index].errors, stats.errors);
+            EXPECT_EQ(res_stats[index].timeouts, stats.timeouts);
+            EXPECT_EQ(res_stats[index].internal_errors, stats.internal_errors);
+        }
+
+        return true;
+    }
+
+    // Since there's no way to terminate private DNS validation threads at any time. Tests that
+    // focus on the results of private DNS validation can interfere with each other if they use the
+    // same IP address for test servers. getUniqueIPv4Address() is a workaround to reduce the
+    // possibility of tests being flaky. A feasible solution is to forbid the validation threads,
+    // which are considered as outdated (e.g. switch the resolver to private DNS OFF mode), updating
+    // the result to the PrivateDnsConfiguration instance.
+    static std::string getUniqueIPv4Address() {
+        static int counter = 0;
+        return fmt::format("127.0.100.{}", (++counter & 0xff));
+    }
+
     DnsResponderClient mDnsClient;
 
     // Use a shared static DNS listener for all tests to avoid registering lots of listeners
@@ -200,11 +292,11 @@
     // TODO: Perhaps add an unregistering listener binder call or fork a listener process which
     // could be terminated earlier.
     static std::shared_ptr<DnsMetricsListener>
-            sDnsMetricsListener;  // Initialized in SetUpTestCase.
+            sDnsMetricsListener;  // Initialized in SetUpTestSuite.
 
     // Use a shared static death recipient to monitor the service death. The static death
     // recipient could monitor the death not only during the test but also between tests.
-    static AIBinder_DeathRecipient* sResolvDeathRecipient;  // Initialized in SetUpTestCase.
+    static AIBinder_DeathRecipient* sResolvDeathRecipient;  // Initialized in SetUpTestSuite.
 };
 
 // Initialize static member of class.
@@ -941,23 +1033,12 @@
         EXPECT_TRUE(safe_getaddrinfo(hostName.c_str(), nullptr, &hints) != nullptr);
     }
 
-    std::vector<std::string> res_servers;
-    std::vector<std::string> res_domains;
-    std::vector<std::string> res_tls_servers;
-    res_params res_params;
-    std::vector<ResolverStats> res_stats;
-    int wait_for_pending_req_timeout_count;
-    ASSERT_TRUE(DnsResponderClient::GetResolverInfo(
-            mDnsClient.resolvService(), TEST_NETID, &res_servers, &res_domains, &res_tls_servers,
-            &res_params, &res_stats, &wait_for_pending_req_timeout_count));
-
-    // Verify the result by means of the statistics.
-    EXPECT_EQ(res_stats[0].successes, 0);
-    EXPECT_EQ(res_stats[1].successes, 0);
-    EXPECT_EQ(res_stats[2].successes, 5);
-    EXPECT_EQ(res_stats[0].internal_errors, 2);
-    EXPECT_EQ(res_stats[1].internal_errors, 2);
-    EXPECT_EQ(res_stats[2].internal_errors, 0);
+    const std::vector<NameserverStats> expectedCleartextDnsStats = {
+            NameserverStats(listen_addr1).setInternalErrors(2),
+            NameserverStats(listen_addr2).setInternalErrors(2),
+            NameserverStats(listen_addr3).setSuccesses(5),
+    };
+    EXPECT_TRUE(expectStatsFromGetResolverInfo(expectedCleartextDnsStats));
 }
 
 TEST_F(ResolverTest, SkipBadServersDueToTimeout) {
@@ -987,21 +1068,11 @@
         EXPECT_TRUE(safe_getaddrinfo(hostName.c_str(), nullptr, &hints) != nullptr);
     }
 
-    std::vector<std::string> res_servers;
-    std::vector<std::string> res_domains;
-    std::vector<std::string> res_tls_servers;
-    res_params res_params;
-    std::vector<ResolverStats> res_stats;
-    int wait_for_pending_req_timeout_count;
-    ASSERT_TRUE(DnsResponderClient::GetResolverInfo(
-            mDnsClient.resolvService(), TEST_NETID, &res_servers, &res_domains, &res_tls_servers,
-            &res_params, &res_stats, &wait_for_pending_req_timeout_count));
-
-    // Verify the result by means of the statistics as well as the query counts.
-    EXPECT_EQ(res_stats[0].successes, 0);
-    EXPECT_EQ(res_stats[1].successes, 5);
-    EXPECT_EQ(res_stats[0].timeouts, 2);
-    EXPECT_EQ(res_stats[1].timeouts, 0);
+    const std::vector<NameserverStats> expectedCleartextDnsStats = {
+            NameserverStats(listen_addr1).setTimeouts(2),
+            NameserverStats(listen_addr2).setSuccesses(5),
+    };
+    EXPECT_TRUE(expectStatsFromGetResolverInfo(expectedCleartextDnsStats));
     EXPECT_EQ(dns1.queries().size(), 2U);
     EXPECT_EQ(dns2.queries().size(), 5U);
 }
@@ -1384,19 +1455,12 @@
     std::string result_str = ToString(result);
     EXPECT_TRUE(result_str == "1.2.3.4") << ", result_str='" << result_str << "'";
 
-    std::vector<std::string> res_servers;
-    std::vector<std::string> res_domains;
-    std::vector<std::string> res_tls_servers;
-    res_params res_params;
-    std::vector<ResolverStats> res_stats;
-    int wait_for_pending_req_timeout_count;
-    ASSERT_TRUE(DnsResponderClient::GetResolverInfo(
-            mDnsClient.resolvService(), TEST_NETID, &res_servers, &res_domains, &res_tls_servers,
-            &res_params, &res_stats, &wait_for_pending_req_timeout_count));
-
-    EXPECT_EQ(1, res_stats[0].timeouts);
-    EXPECT_EQ(1, res_stats[1].errors);
-    EXPECT_EQ(1, res_stats[2].successes);
+    const std::vector<NameserverStats> expectedCleartextDnsStats = {
+            NameserverStats(listen_addr1).setTimeouts(1),
+            NameserverStats(listen_addr2).setErrors(1),
+            NameserverStats(listen_addr3).setSuccesses(1),
+    };
+    EXPECT_TRUE(expectStatsFromGetResolverInfo(expectedCleartextDnsStats));
 }
 
 TEST_F(ResolverTest, AlwaysUseLatestSetupParamsInLookups) {
@@ -1449,25 +1513,12 @@
     EXPECT_EQ(0U, GetNumQueriesForType(dns3, ns_type::ns_t_aaaa, fqdn_with_search_domain));
     EXPECT_EQ(1U, GetNumQueriesForType(dns3, ns_type::ns_t_a, fqdn_with_search_domain));
 
-    std::vector<std::string> res_servers;
-    std::vector<std::string> res_domains;
-    std::vector<std::string> res_tls_servers;
-    res_params res_params;
-    std::vector<ResolverStats> res_stats;
-    int wait_for_pending_req_timeout_count;
-    ASSERT_TRUE(DnsResponderClient::GetResolverInfo(
-            mDnsClient.resolvService(), TEST_NETID, &res_servers, &res_domains, &res_tls_servers,
-            &res_params, &res_stats, &wait_for_pending_req_timeout_count));
-    EXPECT_EQ(res_stats[0].successes, 1);
-    EXPECT_EQ(res_stats[0].timeouts, 0);
-    EXPECT_EQ(res_stats[0].internal_errors, 0);
-    EXPECT_EQ(res_stats[1].successes, 0);
-    EXPECT_EQ(res_stats[1].timeouts, 0);
-    EXPECT_EQ(res_stats[1].internal_errors, 0);
-    EXPECT_EQ(res_stats[2].successes, 0);
-    EXPECT_EQ(res_stats[2].timeouts, 0);
-    EXPECT_EQ(res_stats[2].internal_errors, 0);
-    EXPECT_EQ(res_servers, parcel.servers);
+    const std::vector<NameserverStats> expectedCleartextDnsStats = {
+            NameserverStats(listen_addr1),
+            NameserverStats(listen_addr2),
+            NameserverStats(listen_addr3).setSuccesses(1),
+    };
+    EXPECT_TRUE(expectStatsFromGetResolverInfo(expectedCleartextDnsStats));
 }
 
 // Test what happens if the specified TLS server is nonexistent.
@@ -4109,6 +4160,310 @@
     }
 }
 
+TEST_F(ResolverTest, RepeatedSetup_ResolverStatusRemains) {
+    constexpr char unusable_listen_addr[] = "127.0.0.3";
+    constexpr char listen_addr[] = "127.0.0.4";
+    constexpr char hostname[] = "a.hello.query.";
+    const auto repeatedSetResolversFromParcel = [&](const ResolverParamsParcel& parcel) {
+        ASSERT_TRUE(mDnsClient.SetResolversFromParcel(parcel));
+        ASSERT_TRUE(mDnsClient.SetResolversFromParcel(parcel));
+        ASSERT_TRUE(mDnsClient.SetResolversFromParcel(parcel));
+    };
+
+    test::DNSResponder dns(listen_addr);
+    StartDns(dns, {{hostname, ns_type::ns_t_a, "1.2.3.3"}});
+    test::DnsTlsFrontend tls1(listen_addr, "853", listen_addr, "53");
+    ASSERT_TRUE(tls1.startServer());
+
+    // Private DNS off mode.
+    ResolverParamsParcel parcel = DnsResponderClient::GetDefaultResolverParamsParcel();
+    parcel.servers = {unusable_listen_addr, listen_addr};
+    parcel.tlsServers.clear();
+    ASSERT_TRUE(mDnsClient.SetResolversFromParcel(parcel));
+
+    // Send a query.
+    const addrinfo hints = {.ai_family = AF_INET, .ai_socktype = SOCK_DGRAM};
+    EXPECT_NE(safe_getaddrinfo(hostname, nullptr, &hints), nullptr);
+
+    // Check the stats as expected.
+    const std::vector<NameserverStats> expectedCleartextDnsStats = {
+            NameserverStats(unusable_listen_addr).setInternalErrors(1),
+            NameserverStats(listen_addr).setSuccesses(1),
+    };
+    EXPECT_TRUE(expectStatsFromGetResolverInfo(expectedCleartextDnsStats));
+    EXPECT_EQ(GetNumQueries(dns, hostname), 1U);
+
+    // The stats is supposed to remain as long as the list of cleartext DNS servers is unchanged.
+    static const struct TestConfig {
+        std::vector<std::string> servers;
+        std::vector<std::string> tlsServers;
+        std::string tlsName;
+    } testConfigs[] = {
+            // Private DNS opportunistic mode.
+            {{listen_addr, unusable_listen_addr}, {listen_addr, unusable_listen_addr}, ""},
+            {{unusable_listen_addr, listen_addr}, {unusable_listen_addr, listen_addr}, ""},
+
+            // Private DNS strict mode.
+            {{listen_addr, unusable_listen_addr}, {"127.0.0.100"}, kDefaultPrivateDnsHostName},
+            {{unusable_listen_addr, listen_addr}, {"127.0.0.100"}, kDefaultPrivateDnsHostName},
+
+            // Private DNS off mode.
+            {{unusable_listen_addr, listen_addr}, {}, ""},
+            {{listen_addr, unusable_listen_addr}, {}, ""},
+    };
+
+    for (const auto& config : testConfigs) {
+        SCOPED_TRACE(fmt::format("testConfig: [{}] [{}] [{}]", fmt::join(config.servers, ","),
+                                 fmt::join(config.tlsServers, ","), config.tlsName));
+        parcel = DnsResponderClient::GetDefaultResolverParamsParcel();
+        parcel.servers = config.servers;
+        parcel.tlsServers = config.tlsServers;
+        parcel.tlsName = config.tlsName;
+        repeatedSetResolversFromParcel(parcel);
+        EXPECT_TRUE(expectStatsFromGetResolverInfo(expectedCleartextDnsStats));
+
+        // The stats remains when the list of search domains changes.
+        parcel.domains.push_back("tmp.domains");
+        repeatedSetResolversFromParcel(parcel);
+        EXPECT_TRUE(expectStatsFromGetResolverInfo(expectedCleartextDnsStats));
+
+        // The stats remains when the parameters change (except maxSamples).
+        parcel.sampleValiditySeconds++;
+        parcel.successThreshold++;
+        parcel.minSamples++;
+        parcel.baseTimeoutMsec++;
+        parcel.retryCount++;
+        repeatedSetResolversFromParcel(parcel);
+        EXPECT_TRUE(expectStatsFromGetResolverInfo(expectedCleartextDnsStats));
+    }
+
+    // The cache remains.
+    EXPECT_NE(safe_getaddrinfo(hostname, nullptr, &hints), nullptr);
+    EXPECT_EQ(GetNumQueries(dns, hostname), 1U);
+}
+
+TEST_F(ResolverTest, RepeatedSetup_NoRedundantPrivateDnsValidation) {
+    const std::string addr1 = getUniqueIPv4Address();  // For a workable DNS server.
+    const std::string addr2 = getUniqueIPv4Address();  // For an unresponsive DNS server.
+    const std::string unusable_addr = getUniqueIPv4Address();
+    const auto waitForPrivateDnsStateUpdated = []() {
+        // A buffer time for the PrivateDnsConfiguration instance to update its map,
+        // mPrivateDnsValidateThreads, which is used for tracking validation threads.
+        // Since there is a time gap between when PrivateDnsConfiguration reports
+        // onPrivateDnsValidationEvent and when PrivateDnsConfiguration updates the map, this is a
+        // workaround to avoid the test starts a subsequent resolver setup during the time gap.
+        // TODO: Report onPrivateDnsValidationEvent after all the relevant updates are complete.
+        // Reference to b/152009023.
+        std::this_thread::sleep_for(20ms);
+    };
+
+    test::DNSResponder dns1(addr1);
+    test::DNSResponder dns2(addr2);
+    StartDns(dns1, {});
+    StartDns(dns2, {});
+    test::DnsTlsFrontend workableTls(addr1, "853", addr1, "53");
+    test::DnsTlsFrontend unresponsiveTls(addr2, "853", addr2, "53");
+    unresponsiveTls.setHangOnHandshakeForTesting(true);
+    ASSERT_TRUE(workableTls.startServer());
+    ASSERT_TRUE(unresponsiveTls.startServer());
+
+    // First setup.
+    ResolverParamsParcel parcel = DnsResponderClient::GetDefaultResolverParamsParcel();
+    parcel.servers = {addr1, addr2, unusable_addr};
+    parcel.tlsServers = {addr1, addr2, unusable_addr};
+    ASSERT_TRUE(mDnsClient.SetResolversFromParcel(parcel));
+
+    // Check the validation results.
+    EXPECT_TRUE(WaitForPrivateDnsValidation(workableTls.listen_address(), true));
+    EXPECT_TRUE(WaitForPrivateDnsValidation(unusable_addr, false));
+    EXPECT_EQ(unresponsiveTls.acceptConnectionsCount(), 1);  // The validation is still in progress.
+
+    static const struct TestConfig {
+        std::vector<std::string> tlsServers;
+        std::string tlsName;
+    } testConfigs[] = {
+            {{addr1, addr2, unusable_addr}, ""},
+            {{unusable_addr, addr1, addr2}, ""},
+            {{unusable_addr, addr1, addr2}, kDefaultPrivateDnsHostName},
+            {{addr1, addr2, unusable_addr}, kDefaultPrivateDnsHostName},
+    };
+
+    std::string TlsNameLastTime;
+    for (const auto& config : testConfigs) {
+        SCOPED_TRACE(fmt::format("testConfig: [{}] [{}]", fmt::join(config.tlsServers, ","),
+                                 config.tlsName));
+        parcel.servers = config.tlsServers;
+        parcel.tlsServers = config.tlsServers;
+        parcel.tlsName = config.tlsName;
+        parcel.caCertificate = config.tlsName.empty() ? "" : kCaCert;
+
+        const bool dnsModeChanged = (TlsNameLastTime != config.tlsName);
+
+        waitForPrivateDnsStateUpdated();
+        ASSERT_TRUE(mDnsClient.SetResolversFromParcel(parcel));
+
+        for (const auto& serverAddr : parcel.tlsServers) {
+            SCOPED_TRACE(serverAddr);
+            if (serverAddr == workableTls.listen_address()) {
+                if (dnsModeChanged) {
+                    // In despite of the identical IP address, the server is regarded as a different
+                    // server when DnsTlsServer.name is different. The resolver treats it as a
+                    // different object and begins the validation process.
+                    EXPECT_TRUE(WaitForPrivateDnsValidation(serverAddr, true));
+                }
+            } else if (serverAddr == unresponsiveTls.listen_address()) {
+                // No revalidation needed for the server which have been marked as in_progesss.
+            } else {
+                // Must be unusable_addr.
+                // In opportunistic mode, when a validation for a private DNS server fails, the
+                // resolver just marks the server as failed and doesn't re-evaluate it, but the
+                // server can be re-evaluated when setResolverConfiguration() is called.
+                // However, in strict mode, the resolver automatically re-evaluates the server and
+                // marks the server as in_progress until the validation succeeds, so repeated setup
+                // makes no effect.
+                if (dnsModeChanged || config.tlsName.empty() /* not in strict mode */) {
+                    EXPECT_TRUE(WaitForPrivateDnsValidation(serverAddr, false));
+                }
+            }
+        }
+
+        // Repeated setups make no effect in strict mode.
+        waitForPrivateDnsStateUpdated();
+        ASSERT_TRUE(mDnsClient.SetResolversFromParcel(parcel));
+        if (config.tlsName.empty()) {
+            EXPECT_TRUE(WaitForPrivateDnsValidation(unusable_addr, false));
+        }
+        waitForPrivateDnsStateUpdated();
+        ASSERT_TRUE(mDnsClient.SetResolversFromParcel(parcel));
+        if (config.tlsName.empty()) {
+            EXPECT_TRUE(WaitForPrivateDnsValidation(unusable_addr, false));
+        }
+
+        EXPECT_EQ(unresponsiveTls.acceptConnectionsCount(), 1);
+
+        TlsNameLastTime = config.tlsName;
+    }
+
+    // Check that all the validation results are caught.
+    // Note: it doesn't mean no validation being in progress.
+    EXPECT_FALSE(hasUncaughtPrivateDnsValidation(addr1));
+    EXPECT_FALSE(hasUncaughtPrivateDnsValidation(addr2));
+    EXPECT_FALSE(hasUncaughtPrivateDnsValidation(unusable_addr));
+}
+
+TEST_F(ResolverTest, RepeatedSetup_KeepChangingPrivateDnsServers) {
+    enum TlsServerState { WORKING, UNSUPPORTED, UNRESPONSIVE };
+    const std::string addr1 = getUniqueIPv4Address();
+    const std::string addr2 = getUniqueIPv4Address();
+    const auto waitForPrivateDnsStateUpdated = []() {
+        // A buffer time for PrivateDnsConfiguration to update its state. It prevents this test
+        // being flaky. See b/152009023 for the reason.
+        std::this_thread::sleep_for(20ms);
+    };
+
+    test::DNSResponder dns1(addr1);
+    test::DNSResponder dns2(addr2);
+    StartDns(dns1, {});
+    StartDns(dns2, {});
+    test::DnsTlsFrontend tls1(addr1, "853", addr1, "53");
+    test::DnsTlsFrontend tls2(addr2, "853", addr2, "53");
+    ASSERT_TRUE(tls1.startServer());
+    ASSERT_TRUE(tls2.startServer());
+
+    static const struct TestConfig {
+        std::string tlsServer;
+        std::string tlsName;
+        bool expectNothingHappenWhenServerUnsupported;
+        bool expectNothingHappenWhenServerUnresponsive;
+        std::string asTestName() const {
+            return fmt::format("{}, {}, {}, {}", tlsServer, tlsName,
+                               expectNothingHappenWhenServerUnsupported,
+                               expectNothingHappenWhenServerUnresponsive);
+        }
+    } testConfigs[] = {
+            {{addr1}, "", false, false},
+            {{addr2}, "", false, false},
+            {{addr1}, "", false, true},
+            {{addr2}, "", false, true},
+            {{addr1}, kDefaultPrivateDnsHostName, false, true},
+            {{addr2}, kDefaultPrivateDnsHostName, false, true},
+            {{addr1}, kDefaultPrivateDnsHostName, true, true},
+            {{addr2}, kDefaultPrivateDnsHostName, true, true},
+
+            // There's no new validation to start because there are already two validation threads
+            // running (one is for addr1, the other is for addr2). This is because the comparator
+            // doesn't compare DnsTlsServer.name. Keep the design as-is until it's known to be
+            // harmful.
+            {{addr1}, "", true, true},
+            {{addr2}, "", true, true},
+            {{addr1}, "", true, true},
+            {{addr2}, "", true, true},
+    };
+
+    for (const auto& serverState : {WORKING, UNSUPPORTED, UNRESPONSIVE}) {
+        int testIndex = 0;
+        for (const auto& config : testConfigs) {
+            SCOPED_TRACE(fmt::format("serverState:{} testIndex:{} testConfig:[{}]", serverState,
+                                     testIndex++, config.asTestName()));
+            auto& tls = (config.tlsServer == addr1) ? tls1 : tls2;
+
+            if (serverState == UNSUPPORTED && tls.running()) ASSERT_TRUE(tls.stopServer());
+            if (serverState != UNSUPPORTED && !tls.running()) ASSERT_TRUE(tls.startServer());
+
+            tls.setHangOnHandshakeForTesting(serverState == UNRESPONSIVE);
+            const int connectCountsBefore = tls.acceptConnectionsCount();
+
+            waitForPrivateDnsStateUpdated();
+            ResolverParamsParcel parcel = DnsResponderClient::GetDefaultResolverParamsParcel();
+            parcel.servers = {config.tlsServer};
+            parcel.tlsServers = {config.tlsServer};
+            parcel.tlsName = config.tlsName;
+            parcel.caCertificate = config.tlsName.empty() ? "" : kCaCert;
+            ASSERT_TRUE(mDnsClient.SetResolversFromParcel(parcel));
+
+            if (serverState == WORKING) {
+                EXPECT_TRUE(WaitForPrivateDnsValidation(config.tlsServer, true));
+            } else if (serverState == UNSUPPORTED) {
+                if (config.expectNothingHappenWhenServerUnsupported) {
+                    // It's possible that the resolver hasn't yet started to
+                    // connect. Wait a while.
+                    // TODO: See if we can get rid of the hard waiting time, such as comparing
+                    // the CountDiff across two tests.
+                    std::this_thread::sleep_for(100ms);
+                    EXPECT_EQ(tls.acceptConnectionsCount(), connectCountsBefore);
+                } else {
+                    EXPECT_TRUE(WaitForPrivateDnsValidation(config.tlsServer, false));
+                }
+            } else {
+                // Must be UNRESPONSIVE.
+                // DnsTlsFrontend is the only signal for checking whether or not the resolver starts
+                // another validation when the server is unresponsive.
+                const int expectCountDiff =
+                        config.expectNothingHappenWhenServerUnresponsive ? 0 : 1;
+                if (expectCountDiff == 0) {
+                    // It's possible that the resolver hasn't yet started to
+                    // connect. Wait a while.
+                    std::this_thread::sleep_for(100ms);
+                }
+                const auto condition = [&]() {
+                    return tls.acceptConnectionsCount() == connectCountsBefore + expectCountDiff;
+                };
+                EXPECT_TRUE(PollForCondition(condition));
+            }
+        }
+
+        // Set to off mode to reset the PrivateDnsConfiguration state.
+        ResolverParamsParcel setupOffmode = DnsResponderClient::GetDefaultResolverParamsParcel();
+        setupOffmode.tlsServers.clear();
+        ASSERT_TRUE(mDnsClient.SetResolversFromParcel(setupOffmode));
+    }
+
+    // Check that all the validation results are caught.
+    // Note: it doesn't mean no validation being in progress.
+    EXPECT_FALSE(hasUncaughtPrivateDnsValidation(addr1));
+    EXPECT_FALSE(hasUncaughtPrivateDnsValidation(addr2));
+}
+
 // Parameterized tests.
 // TODO: Merge the existing tests as parameterized test if possible.
 // TODO: Perhaps move parameterized tests to an independent file.
diff --git a/tests/resolv_stress_test_config.xml b/tests/resolv_stress_test_config.xml
deleted file mode 100644
index 09ebdbc..0000000
--- a/tests/resolv_stress_test_config.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2019 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<configuration description="Config for resolv_stress_test.">
-    <option name="test-suite-tag" value="apct" />
-    <option name="test-suite-tag" value="apct-native" />
-    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
-        <option name="cleanup" value="true" />
-        <option name="push" value="resolv_stress_test->/data/local/tmp/resolv_stress_test" />
-    </target_preparer>
-    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
-
-    <test class="com.android.tradefed.testtype.GTest" >
-        <option name="native-test-device-path" value="/data/local/tmp" />
-        <option name="module-name" value="resolv_stress_test" />
-        <!--
-            On 2018-12-12, GetAddrInfoStressTest_Binder_100 suddenly jumped
-            from ~1xs to ~70s runtime in APCT continuous integration, causing
-            resolv_integration_test to flake with the default 60s timeout.
-            We're not sure what caused the regression, but it's not due to a change
-            in the Android image and unlikely to affect users.
-            Just bump the timeout to 120s for now.
-        -->
-        <option name="native-test-timeout" value="120000" />
-    </test>
-</configuration>
diff --git a/tests/resolv_test_utils.cpp b/tests/resolv_test_utils.cpp
index 31245f3..3c129a2 100644
--- a/tests/resolv_test_utils.cpp
+++ b/tests/resolv_test_utils.cpp
@@ -19,6 +19,7 @@
 
 #include <arpa/inet.h>
 
+#include <android-base/chrono_utils.h>
 #include <netdutils/InternetAddresses.h>
 
 using android::netdutils::ScopedAddrinfo;
@@ -34,14 +35,12 @@
 
 std::string ToString(const addrinfo* ai) {
     if (!ai) return "<null>";
-    for (const auto* aip = ai; aip != nullptr; aip = aip->ai_next) {
-        char host[NI_MAXHOST];
-        int rv = getnameinfo(aip->ai_addr, aip->ai_addrlen, host, sizeof(host), nullptr, 0,
-                             NI_NUMERICHOST);
-        if (rv != 0) return gai_strerror(rv);
-        return host;
-    }
-    return "<invalid>";
+
+    char host[NI_MAXHOST];
+    int rv = getnameinfo(ai->ai_addr, ai->ai_addrlen, host, sizeof(host), nullptr, 0,
+                         NI_NUMERICHOST);
+    if (rv != 0) return gai_strerror(rv);
+    return host;
 }
 
 std::string ToString(const ScopedAddrinfo& ai) {
@@ -137,3 +136,13 @@
     }
     return found;
 }
+
+bool PollForCondition(const std::function<bool()>& condition, std::chrono::milliseconds timeout) {
+    constexpr std::chrono::milliseconds retryIntervalMs{5};
+    android::base::Timer t;
+    while (t.duration() < timeout) {
+        if (condition()) return true;
+        std::this_thread::sleep_for(retryIntervalMs);
+    }
+    return false;
+}
diff --git a/tests/resolv_test_utils.h b/tests/resolv_test_utils.h
index 5495185..2177510 100644
--- a/tests/resolv_test_utils.h
+++ b/tests/resolv_test_utils.h
@@ -142,3 +142,7 @@
 std::vector<std::string> ToStrings(const hostent* he);
 std::vector<std::string> ToStrings(const addrinfo* ai);
 std::vector<std::string> ToStrings(const android::netdutils::ScopedAddrinfo& ai);
+
+// Wait for |condition| to be met until |timeout|.
+bool PollForCondition(const std::function<bool()>& condition,
+                      std::chrono::milliseconds timeout = std::chrono::milliseconds(1000));
diff --git a/tests/testdata/pb/getaddrinfo.tls.topsite.google.pb b/tests/testdata/pb/getaddrinfo.tls.topsite.google.pb
deleted file mode 100644
index f314333..0000000
--- a/tests/testdata/pb/getaddrinfo.tls.topsite.google.pb
+++ /dev/null
Binary files differ
diff --git a/tests/testdata/pb/getaddrinfo.topsite.amazon.pb b/tests/testdata/pb/getaddrinfo.topsite.amazon.pb
deleted file mode 100644
index 7f9f047..0000000
--- a/tests/testdata/pb/getaddrinfo.topsite.amazon.pb
+++ /dev/null
Binary files differ
diff --git a/tests/testdata/pb/getaddrinfo.topsite.bing.pb b/tests/testdata/pb/getaddrinfo.topsite.bing.pb
deleted file mode 100644
index 714adfb..0000000
--- a/tests/testdata/pb/getaddrinfo.topsite.bing.pb
+++ /dev/null
Binary files differ
diff --git a/tests/testdata/pb/getaddrinfo.topsite.ebay.pb b/tests/testdata/pb/getaddrinfo.topsite.ebay.pb
deleted file mode 100644
index 679320a..0000000
--- a/tests/testdata/pb/getaddrinfo.topsite.ebay.pb
+++ /dev/null
Binary files differ
diff --git a/tests/testdata/pb/getaddrinfo.topsite.facebook.pb b/tests/testdata/pb/getaddrinfo.topsite.facebook.pb
deleted file mode 100644
index f3a8015..0000000
--- a/tests/testdata/pb/getaddrinfo.topsite.facebook.pb
+++ /dev/null
Binary files differ
diff --git a/tests/testdata/pb/getaddrinfo.topsite.google.pb b/tests/testdata/pb/getaddrinfo.topsite.google.pb
deleted file mode 100644
index 70502b8..0000000
--- a/tests/testdata/pb/getaddrinfo.topsite.google.pb
+++ /dev/null
Binary files differ
diff --git a/tests/testdata/pb/getaddrinfo.topsite.netflix.pb b/tests/testdata/pb/getaddrinfo.topsite.netflix.pb
deleted file mode 100644
index ed415fa..0000000
--- a/tests/testdata/pb/getaddrinfo.topsite.netflix.pb
+++ /dev/null
Binary files differ
diff --git a/tests/testdata/pb/getaddrinfo.topsite.reddit.pb b/tests/testdata/pb/getaddrinfo.topsite.reddit.pb
deleted file mode 100644
index fe8eb22..0000000
--- a/tests/testdata/pb/getaddrinfo.topsite.reddit.pb
+++ /dev/null
Binary files differ
diff --git a/tests/testdata/pb/getaddrinfo.topsite.wikipedia.pb b/tests/testdata/pb/getaddrinfo.topsite.wikipedia.pb
deleted file mode 100644
index 56455b4..0000000
--- a/tests/testdata/pb/getaddrinfo.topsite.wikipedia.pb
+++ /dev/null
Binary files differ
diff --git a/tests/testdata/pb/getaddrinfo.topsite.yahoo.pb b/tests/testdata/pb/getaddrinfo.topsite.yahoo.pb
deleted file mode 100644
index 924378e..0000000
--- a/tests/testdata/pb/getaddrinfo.topsite.yahoo.pb
+++ /dev/null
Binary files differ
diff --git a/tests/testdata/pb/getaddrinfo.topsite.youtube.pb b/tests/testdata/pb/getaddrinfo.topsite.youtube.pb
deleted file mode 100644
index c6b0204..0000000
--- a/tests/testdata/pb/getaddrinfo.topsite.youtube.pb
+++ /dev/null
Binary files differ
diff --git a/tests/testdata/pb/gethostbyname.tls.topsite.youtube.pb b/tests/testdata/pb/gethostbyname.tls.topsite.youtube.pb
deleted file mode 100644
index 6253c22..0000000
--- a/tests/testdata/pb/gethostbyname.tls.topsite.youtube.pb
+++ /dev/null
Binary files differ
diff --git a/tests/testdata/pb/gethostbyname.topsite.youtube.pb b/tests/testdata/pb/gethostbyname.topsite.youtube.pb
deleted file mode 100644
index 505b40a..0000000
--- a/tests/testdata/pb/gethostbyname.topsite.youtube.pb
+++ /dev/null
Binary files differ