Snap for 6617762 from c35b4541c3c7e7e7bd339a036ebe1ad9e94a10eb to rvc-release

Change-Id: I30b245ca8956fc9930dffd089ab91456a9763c16
diff --git a/Android.bp b/Android.bp
index 559b62d..f84f7ab 100644
--- a/Android.bp
+++ b/Android.bp
@@ -49,6 +49,7 @@
         "3",
         "4",
         "5",
+        "6",
     ],
 }
 
diff --git a/aidl_api/dnsresolver_aidl_interface/6/.hash b/aidl_api/dnsresolver_aidl_interface/6/.hash
new file mode 100644
index 0000000..77b34a4
--- /dev/null
+++ b/aidl_api/dnsresolver_aidl_interface/6/.hash
@@ -0,0 +1 @@
+5bc773534ffa9d7614ccd27d5de6daefdeeee2b8
diff --git a/aidl_api/dnsresolver_aidl_interface/6/android/net/IDnsResolver.aidl b/aidl_api/dnsresolver_aidl_interface/6/android/net/IDnsResolver.aidl
new file mode 100644
index 0000000..863927b
--- /dev/null
+++ b/aidl_api/dnsresolver_aidl_interface/6/android/net/IDnsResolver.aidl
@@ -0,0 +1,64 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+interface IDnsResolver {
+  boolean isAlive();
+  void registerEventListener(android.net.metrics.INetdEventListener listener);
+  void setResolverConfiguration(in android.net.ResolverParamsParcel resolverParams);
+  void getResolverInfo(int netId, out @utf8InCpp String[] servers, out @utf8InCpp String[] domains, out @utf8InCpp String[] tlsServers, out int[] params, out int[] stats, out int[] wait_for_pending_req_timeout_count);
+  void startPrefix64Discovery(int netId);
+  void stopPrefix64Discovery(int netId);
+  @utf8InCpp String getPrefix64(int netId);
+  void createNetworkCache(int netId);
+  void destroyNetworkCache(int netId);
+  void setLogSeverity(int logSeverity);
+  void flushNetworkCache(int netId);
+  void setPrefix64(int netId, @utf8InCpp String prefix);
+  const int RESOLVER_PARAMS_SAMPLE_VALIDITY = 0;
+  const int RESOLVER_PARAMS_SUCCESS_THRESHOLD = 1;
+  const int RESOLVER_PARAMS_MIN_SAMPLES = 2;
+  const int RESOLVER_PARAMS_MAX_SAMPLES = 3;
+  const int RESOLVER_PARAMS_BASE_TIMEOUT_MSEC = 4;
+  const int RESOLVER_PARAMS_RETRY_COUNT = 5;
+  const int RESOLVER_PARAMS_COUNT = 6;
+  const int RESOLVER_STATS_SUCCESSES = 0;
+  const int RESOLVER_STATS_ERRORS = 1;
+  const int RESOLVER_STATS_TIMEOUTS = 2;
+  const int RESOLVER_STATS_INTERNAL_ERRORS = 3;
+  const int RESOLVER_STATS_RTT_AVG = 4;
+  const int RESOLVER_STATS_LAST_SAMPLE_TIME = 5;
+  const int RESOLVER_STATS_USABLE = 6;
+  const int RESOLVER_STATS_COUNT = 7;
+  const int DNS_RESOLVER_LOG_VERBOSE = 0;
+  const int DNS_RESOLVER_LOG_DEBUG = 1;
+  const int DNS_RESOLVER_LOG_INFO = 2;
+  const int DNS_RESOLVER_LOG_WARNING = 3;
+  const int DNS_RESOLVER_LOG_ERROR = 4;
+  const int TC_MODE_DEFAULT = 0;
+  const int TC_MODE_UDP_TCP = 1;
+  const int TRANSPORT_UNKNOWN = -1;
+  const int TRANSPORT_CELLULAR = 0;
+  const int TRANSPORT_WIFI = 1;
+  const int TRANSPORT_BLUETOOTH = 2;
+  const int TRANSPORT_ETHERNET = 3;
+  const int TRANSPORT_VPN = 4;
+  const int TRANSPORT_WIFI_AWARE = 5;
+  const int TRANSPORT_LOWPAN = 6;
+  const int TRANSPORT_TEST = 7;
+}
diff --git a/aidl_api/dnsresolver_aidl_interface/6/android/net/ResolverHostsParcel.aidl b/aidl_api/dnsresolver_aidl_interface/6/android/net/ResolverHostsParcel.aidl
new file mode 100644
index 0000000..3ab0533
--- /dev/null
+++ b/aidl_api/dnsresolver_aidl_interface/6/android/net/ResolverHostsParcel.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+parcelable ResolverHostsParcel {
+  @utf8InCpp String ipAddr;
+  @utf8InCpp String hostName = "";
+}
diff --git a/aidl_api/dnsresolver_aidl_interface/6/android/net/ResolverOptionsParcel.aidl b/aidl_api/dnsresolver_aidl_interface/6/android/net/ResolverOptionsParcel.aidl
new file mode 100644
index 0000000..d55ae46
--- /dev/null
+++ b/aidl_api/dnsresolver_aidl_interface/6/android/net/ResolverOptionsParcel.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+parcelable ResolverOptionsParcel {
+  android.net.ResolverHostsParcel[] hosts = {};
+  int tcMode = 0;
+  boolean enforceDnsUid = false;
+}
diff --git a/aidl_api/dnsresolver_aidl_interface/6/android/net/ResolverParamsParcel.aidl b/aidl_api/dnsresolver_aidl_interface/6/android/net/ResolverParamsParcel.aidl
new file mode 100644
index 0000000..5dae1ca
--- /dev/null
+++ b/aidl_api/dnsresolver_aidl_interface/6/android/net/ResolverParamsParcel.aidl
@@ -0,0 +1,37 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+parcelable ResolverParamsParcel {
+  int netId;
+  int sampleValiditySeconds;
+  int successThreshold;
+  int minSamples;
+  int maxSamples;
+  int baseTimeoutMsec;
+  int retryCount;
+  @utf8InCpp String[] servers;
+  @utf8InCpp String[] domains;
+  @utf8InCpp String tlsName;
+  @utf8InCpp String[] tlsServers;
+  @utf8InCpp String[] tlsFingerprints = {};
+  @utf8InCpp String caCertificate = "";
+  int tlsConnectTimeoutMs = 0;
+  android.net.ResolverOptionsParcel resolverOptions;
+  int[] transportTypes = {};
+}
diff --git a/aidl_api/dnsresolver_aidl_interface/current/android/net/ResolverOptionsParcel.aidl b/aidl_api/dnsresolver_aidl_interface/current/android/net/ResolverOptionsParcel.aidl
index a13216a..d55ae46 100644
--- a/aidl_api/dnsresolver_aidl_interface/current/android/net/ResolverOptionsParcel.aidl
+++ b/aidl_api/dnsresolver_aidl_interface/current/android/net/ResolverOptionsParcel.aidl
@@ -20,4 +20,5 @@
 parcelable ResolverOptionsParcel {
   android.net.ResolverHostsParcel[] hosts = {};
   int tcMode = 0;
+  boolean enforceDnsUid = false;
 }
