Add RESOLVER_PARAMS_RETRY_COUNT for configuring the retries.

Test: built / flashed / booted
      netd_unit_test, netd_integration_test, libnetd_resolv_test

Change-Id: I68db331b3c8ad8e43696816642f4d5941138c8bc
diff --git a/dns_responder/dns_responder_client.h b/dns_responder/dns_responder_client.h
index f3440f2..b31d987 100644
--- a/dns_responder/dns_responder_client.h
+++ b/dns_responder/dns_responder_client.h
@@ -39,6 +39,7 @@
         25,      // success threshod in percent
         8,   8,  // {MIN,MAX}_SAMPLES
         100,     // BASE_TIMEOUT_MSEC
+        2,       // retry count
 };
 
 class DnsResponderClient {
diff --git a/include/netd_resolv/params.h b/include/netd_resolv/params.h
index 939bfc4..c565753 100644
--- a/include/netd_resolv/params.h
+++ b/include/netd_resolv/params.h
@@ -34,6 +34,7 @@
     uint8_t min_samples;        // min # samples needed for statistics to be considered meaningful
     uint8_t max_samples;        // max # samples taken into account for statistics
     int base_timeout_msec;      // base query retry timeout (if 0, use RES_TIMEOUT)
+    int retry_count;            // number of retries
 };
 
 // The DNS over TLS mode on a specific netId.
diff --git a/res_cache.cpp b/res_cache.cpp
index 756844c..d766baf 100644
--- a/res_cache.cpp
+++ b/res_cache.cpp
@@ -1712,6 +1712,7 @@
     params->min_samples = 0;
     params->max_samples = 0;
     params->base_timeout_msec = 0;  // 0 = legacy algorithm
+    params->retry_count = 0;
 }
 
 int resolv_set_nameservers_for_net(unsigned netid, const char** servers, const int numservers,
diff --git a/res_send.cpp b/res_send.cpp
index 06cdb5b..0f048b4 100644
--- a/res_send.cpp
+++ b/res_send.cpp
@@ -506,17 +506,19 @@
         statp->_u._ext.nstimes[lastns] = nstime;
     }
 
+    struct res_stats stats[MAXNS];
+    struct __res_params params;
+    int revision_id = resolv_cache_get_resolver_stats(statp->netid, &params, stats);
+    bool usable_servers[MAXNS];
+    android_net_res_stats_get_usable_servers(&params, stats, statp->nscount, usable_servers);
+    if (params.retry_count != 0) statp->retry = params.retry_count;
+
     /*
      * Send request, RETRY times, or until successful.
      */
     int retryTimes = (flags & ANDROID_RESOLV_NO_RETRY) ? 1 : statp->retry;
 
     for (int attempt = 0; attempt < retryTimes; ++attempt) {
-        struct res_stats stats[MAXNS];
-        struct __res_params params;
-        int revision_id = resolv_cache_get_resolver_stats(statp->netid, &params, stats);
-        bool usable_servers[MAXNS];
-        android_net_res_stats_get_usable_servers(&params, stats, statp->nscount, usable_servers);
 
         for (int ns = 0; ns < statp->nscount; ns++) {
             if (!usable_servers[ns]) continue;
diff --git a/resolver_test.cpp b/resolver_test.cpp
index 4be5f48..623ec79 100644
--- a/resolver_test.cpp
+++ b/resolver_test.cpp
@@ -133,16 +133,15 @@
         if (!rv.isOk() || params32.size() != static_cast<size_t>(INetd::RESOLVER_PARAMS_COUNT)) {
             return false;
         }
-        *params = __res_params {
-            .sample_validity = static_cast<uint16_t>(
-                    params32[INetd::RESOLVER_PARAMS_SAMPLE_VALIDITY]),
-            .success_threshold = static_cast<uint8_t>(
-                    params32[INetd::RESOLVER_PARAMS_SUCCESS_THRESHOLD]),
-            .min_samples = static_cast<uint8_t>(
-                    params32[INetd::RESOLVER_PARAMS_MIN_SAMPLES]),
-            .max_samples = static_cast<uint8_t>(
-                    params32[INetd::RESOLVER_PARAMS_MAX_SAMPLES]),
-            .base_timeout_msec = params32[INetd::RESOLVER_PARAMS_BASE_TIMEOUT_MSEC],
+        *params = __res_params{
+                .sample_validity =
+                        static_cast<uint16_t>(params32[INetd::RESOLVER_PARAMS_SAMPLE_VALIDITY]),
+                .success_threshold =
+                        static_cast<uint8_t>(params32[INetd::RESOLVER_PARAMS_SUCCESS_THRESHOLD]),
+                .min_samples = static_cast<uint8_t>(params32[INetd::RESOLVER_PARAMS_MIN_SAMPLES]),
+                .max_samples = static_cast<uint8_t>(params32[INetd::RESOLVER_PARAMS_MAX_SAMPLES]),
+                .base_timeout_msec = params32[INetd::RESOLVER_PARAMS_BASE_TIMEOUT_MSEC],
+                .retry_count = params32[INetd::RESOLVER_PARAMS_RETRY_COUNT],
         };
         *wait_for_pending_req_timeout_count = wait_for_pending_req_timeout_count32[0];
         return ResolverStats::decodeAll(stats32, stats);
@@ -433,11 +432,9 @@
 TEST_F(ResolverTest, BinderSerialization) {
     using android::net::INetd;
     std::vector<int> params_offsets = {
-        INetd::RESOLVER_PARAMS_SAMPLE_VALIDITY,
-        INetd::RESOLVER_PARAMS_SUCCESS_THRESHOLD,
-        INetd::RESOLVER_PARAMS_MIN_SAMPLES,
-        INetd::RESOLVER_PARAMS_MAX_SAMPLES,
-        INetd::RESOLVER_PARAMS_BASE_TIMEOUT_MSEC,
+            INetd::RESOLVER_PARAMS_SAMPLE_VALIDITY,   INetd::RESOLVER_PARAMS_SUCCESS_THRESHOLD,
+            INetd::RESOLVER_PARAMS_MIN_SAMPLES,       INetd::RESOLVER_PARAMS_MAX_SAMPLES,
+            INetd::RESOLVER_PARAMS_BASE_TIMEOUT_MSEC, INetd::RESOLVER_PARAMS_RETRY_COUNT,
     };
     const int size = static_cast<int>(params_offsets.size());
     EXPECT_EQ(size, INetd::RESOLVER_PARAMS_COUNT);
@@ -888,6 +885,7 @@
     EXPECT_EQ(kDefaultParams[INetd::RESOLVER_PARAMS_MAX_SAMPLES], res_params.max_samples);
     EXPECT_EQ(kDefaultParams[INetd::RESOLVER_PARAMS_BASE_TIMEOUT_MSEC],
               res_params.base_timeout_msec);
+    EXPECT_EQ(kDefaultParams[INetd::RESOLVER_PARAMS_RETRY_COUNT], res_params.retry_count);
 }
 
 TEST_F(ResolverTest, SearchPathChange) {