Add an API to flush cache on designated network

Flush entire cache on a specified network. The API acquires lock before
manipulate cache. It's thread-safe API.

Bug: 139646101
Test: atest resolv_cache_unit_test.cpp#FlushCache
Test: atest resolv_integration_test.cpp#FlushNetworkCache

Change-Id: I4ea34a256013468ceac21ce5067d6a493d8631f8
diff --git a/resolv_cache_unit_test.cpp b/resolv_cache_unit_test.cpp
index 997a58a..900b8f5 100644
--- a/resolv_cache_unit_test.cpp
+++ b/resolv_cache_unit_test.cpp
@@ -25,6 +25,7 @@
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 #include <android/multinetwork.h>
+#include <arpa/inet.h>
 #include <cutils/properties.h>
 #include <gmock/gmock-matchers.h>
 #include <gtest/gtest.h>
@@ -39,6 +40,7 @@
 
 constexpr int TEST_NETID = 30;
 constexpr int TEST_NETID_2 = 31;
+constexpr int DNS_PORT = 53;
 
 // Constant values sync'd from res_cache.cpp
 constexpr int DNS_HEADER_SIZE = 12;
@@ -188,6 +190,13 @@
         return resolv_set_nameservers(netId, setup.servers, setup.domains, setup.params);
     }
 
+    void cacheAddStats(uint32_t netId, int revision_id, const sockaddr* sa,
+                       const res_sample& sample, int max_samples) {
+        resolv_cache_add_resolver_stats_sample(netId, revision_id, sa, sample, max_samples);
+    }
+
+    int cacheFlush(uint32_t netId) { return resolv_flush_cache_for_net(netId); }
+
     void expectCacheStats(const std::string& msg, uint32_t netId, const CacheStats& expected) {
         int nscount = -1;
         sockaddr_storage servers[MAXNS];
@@ -713,6 +722,38 @@
     expectCacheStats("GetStats", TEST_NETID, cacheStats);
 }
 
+TEST_F(ResolvCacheTest, FlushCache) {
+    EXPECT_EQ(0, cacheCreate(TEST_NETID));
+    const SetupParams setup = {
+            .servers = {"127.0.0.1", "::127.0.0.2", "fe80::3"},
+            .domains = {"domain1.com", "domain2.com"},
+            .params = kParams,
+    };
+    EXPECT_EQ(0, cacheSetupResolver(TEST_NETID, setup));
+    EXPECT_TRUE(resolv_has_nameservers(TEST_NETID));
+
+    res_sample sample = {.at = time(NULL), .rtt = 100, .rcode = ns_r_noerror};
+    sockaddr_in sin = {.sin_family = AF_INET, .sin_port = htons(DNS_PORT)};
+    ASSERT_TRUE(inet_pton(AF_INET, setup.servers[0].c_str(), &sin.sin_addr));
+    cacheAddStats(TEST_NETID, 1 /*revision_id*/, (const sockaddr*)&sin, sample,
+                  setup.params.max_samples);
+
+    const CacheStats cacheStats = {
+            .setup = setup,
+            .stats = {{{sample}, 1 /*sample_count*/, 1 /*sample_next*/}},
+            .pendingReqTimeoutCount = 0,
+    };
+    expectCacheStats("FlushCache: a record in cache stats", TEST_NETID, cacheStats);
+
+    EXPECT_EQ(0, cacheFlush(TEST_NETID));
+    const CacheStats cacheStats_empty = {
+            .setup = setup,
+            .stats = {},
+            .pendingReqTimeoutCount = 0,
+    };
+    expectCacheStats("FlushCache: no record in cache stats", TEST_NETID, cacheStats_empty);
+}
+
 TEST_F(ResolvCacheTest, GetHostByAddrFromCache_InvalidArgs) {
     char domain_name[NS_MAXDNAME] = {};
     const char query_v4[] = "1.2.3.5";