diff --git a/binder/android/net/ResolverOptionsParcel.aidl b/binder/android/net/ResolverOptionsParcel.aidl
index 8e435de..bca9fb6 100644
--- a/binder/android/net/ResolverOptionsParcel.aidl
+++ b/binder/android/net/ResolverOptionsParcel.aidl
@@ -43,4 +43,18 @@
      * Other values are invalid.
      */
     int tcMode = 0;
+
+    /**
+     * The default behavior is that plaintext DNS queries are sent by the application's UID using
+     * fchown(). DoT are sent with an UID of AID_DNS. This option control the plaintext uid of DNS
+     * query.
+     * Setting this option to true decreases battery life because it results in the device sending
+     * UDP DNS queries even if the app that made the DNS lookup does not have network access.
+     * Anecdotal data from the field suggests that about 15% of DNS lookups are in this category.
+     * This option also results in data usage for UDP DNS queries being attributed to the OS instead
+     * of to the requesting app.
+     * false: set application uid on DNS sockets (default)
+     * true: set AID_DNS on DNS sockets
+     */
+    boolean enforceDnsUid = false;
 }
diff --git a/res_cache.cpp b/res_cache.cpp
index 07985d1..560de93 100644
--- a/res_cache.cpp
+++ b/res_cache.cpp
@@ -1003,6 +1003,7 @@
     // If resolverParams.hosts is empty, the existing customized table will be erased.
     HostMapping customizedTable = {};
     int tc_mode = aidl::android::net::IDnsResolver::TC_MODE_DEFAULT;
