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_integration_test.cpp b/resolv_integration_test.cpp
index 0129f92..3f37c29 100644
--- a/resolv_integration_test.cpp
+++ b/resolv_integration_test.cpp
@@ -3532,6 +3532,101 @@
     EXPECT_LE(timeTakenMs, expectedTimeout);
 }
 
+TEST_F(ResolverTest, FlushNetworkCache) {
+    test::DNSResponder dns;
+    StartDns(dns, {{kHelloExampleCom, ns_type::ns_t_a, kHelloExampleComAddrV4}});
+    ASSERT_TRUE(mDnsClient.SetResolversForNetwork());
+
+    const hostent* result = gethostbyname("hello");
+    EXPECT_EQ(1U, GetNumQueriesForType(dns, ns_type::ns_t_a, kHelloExampleCom));
+
+    // get result from cache
+    result = gethostbyname("hello");
+    EXPECT_EQ(1U, GetNumQueriesForType(dns, ns_type::ns_t_a, kHelloExampleCom));
+
+    EXPECT_TRUE(mDnsClient.resolvService()->flushNetworkCache(TEST_NETID).isOk());
+
+    result = gethostbyname("hello");
+    EXPECT_EQ(2U, GetNumQueriesForType(dns, ns_type::ns_t_a, kHelloExampleCom));
+}
+
+TEST_F(ResolverTest, FlushNetworkCache_random) {
+    constexpr int num_flush = 10;
+    constexpr int num_queries = 20;
+    test::DNSResponder dns;
+    StartDns(dns, {{kHelloExampleCom, ns_type::ns_t_a, kHelloExampleComAddrV4}});
+    ASSERT_TRUE(mDnsClient.SetResolversForNetwork());
+    const addrinfo hints = {.ai_family = AF_INET};
+
+    std::thread t([this]() {
+        for (int i = 0; i < num_flush; ++i) {
+            unsigned delay = arc4random_uniform(10 * 1000);  // 10ms
+            usleep(delay);
+            EXPECT_TRUE(mDnsClient.resolvService()->flushNetworkCache(TEST_NETID).isOk());
+        }
+    });
+
+    for (int i = 0; i < num_queries; ++i) {
+        ScopedAddrinfo result = safe_getaddrinfo("hello", nullptr, &hints);
+        EXPECT_TRUE(result != nullptr);
+        EXPECT_EQ(kHelloExampleComAddrV4, ToString(result));
+    }
+    t.join();
+}
+
+// flush cache while one query is wait-for-response, another is pending.
+TEST_F(ResolverTest, FlushNetworkCache_concurrent) {
+    const char* listen_addr1 = "127.0.0.9";
+    const char* listen_addr2 = "127.0.0.10";
+    test::DNSResponder dns1(listen_addr1);
+    test::DNSResponder dns2(listen_addr2);
+    StartDns(dns1, {{kHelloExampleCom, ns_type::ns_t_a, kHelloExampleComAddrV4}});
+    StartDns(dns2, {{kHelloExampleCom, ns_type::ns_t_a, kHelloExampleComAddrV4}});
+    addrinfo hints = {.ai_family = AF_INET};
+
+    // step 1: set server#1 into deferred responding mode
+    dns1.setDeferredResp(true);
+    std::thread t1([&listen_addr1, &hints, this]() {
+        ASSERT_TRUE(mDnsClient.SetResolversForNetwork({listen_addr1}));
+        // step 3: query
+        ScopedAddrinfo result = safe_getaddrinfo("hello", nullptr, &hints);
+        // step 9: check result
+        EXPECT_TRUE(result != nullptr);
+        EXPECT_EQ(kHelloExampleComAddrV4, ToString(result));
+    });
+
+    // step 2: wait for the query to reach the server
+    while (GetNumQueries(dns1, kHelloExampleCom) == 0) {
+        usleep(1000);  // 1ms
+    }
+
+    std::thread t2([&listen_addr2, &hints, &dns2, this]() {
+        ASSERT_TRUE(mDnsClient.SetResolversForNetwork({listen_addr2}));
+        // step 5: query (should be blocked in resolver)
+        ScopedAddrinfo result = safe_getaddrinfo("hello", nullptr, &hints);
+        // step 7: check result
+        EXPECT_TRUE(result != nullptr);
+        EXPECT_EQ(kHelloExampleComAddrV4, ToString(result));
+        EXPECT_EQ(1U, GetNumQueriesForType(dns2, ns_type::ns_t_a, kHelloExampleCom));
+    });
+
+    // step 4: wait a bit for the 2nd query to enter pending state
+    usleep(100 * 1000);  // 100ms
+    // step 6: flush cache (will unblock pending queries)
+    EXPECT_TRUE(mDnsClient.resolvService()->flushNetworkCache(TEST_NETID).isOk());
+    t2.join();
+
+    // step 8: resume server#1
+    dns1.setDeferredResp(false);
+    t1.join();
+
+    // step 10: verify if result is correctly cached
+    dns2.clearQueries();
+    ScopedAddrinfo result = safe_getaddrinfo("hello", nullptr, &hints);
+    EXPECT_EQ(0U, GetNumQueries(dns2, kHelloExampleCom));
+    EXPECT_EQ(kHelloExampleComAddrV4, ToString(result));
+}
+
 // Parameterized tests.
 // TODO: Merge the existing tests as parameterized test if possible.
 // TODO: Perhaps move parameterized tests to an independent file.