Allow changing retry limit and timeout via experiment flags.

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

Change-Id: Ica8f2ccddc60f2b8e006ac6923064b6171a13821
diff --git a/resolv/Android.bp b/resolv/Android.bp
index a54245f..7f0df77 100644
--- a/resolv/Android.bp
+++ b/resolv/Android.bp
@@ -54,6 +54,7 @@
         "libsysutils",
         "netd_event_listener_interface-ndk_platform",
         "dnsresolver_aidl_interface-ndk_platform",
+        "server_configurable_flags",
     ],
     shared_libs: [
         "libbinder_ndk",
@@ -131,5 +132,6 @@
         "libnetd_resolv",
         "libnetd_test_dnsresponder",
         "libnetdutils",
+        "server_configurable_flags",
     ],
 }
diff --git a/resolv/dns_responder/dns_responder_client.h b/resolv/dns_responder/dns_responder_client.h
index b31d987..6dc6ae3 100644
--- a/resolv/dns_responder/dns_responder_client.h
+++ b/resolv/dns_responder/dns_responder_client.h
@@ -35,11 +35,11 @@
 inline const std::vector<std::string> kDefaultServers = {"127.0.0.3"};
 inline const std::vector<std::string> kDefaultSearchDomains = {"example.com"};
 inline const std::vector<int> kDefaultParams = {
-        300,     // sample validity in seconds
-        25,      // success threshod in percent
-        8,   8,  // {MIN,MAX}_SAMPLES
-        100,     // BASE_TIMEOUT_MSEC
-        2,       // retry count
+        300,      // sample validity in seconds
+        25,       // success threshod in percent
+        8,    8,  // {MIN,MAX}_SAMPLES
+        1000,     // BASE_TIMEOUT_MSEC
+        2,        // retry count
 };
 
 class DnsResponderClient {
diff --git a/resolv/libnetd_resolv_test.cpp b/resolv/libnetd_resolv_test.cpp
index f4812a6..d5b1b73 100644
--- a/resolv/libnetd_resolv_test.cpp
+++ b/resolv/libnetd_resolv_test.cpp
@@ -84,7 +84,8 @@
             .success_threshold = 25,
             .min_samples = 8,
             .max_samples = 8,
-            .base_timeout_msec = 100,
+            .base_timeout_msec = 1000,
+            .retry_count = 2,
     };
     const android_net_context mNetcontext = {
             .app_netid = TEST_NETID,
diff --git a/resolv/res_cache.cpp b/resolv/res_cache.cpp
index ad5a2c5..53122f6 100644
--- a/resolv/res_cache.cpp
+++ b/resolv/res_cache.cpp
@@ -46,9 +46,12 @@
 #include <netdb.h>
 
 #include <android-base/logging.h>
+#include <android-base/parseint.h>
 #include <android-base/thread_annotations.h>
 #include <android/multinetwork.h>  // ResNsendFlags
 
+#include <server_configurable_flags/get_flags.h>
+
 #include "res_state_ext.h"
 #include "resolv_private.h"
 
@@ -1674,6 +1677,22 @@
     params->retry_count = 0;
 }
 
+static void resolv_set_experiment_params(res_params* params) {
+    using android::base::ParseInt;
+    using server_configurable_flags::GetServerConfigurableFlag;
+
+    if (params->retry_count == 0) {
+        params->retry_count = RES_DFLRETRY;
+        ParseInt(GetServerConfigurableFlag("netd_native", "retry_count", ""), &params->retry_count);
+    }
+
+    if (params->base_timeout_msec == 0) {
+        params->base_timeout_msec = RES_TIMEOUT;
+        ParseInt(GetServerConfigurableFlag("netd_native", "retransmission_time_interval", ""),
+                 &params->base_timeout_msec);
+    }
+}
+
 int resolv_set_nameservers_for_net(unsigned netid, const char** servers, const int numservers,
                                    const char* domains, const res_params* params) {
     char* cp;
@@ -1717,7 +1736,7 @@
         } else {
             resolv_set_default_params(&cache_info->params);
         }