+    bool enforceDnsUid = false;
     std::vector<int32_t> transportTypes;
 };
 
@@ -1645,6 +1646,7 @@
         return -EINVAL;
     }
     netconfig->tc_mode = resolverOptions.tcMode;
+    netconfig->enforceDnsUid = resolverOptions.enforceDnsUid;
 
     netconfig->transportTypes = transportTypes;
 
@@ -1683,6 +1685,7 @@
     statp->nsaddrs = info->nameserverSockAddrs;
     statp->search_domains = info->search_domains;
     statp->tc_mode = info->tc_mode;
+    statp->enforce_dns_uid = info->enforceDnsUid;
 }
 
 /* Resolver reachability statistics. */
diff --git a/res_send.cpp b/res_send.cpp
index 6646310..2db8220 100644
--- a/res_send.cpp
+++ b/res_send.cpp
@@ -707,7 +707,8 @@
                     return -1;
             }
         }
-        resolv_tag_socket(statp->tcp_nssock, statp->uid, statp->pid);
+        const uid_t uid = statp->enforce_dns_uid ? AID_DNS : statp->uid;
+        resolv_tag_socket(statp->tcp_nssock, uid, statp->pid);
         if (statp->_mark != MARK_UNSET) {
             if (setsockopt(statp->tcp_nssock, SOL_SOCKET, SO_MARK, &statp->_mark,
                            sizeof(statp->_mark)) < 0) {
@@ -1018,7 +1019,8 @@
             }
         }
 
-        resolv_tag_socket(statp->nssocks[*ns], statp->uid, statp->pid);
+        const uid_t uid = statp->enforce_dns_uid ? AID_DNS : statp->uid;
+        resolv_tag_socket(statp->nssocks[*ns], uid, statp->pid);
         if (statp->_mark != MARK_UNSET) {
             if (setsockopt(statp->nssocks[*ns], SOL_SOCKET, SO_MARK, &(statp->_mark),
                            sizeof(statp->_mark)) < 0) {
diff --git a/resolv_cache.h b/resolv_cache.h
index 49c7f56..d8a3afc 100644
--- a/resolv_cache.h
+++ b/resolv_cache.h
@@ -84,7 +84,8 @@
                            const std::vector<std::string>& domains, const res_params& params,
                            const aidl::android::net::ResolverOptionsParcel& resolverOptions =
                                    {{} /* hosts */,
-                                    aidl::android::net::IDnsResolver::TC_MODE_DEFAULT},
+                                    aidl::android::net::IDnsResolver::TC_MODE_DEFAULT,
+                                    false /* enforceDnsUid */},
                            const std::vector<int32_t>& transportTypes = {});
 
 // Creates the cache associated with the given network.
diff --git a/resolv_cache_unit_test.cpp b/resolv_cache_unit_test.cpp
index 7b022bb..d604b2d 100644
--- a/resolv_cache_unit_test.cpp
+++ b/resolv_cache_unit_test.cpp
@@ -104,9 +104,20 @@
     return std::time(nullptr);
 }
 
-// Comparison for res_stats. Simply check the count in the cache test.
+// Comparison for res_sample.
+bool operator==(const res_sample& a, const res_sample& b) {
+    return std::tie(a.at, a.rtt, a.rcode) == std::tie(b.at, b.rtt, b.rcode);
+}
+
+// Comparison for res_stats.
 bool operator==(const res_stats& a, const res_stats& b) {
-    return std::tie(a.sample_count, a.sample_next) == std::tie(b.sample_count, b.sample_next);
+    if (std::tie(a.sample_count, a.sample_next) != std::tie(b.sample_count, b.sample_next)) {
+        return false;
+    }
+    for (int i = 0; i < a.sample_count; i++) {
+        if (a.samples[i] != b.samples[i]) return false;
+    }
+    return true;
 }
 
 // Comparison for res_params.
