Implement DoT revalidation

The revalidation starts from DnsTlsDispatcher which uses a counter
for counting the number of continuous network_error failures of a
DoT server. The mechanics works for private DNS opportunistic mode.

- Once the counter reaches dot_revalidation_threshold, DnsTlsDispatcher
  sends a revalidation request to PrivateDnsConfiguration to validate
  the DoT server.
- Once the counter reaches dot_xport_unusable_threshold, DnsTlsDispatcher
  marks the transport of the DoT server as unusable. The DoT server
  won't be used for at least 5 minutes.

DoT revalidation runs when the followings are met:
  [1] the private DNS setting is opportunistic mode
  [2] the requested DoT server is valid to be used on the network
  [3] the requested DoT server is currently marked as Validation::success

The above mechanics runs when the feature flag "dot_revalidation_threshold"
is a positive and zon-zero value, and is -1 when the mechanics is
disabled.

Bug: 79727473
Test: atest when all the flags off
        dot_revalidation_threshold: -1
        dot_async_handshake: 0
        dot_xport_unusable_threshold: -1
        dot_maxtries: 3
        parallel_lookup_sleep_time: 2
        dot_connect_timeout_ms: 127000
        parallel_lookup_release: 0
        sort_nameservers: 0
        keep_listening_udp: 0

Test: atest when all the flags on
        dot_revalidation_threshold: 10
        dot_async_handshake: 1
        dot_xport_unusable_threshold: 20
        dot_maxtries: 1
        parallel_lookup_sleep_time: 2
        dot_connect_timeout_ms: 10000
        parallel_lookup_release: 1
        sort_nameservers: 1
        keep_listening_udp: 1

Change-Id: Id442529468d63156a9aebf30ea5f142dfa689a97
diff --git a/PrivateDnsConfiguration.cpp b/PrivateDnsConfiguration.cpp
index c8b070a..610d55b 100644
--- a/PrivateDnsConfiguration.cpp
+++ b/PrivateDnsConfiguration.cpp
@@ -110,14 +110,14 @@
 
         if (needsValidation(server)) {
             updateServerState(identity, Validation::in_process, netId);
-            startValidation(server, netId);
+            startValidation(server, netId, false);
         }
     }
 
     return 0;
 }
 
-PrivateDnsStatus PrivateDnsConfiguration::getStatus(unsigned netId) {
+PrivateDnsStatus PrivateDnsConfiguration::getStatus(unsigned netId) const {
     PrivateDnsStatus status{PrivateDnsMode::OFF, {}};
     std::lock_guard guard(mPrivateDnsLock);
 
@@ -144,41 +144,55 @@
     mPrivateDnsTransports.erase(netId);
 }
 
-bool PrivateDnsConfiguration::requestValidation(unsigned netId, const DnsTlsServer& server,
-                                                uint32_t mark) {
+base::Result<void> PrivateDnsConfiguration::requestValidation(unsigned netId,
+                                                              const DnsTlsServer& server,
+                                                              uint32_t mark) {
     std::lock_guard guard(mPrivateDnsLock);
+
+    // Running revalidation requires to mark the server as in_process, which means the server
+    // won't be used until the validation passes. It's necessary and safe to run revalidation
+    // when in private DNS opportunistic mode, because there's a fallback mechanics even if
+    // all of the private DNS servers are in in_process state.
+    if (auto it = mPrivateDnsModes.find(netId); it == mPrivateDnsModes.end()) {
+        return Errorf("NetId not found in mPrivateDnsModes");
+    } else if (it->second != PrivateDnsMode::OPPORTUNISTIC) {
+        return Errorf("Private DNS setting is not opportunistic mode");
+    }
+
     auto netPair = mPrivateDnsTransports.find(netId);
     if (netPair == mPrivateDnsTransports.end()) {
-        return false;
+        return Errorf("NetId not found in mPrivateDnsTransports");
     }
 
     auto& tracker = netPair->second;
     const ServerIdentity identity = ServerIdentity(server);
     auto it = tracker.find(identity);
     if (it == tracker.end()) {
-        return false;
+        return Errorf("Server was removed");
     }
 
     const DnsTlsServer& target = it->second;
 
-    if (!target.active()) return false;
+    if (!target.active()) return Errorf("Server is not active");
 
-    if (target.validationState() != Validation::success) return false;
+    if (target.validationState() != Validation::success) {
+        return Errorf("Server validation state mismatched");
+    }
 
     // Don't run the validation if |mark| (from android_net_context.dns_mark) is different.
     // This is to protect validation from running on unexpected marks.
     // Validation should be associated with a mark gotten by system permission.
-    if (target.mark != mark) return false;
+    if (target.mark != mark) return Errorf("Socket mark mismatched");
 
     updateServerState(identity, Validation::in_process, netId);
-    startValidation(target, netId);
-    return true;
+    startValidation(target, netId, true);
+    return {};
 }
 
-void PrivateDnsConfiguration::startValidation(const DnsTlsServer& server, unsigned netId)
-        REQUIRES(mPrivateDnsLock) {
-    // Note that capturing |server| and |netId| in this lambda create copies.
-    std::thread validate_thread([this, server, netId] {
+void PrivateDnsConfiguration::startValidation(const DnsTlsServer& server, unsigned netId,
+                                              bool isRevalidation) REQUIRES(mPrivateDnsLock) {
+    // Note that capturing |server|, |netId|, and |isRevalidation| in this lambda create copies.
+    std::thread validate_thread([this, server, netId, isRevalidation] {
         setThreadName(StringPrintf("TlsVerify_%u", netId).c_str());
 
         // cat /proc/sys/net/ipv4/tcp_syn_retries yields "6".
@@ -208,7 +222,9 @@
             LOG(WARNING) << "validateDnsTlsServer returned " << success << " for "
                          << server.toIpString();
 
-            const bool needs_reeval = this->recordPrivateDnsValidation(server, netId, success);
+            const bool needs_reeval =
+                    this->recordPrivateDnsValidation(server, netId, success, isRevalidation);
+
             if (!needs_reeval) {
                 break;
             }
@@ -254,7 +270,7 @@
 }
 
 bool PrivateDnsConfiguration::recordPrivateDnsValidation(const DnsTlsServer& server, unsigned netId,
-                                                         bool success) {
+                                                         bool success, bool isRevalidation) {
     constexpr bool NEEDS_REEVALUATION = true;
     constexpr bool DONT_REEVALUATE = false;
     const ServerIdentity identity = ServerIdentity(server);
@@ -274,10 +290,15 @@
         notifyValidationStateUpdate(identity.ip.toString(), Validation::fail, netId);
         return DONT_REEVALUATE;
     }
-    const bool modeDoesReevaluation = (mode->second == PrivateDnsMode::STRICT);
 
-    bool reevaluationStatus =
-            (success || !modeDoesReevaluation) ? DONT_REEVALUATE : NEEDS_REEVALUATION;
+    bool reevaluationStatus = NEEDS_REEVALUATION;
+    if (success) {
+        reevaluationStatus = DONT_REEVALUATE;
+    } else if (mode->second == PrivateDnsMode::OFF) {
+        reevaluationStatus = DONT_REEVALUATE;
+    } else if (mode->second == PrivateDnsMode::OPPORTUNISTIC && !isRevalidation) {
+        reevaluationStatus = DONT_REEVALUATE;
+    }
 
     auto& tracker = netPair->second;
     auto serverPair = tracker.find(identity);