-
+        resolv_set_experiment_params(&cache_info->params);
         if (!resolv_is_nameservers_equal_locked(cache_info, servers, numservers)) {
             // free current before adding new
             free_nameservers_locked(cache_info);
diff --git a/resolv/res_init.cpp b/resolv/res_init.cpp
index 921445c..7f11ce6 100644
--- a/resolv/res_init.cpp
+++ b/resolv/res_init.cpp
@@ -140,8 +140,6 @@
 
     if (!preinit) {
         statp->netid = NETID_UNSET;
-        statp->retrans = RES_TIMEOUT;
-        statp->retry = RES_DFLRETRY;
         statp->options = RES_DEFAULT;
         statp->id = arc4random_uniform(65536);
         statp->_mark = MARK_UNSET;
@@ -218,27 +216,8 @@
                 statp->ndots = i;
             else
                 statp->ndots = RES_MAXNDOTS;
-
             LOG(DEBUG) << ";;\tndots=" << statp->ndots;
 
-        } else if (!strncmp(cp, "timeout:", sizeof("timeout:") - 1)) {
-            i = atoi(cp + sizeof("timeout:") - 1);
-            if (i <= RES_MAXRETRANS)
-                statp->retrans = i;
-            else
-                statp->retrans = RES_MAXRETRANS;
-
-            LOG(DEBUG) << ";;\ttimeout=" << statp->retrans;
-
-        } else if (!strncmp(cp, "attempts:", sizeof("attempts:") - 1)) {
-            i = atoi(cp + sizeof("attempts:") - 1);
-            if (i <= RES_MAXRETRY)
-                statp->retry = i;
-            else
-                statp->retry = RES_MAXRETRY;
-
-            LOG(DEBUG) << ";;\tattempts=" << statp->retry;
-
         } else if (!strncmp(cp, "debug", sizeof("debug") - 1)) {
             if (!(statp->options & RES_DEBUG)) {
                 LOG(DEBUG) << ";; res_setoptions(\"" << options << "\", \"" << source << "\")..";
diff --git a/resolv/res_send.cpp b/resolv/res_send.cpp
index 118a081..daa86ec 100644
--- a/resolv/res_send.cpp
+++ b/resolv/res_send.cpp
@@ -512,12 +512,11 @@
         int selectedServer = (hp->id % usableServersCount) + 1;
         res_set_usable_server(selectedServer, 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;
+    int retryTimes = (flags & ANDROID_RESOLV_NO_RETRY) ? 1 : params.retry_count;
 
     for (int attempt = 0; attempt < retryTimes; ++attempt) {
 
@@ -685,20 +684,16 @@
 
 static struct timespec get_timeout(const res_state statp, const res_params* params, const int ns) {
     int msec;
-    if (params->base_timeout_msec != 0) {
-        // TODO: scale the timeout by retry attempt and maybe number of servers
-        msec = params->base_timeout_msec;
-    } else {
-        // Legacy algorithm which scales the timeout by nameserver number.
-        // For instance, with 4 nameservers: 5s, 2.5s, 5s, 10s
-        // This has no effect with 1 or 2 nameservers
-        msec = (statp->retrans * 1000) << ns;
-        if (ns > 0) {
-            msec /= statp->nscount;
-        }
-        if (msec < 1000) {
-            msec = 1000;  // Use at least 100ms
-        }
+    // Legacy algorithm which scales the timeout by nameserver number.
+    // For instance, with 4 nameservers: 5s, 2.5s, 5s, 10s
+    // This has no effect with 1 or 2 nameservers
+    msec = params->base_timeout_msec << ns;
+    if (ns > 0) {
+        msec /= statp->nscount;
+    }
+    // For safety, don't allow OEMs and experiments to configure a timeout shorter than 1s.
+    if (msec < 1000) {
+        msec = 1000;  // Use at least 1000ms
     }
     LOG(INFO) << "using timeout of " << msec << " msec";
 
diff --git a/resolv/resolv_private.h b/resolv/resolv_private.h
index 46590b8..9fb0d48 100644
--- a/resolv/resolv_private.h
+++ b/resolv/resolv_private.h
@@ -78,11 +78,9 @@
 #define MAXDFLSRCH 3       /* # default domain levels to try */
 #define LOCALDOMAINPARTS 2 /* min levels in name that is "local" */
 
-#define RES_TIMEOUT 5     /* min. seconds between retries */
+#define RES_TIMEOUT 5000 /* min. milliseconds between retries */
 #define MAXRESOLVSORT 10  /* number of net to sort on */
 #define RES_MAXNDOTS 15   /* should reflect bit field size */
-#define RES_MAXRETRANS 30 /* only for resolv.conf/RES_OPTIONS */
-#define RES_MAXRETRY 5    /* only for resolv.conf/RES_OPTIONS */
 #define RES_DFLRETRY 2    /* Default #/tries. */
 #define RES_MAXTIME 65535 /* Infinity, in milliseconds. */
 
@@ -90,8 +88,6 @@
 
 struct __res_state {
     unsigned netid;                        /* NetId: cache key and socket mark */
-    int retrans;                           /* retransmission time interval */
-    int retry;                             /* number of times to retransmit */
     u_long options;                        /* option flags - see below. */
     int nscount;                           /* number of name srvers */
     struct sockaddr_in nsaddr_list[MAXNS]; /* address of name server */