@@ -837,6 +848,65 @@
     EXPECT_STREQ(answer, domain_name);
 }
 
+TEST_F(ResolvCacheTest, GetResolverStats) {
+    const res_sample sample1 = {.at = time(nullptr), .rtt = 100, .rcode = ns_r_noerror};
+    const res_sample sample2 = {.at = time(nullptr), .rtt = 200, .rcode = ns_r_noerror};
+    const res_sample sample3 = {.at = time(nullptr), .rtt = 300, .rcode = ns_r_noerror};
+    const res_stats expectedStats[MAXNS] = {
+            {{sample1}, 1 /*sample_count*/, 1 /*sample_next*/},
+            {{sample2}, 1, 1},
+            {{sample3}, 1, 1},
+    };
+    std::vector<IPSockAddr> nameserverSockAddrs = {
+            IPSockAddr::toIPSockAddr("127.0.0.1", DNS_PORT),
+            IPSockAddr::toIPSockAddr("::127.0.0.2", DNS_PORT),
+            IPSockAddr::toIPSockAddr("fe80::3", DNS_PORT),
+    };
+    const SetupParams setup = {
+            .servers = {"127.0.0.1", "::127.0.0.2", "fe80::3"},
+            .domains = {"domain1.com", "domain2.com"},
+            .params = kParams,
+    };
+    EXPECT_EQ(0, cacheCreate(TEST_NETID));
+    EXPECT_EQ(0, cacheSetupResolver(TEST_NETID, setup));
+    int revision_id = 1;
+    cacheAddStats(TEST_NETID, revision_id, nameserverSockAddrs[0], sample1,
+                  setup.params.max_samples);
+    cacheAddStats(TEST_NETID, revision_id, nameserverSockAddrs[1], sample2,
+                  setup.params.max_samples);
+    cacheAddStats(TEST_NETID, revision_id, nameserverSockAddrs[2], sample3,
+                  setup.params.max_samples);
+
+    res_stats cacheStats[MAXNS]{};
+    res_params params;
+    EXPECT_EQ(resolv_cache_get_resolver_stats(TEST_NETID, &params, cacheStats, nameserverSockAddrs),
+              revision_id);
+    EXPECT_TRUE(params == kParams);
+    for (size_t i = 0; i < MAXNS; i++) {
+        EXPECT_TRUE(cacheStats[i] == expectedStats[i]);
+    }
+
+    // pass another list of IPSockAddr
+    const res_stats expectedStats2[MAXNS] = {
+            {{sample3, sample2}, 2, 2},
+            {{sample2}, 1, 1},
+            {{sample1}, 1, 1},
+    };
+    nameserverSockAddrs = {
+            IPSockAddr::toIPSockAddr("fe80::3", DNS_PORT),
+            IPSockAddr::toIPSockAddr("::127.0.0.2", DNS_PORT),
+            IPSockAddr::toIPSockAddr("127.0.0.1", DNS_PORT),
+    };
+    cacheAddStats(TEST_NETID, revision_id, nameserverSockAddrs[0], sample2,
+                  setup.params.max_samples);
+    EXPECT_EQ(resolv_cache_get_resolver_stats(TEST_NETID, &params, cacheStats, nameserverSockAddrs),
+              revision_id);
+    EXPECT_TRUE(params == kParams);
+    for (size_t i = 0; i < MAXNS; i++) {
+        EXPECT_TRUE(cacheStats[i] == expectedStats2[i]);
+    }
+}
+
 namespace {
 
 constexpr int EAI_OK = 0;
@@ -907,8 +977,6 @@
 }
 
 // TODO: Tests for NetConfig, including:
-//     - res_params
-//         -- resolv_cache_get_resolver_stats()
 //     - res_stats
 //         -- _resolv_cache_add_resolver_stats_sample()
 //         -- android_net_res_stats_get_info_for_net()
diff --git a/resolv_private.h b/resolv_private.h
index 61d87f2..f1b667e 100644
--- a/resolv_private.h
+++ b/resolv_private.h
@@ -112,6 +112,7 @@
     android::net::NetworkDnsEventReported* event;
     uint32_t netcontext_flags;
     int tc_mode = 0;
+    bool enforce_dns_uid = false;
     // clang-format on
 };
 
diff --git a/tests/resolv_integration_test.cpp b/tests/resolv_integration_test.cpp
index 236b031..95b5a5c 100644
--- a/tests/resolv_integration_test.cpp
+++ b/tests/resolv_integration_test.cpp
@@ -4018,6 +4018,71 @@
     EXPECT_EQ(-ECONNREFUSED, res);
 }
 
+TEST_F(ResolverTest, EnforceDnsUid) {
+    SKIP_IF_BPF_NOT_SUPPORTED;
+
+    constexpr char listen_addr1[] = "127.0.0.4";
+    constexpr char listen_addr2[] = "::1";
+    constexpr char host_name[] = "howdy.example.com.";
+    const std::vector<DnsRecord> records = {
+            {host_name, ns_type::ns_t_a, "1.2.3.4"},
+            {host_name, ns_type::ns_t_aaaa, "::1.2.3.4"},
+    };
+    INetd* netdService = mDnsClient.netdService();
+
+    test::DNSResponder dns1(listen_addr1);
+    test::DNSResponder dns2(listen_addr2);
+    StartDns(dns1, records);
+    StartDns(dns2, records);
+
+    // switch uid of DNS queries from applications to AID_DNS
+    ResolverParamsParcel parcel = DnsResponderClient::GetDefaultResolverParamsParcel();
+    parcel.servers = {listen_addr1, listen_addr2};
+    ASSERT_TRUE(mDnsClient.resolvService()->setResolverConfiguration(parcel).isOk());
+
+    uint8_t buf[MAXPACKET] = {};
+    int rcode;
+    {
+        ScopeBlockedUIDRule scopeBlockUidRule(netdService, TEST_UID);
+        // Dns Queries should be blocked
+        int fd1 = resNetworkQuery(TEST_NETID, host_name, ns_c_in, ns_t_a, 0);
+        int fd2 = resNetworkQuery(TEST_NETID, host_name, ns_c_in, ns_t_aaaa, 0);
+        EXPECT_TRUE(fd1 != -1);
+        EXPECT_TRUE(fd2 != -1);
+
+        int res = getAsyncResponse(fd2, &rcode, buf, MAXPACKET);
+        EXPECT_EQ(-ECONNREFUSED, res);
+
+        memset(buf, 0, MAXPACKET);
+        res = getAsyncResponse(fd1, &rcode, buf, MAXPACKET);
+        EXPECT_EQ(-ECONNREFUSED, res);
+    }
+
+    parcel.resolverOptions.enforceDnsUid = true;
+    ASSERT_TRUE(mDnsClient.resolvService()->setResolverConfiguration(parcel).isOk());
+    {
+        ScopeBlockedUIDRule scopeBlockUidRule(netdService, TEST_UID);
+        // Dns Queries should NOT be blocked
+        int fd1 = resNetworkQuery(TEST_NETID, host_name, ns_c_in, ns_t_a, 0);
+        int fd2 = resNetworkQuery(TEST_NETID, host_name, ns_c_in, ns_t_aaaa, 0);
+        EXPECT_TRUE(fd1 != -1);
+        EXPECT_TRUE(fd2 != -1);
+
+        int res = getAsyncResponse(fd2, &rcode, buf, MAXPACKET);
+        EXPECT_EQ("::1.2.3.4", toString(buf, res, AF_INET6));
+
+        memset(buf, 0, MAXPACKET);
+        res = getAsyncResponse(fd1, &rcode, buf, MAXPACKET);
+        EXPECT_EQ("1.2.3.4", toString(buf, res, AF_INET));
+
+        // @TODO: So far we know that uid of DNS queries are no more set to DNS requester. But we
+        // don't check if they are actually being set to AID_DNS, because system uids are always
+        // allowed in bpf_owner_match(). Audit by firewallSetUidRule(AID_DNS) + sending queries is
+        // infeasible. Fix it if the behavior of bpf_owner_match() is changed in the future, or if
+        // we have better idea to deal with this.
+    }
+}
+
 namespace {
 
 const std::string kDotConnectTimeoutMsFlag(