[automerger skipped] dns_tls_frontend.cpp: set queries_ to 0 in startServer am: 3fff84ade0 -s ours am: c8860724ad -s ours am: f74fc01e97 -s ours am: e035fae1dc -s ours

am skip reason: Change-Id I9ce9314c34420b346703500f4120304dfa58b9af with SHA-1 589bd52d90 is in history

Original change: https://android-review.googlesource.com/c/platform/system/netd/+/1112480

Change-Id: Id2526e4184c7869a5ad4d44dd857ae6413aa708f
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/Android.bp b/Android.bp
index 0838a8d..8fe83f0 100644
--- a/Android.bp
+++ b/Android.bp
@@ -20,7 +20,6 @@
     export_include_dirs: ["include"],
     apex_available: [
         "//apex_available:platform",
-        "com.android.tethering",
     ],
 }
 
@@ -74,16 +73,14 @@
         "-misc-non-private-member-variables-in-classes",  // Also complains about structs
         "-performance-noexcept-move-constructor",
         "-performance-unnecessary-value-param",
-        "-performance-no-int-to-ptr",
     ],
-    tidy_flags: [
-        "-warnings-as-errors="
-        + "android-*,"
-        + "bugprone-*,"
-        + "cert-*,"
-        + "clang-analyzer-security*,"
-        + "google-*,"
-        + "misc-*,"
-        + "performance-*"
+    tidy_checks_as_errors: [
+        "android-*",
+        "bugprone-*",
+        "cert-*",
+        "clang-analyzer-security*",
+        "google-*",
+        "misc-*",
+        "performance-*",
     ],
 }
diff --git a/OWNERS b/OWNERS
index 94e70d5..a29a33b 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,11 +1,4 @@
-cken@google.com
-codewiz@google.com
-huangluke@google.com
-jchalard@google.com
-lorenzo@google.com
-maze@google.com
-nuccachen@google.com
-reminv@google.com
-satk@google.com
-xiaom@google.com
-yumike@google.com
\ No newline at end of file
+set noparent
+file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking
+
+per-file **Xfrm* = file:platform/frameworks/base:master:/services/core/java/com/android/server/vcn/OWNERS
\ No newline at end of file
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 095fa7d..5e200e9 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -1,14 +1,11 @@
 {
     "presubmit": [
-        { "name": "libnetdbpf_test" },
         { "name": "netd_integration_test" },
         { "name": "netd_unit_test" },
         { "name": "netdclient_test" },
         { "name": "netdutils_test" }
     ],
     "postsubmit": [
-        { "name": "libnetdbpf_test",
-          "keywords": ["netd-device-kernel-4.9", "netd-device-kernel-4.14"]},
         { "name": "netd_integration_test",
           "keywords": ["netd-device-kernel-4.9", "netd-device-kernel-4.14"]},
         { "name": "netd_unit_test",
@@ -16,5 +13,11 @@
     ],
     "imports": [
         { "path": "packages/modules/DnsResolver" }
+    ],
+    "hwasan-presubmit": [
+        { "name": "netd_integration_test" },
+        { "name": "netd_unit_test" },
+        { "name": "netdclient_test" },
+        { "name": "netdutils_test" }
     ]
 }
diff --git a/bpf_progs/Android.bp b/bpf_progs/Android.bp
deleted file mode 100644
index 1311ca9..0000000
--- a/bpf_progs/Android.bp
+++ /dev/null
@@ -1,58 +0,0 @@
-//
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-package {
-    // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "system_netd_license"
-    // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
-    default_applicable_licenses: ["system_netd_license"],
-}
-
-cc_library_headers {
-    name: "netd_bpf_progs_headers",
-    export_include_dirs: ["."],
-}
-
-//
-// bpf kernel programs
-//
-bpf {
-    name: "clatd.o",
-    srcs: ["clatd.c"],
-    cflags: [
-        "-Wall",
-        "-Werror",
-    ],
-    include_dirs: [
-        "system/netd/libnetdbpf/include",
-        "system/netd/libnetdutils/include",
-    ],
-}
-
-bpf {
-    name: "netd.o",
-    srcs: ["netd.c"],
-    cflags: [
-        "-Wall",
-        "-Werror",
-    ],
-    include_dirs: [
-        "system/netd/libnetdbpf/include",
-        "system/netd/libnetdutils/include",
-    ],
-}
diff --git a/bpf_progs/bpf_net_helpers.h b/bpf_progs/bpf_net_helpers.h
deleted file mode 100644
index d978f3a..0000000
--- a/bpf_progs/bpf_net_helpers.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NETDBPF_BPF_NET_HELPERS_H
-#define NETDBPF_BPF_NET_HELPERS_H
-
-#include <linux/bpf.h>
-#include <linux/if_packet.h>
-#include <stdbool.h>
-#include <stdint.h>
-
-// this returns 0 iff skb->sk is NULL
-static uint64_t (*bpf_get_socket_cookie)(struct __sk_buff* skb) = (void*)BPF_FUNC_get_socket_cookie;
-
-static uint32_t (*bpf_get_socket_uid)(struct __sk_buff* skb) = (void*)BPF_FUNC_get_socket_uid;
-
-static int (*bpf_skb_pull_data)(struct __sk_buff* skb, __u32 len) = (void*)BPF_FUNC_skb_pull_data;
-
-static int (*bpf_skb_load_bytes)(struct __sk_buff* skb, int off, void* to,
-                                 int len) = (void*)BPF_FUNC_skb_load_bytes;
-
-static int (*bpf_skb_store_bytes)(struct __sk_buff* skb, __u32 offset, const void* from, __u32 len,
-                                  __u64 flags) = (void*)BPF_FUNC_skb_store_bytes;
-
-static int64_t (*bpf_csum_diff)(__be32* from, __u32 from_size, __be32* to, __u32 to_size,
-                                __wsum seed) = (void*)BPF_FUNC_csum_diff;
-
-static int64_t (*bpf_csum_update)(struct __sk_buff* skb, __wsum csum) = (void*)BPF_FUNC_csum_update;
-
-static int (*bpf_skb_change_proto)(struct __sk_buff* skb, __be16 proto,
-                                   __u64 flags) = (void*)BPF_FUNC_skb_change_proto;
-static int (*bpf_l3_csum_replace)(struct __sk_buff* skb, __u32 offset, __u64 from, __u64 to,
-                                  __u64 flags) = (void*)BPF_FUNC_l3_csum_replace;
-static int (*bpf_l4_csum_replace)(struct __sk_buff* skb, __u32 offset, __u64 from, __u64 to,
-                                  __u64 flags) = (void*)BPF_FUNC_l4_csum_replace;
-static int (*bpf_redirect)(__u32 ifindex, __u64 flags) = (void*)BPF_FUNC_redirect;
-static int (*bpf_redirect_map)(const struct bpf_map_def* map, __u32 key,
-                               __u64 flags) = (void*)BPF_FUNC_redirect_map;
-
-static int (*bpf_skb_change_head)(struct __sk_buff* skb, __u32 head_room,
-                                  __u64 flags) = (void*)BPF_FUNC_skb_change_head;
-static int (*bpf_skb_adjust_room)(struct __sk_buff* skb, __s32 len_diff, __u32 mode,
-                                  __u64 flags) = (void*)BPF_FUNC_skb_adjust_room;
-
-// Android only supports little endian architectures
-#define htons(x) (__builtin_constant_p(x) ? ___constant_swab16(x) : __builtin_bswap16(x))
-#define htonl(x) (__builtin_constant_p(x) ? ___constant_swab32(x) : __builtin_bswap32(x))
-#define ntohs(x) htons(x)
-#define ntohl(x) htonl(x)
-
-static inline __always_inline __unused bool is_received_skb(struct __sk_buff* skb) {
-    return skb->pkt_type == PACKET_HOST || skb->pkt_type == PACKET_BROADCAST ||
-           skb->pkt_type == PACKET_MULTICAST;
-}
-
-// try to make the first 'len' header bytes readable via direct packet access
-static inline __always_inline void try_make_readable(struct __sk_buff* skb, int len) {
-    if (len > skb->len) len = skb->len;
-    if (skb->data_end - skb->data < len) bpf_skb_pull_data(skb, len);
-}
-
-#endif  // NETDBPF_BPF_NET_HELPERS_H
diff --git a/bpf_progs/clatd.c b/bpf_progs/clatd.c
deleted file mode 100644
index 31e0522..0000000
--- a/bpf_progs/clatd.c
+++ /dev/null
@@ -1,322 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <linux/bpf.h>
-#include <linux/if.h>
-#include <linux/if_ether.h>
-#include <linux/in.h>
-#include <linux/in6.h>
-#include <linux/ip.h>
-#include <linux/ipv6.h>
-#include <linux/pkt_cls.h>
-#include <linux/swab.h>
-#include <stdbool.h>
-#include <stdint.h>
-
-// bionic kernel uapi linux/udp.h header is munged...
-#define __kernel_udphdr udphdr
-#include <linux/udp.h>
-
-#include "bpf_helpers.h"
-#include "bpf_net_helpers.h"
-#include "netdbpf/bpf_shared.h"
-
-// From kernel:include/net/ip.h
-#define IP_DF 0x4000  // Flag: "Don't Fragment"
-
-DEFINE_BPF_MAP(clat_ingress6_map, HASH, ClatIngress6Key, ClatIngress6Value, 16)
-
-static inline __always_inline int nat64(struct __sk_buff* skb, bool is_ethernet) {
-    const int l2_header_size = is_ethernet ? sizeof(struct ethhdr) : 0;
-    void* data = (void*)(long)skb->data;
-    const void* data_end = (void*)(long)skb->data_end;
-    const struct ethhdr* const eth = is_ethernet ? data : NULL;  // used iff is_ethernet
-    const struct ipv6hdr* const ip6 = is_ethernet ? (void*)(eth + 1) : data;
-
-    // Require ethernet dst mac address to be our unicast address.
-    if (is_ethernet && (skb->pkt_type != PACKET_HOST)) return TC_ACT_OK;
-
-    // Must be meta-ethernet IPv6 frame
-    if (skb->protocol != htons(ETH_P_IPV6)) return TC_ACT_OK;
-
-    // Must have (ethernet and) ipv6 header
-    if (data + l2_header_size + sizeof(*ip6) > data_end) return TC_ACT_OK;
-
-    // Ethertype - if present - must be IPv6
-    if (is_ethernet && (eth->h_proto != htons(ETH_P_IPV6))) return TC_ACT_OK;
-
-    // IP version must be 6
-    if (ip6->version != 6) return TC_ACT_OK;
-
-    // Maximum IPv6 payload length that can be translated to IPv4
-    if (ntohs(ip6->payload_len) > 0xFFFF - sizeof(struct iphdr)) return TC_ACT_OK;
-
-    switch (ip6->nexthdr) {
-        case IPPROTO_TCP:  // For TCP & UDP the checksum neutrality of the chosen IPv6
-        case IPPROTO_UDP:  // address means there is no need to update their checksums.
-        case IPPROTO_GRE:  // We do not need to bother looking at GRE/ESP headers,
-        case IPPROTO_ESP:  // since there is never a checksum to update.
-            break;
-
-        default:  // do not know how to handle anything else
-            return TC_ACT_OK;
-    }
-
-    ClatIngress6Key k = {
-            .iif = skb->ifindex,
-            .pfx96.in6_u.u6_addr32 =
-                    {
-                            ip6->saddr.in6_u.u6_addr32[0],
-                            ip6->saddr.in6_u.u6_addr32[1],
-                            ip6->saddr.in6_u.u6_addr32[2],
-                    },
-            .local6 = ip6->daddr,
-    };
-
-    ClatIngress6Value* v = bpf_clat_ingress6_map_lookup_elem(&k);
-
-    if (!v) return TC_ACT_OK;
-
-    struct ethhdr eth2;  // used iff is_ethernet
-    if (is_ethernet) {
-        eth2 = *eth;                     // Copy over the ethernet header (src/dst mac)
-        eth2.h_proto = htons(ETH_P_IP);  // But replace the ethertype
-    }
-
-    struct iphdr ip = {
-            .version = 4,                                                      // u4
-            .ihl = sizeof(struct iphdr) / sizeof(__u32),                       // u4
-            .tos = (ip6->priority << 4) + (ip6->flow_lbl[0] >> 4),             // u8
-            .tot_len = htons(ntohs(ip6->payload_len) + sizeof(struct iphdr)),  // u16
-            .id = 0,                                                           // u16
-            .frag_off = htons(IP_DF),                                          // u16
-            .ttl = ip6->hop_limit,                                             // u8
-            .protocol = ip6->nexthdr,                                          // u8
-            .check = 0,                                                        // u16
-            .saddr = ip6->saddr.in6_u.u6_addr32[3],                            // u32
-            .daddr = v->local4.s_addr,                                         // u32
-    };
-
-    // Calculate the IPv4 one's complement checksum of the IPv4 header.
-    __wsum sum4 = 0;
-    for (int i = 0; i < sizeof(ip) / sizeof(__u16); ++i) {
-        sum4 += ((__u16*)&ip)[i];
-    }
-    // Note that sum4 is guaranteed to be non-zero by virtue of ip.version == 4
-    sum4 = (sum4 & 0xFFFF) + (sum4 >> 16);  // collapse u32 into range 1 .. 0x1FFFE
-    sum4 = (sum4 & 0xFFFF) + (sum4 >> 16);  // collapse any potential carry into u16
-    ip.check = (__u16)~sum4;                // sum4 cannot be zero, so this is never 0xFFFF
-
-    // Calculate the *negative* IPv6 16-bit one's complement checksum of the IPv6 header.
-    __wsum sum6 = 0;
-    // We'll end up with a non-zero sum due to ip6->version == 6 (which has '0' bits)
-    for (int i = 0; i < sizeof(*ip6) / sizeof(__u16); ++i) {
-        sum6 += ~((__u16*)ip6)[i];  // note the bitwise negation
-    }
-
-    // Note that there is no L4 checksum update: we are relying on the checksum neutrality
-    // of the ipv6 address chosen by netd's ClatdController.
-
-    // Packet mutations begin - point of no return, but if this first modification fails
-    // the packet is probably still pristine, so let clatd handle it.
-    if (bpf_skb_change_proto(skb, htons(ETH_P_IP), 0)) return TC_ACT_OK;
-
-    // This takes care of updating the skb->csum field for a CHECKSUM_COMPLETE packet.
-    //
-    // In such a case, skb->csum is a 16-bit one's complement sum of the entire payload,
-    // thus we need to subtract out the ipv6 header's sum, and add in the ipv4 header's sum.
-    // However, by construction of ip.check above the checksum of an ipv4 header is zero.
-    // Thus we only need to subtract the ipv6 header's sum, which is the same as adding
-    // in the sum of the bitwise negation of the ipv6 header.
-    //
-    // bpf_csum_update() always succeeds if the skb is CHECKSUM_COMPLETE and returns an error
-    // (-ENOTSUPP) if it isn't.  So we just ignore the return code.
-    //
-    // if (skb->ip_summed == CHECKSUM_COMPLETE)
-    //   return (skb->csum = csum_add(skb->csum, csum));
-    // else
-    //   return -ENOTSUPP;
-    bpf_csum_update(skb, sum6);
-
-    // bpf_skb_change_proto() invalidates all pointers - reload them.
-    data = (void*)(long)skb->data;
-    data_end = (void*)(long)skb->data_end;
-
-    // I cannot think of any valid way for this error condition to trigger, however I do
-    // believe the explicit check is required to keep the in kernel ebpf verifier happy.
-    if (data + l2_header_size + sizeof(struct iphdr) > data_end) return TC_ACT_SHOT;
-
-    if (is_ethernet) {
-        struct ethhdr* new_eth = data;
-
-        // Copy over the updated ethernet header
-        *new_eth = eth2;
-
-        // Copy over the new ipv4 header.
-        *(struct iphdr*)(new_eth + 1) = ip;
-    } else {
-        // Copy over the new ipv4 header without an ethernet header.
-        *(struct iphdr*)data = ip;
-    }
-
-    // Redirect, possibly back to same interface, so tcpdump sees packet twice.
-    if (v->oif) return bpf_redirect(v->oif, BPF_F_INGRESS);
-
-    // Just let it through, tcpdump will not see IPv4 packet.
-    return TC_ACT_OK;
-}
-
-DEFINE_BPF_PROG("schedcls/ingress6/clat_ether", AID_ROOT, AID_ROOT, sched_cls_ingress6_clat_ether)
-(struct __sk_buff* skb) {
-    return nat64(skb, true);
-}
-
-DEFINE_BPF_PROG("schedcls/ingress6/clat_rawip", AID_ROOT, AID_ROOT, sched_cls_ingress6_clat_rawip)
-(struct __sk_buff* skb) {
-    return nat64(skb, false);
-}
-
-DEFINE_BPF_MAP(clat_egress4_map, HASH, ClatEgress4Key, ClatEgress4Value, 16)
-
-DEFINE_BPF_PROG("schedcls/egress4/clat_ether", AID_ROOT, AID_ROOT, sched_cls_egress4_clat_ether)
-(struct __sk_buff* skb) {
-    return TC_ACT_OK;
-}
-
-DEFINE_BPF_PROG("schedcls/egress4/clat_rawip", AID_ROOT, AID_ROOT, sched_cls_egress4_clat_rawip)
-(struct __sk_buff* skb) {
-    void* data = (void*)(long)skb->data;
-    const void* data_end = (void*)(long)skb->data_end;
-    const struct iphdr* const ip4 = data;
-
-    // Must be meta-ethernet IPv4 frame
-    if (skb->protocol != htons(ETH_P_IP)) return TC_ACT_OK;
-
-    // Must have ipv4 header
-    if (data + sizeof(*ip4) > data_end) return TC_ACT_OK;
-
-    // IP version must be 4
-    if (ip4->version != 4) return TC_ACT_OK;
-
-    // We cannot handle IP options, just standard 20 byte == 5 dword minimal IPv4 header
-    if (ip4->ihl != 5) return TC_ACT_OK;
-
-    // Calculate the IPv4 one's complement checksum of the IPv4 header.
-    __wsum sum4 = 0;
-    for (int i = 0; i < sizeof(*ip4) / sizeof(__u16); ++i) {
-        sum4 += ((__u16*)ip4)[i];
-    }
-    // Note that sum4 is guaranteed to be non-zero by virtue of ip4->version == 4
-    sum4 = (sum4 & 0xFFFF) + (sum4 >> 16);  // collapse u32 into range 1 .. 0x1FFFE
-    sum4 = (sum4 & 0xFFFF) + (sum4 >> 16);  // collapse any potential carry into u16
-    // for a correct checksum we should get *a* zero, but sum4 must be positive, ie 0xFFFF
-    if (sum4 != 0xFFFF) return TC_ACT_OK;
-
-    // Minimum IPv4 total length is the size of the header
-    if (ntohs(ip4->tot_len) < sizeof(*ip4)) return TC_ACT_OK;
-
-    // We are incapable of dealing with IPv4 fragments
-    if (ip4->frag_off & ~htons(IP_DF)) return TC_ACT_OK;
-
-    switch (ip4->protocol) {
-        case IPPROTO_TCP:  // For TCP & UDP the checksum neutrality of the chosen IPv6
-        case IPPROTO_GRE:  // address means there is no need to update their checksums.
-        case IPPROTO_ESP:  // We do not need to bother looking at GRE/ESP headers,
-            break;         // since there is never a checksum to update.
-
-        case IPPROTO_UDP:  // See above comment, but must also have UDP header...
-            if (data + sizeof(*ip4) + sizeof(struct udphdr) > data_end) return TC_ACT_OK;
-            const struct udphdr* uh = (const struct udphdr*)(ip4 + 1);
-            // If IPv4/UDP checksum is 0 then fallback to clatd so it can calculate the
-            // checksum.  Otherwise the network or more likely the NAT64 gateway might
-            // drop the packet because in most cases IPv6/UDP packets with a zero checksum
-            // are invalid. See RFC 6935.  TODO: calculate checksum via bpf_csum_diff()
-            if (!uh->check) return TC_ACT_OK;
-            break;
-
-        default:  // do not know how to handle anything else
-            return TC_ACT_OK;
-    }
-
-    ClatEgress4Key k = {
-            .iif = skb->ifindex,
-            .local4.s_addr = ip4->saddr,
-    };
-
-    ClatEgress4Value* v = bpf_clat_egress4_map_lookup_elem(&k);
-
-    if (!v) return TC_ACT_OK;
-
-    // Translating without redirecting doesn't make sense.
-    if (!v->oif) return TC_ACT_OK;
-
-    // This implementation is currently limited to rawip.
-    if (v->oifIsEthernet) return TC_ACT_OK;
-
-    struct ipv6hdr ip6 = {
-            .version = 6,                                    // __u8:4
-            .priority = ip4->tos >> 4,                       // __u8:4
-            .flow_lbl = {(ip4->tos & 0xF) << 4, 0, 0},       // __u8[3]
-            .payload_len = htons(ntohs(ip4->tot_len) - 20),  // __be16
-            .nexthdr = ip4->protocol,                        // __u8
-            .hop_limit = ip4->ttl,                           // __u8
-            .saddr = v->local6,                              // struct in6_addr
-            .daddr = v->pfx96,                               // struct in6_addr
-    };
-    ip6.daddr.in6_u.u6_addr32[3] = ip4->daddr;
-
-    // Calculate the IPv6 16-bit one's complement checksum of the IPv6 header.
-    __wsum sum6 = 0;
-    // We'll end up with a non-zero sum due to ip6.version == 6
-    for (int i = 0; i < sizeof(ip6) / sizeof(__u16); ++i) {
-        sum6 += ((__u16*)&ip6)[i];
-    }
-
-    // Note that there is no L4 checksum update: we are relying on the checksum neutrality
-    // of the ipv6 address chosen by netd's ClatdController.
-
-    // Packet mutations begin - point of no return, but if this first modification fails
-    // the packet is probably still pristine, so let clatd handle it.
-    if (bpf_skb_change_proto(skb, htons(ETH_P_IPV6), 0)) return TC_ACT_OK;
-
-    // This takes care of updating the skb->csum field for a CHECKSUM_COMPLETE packet.
-    //
-    // In such a case, skb->csum is a 16-bit one's complement sum of the entire payload,
-    // thus we need to subtract out the ipv4 header's sum, and add in the ipv6 header's sum.
-    // However, we've already verified the ipv4 checksum is correct and thus 0.
-    // Thus we only need to add the ipv6 header's sum.
-    //
-    // bpf_csum_update() always succeeds if the skb is CHECKSUM_COMPLETE and returns an error
-    // (-ENOTSUPP) if it isn't.  So we just ignore the return code (see above for more details).
-    bpf_csum_update(skb, sum6);
-
-    // bpf_skb_change_proto() invalidates all pointers - reload them.
-    data = (void*)(long)skb->data;
-    data_end = (void*)(long)skb->data_end;
-
-    // I cannot think of any valid way for this error condition to trigger, however I do
-    // believe the explicit check is required to keep the in kernel ebpf verifier happy.
-    if (data + sizeof(ip6) > data_end) return TC_ACT_SHOT;
-
-    // Copy over the new ipv6 header without an ethernet header.
-    *(struct ipv6hdr*)data = ip6;
-
-    // Redirect to non v4-* interface.  Tcpdump only sees packet after this redirect.
-    return bpf_redirect(v->oif, 0 /* this is effectively BPF_F_EGRESS */);
-}
-
-LICENSE("Apache 2.0");
-CRITICAL("netd");
diff --git a/bpf_progs/netd.c b/bpf_progs/netd.c
deleted file mode 100644
index e9e1477..0000000
--- a/bpf_progs/netd.c
+++ /dev/null
@@ -1,370 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <bpf_helpers.h>
-#include <linux/bpf.h>
-#include <linux/if.h>
-#include <linux/if_ether.h>
-#include <linux/if_packet.h>
-#include <linux/in.h>
-#include <linux/in6.h>
-#include <linux/ip.h>
-#include <linux/ipv6.h>
-#include <linux/tcp.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include "bpf_net_helpers.h"
-#include "netdbpf/bpf_shared.h"
-
-// This is defined for cgroup bpf filter only.
-#define BPF_DROP_UNLESS_DNS 2
-#define BPF_PASS 1
-#define BPF_DROP 0
-
-// This is used for xt_bpf program only.
-#define BPF_NOMATCH 0
-#define BPF_MATCH 1
-
-#define BPF_EGRESS 0
-#define BPF_INGRESS 1
-
-#define IP_PROTO_OFF offsetof(struct iphdr, protocol)
-#define IPV6_PROTO_OFF offsetof(struct ipv6hdr, nexthdr)
-#define IPPROTO_IHL_OFF 0
-#define TCP_FLAG_OFF 13
-#define RST_OFFSET 2
-
-DEFINE_BPF_MAP_GRO(cookie_tag_map, HASH, uint64_t, UidTagValue, COOKIE_UID_MAP_SIZE,
-                   AID_NET_BW_ACCT)
-DEFINE_BPF_MAP_GRO(uid_counterset_map, HASH, uint32_t, uint8_t, UID_COUNTERSET_MAP_SIZE,
-                   AID_NET_BW_ACCT)
-DEFINE_BPF_MAP_GRO(app_uid_stats_map, HASH, uint32_t, StatsValue, APP_STATS_MAP_SIZE,
-                   AID_NET_BW_STATS)
-DEFINE_BPF_MAP_GRW(stats_map_A, HASH, StatsKey, StatsValue, STATS_MAP_SIZE, AID_NET_BW_STATS)
-DEFINE_BPF_MAP_GRW(stats_map_B, HASH, StatsKey, StatsValue, STATS_MAP_SIZE, AID_NET_BW_STATS)
-DEFINE_BPF_MAP_GRO(iface_stats_map, HASH, uint32_t, StatsValue, IFACE_STATS_MAP_SIZE,
-                   AID_NET_BW_STATS)
-DEFINE_BPF_MAP_GRO(configuration_map, HASH, uint32_t, uint8_t, CONFIGURATION_MAP_SIZE,
-                   AID_NET_BW_STATS)
-DEFINE_BPF_MAP(uid_owner_map, HASH, uint32_t, UidOwnerValue, UID_OWNER_MAP_SIZE)
-
-/* never actually used from ebpf */
-DEFINE_BPF_MAP_GRO(iface_index_name_map, HASH, uint32_t, IfaceValue, IFACE_INDEX_NAME_MAP_SIZE,
-                   AID_NET_BW_STATS)
-
-static __always_inline int is_system_uid(uint32_t uid) {
-    return (uid <= MAX_SYSTEM_UID) && (uid >= MIN_SYSTEM_UID);
-}
-
-/*
- * Note: this blindly assumes an MTU of 1500, and that packets > MTU are always TCP,
- * and that TCP is using the Linux default settings with TCP timestamp option enabled
- * which uses 12 TCP option bytes per frame.
- *
- * These are not unreasonable assumptions:
- *
- * The internet does not really support MTUs greater than 1500, so most TCP traffic will
- * be at that MTU, or slightly below it (worst case our upwards adjustment is too small).
- *
- * The chance our traffic isn't IP at all is basically zero, so the IP overhead correction
- * is bound to be needed.
- *
- * Furthermore, the likelyhood that we're having to deal with GSO (ie. > MTU) packets that
- * are not IP/TCP is pretty small (few other things are supported by Linux) and worse case
- * our extra overhead will be slightly off, but probably still better than assuming none.
- *
- * Most servers are also Linux and thus support/default to using TCP timestamp option
- * (and indeed TCP timestamp option comes from RFC 1323 titled "TCP Extensions for High
- * Performance" which also defined TCP window scaling and are thus absolutely ancient...).
- *
- * All together this should be more correct than if we simply ignored GSO frames
- * (ie. counted them as single packets with no extra overhead)
- *
- * Especially since the number of packets is important for any future clat offload correction.
- * (which adjusts upward by 20 bytes per packet to account for ipv4 -> ipv6 header conversion)
- */
-#define DEFINE_UPDATE_STATS(the_stats_map, TypeOfKey)                                          \
-    static __always_inline inline void update_##the_stats_map(struct __sk_buff* skb,           \
-                                                              int direction, TypeOfKey* key) { \
-        StatsValue* value = bpf_##the_stats_map##_lookup_elem(key);                            \
-        if (!value) {                                                                          \
-            StatsValue newValue = {};                                                          \
-            bpf_##the_stats_map##_update_elem(key, &newValue, BPF_NOEXIST);                    \
-            value = bpf_##the_stats_map##_lookup_elem(key);                                    \
-        }                                                                                      \
-        if (value) {                                                                           \
-            const int mtu = 1500;                                                              \
-            uint64_t packets = 1;                                                              \
-            uint64_t bytes = skb->len;                                                         \
-            if (bytes > mtu) {                                                                 \
-                bool is_ipv6 = (skb->protocol == htons(ETH_P_IPV6));                           \
-                int ip_overhead = (is_ipv6 ? sizeof(struct ipv6hdr) : sizeof(struct iphdr));   \
-                int tcp_overhead = ip_overhead + sizeof(struct tcphdr) + 12;                   \
-                int mss = mtu - tcp_overhead;                                                  \
-                uint64_t payload = bytes - tcp_overhead;                                       \
-                packets = (payload + mss - 1) / mss;                                           \
-                bytes = tcp_overhead * packets + payload;                                      \
-            }                                                                                  \
-            if (direction == BPF_EGRESS) {                                                     \
-                __sync_fetch_and_add(&value->txPackets, packets);                              \
-                __sync_fetch_and_add(&value->txBytes, bytes);                                  \
-            } else if (direction == BPF_INGRESS) {                                             \
-                __sync_fetch_and_add(&value->rxPackets, packets);                              \
-                __sync_fetch_and_add(&value->rxBytes, bytes);                                  \
-            }                                                                                  \
-        }                                                                                      \
-    }
-
-DEFINE_UPDATE_STATS(app_uid_stats_map, uint32_t)
-DEFINE_UPDATE_STATS(iface_stats_map, uint32_t)
-DEFINE_UPDATE_STATS(stats_map_A, StatsKey)
-DEFINE_UPDATE_STATS(stats_map_B, StatsKey)
-
-static inline bool skip_owner_match(struct __sk_buff* skb) {
-    int offset = -1;
-    int ret = 0;
-    if (skb->protocol == htons(ETH_P_IP)) {
-        offset = IP_PROTO_OFF;
-        uint8_t proto, ihl;
-        uint8_t flag;
-        ret = bpf_skb_load_bytes(skb, offset, &proto, 1);
-        if (!ret) {
-            if (proto == IPPROTO_ESP) {
-                return true;
-            } else if (proto == IPPROTO_TCP) {
-                ret = bpf_skb_load_bytes(skb, IPPROTO_IHL_OFF, &ihl, 1);
-                ihl = ihl & 0x0F;
-                ret = bpf_skb_load_bytes(skb, ihl * 4 + TCP_FLAG_OFF, &flag, 1);
-                if (ret == 0 && (flag >> RST_OFFSET & 1)) {
-                    return true;
-                }
-            }
-        }
-    } else if (skb->protocol == htons(ETH_P_IPV6)) {
-        offset = IPV6_PROTO_OFF;
-        uint8_t proto;
-        ret = bpf_skb_load_bytes(skb, offset, &proto, 1);
-        if (!ret) {
-            if (proto == IPPROTO_ESP) {
-                return true;
-            } else if (proto == IPPROTO_TCP) {
-                uint8_t flag;
-                ret = bpf_skb_load_bytes(skb, sizeof(struct ipv6hdr) + TCP_FLAG_OFF, &flag, 1);
-                if (ret == 0 && (flag >> RST_OFFSET & 1)) {
-                    return true;
-                }
-            }
-        }
-    }
-    return false;
-}
-
-static __always_inline BpfConfig getConfig(uint32_t configKey) {
-    uint32_t mapSettingKey = configKey;
-    BpfConfig* config = bpf_configuration_map_lookup_elem(&mapSettingKey);
-    if (!config) {
-        // Couldn't read configuration entry. Assume everything is disabled.
-        return DEFAULT_CONFIG;
-    }
-    return *config;
-}
-
-static inline int bpf_owner_match(struct __sk_buff* skb, uint32_t uid, int direction) {
-    if (skip_owner_match(skb)) return BPF_PASS;
-
-    if (is_system_uid(uid)) return BPF_PASS;
-
-    BpfConfig enabledRules = getConfig(UID_RULES_CONFIGURATION_KEY);
-
-    UidOwnerValue* uidEntry = bpf_uid_owner_map_lookup_elem(&uid);
-    uint8_t uidRules = uidEntry ? uidEntry->rule : 0;
-    uint32_t allowed_iif = uidEntry ? uidEntry->iif : 0;
-
-    if (enabledRules) {
-        if ((enabledRules & DOZABLE_MATCH) && !(uidRules & DOZABLE_MATCH)) {
-            return BPF_DROP;
-        }
-        if ((enabledRules & STANDBY_MATCH) && (uidRules & STANDBY_MATCH)) {
-            return BPF_DROP;
-        }
-        if ((enabledRules & POWERSAVE_MATCH) && !(uidRules & POWERSAVE_MATCH)) {
-            return BPF_DROP;
-        }
-        if ((enabledRules & RESTRICTED_MATCH) && !(uidRules & RESTRICTED_MATCH)) {
-            return BPF_DROP;
-        }
-    }
-    if (direction == BPF_INGRESS && (uidRules & IIF_MATCH)) {
-        // Drops packets not coming from lo nor the allowlisted interface
-        if (allowed_iif && skb->ifindex != 1 && skb->ifindex != allowed_iif) {
-            return BPF_DROP_UNLESS_DNS;
-        }
-    }
-    return BPF_PASS;
-}
-
-static __always_inline inline void update_stats_with_config(struct __sk_buff* skb, int direction,
-                                                            StatsKey* key, uint8_t selectedMap) {
-    if (selectedMap == SELECT_MAP_A) {
-        update_stats_map_A(skb, direction, key);
-    } else if (selectedMap == SELECT_MAP_B) {
-        update_stats_map_B(skb, direction, key);
-    }
-}
-
-static __always_inline inline int bpf_traffic_account(struct __sk_buff* skb, int direction) {
-    uint32_t sock_uid = bpf_get_socket_uid(skb);
-    // Always allow and never count clat traffic. Only the IPv4 traffic on the stacked
-    // interface is accounted for and subject to usage restrictions.
-    if (sock_uid == AID_CLAT) {
-        return BPF_PASS;
-    }
-
-    int match = bpf_owner_match(skb, sock_uid, direction);
-    if ((direction == BPF_EGRESS) && (match == BPF_DROP)) {
-        // If an outbound packet is going to be dropped, we do not count that
-        // traffic.
-        return match;
-    }
-
-    uint64_t cookie = bpf_get_socket_cookie(skb);
-    UidTagValue* utag = bpf_cookie_tag_map_lookup_elem(&cookie);
-    uint32_t uid, tag;
-    if (utag) {
-        uid = utag->uid;
-        tag = utag->tag;
-    } else {
-        uid = sock_uid;
-        tag = 0;
-    }
-
-// Workaround for secureVPN with VpnIsolation enabled, refer to b/159994981 for details.
-// Keep TAG_SYSTEM_DNS in sync with DnsResolver/include/netd_resolv/resolv.h
-// and TrafficStatsConstants.java
-#define TAG_SYSTEM_DNS 0xFFFFFF82
-    if (tag == TAG_SYSTEM_DNS && uid == AID_DNS) {
-        uid = sock_uid;
-        if (match == BPF_DROP_UNLESS_DNS) match = BPF_PASS;
-    } else {
-        if (match == BPF_DROP_UNLESS_DNS) match = BPF_DROP;
-    }
-
-    StatsKey key = {.uid = uid, .tag = tag, .counterSet = 0, .ifaceIndex = skb->ifindex};
-
-    uint8_t* counterSet = bpf_uid_counterset_map_lookup_elem(&uid);
-    if (counterSet) key.counterSet = (uint32_t)*counterSet;
-
-    uint32_t mapSettingKey = CURRENT_STATS_MAP_CONFIGURATION_KEY;
-    uint8_t* selectedMap = bpf_configuration_map_lookup_elem(&mapSettingKey);
-    if (!selectedMap) {
-        return match;
-    }
-
-    if (key.tag) {
-        update_stats_with_config(skb, direction, &key, *selectedMap);
-        key.tag = 0;
-    }
-
-    update_stats_with_config(skb, direction, &key, *selectedMap);
-    update_app_uid_stats_map(skb, direction, &uid);
-    return match;
-}
-
-DEFINE_BPF_PROG("cgroupskb/ingress/stats", AID_ROOT, AID_ROOT, bpf_cgroup_ingress)
-(struct __sk_buff* skb) {
-    return bpf_traffic_account(skb, BPF_INGRESS);
-}
-
-DEFINE_BPF_PROG("cgroupskb/egress/stats", AID_ROOT, AID_ROOT, bpf_cgroup_egress)
-(struct __sk_buff* skb) {
-    return bpf_traffic_account(skb, BPF_EGRESS);
-}
-
-DEFINE_BPF_PROG("skfilter/egress/xtbpf", AID_ROOT, AID_NET_ADMIN, xt_bpf_egress_prog)
-(struct __sk_buff* skb) {
-    // Clat daemon does not generate new traffic, all its traffic is accounted for already
-    // on the v4-* interfaces (except for the 20 (or 28) extra bytes of IPv6 vs IPv4 overhead,
-    // but that can be corrected for later when merging v4-foo stats into interface foo's).
-    uint32_t sock_uid = bpf_get_socket_uid(skb);
-    if (sock_uid == AID_CLAT) return BPF_NOMATCH;
-
-    uint32_t key = skb->ifindex;
-    update_iface_stats_map(skb, BPF_EGRESS, &key);
-    return BPF_MATCH;
-}
-
-DEFINE_BPF_PROG("skfilter/ingress/xtbpf", AID_ROOT, AID_NET_ADMIN, xt_bpf_ingress_prog)
-(struct __sk_buff* skb) {
-    // Clat daemon traffic is not accounted by virtue of iptables raw prerouting drop rule
-    // (in clat_raw_PREROUTING chain), which triggers before this (in bw_raw_PREROUTING chain).
-    // It will be accounted for on the v4-* clat interface instead.
-    // Keep that in mind when moving this out of iptables xt_bpf and into tc ingress (or xdp).
-
-    uint32_t key = skb->ifindex;
-    update_iface_stats_map(skb, BPF_INGRESS, &key);
-    return BPF_MATCH;
-}
-
-DEFINE_BPF_PROG("skfilter/allowlist/xtbpf", AID_ROOT, AID_NET_ADMIN, xt_bpf_allowlist_prog)
-(struct __sk_buff* skb) {
-    uint32_t sock_uid = bpf_get_socket_uid(skb);
-    if (is_system_uid(sock_uid)) return BPF_MATCH;
-
-    // 65534 is the overflow 'nobody' uid, usually this being returned means
-    // that skb->sk is NULL during RX (early decap socket lookup failure),
-    // which commonly happens for incoming packets to an unconnected udp socket.
-    // Additionally bpf_get_socket_cookie() returns 0 if skb->sk is NULL
-    if ((sock_uid == 65534) && !bpf_get_socket_cookie(skb) && is_received_skb(skb))
-        return BPF_MATCH;
-
-    UidOwnerValue* allowlistMatch = bpf_uid_owner_map_lookup_elem(&sock_uid);
-    if (allowlistMatch) return allowlistMatch->rule & HAPPY_BOX_MATCH ? BPF_MATCH : BPF_NOMATCH;
-    return BPF_NOMATCH;
-}
-
-DEFINE_BPF_PROG("skfilter/denylist/xtbpf", AID_ROOT, AID_NET_ADMIN, xt_bpf_denylist_prog)
-(struct __sk_buff* skb) {
-    uint32_t sock_uid = bpf_get_socket_uid(skb);
-    UidOwnerValue* denylistMatch = bpf_uid_owner_map_lookup_elem(&sock_uid);
-    if (denylistMatch) return denylistMatch->rule & PENALTY_BOX_MATCH ? BPF_MATCH : BPF_NOMATCH;
-    return BPF_NOMATCH;
-}
-
-DEFINE_BPF_MAP(uid_permission_map, HASH, uint32_t, uint8_t, UID_OWNER_MAP_SIZE)
-
-DEFINE_BPF_PROG_KVER("cgroupsock/inet/create", AID_ROOT, AID_ROOT, inet_socket_create,
-                     KVER(4, 14, 0))
-(struct bpf_sock* sk) {
-    uint64_t gid_uid = bpf_get_current_uid_gid();
-    /*
-     * A given app is guaranteed to have the same app ID in all the profiles in
-     * which it is installed, and install permission is granted to app for all
-     * user at install time so we only check the appId part of a request uid at
-     * run time. See UserHandle#isSameApp for detail.
-     */
-    uint32_t appId = (gid_uid & 0xffffffff) % PER_USER_RANGE;
-    uint8_t* permissions = bpf_uid_permission_map_lookup_elem(&appId);
-    if (!permissions) {
-        // UID not in map. Default to just INTERNET permission.
-        return 1;
-    }
-
-    // A return value of 1 means allow, everything else means deny.
-    return (*permissions & BPF_PERMISSION_INTERNET) == BPF_PERMISSION_INTERNET;
-}
-
-LICENSE("Apache 2.0");
-CRITICAL("netd");
diff --git a/client/Android.bp b/client/Android.bp
index b8eb56c..22cb5c1 100644
--- a/client/Android.bp
+++ b/client/Android.bp
@@ -34,7 +34,7 @@
     ],
     export_header_lib_headers: ["libnetd_client_headers"],
     include_dirs: [
-        "system/netd/libnetdutils/include",
+        "frameworks/libs/net/common/netd/libnetdutils/include",
     ],
     defaults: ["netd_defaults"],
     sanitize: {
@@ -42,7 +42,6 @@
     },
     apex_available: [
         "//apex_available:platform",
-        "com.android.tethering",
     ],
 }
 
diff --git a/client/FwmarkClient.cpp b/client/FwmarkClient.cpp
index 592fe31..c56e767 100644
--- a/client/FwmarkClient.cpp
+++ b/client/FwmarkClient.cpp
@@ -37,9 +37,7 @@
 const sockaddr_un FWMARK_SERVER_PATH = {AF_UNIX, "/dev/socket/fwmarkd"};
 
 bool commandHasFd(int cmdId) {
-    return (cmdId != FwmarkCommand::QUERY_USER_ACCESS) &&
-        (cmdId != FwmarkCommand::SET_COUNTERSET) &&
-        (cmdId != FwmarkCommand::DELETE_TAGDATA);
+    return (cmdId != FwmarkCommand::QUERY_USER_ACCESS);
 }
 
 }  // namespace
diff --git a/client/NetdClient.cpp b/client/NetdClient.cpp
index 0105a04..2a09a44 100644
--- a/client/NetdClient.cpp
+++ b/client/NetdClient.cpp
@@ -516,14 +516,12 @@
     return FwmarkClient().send(&command, socketFd, nullptr);
 }
 
-extern "C" int setCounterSet(uint32_t counterSet, uid_t uid) {
-    FwmarkCommand command = {FwmarkCommand::SET_COUNTERSET, 0, uid, counterSet};
-    return FwmarkClient().send(&command, -1, nullptr);
+extern "C" int setCounterSet(uint32_t, uid_t) {
+    return -ENOTSUP;
 }
 
-extern "C" int deleteTagData(uint32_t tag, uid_t uid) {
-    FwmarkCommand command = {FwmarkCommand::DELETE_TAGDATA, 0, uid, tag};
-    return FwmarkClient().send(&command, -1, nullptr);
+extern "C" int deleteTagData(uint32_t, uid_t) {
+    return -ENOTSUP;
 }
 
 extern "C" int resNetworkQuery(unsigned netId, const char* dname, int ns_class, int ns_type,
diff --git a/include/FwmarkCommand.h b/include/FwmarkCommand.h
index 83e62d3..c215ed4 100644
--- a/include/FwmarkCommand.h
+++ b/include/FwmarkCommand.h
@@ -64,11 +64,8 @@
         ON_CONNECT_COMPLETE,
         TAG_SOCKET,
         UNTAG_SOCKET,
-        // TODO: use binder to pass the following two request in future after we
-        // completely get rid of qtaguid module, since these are privileged
-        // command.
-        SET_COUNTERSET,
-        DELETE_TAGDATA,
+        _UNUSED_SET_COUNTERSET,  // unsupported, do not use this command
+        _UNUSED_DELETE_TAGDATA,  // unsupported, do not use this command
         ON_SENDMMSG,
         ON_SENDMSG,
         ON_SENDTO,
diff --git a/include/NetdClient.h b/include/NetdClient.h
index cc835ed..9e722f4 100644
--- a/include/NetdClient.h
+++ b/include/NetdClient.h
@@ -46,10 +46,6 @@
 
 int untagSocket(int socketFd);
 
-int setCounterSet(uint32_t counterSet, uid_t uid);
-
-int deleteTagData(uint32_t tag, uid_t uid);
-
 int resNetworkQuery(unsigned netId, const char* dname, int ns_class, int ns_type, uint32_t flags);
 
 int resNetworkResult(int query_fd, int* rcode, uint8_t* answer, size_t anslen);
diff --git a/include/binder_utils/BinderUtil.h b/include/binder_utils/BinderUtil.h
index 469fa68..92754c8 100644
--- a/include/binder_utils/BinderUtil.h
+++ b/include/binder_utils/BinderUtil.h
@@ -16,8 +16,15 @@
 
 #pragma once
 
+#include "NetdPermissions.h"
+
+#include <android-base/stringprintf.h>
 #include <android-base/strings.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/Status.h>
 #include <fmt/format.h>
+#include <private/android_filesystem_config.h>
 
 #ifdef ANDROID_BINDER_STATUS_H
 #define IS_BINDER_OK(__ex__) (__ex__ == ::android::binder::Status::EX_NONE)
@@ -39,7 +46,7 @@
 
 #endif
 
-std::string exceptionToString(int32_t exception) {
+inline std::string exceptionToString(int32_t exception) {
     switch (exception) {
         EXCEPTION_TO_STRING(EX_SECURITY, "SecurityException")
         EXCEPTION_TO_STRING(EX_BAD_PARCELABLE, "BadParcelableException")
@@ -100,3 +107,54 @@
     // escape newline characters to avoid multiline log entries
     logFn(::android::base::StringReplace(output, "\n", "\\n", true));
 }
+
+// The input permissions should be equivalent that this function would return ok if any of them is
+// granted.
+inline android::binder::Status checkAnyPermission(const std::vector<const char*>& permissions) {
+    pid_t pid = android::IPCThreadState::self()->getCallingPid();
+    uid_t uid = android::IPCThreadState::self()->getCallingUid();
+
+    // TODO: Do the pure permission check in this function. Have another method
+    // (e.g. checkNetworkStackPermission) to wrap AID_SYSTEM and
+    // AID_NETWORK_STACK uid check.
+    // If the caller is the system UID, don't check permissions.
+    // Otherwise, if the system server's binder thread pool is full, and all the threads are
+    // blocked on a thread that's waiting for us to complete, we deadlock. http://b/69389492
+    //
+    // From a security perspective, there is currently no difference, because:
+    // 1. The system server has the NETWORK_STACK permission, which grants access to all the
+    //    IPCs in this file.
+    // 2. AID_SYSTEM always has all permissions. See ActivityManager#checkComponentPermission.
+    if (uid == AID_SYSTEM) {
+        return android::binder::Status::ok();
+    }
+    // AID_NETWORK_STACK own MAINLINE_NETWORK_STACK permission, don't IPC to system server to check
+    // MAINLINE_NETWORK_STACK permission. Cross-process(netd, networkstack and system server)
+    // deadlock: http://b/149766727
+    if (uid == AID_NETWORK_STACK) {
+        for (const char* permission : permissions) {
+            if (std::strcmp(permission, PERM_MAINLINE_NETWORK_STACK) == 0) {
+                return android::binder::Status::ok();
+            }
+        }
+    }
+
+    for (const char* permission : permissions) {
+        if (checkPermission(android::String16(permission), pid, uid)) {
+            return android::binder::Status::ok();
+        }
+    }
+
+    auto err = android::base::StringPrintf(
+            "UID %d / PID %d does not have any of the following permissions: %s", uid, pid,
+            android::base::Join(permissions, ',').c_str());
+    return android::binder::Status::fromExceptionCode(android::binder::Status::EX_SECURITY,
+                                                      err.c_str());
+}
+
+inline android::binder::Status statusFromErrcode(int ret) {
+    if (ret) {
+        return android::binder::Status::fromServiceSpecificError(-ret, strerror(-ret));
+    }
+    return android::binder::Status::ok();
+}
diff --git a/libnetdbpf/Android.bp b/libnetdbpf/Android.bp
deleted file mode 100644
index 7c0207c..0000000
--- a/libnetdbpf/Android.bp
+++ /dev/null
@@ -1,63 +0,0 @@
-//
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-package {
-    // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "system_netd_license"
-    // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
-    default_applicable_licenses: ["system_netd_license"],
-}
-
-cc_library {
-    name: "libnetdbpf",
-    vendor_available: false,
-    host_supported: false,
-    srcs: [
-        "BpfNetworkStats.cpp"
-    ],
-    shared_libs: [
-        "libbase",
-        "libbpf_android",
-        "liblog",
-        "libnetdutils",
-    ],
-    export_include_dirs: ["include"],
-    defaults: ["netd_defaults"],
-    sanitize: {
-        cfi: true,
-    },
-}
-
-cc_test {
-    name: "libnetdbpf_test",
-    test_suites: ["device-tests"],
-    require_root: true,
-    srcs: [
-        "BpfNetworkStatsTest.cpp",
-    ],
-    defaults: ["netd_defaults"],
-    static_libs: ["libgmock"],
-    shared_libs: [
-        "libbase",
-        "libbpf_android",
-        "liblog",
-        "libnetdbpf",
-        "libnetdutils",
-        "libutils",
-    ],
-}
diff --git a/libnetdbpf/BpfNetworkStats.cpp b/libnetdbpf/BpfNetworkStats.cpp
deleted file mode 100644
index a77f6f9..0000000
--- a/libnetdbpf/BpfNetworkStats.cpp
+++ /dev/null
@@ -1,350 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <inttypes.h>
-#include <net/if.h>
-#include <string.h>
-#include <unordered_set>
-
-#include <utils/Log.h>
-#include <utils/misc.h>
-
-#include "android-base/file.h"
-#include "android-base/strings.h"
-#include "android-base/unique_fd.h"
-#include "bpf/BpfMap.h"
-#include "netdbpf/BpfNetworkStats.h"
-#include "netdbpf/bpf_shared.h"
-
-#ifdef LOG_TAG
-#undef LOG_TAG
-#endif
-
-#define LOG_TAG "BpfNetworkStats"
-
-namespace android {
-namespace bpf {
-
-using base::Result;
-
-// The target map for stats reading should be the inactive map, which is oppsite
-// from the config value.
-static constexpr char const* STATS_MAP_PATH[] = {STATS_MAP_B_PATH, STATS_MAP_A_PATH};
-
-int bpfGetUidStatsInternal(uid_t uid, Stats* stats,
-                           const BpfMap<uint32_t, StatsValue>& appUidStatsMap) {
-    auto statsEntry = appUidStatsMap.readValue(uid);
-    if (statsEntry.ok()) {
-        stats->rxPackets = statsEntry.value().rxPackets;
-        stats->txPackets = statsEntry.value().txPackets;
-        stats->rxBytes = statsEntry.value().rxBytes;
-        stats->txBytes = statsEntry.value().txBytes;
-    }
-    return (statsEntry.ok() || statsEntry.error().code() == ENOENT) ? 0
-                                                                    : -statsEntry.error().code();
-}
-
-int bpfGetUidStats(uid_t uid, Stats* stats) {
-    BpfMapRO<uint32_t, StatsValue> appUidStatsMap(APP_UID_STATS_MAP_PATH);
-
-    if (!appUidStatsMap.isValid()) {
-        int ret = -errno;
-        ALOGE("Opening appUidStatsMap(%s) failed: %s", APP_UID_STATS_MAP_PATH, strerror(errno));
-        return ret;
-    }
-    return bpfGetUidStatsInternal(uid, stats, appUidStatsMap);
-}
-
-int bpfGetIfaceStatsInternal(const char* iface, Stats* stats,
-                             const BpfMap<uint32_t, StatsValue>& ifaceStatsMap,
-                             const BpfMap<uint32_t, IfaceValue>& ifaceNameMap) {
-    int64_t unknownIfaceBytesTotal = 0;
-    stats->tcpRxPackets = -1;
-    stats->tcpTxPackets = -1;
-    const auto processIfaceStats =
-            [iface, stats, &ifaceNameMap, &unknownIfaceBytesTotal](
-                    const uint32_t& key,
-                    const BpfMap<uint32_t, StatsValue>& ifaceStatsMap) -> Result<void> {
-        char ifname[IFNAMSIZ];
-        if (getIfaceNameFromMap(ifaceNameMap, ifaceStatsMap, key, ifname, key,
-                                &unknownIfaceBytesTotal)) {
-            return Result<void>();
-        }
-        if (!iface || !strcmp(iface, ifname)) {
-            Result<StatsValue> statsEntry = ifaceStatsMap.readValue(key);
-            if (!statsEntry.ok()) {
-                return statsEntry.error();
-            }
-            stats->rxPackets += statsEntry.value().rxPackets;
-            stats->txPackets += statsEntry.value().txPackets;
-            stats->rxBytes += statsEntry.value().rxBytes;
-            stats->txBytes += statsEntry.value().txBytes;
-        }
-        return Result<void>();
-    };
-    auto res = ifaceStatsMap.iterate(processIfaceStats);
-    return res.ok() ? 0 : -res.error().code();
-}
-
-int bpfGetIfaceStats(const char* iface, Stats* stats) {
-    BpfMapRO<uint32_t, StatsValue> ifaceStatsMap(IFACE_STATS_MAP_PATH);
-    int ret;
-    if (!ifaceStatsMap.isValid()) {
-        ret = -errno;
-        ALOGE("get ifaceStats map fd failed: %s", strerror(errno));
-        return ret;
-    }
-    BpfMapRO<uint32_t, IfaceValue> ifaceIndexNameMap(IFACE_INDEX_NAME_MAP_PATH);
-    if (!ifaceIndexNameMap.isValid()) {
-        ret = -errno;
-        ALOGE("get ifaceIndexName map fd failed: %s", strerror(errno));
-        return ret;
-    }
-    return bpfGetIfaceStatsInternal(iface, stats, ifaceStatsMap, ifaceIndexNameMap);
-}
-
-stats_line populateStatsEntry(const StatsKey& statsKey, const StatsValue& statsEntry,
-                              const char* ifname) {
-    stats_line newLine;
-    strlcpy(newLine.iface, ifname, sizeof(newLine.iface));
-    newLine.uid = (int32_t)statsKey.uid;
-    newLine.set = (int32_t)statsKey.counterSet;
-    newLine.tag = (int32_t)statsKey.tag;
-    newLine.rxPackets = statsEntry.rxPackets;
-    newLine.txPackets = statsEntry.txPackets;
-    newLine.rxBytes = statsEntry.rxBytes;
-    newLine.txBytes = statsEntry.txBytes;
-    return newLine;
-}
-
-int parseBpfNetworkStatsDetailInternal(std::vector<stats_line>* lines,
-                                       const std::vector<std::string>& limitIfaces, int limitTag,
-                                       int limitUid, const BpfMap<StatsKey, StatsValue>& statsMap,
-                                       const BpfMap<uint32_t, IfaceValue>& ifaceMap) {
-    int64_t unknownIfaceBytesTotal = 0;
-    const auto processDetailUidStats =
-            [lines, &limitIfaces, &limitTag, &limitUid, &unknownIfaceBytesTotal, &ifaceMap](
-                    const StatsKey& key,
-                    const BpfMap<StatsKey, StatsValue>& statsMap) -> Result<void> {
-        char ifname[IFNAMSIZ];
-        if (getIfaceNameFromMap(ifaceMap, statsMap, key.ifaceIndex, ifname, key,
-                                &unknownIfaceBytesTotal)) {
-            return Result<void>();
-        }
-        std::string ifnameStr(ifname);
-        if (limitIfaces.size() > 0 &&
-            std::find(limitIfaces.begin(), limitIfaces.end(), ifnameStr) == limitIfaces.end()) {
-            // Nothing matched; skip this line.
-            return Result<void>();
-        }
-        if (limitTag != TAG_ALL && uint32_t(limitTag) != key.tag) {
-            return Result<void>();
-        }
-        if (limitUid != UID_ALL && uint32_t(limitUid) != key.uid) {
-            return Result<void>();
-        }
-        Result<StatsValue> statsEntry = statsMap.readValue(key);
-        if (!statsEntry.ok()) {
-            return base::ResultError(statsEntry.error().message(), statsEntry.error().code());
-        }
-        lines->push_back(populateStatsEntry(key, statsEntry.value(), ifname));
-        return Result<void>();
-    };
-    Result<void> res = statsMap.iterate(processDetailUidStats);
-    if (!res.ok()) {
-        ALOGE("failed to iterate per uid Stats map for detail traffic stats: %s",
-              strerror(res.error().code()));
-        return -res.error().code();
-    }
-
-    // Since eBPF use hash map to record stats, network stats collected from
-    // eBPF will be out of order. And the performance of findIndexHinted in
-    // NetworkStats will also be impacted.
-    //
-    // Furthermore, since the StatsKey contains iface index, the network stats
-    // reported to framework would create items with the same iface, uid, tag
-    // and set, which causes NetworkStats maps wrong item to subtract.
-    //
-    // Thus, the stats needs to be properly sorted and grouped before reported.
-    groupNetworkStats(lines);
-    return 0;
-}
-
-int parseBpfNetworkStatsDetail(std::vector<stats_line>* lines,
-                               const std::vector<std::string>& limitIfaces, int limitTag,
-                               int limitUid) {
-    BpfMapRO<uint32_t, IfaceValue> ifaceIndexNameMap(IFACE_INDEX_NAME_MAP_PATH);
-    if (!ifaceIndexNameMap.isValid()) {
-        int ret = -errno;
-        ALOGE("get ifaceIndexName map fd failed: %s", strerror(errno));
-        return ret;
-    }
-
-    BpfMapRO<uint32_t, uint8_t> configurationMap(CONFIGURATION_MAP_PATH);
-    if (!configurationMap.isValid()) {
-        int ret = -errno;
-        ALOGE("get configuration map fd failed: %s", strerror(errno));
-        return ret;
-    }
-    auto configuration = configurationMap.readValue(CURRENT_STATS_MAP_CONFIGURATION_KEY);
-    if (!configuration.ok()) {
-        ALOGE("Cannot read the old configuration from map: %s",
-              configuration.error().message().c_str());
-        return -configuration.error().code();
-    }
-    const char* statsMapPath = STATS_MAP_PATH[configuration.value()];
-    BpfMap<StatsKey, StatsValue> statsMap(statsMapPath);
-    if (!statsMap.isValid()) {
-        int ret = -errno;
-        ALOGE("get stats map fd failed: %s, path: %s", strerror(errno), statsMapPath);
-        return ret;
-    }
-
-    // It is safe to read and clear the old map now since the
-    // networkStatsFactory should call netd to swap the map in advance already.
-    int ret = parseBpfNetworkStatsDetailInternal(lines, limitIfaces, limitTag, limitUid, statsMap,
-                                                 ifaceIndexNameMap);
-    if (ret) {
-        ALOGE("parse detail network stats failed: %s", strerror(errno));
-        return ret;
-    }
-
-    Result<void> res = statsMap.clear();
-    if (!res.ok()) {
-        ALOGE("Clean up current stats map failed: %s", strerror(res.error().code()));
-        return -res.error().code();
-    }
-
-    return 0;
-}
-
-int parseBpfNetworkStatsDevInternal(std::vector<stats_line>* lines,
-                                    const BpfMap<uint32_t, StatsValue>& statsMap,
-                                    const BpfMap<uint32_t, IfaceValue>& ifaceMap) {
-    int64_t unknownIfaceBytesTotal = 0;
-    const auto processDetailIfaceStats = [lines, &unknownIfaceBytesTotal, &ifaceMap, &statsMap](
-                                             const uint32_t& key, const StatsValue& value,
-                                             const BpfMap<uint32_t, StatsValue>&) {
-        char ifname[IFNAMSIZ];
-        if (getIfaceNameFromMap(ifaceMap, statsMap, key, ifname, key, &unknownIfaceBytesTotal)) {
-            return Result<void>();
-        }
-        StatsKey fakeKey = {
-                .uid = (uint32_t)UID_ALL,
-                .tag = (uint32_t)TAG_NONE,
-                .counterSet = (uint32_t)SET_ALL,
-        };
-        lines->push_back(populateStatsEntry(fakeKey, value, ifname));
-        return Result<void>();
-    };
-    Result<void> res = statsMap.iterateWithValue(processDetailIfaceStats);
-    if (!res.ok()) {
-        ALOGE("failed to iterate per uid Stats map for detail traffic stats: %s",
-              strerror(res.error().code()));
-        return -res.error().code();
-    }
-
-    groupNetworkStats(lines);
-    return 0;
-}
-
-int parseBpfNetworkStatsDev(std::vector<stats_line>* lines) {
-    int ret = 0;
-    BpfMapRO<uint32_t, IfaceValue> ifaceIndexNameMap(IFACE_INDEX_NAME_MAP_PATH);
-    if (!ifaceIndexNameMap.isValid()) {
-        ret = -errno;
-        ALOGE("get ifaceIndexName map fd failed: %s", strerror(errno));
-        return ret;
-    }
-
-    BpfMapRO<uint32_t, StatsValue> ifaceStatsMap(IFACE_STATS_MAP_PATH);
-    if (!ifaceStatsMap.isValid()) {
-        ret = -errno;
-        ALOGE("get ifaceStats map fd failed: %s", strerror(errno));
-        return ret;
-    }
-    return parseBpfNetworkStatsDevInternal(lines, ifaceStatsMap, ifaceIndexNameMap);
-}
-
-uint64_t combineUidTag(const uid_t uid, const uint32_t tag) {
-    return (uint64_t)uid << 32 | tag;
-}
-
-void groupNetworkStats(std::vector<stats_line>* lines) {
-    if (lines->size() <= 1) return;
-    std::sort(lines->begin(), lines->end());
-
-    // Similar to std::unique(), but aggregates the duplicates rather than discarding them.
-    size_t nextOutput = 0;
-    for (size_t i = 1; i < lines->size(); i++) {
-        if (lines->at(nextOutput) == lines->at(i)) {
-            lines->at(nextOutput) += lines->at(i);
-        } else {
-            nextOutput++;
-            if (nextOutput != i) {
-                lines->at(nextOutput) = lines->at(i);
-            }
-        }
-    }
-
-    if (lines->size() != nextOutput + 1) {
-        lines->resize(nextOutput + 1);
-    }
-}
-
-// True if lhs equals to rhs, only compare iface, uid, tag and set.
-bool operator==(const stats_line& lhs, const stats_line& rhs) {
-    return ((lhs.uid == rhs.uid) && (lhs.tag == rhs.tag) && (lhs.set == rhs.set) &&
-            !strncmp(lhs.iface, rhs.iface, sizeof(lhs.iface)));
-}
-
-// True if lhs is smaller then rhs, only compare iface, uid, tag and set.
-bool operator<(const stats_line& lhs, const stats_line& rhs) {
-    int ret = strncmp(lhs.iface, rhs.iface, sizeof(lhs.iface));
-    if (ret != 0) return ret < 0;
-    if (lhs.uid < rhs.uid) return true;
-    if (lhs.uid > rhs.uid) return false;
-    if (lhs.tag < rhs.tag) return true;
-    if (lhs.tag > rhs.tag) return false;
-    if (lhs.set < rhs.set) return true;
-    if (lhs.set > rhs.set) return false;
-    return false;
-}
-
-stats_line& stats_line::operator=(const stats_line& rhs) {
-    if (this == &rhs) return *this;
-
-    strlcpy(iface, rhs.iface, sizeof(iface));
-    uid = rhs.uid;
-    set = rhs.set;
-    tag = rhs.tag;
-    rxPackets = rhs.rxPackets;
-    txPackets = rhs.txPackets;
-    rxBytes = rhs.rxBytes;
-    txBytes = rhs.txBytes;
-    return *this;
-}
-
-stats_line& stats_line::operator+=(const stats_line& rhs) {
-    rxPackets += rhs.rxPackets;
-    txPackets += rhs.txPackets;
-    rxBytes += rhs.rxBytes;
-    txBytes += rhs.txBytes;
-    return *this;
-}
-
-}  // namespace bpf
-}  // namespace android
diff --git a/libnetdbpf/BpfNetworkStatsTest.cpp b/libnetdbpf/BpfNetworkStatsTest.cpp
deleted file mode 100644
index fb8f0ec..0000000
--- a/libnetdbpf/BpfNetworkStatsTest.cpp
+++ /dev/null
@@ -1,570 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <fstream>
-#include <iostream>
-#include <string>
-#include <vector>
-
-#include <fcntl.h>
-#include <inttypes.h>
-#include <linux/inet_diag.h>
-#include <linux/sock_diag.h>
-#include <net/if.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <gtest/gtest.h>
-
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-
-#include <netdutils/MockSyscalls.h>
-#include "bpf/BpfMap.h"
-#include "bpf/BpfUtils.h"
-#include "netdbpf/BpfNetworkStats.h"
-
-using ::testing::Test;
-
-namespace android {
-namespace bpf {
-
-using base::Result;
-using base::unique_fd;
-
-constexpr int TEST_MAP_SIZE = 10;
-constexpr uid_t TEST_UID1 = 10086;
-constexpr uid_t TEST_UID2 = 12345;
-constexpr uint32_t TEST_TAG = 42;
-constexpr int TEST_COUNTERSET0 = 0;
-constexpr int TEST_COUNTERSET1 = 1;
-constexpr uint64_t TEST_BYTES0 = 1000;
-constexpr uint64_t TEST_BYTES1 = 2000;
-constexpr uint64_t TEST_PACKET0 = 100;
-constexpr uint64_t TEST_PACKET1 = 200;
-constexpr const char IFACE_NAME1[] = "lo";
-constexpr const char IFACE_NAME2[] = "wlan0";
-constexpr const char IFACE_NAME3[] = "rmnet_data0";
-// A iface name that the size is bigger then IFNAMSIZ
-constexpr const char LONG_IFACE_NAME[] = "wlanWithALongName";
-constexpr const char TRUNCATED_IFACE_NAME[] = "wlanWithALongNa";
-constexpr uint32_t IFACE_INDEX1 = 1;
-constexpr uint32_t IFACE_INDEX2 = 2;
-constexpr uint32_t IFACE_INDEX3 = 3;
-constexpr uint32_t IFACE_INDEX4 = 4;
-constexpr uint32_t UNKNOWN_IFACE = 0;
-
-class BpfNetworkStatsHelperTest : public testing::Test {
-  protected:
-    BpfNetworkStatsHelperTest() {}
-    BpfMap<uint64_t, UidTagValue> mFakeCookieTagMap;
-    BpfMap<uint32_t, StatsValue> mFakeAppUidStatsMap;
-    BpfMap<StatsKey, StatsValue> mFakeStatsMap;
-    BpfMap<uint32_t, IfaceValue> mFakeIfaceIndexNameMap;
-    BpfMap<uint32_t, StatsValue> mFakeIfaceStatsMap;
-
-    void SetUp() {
-        ASSERT_EQ(0, setrlimitForTest());
-
-        mFakeCookieTagMap = BpfMap<uint64_t, UidTagValue>(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, 0);
-        ASSERT_LE(0, mFakeCookieTagMap.getMap());
-
-        mFakeAppUidStatsMap = BpfMap<uint32_t, StatsValue>(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, 0);
-        ASSERT_LE(0, mFakeAppUidStatsMap.getMap());
-
-        mFakeStatsMap = BpfMap<StatsKey, StatsValue>(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, 0);
-        ASSERT_LE(0, mFakeStatsMap.getMap());
-
-        mFakeIfaceIndexNameMap = BpfMap<uint32_t, IfaceValue>(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, 0);
-        ASSERT_LE(0, mFakeIfaceIndexNameMap.getMap());
-
-        mFakeIfaceStatsMap = BpfMap<uint32_t, StatsValue>(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, 0);
-        ASSERT_LE(0, mFakeIfaceStatsMap.getMap());
-    }
-
-    void expectUidTag(uint64_t cookie, uid_t uid, uint32_t tag) {
-        auto tagResult = mFakeCookieTagMap.readValue(cookie);
-        EXPECT_RESULT_OK(tagResult);
-        EXPECT_EQ(uid, tagResult.value().uid);
-        EXPECT_EQ(tag, tagResult.value().tag);
-    }
-
-    void populateFakeStats(uid_t uid, uint32_t tag, uint32_t ifaceIndex, uint32_t counterSet,
-                           StatsValue value, BpfMap<StatsKey, StatsValue>& map) {
-        StatsKey key = {
-            .uid = (uint32_t)uid, .tag = tag, .counterSet = counterSet, .ifaceIndex = ifaceIndex};
-        EXPECT_RESULT_OK(map.writeValue(key, value, BPF_ANY));
-    }
-
-    void updateIfaceMap(const char* ifaceName, uint32_t ifaceIndex) {
-        IfaceValue iface;
-        strlcpy(iface.name, ifaceName, IFNAMSIZ);
-        EXPECT_RESULT_OK(mFakeIfaceIndexNameMap.writeValue(ifaceIndex, iface, BPF_ANY));
-    }
-
-    void expectStatsEqual(const StatsValue& target, const Stats& result) {
-        EXPECT_EQ(target.rxPackets, result.rxPackets);
-        EXPECT_EQ(target.rxBytes, result.rxBytes);
-        EXPECT_EQ(target.txPackets, result.txPackets);
-        EXPECT_EQ(target.txBytes, result.txBytes);
-    }
-
-    void expectStatsLineEqual(const StatsValue target, const char* iface, uint32_t uid,
-                              int counterSet, uint32_t tag, const stats_line& result) {
-        EXPECT_EQ(0, strcmp(iface, result.iface));
-        EXPECT_EQ(uid, (uint32_t)result.uid);
-        EXPECT_EQ((uint32_t) counterSet, result.set);
-        EXPECT_EQ(tag, (uint32_t)result.tag);
-        EXPECT_EQ(target.rxPackets, (uint64_t)result.rxPackets);
-        EXPECT_EQ(target.rxBytes, (uint64_t)result.rxBytes);
-        EXPECT_EQ(target.txPackets, (uint64_t)result.txPackets);
-        EXPECT_EQ(target.txBytes, (uint64_t)result.txBytes);
-    }
-};
-
-// TEST to verify the behavior of bpf map when cocurrent deletion happens when
-// iterating the same map.
-TEST_F(BpfNetworkStatsHelperTest, TestIterateMapWithDeletion) {
-    for (int i = 0; i < 5; i++) {
-        uint64_t cookie = i + 1;
-        UidTagValue tag = {.uid = TEST_UID1, .tag = TEST_TAG};
-        EXPECT_RESULT_OK(mFakeCookieTagMap.writeValue(cookie, tag, BPF_ANY));
-    }
-    uint64_t curCookie = 0;
-    auto nextCookie = mFakeCookieTagMap.getNextKey(curCookie);
-    EXPECT_RESULT_OK(nextCookie);
-    uint64_t headOfMap = nextCookie.value();
-    curCookie = nextCookie.value();
-    // Find the second entry in the map, then immediately delete it.
-    nextCookie = mFakeCookieTagMap.getNextKey(curCookie);
-    EXPECT_RESULT_OK(nextCookie);
-    EXPECT_RESULT_OK(mFakeCookieTagMap.deleteValue((nextCookie.value())));
-    // Find the entry that is now immediately after headOfMap, then delete that.
-    nextCookie = mFakeCookieTagMap.getNextKey(curCookie);
-    EXPECT_RESULT_OK(nextCookie);
-    EXPECT_RESULT_OK(mFakeCookieTagMap.deleteValue((nextCookie.value())));
-    // Attempting to read an entry that has been deleted fails with ENOENT.
-    curCookie = nextCookie.value();
-    auto tagResult = mFakeCookieTagMap.readValue(curCookie);
-    EXPECT_EQ(ENOENT, tagResult.error().code());
-    // Finding the entry after our deleted entry restarts iteration from the beginning of the map.
-    nextCookie = mFakeCookieTagMap.getNextKey(curCookie);
-    EXPECT_RESULT_OK(nextCookie);
-    EXPECT_EQ(headOfMap, nextCookie.value());
-}
-
-TEST_F(BpfNetworkStatsHelperTest, TestBpfIterateMap) {
-    for (int i = 0; i < 5; i++) {
-        uint64_t cookie = i + 1;
-        UidTagValue tag = {.uid = TEST_UID1, .tag = TEST_TAG};
-        EXPECT_RESULT_OK(mFakeCookieTagMap.writeValue(cookie, tag, BPF_ANY));
-    }
-    int totalCount = 0;
-    int totalSum = 0;
-    const auto iterateWithoutDeletion =
-            [&totalCount, &totalSum](const uint64_t& key, const BpfMap<uint64_t, UidTagValue>&) {
-                EXPECT_GE((uint64_t)5, key);
-                totalCount++;
-                totalSum += key;
-                return Result<void>();
-            };
-    EXPECT_RESULT_OK(mFakeCookieTagMap.iterate(iterateWithoutDeletion));
-    EXPECT_EQ(5, totalCount);
-    EXPECT_EQ(1 + 2 + 3 + 4 + 5, totalSum);
-}
-
-TEST_F(BpfNetworkStatsHelperTest, TestUidStatsNoTraffic) {
-    StatsValue value1 = {
-            .rxPackets = 0,
-            .rxBytes = 0,
-            .txPackets = 0,
-            .txBytes = 0,
-    };
-    Stats result1 = {};
-    ASSERT_EQ(0, bpfGetUidStatsInternal(TEST_UID1, &result1, mFakeAppUidStatsMap));
-    expectStatsEqual(value1, result1);
-}
-
-TEST_F(BpfNetworkStatsHelperTest, TestGetUidStatsTotal) {
-    updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
-    updateIfaceMap(IFACE_NAME2, IFACE_INDEX2);
-    updateIfaceMap(IFACE_NAME3, IFACE_INDEX3);
-    StatsValue value1 = {
-            .rxPackets = TEST_PACKET0,
-            .rxBytes = TEST_BYTES0,
-            .txPackets = TEST_PACKET1,
-            .txBytes = TEST_BYTES1,
-    };
-    StatsValue value2 = {
-            .rxPackets = TEST_PACKET0 * 2,
-            .rxBytes = TEST_BYTES0 * 2,
-            .txPackets = TEST_PACKET1 * 2,
-            .txBytes = TEST_BYTES1 * 2,
-    };
-    ASSERT_RESULT_OK(mFakeAppUidStatsMap.writeValue(TEST_UID1, value1, BPF_ANY));
-    ASSERT_RESULT_OK(mFakeAppUidStatsMap.writeValue(TEST_UID2, value2, BPF_ANY));
-    Stats result1 = {};
-    ASSERT_EQ(0, bpfGetUidStatsInternal(TEST_UID1, &result1, mFakeAppUidStatsMap));
-    expectStatsEqual(value1, result1);
-
-    Stats result2 = {};
-    ASSERT_EQ(0, bpfGetUidStatsInternal(TEST_UID2, &result2, mFakeAppUidStatsMap));
-    expectStatsEqual(value2, result2);
-    std::vector<stats_line> lines;
-    std::vector<std::string> ifaces;
-    populateFakeStats(TEST_UID1, 0, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
-    populateFakeStats(TEST_UID1, 0, IFACE_INDEX2, TEST_COUNTERSET1, value1, mFakeStatsMap);
-    populateFakeStats(TEST_UID2, 0, IFACE_INDEX3, TEST_COUNTERSET1, value1, mFakeStatsMap);
-    ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, TEST_UID1,
-                                                    mFakeStatsMap, mFakeIfaceIndexNameMap));
-    ASSERT_EQ((unsigned long)2, lines.size());
-    lines.clear();
-    ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, TEST_UID2,
-                                                    mFakeStatsMap, mFakeIfaceIndexNameMap));
-    ASSERT_EQ((unsigned long)1, lines.size());
-    expectStatsLineEqual(value1, IFACE_NAME3, TEST_UID2, TEST_COUNTERSET1, 0, lines.front());
-}
-
-TEST_F(BpfNetworkStatsHelperTest, TestGetIfaceStatsInternal) {
-    updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
-    updateIfaceMap(IFACE_NAME2, IFACE_INDEX2);
-    updateIfaceMap(IFACE_NAME3, IFACE_INDEX3);
-    StatsValue value1 = {
-            .rxPackets = TEST_PACKET0,
-            .rxBytes = TEST_BYTES0,
-            .txPackets = TEST_PACKET1,
-            .txBytes = TEST_BYTES1,
-    };
-    StatsValue value2 = {
-            .rxPackets = TEST_PACKET1,
-            .rxBytes = TEST_BYTES1,
-            .txPackets = TEST_PACKET0,
-            .txBytes = TEST_BYTES0,
-    };
-    uint32_t ifaceStatsKey = IFACE_INDEX1;
-    EXPECT_RESULT_OK(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value1, BPF_ANY));
-    ifaceStatsKey = IFACE_INDEX2;
-    EXPECT_RESULT_OK(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value2, BPF_ANY));
-    ifaceStatsKey = IFACE_INDEX3;
-    EXPECT_RESULT_OK(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value1, BPF_ANY));
-
-    Stats result1 = {};
-    ASSERT_EQ(0, bpfGetIfaceStatsInternal(IFACE_NAME1, &result1, mFakeIfaceStatsMap,
-                                          mFakeIfaceIndexNameMap));
-    expectStatsEqual(value1, result1);
-    Stats result2 = {};
-    ASSERT_EQ(0, bpfGetIfaceStatsInternal(IFACE_NAME2, &result2, mFakeIfaceStatsMap,
-                                          mFakeIfaceIndexNameMap));
-    expectStatsEqual(value2, result2);
-    Stats totalResult = {};
-    ASSERT_EQ(0, bpfGetIfaceStatsInternal(NULL, &totalResult, mFakeIfaceStatsMap,
-                                          mFakeIfaceIndexNameMap));
-    StatsValue totalValue = {
-            .rxPackets = TEST_PACKET0 * 2 + TEST_PACKET1,
-            .rxBytes = TEST_BYTES0 * 2 + TEST_BYTES1,
-            .txPackets = TEST_PACKET1 * 2 + TEST_PACKET0,
-            .txBytes = TEST_BYTES1 * 2 + TEST_BYTES0,
-    };
-    expectStatsEqual(totalValue, totalResult);
-}
-
-TEST_F(BpfNetworkStatsHelperTest, TestGetStatsDetail) {
-    updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
-    updateIfaceMap(IFACE_NAME2, IFACE_INDEX2);
-    StatsValue value1 = {
-            .rxPackets = TEST_PACKET0,
-            .rxBytes = TEST_BYTES0,
-            .txPackets = TEST_PACKET1,
-            .txBytes = TEST_BYTES1,
-    };
-    populateFakeStats(TEST_UID1, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
-    populateFakeStats(TEST_UID1, TEST_TAG, IFACE_INDEX2, TEST_COUNTERSET0, value1, mFakeStatsMap);
-    populateFakeStats(TEST_UID1, TEST_TAG + 1, IFACE_INDEX1, TEST_COUNTERSET0, value1,
-                      mFakeStatsMap);
-    populateFakeStats(TEST_UID2, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
-    std::vector<stats_line> lines;
-    std::vector<std::string> ifaces;
-    ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL, mFakeStatsMap,
-                                                    mFakeIfaceIndexNameMap));
-    ASSERT_EQ((unsigned long)4, lines.size());
-    lines.clear();
-    ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, TEST_UID1,
-                                                    mFakeStatsMap, mFakeIfaceIndexNameMap));
-    ASSERT_EQ((unsigned long)3, lines.size());
-    lines.clear();
-    ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TEST_TAG, TEST_UID1,
-                                                    mFakeStatsMap, mFakeIfaceIndexNameMap));
-    ASSERT_EQ((unsigned long)2, lines.size());
-    lines.clear();
-    ifaces.push_back(std::string(IFACE_NAME1));
-    ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TEST_TAG, TEST_UID1,
-                                                    mFakeStatsMap, mFakeIfaceIndexNameMap));
-    ASSERT_EQ((unsigned long)1, lines.size());
-    expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, TEST_TAG, lines.front());
-}
-
-TEST_F(BpfNetworkStatsHelperTest, TestGetStatsWithSkippedIface) {
-    updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
-    updateIfaceMap(IFACE_NAME2, IFACE_INDEX2);
-    StatsValue value1 = {
-            .rxPackets = TEST_PACKET0,
-            .rxBytes = TEST_BYTES0,
-            .txPackets = TEST_PACKET1,
-            .txBytes = TEST_BYTES1,
-    };
-    populateFakeStats(0, 0, 0, OVERFLOW_COUNTERSET, value1, mFakeStatsMap);
-    populateFakeStats(TEST_UID1, 0, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
-    populateFakeStats(TEST_UID1, 0, IFACE_INDEX2, TEST_COUNTERSET0, value1, mFakeStatsMap);
-    populateFakeStats(TEST_UID1, 0, IFACE_INDEX1, TEST_COUNTERSET1, value1, mFakeStatsMap);
-    populateFakeStats(TEST_UID2, 0, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
-    std::vector<stats_line> lines;
-    std::vector<std::string> ifaces;
-    ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL, mFakeStatsMap,
-                                                    mFakeIfaceIndexNameMap));
-    ASSERT_EQ((unsigned long)4, lines.size());
-    lines.clear();
-    ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, TEST_UID1,
-                                                    mFakeStatsMap, mFakeIfaceIndexNameMap));
-    ASSERT_EQ((unsigned long)3, lines.size());
-    lines.clear();
-    ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, TEST_UID2,
-                                                    mFakeStatsMap, mFakeIfaceIndexNameMap));
-    ASSERT_EQ((unsigned long)1, lines.size());
-    expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID2, TEST_COUNTERSET0, 0, lines.front());
-    lines.clear();
-    ifaces.push_back(std::string(IFACE_NAME1));
-    ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, TEST_UID1,
-                                                    mFakeStatsMap, mFakeIfaceIndexNameMap));
-    ASSERT_EQ((unsigned long)2, lines.size());
-}
-
-TEST_F(BpfNetworkStatsHelperTest, TestUnkownIfaceError) {
-    updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
-    StatsValue value1 = {
-            .rxPackets = TEST_PACKET0,
-            .rxBytes = TEST_BYTES0 * 20,
-            .txPackets = TEST_PACKET1,
-            .txBytes = TEST_BYTES1 * 20,
-    };
-    uint32_t ifaceIndex = UNKNOWN_IFACE;
-    populateFakeStats(TEST_UID1, 0, ifaceIndex, TEST_COUNTERSET0, value1, mFakeStatsMap);
-    populateFakeStats(TEST_UID1, 0, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
-    StatsValue value2 = {
-            .rxPackets = TEST_PACKET0,
-            .rxBytes = TEST_BYTES0 * 40,
-            .txPackets = TEST_PACKET1,
-            .txBytes = TEST_BYTES1 * 40,
-    };
-    populateFakeStats(TEST_UID1, 0, IFACE_INDEX2, TEST_COUNTERSET0, value2, mFakeStatsMap);
-    StatsKey curKey = {
-            .uid = TEST_UID1,
-            .tag = 0,
-            .counterSet = TEST_COUNTERSET0,
-            .ifaceIndex = ifaceIndex,
-    };
-    char ifname[IFNAMSIZ];
-    int64_t unknownIfaceBytesTotal = 0;
-    ASSERT_EQ(-ENODEV, getIfaceNameFromMap(mFakeIfaceIndexNameMap, mFakeStatsMap, ifaceIndex,
-                                           ifname, curKey, &unknownIfaceBytesTotal));
-    ASSERT_EQ(((int64_t)(TEST_BYTES0 * 20 + TEST_BYTES1 * 20)), unknownIfaceBytesTotal);
-    curKey.ifaceIndex = IFACE_INDEX2;
-    ASSERT_EQ(-ENODEV, getIfaceNameFromMap(mFakeIfaceIndexNameMap, mFakeStatsMap, ifaceIndex,
-                                           ifname, curKey, &unknownIfaceBytesTotal));
-    ASSERT_EQ(-1, unknownIfaceBytesTotal);
-    std::vector<stats_line> lines;
-    std::vector<std::string> ifaces;
-    // TODO: find a way to test the total of unknown Iface Bytes go above limit.
-    ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL, mFakeStatsMap,
-                                                    mFakeIfaceIndexNameMap));
-    ASSERT_EQ((unsigned long)1, lines.size());
-    expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, 0, lines.front());
-}
-
-TEST_F(BpfNetworkStatsHelperTest, TestGetIfaceStatsDetail) {
-    updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
-    updateIfaceMap(IFACE_NAME2, IFACE_INDEX2);
-    updateIfaceMap(IFACE_NAME3, IFACE_INDEX3);
-    updateIfaceMap(LONG_IFACE_NAME, IFACE_INDEX4);
-    StatsValue value1 = {
-            .rxPackets = TEST_PACKET0,
-            .rxBytes = TEST_BYTES0,
-            .txPackets = TEST_PACKET1,
-            .txBytes = TEST_BYTES1,
-    };
-    StatsValue value2 = {
-            .rxPackets = TEST_PACKET1,
-            .rxBytes = TEST_BYTES1,
-            .txPackets = TEST_PACKET0,
-            .txBytes = TEST_BYTES0,
-    };
-    uint32_t ifaceStatsKey = IFACE_INDEX1;
-    EXPECT_RESULT_OK(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value1, BPF_ANY));
-    ifaceStatsKey = IFACE_INDEX2;
-    EXPECT_RESULT_OK(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value2, BPF_ANY));
-    ifaceStatsKey = IFACE_INDEX3;
-    EXPECT_RESULT_OK(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value1, BPF_ANY));
-    ifaceStatsKey = IFACE_INDEX4;
-    EXPECT_RESULT_OK(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value2, BPF_ANY));
-    std::vector<stats_line> lines;
-    ASSERT_EQ(0,
-              parseBpfNetworkStatsDevInternal(&lines, mFakeIfaceStatsMap, mFakeIfaceIndexNameMap));
-    ASSERT_EQ((unsigned long)4, lines.size());
-
-    expectStatsLineEqual(value1, IFACE_NAME1, UID_ALL, SET_ALL, TAG_NONE, lines[0]);
-    expectStatsLineEqual(value1, IFACE_NAME3, UID_ALL, SET_ALL, TAG_NONE, lines[1]);
-    expectStatsLineEqual(value2, IFACE_NAME2, UID_ALL, SET_ALL, TAG_NONE, lines[2]);
-    ASSERT_EQ(0, strcmp(TRUNCATED_IFACE_NAME, lines[3].iface));
-    expectStatsLineEqual(value2, TRUNCATED_IFACE_NAME, UID_ALL, SET_ALL, TAG_NONE, lines[3]);
-}
-
-TEST_F(BpfNetworkStatsHelperTest, TestGetStatsSortedAndGrouped) {
-    // Create iface indexes with duplicate iface name.
-    updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
-    updateIfaceMap(IFACE_NAME2, IFACE_INDEX2);
-    updateIfaceMap(IFACE_NAME1, IFACE_INDEX3);  // Duplicate!
-
-    StatsValue value1 = {
-            .rxPackets = TEST_PACKET0,
-            .rxBytes = TEST_BYTES0,
-            .txPackets = TEST_PACKET1,
-            .txBytes = TEST_BYTES1,
-    };
-    StatsValue value2 = {
-            .rxPackets = TEST_PACKET1,
-            .rxBytes = TEST_BYTES1,
-            .txPackets = TEST_PACKET0,
-            .txBytes = TEST_BYTES0,
-    };
-    StatsValue value3 = {
-            .rxPackets = TEST_PACKET0 * 2,
-            .rxBytes = TEST_BYTES0 * 2,
-            .txPackets = TEST_PACKET1 * 2,
-            .txBytes = TEST_BYTES1 * 2,
-    };
-
-    std::vector<stats_line> lines;
-    std::vector<std::string> ifaces;
-
-    // Test empty stats.
-    ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL, mFakeStatsMap,
-                                                    mFakeIfaceIndexNameMap));
-    ASSERT_EQ((size_t) 0, lines.size());
-    lines.clear();
-
-    // Test 1 line stats.
-    populateFakeStats(TEST_UID1, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
-    ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL, mFakeStatsMap,
-                                                    mFakeIfaceIndexNameMap));
-    ASSERT_EQ((size_t) 1, lines.size());
-    expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, TEST_TAG, lines[0]);
-    lines.clear();
-
-    // These items should not be grouped.
-    populateFakeStats(TEST_UID1, TEST_TAG, IFACE_INDEX2, TEST_COUNTERSET0, value2, mFakeStatsMap);
-    populateFakeStats(TEST_UID1, TEST_TAG, IFACE_INDEX3, TEST_COUNTERSET1, value2, mFakeStatsMap);
-    populateFakeStats(TEST_UID1, TEST_TAG + 1, IFACE_INDEX1, TEST_COUNTERSET0, value2,
-                      mFakeStatsMap);
-    populateFakeStats(TEST_UID2, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
-    ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL, mFakeStatsMap,
-                                                    mFakeIfaceIndexNameMap));
-    ASSERT_EQ((size_t) 5, lines.size());
-    lines.clear();
-
-    // These items should be grouped.
-    populateFakeStats(TEST_UID1, TEST_TAG, IFACE_INDEX3, TEST_COUNTERSET0, value1, mFakeStatsMap);
-    populateFakeStats(TEST_UID2, TEST_TAG, IFACE_INDEX3, TEST_COUNTERSET0, value1, mFakeStatsMap);
-
-    ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL, mFakeStatsMap,
-                                                    mFakeIfaceIndexNameMap));
-    ASSERT_EQ((size_t) 5, lines.size());
-
-    // Verify Sorted & Grouped.
-    expectStatsLineEqual(value3, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, TEST_TAG, lines[0]);
-    expectStatsLineEqual(value2, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET1, TEST_TAG, lines[1]);
-    expectStatsLineEqual(value2, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, TEST_TAG + 1, lines[2]);
-    expectStatsLineEqual(value3, IFACE_NAME1, TEST_UID2, TEST_COUNTERSET0, TEST_TAG, lines[3]);
-    expectStatsLineEqual(value2, IFACE_NAME2, TEST_UID1, TEST_COUNTERSET0, TEST_TAG, lines[4]);
-    lines.clear();
-
-    // Perform test on IfaceStats.
-    uint32_t ifaceStatsKey = IFACE_INDEX2;
-    EXPECT_RESULT_OK(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value2, BPF_ANY));
-    ifaceStatsKey = IFACE_INDEX1;
-    EXPECT_RESULT_OK(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value1, BPF_ANY));
-
-    // This should be grouped.
-    ifaceStatsKey = IFACE_INDEX3;
-    EXPECT_RESULT_OK(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value1, BPF_ANY));
-
-    ASSERT_EQ(0,
-              parseBpfNetworkStatsDevInternal(&lines, mFakeIfaceStatsMap, mFakeIfaceIndexNameMap));
-    ASSERT_EQ((size_t) 2, lines.size());
-
-    expectStatsLineEqual(value3, IFACE_NAME1, UID_ALL, SET_ALL, TAG_NONE, lines[0]);
-    expectStatsLineEqual(value2, IFACE_NAME2, UID_ALL, SET_ALL, TAG_NONE, lines[1]);
-    lines.clear();
-}
-
-// Test to verify that subtract overflow will not be triggered by the compare function invoked from
-// sorting. See http:/b/119193941.
-TEST_F(BpfNetworkStatsHelperTest, TestGetStatsSortAndOverflow) {
-    updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
-
-    StatsValue value1 = {
-            .rxPackets = TEST_PACKET0,
-            .rxBytes = TEST_BYTES0,
-            .txPackets = TEST_PACKET1,
-            .txBytes = TEST_BYTES1,
-    };
-
-    // Mutate uid, 0 < TEST_UID1 < INT_MAX < INT_MIN < UINT_MAX.
-    populateFakeStats(0, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
-    populateFakeStats(UINT_MAX, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
-    populateFakeStats(INT_MIN, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
-    populateFakeStats(INT_MAX, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
-
-    // Mutate tag, 0 < TEST_TAG < INT_MAX < INT_MIN < UINT_MAX.
-    populateFakeStats(TEST_UID1, INT_MAX, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
-    populateFakeStats(TEST_UID1, INT_MIN, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
-    populateFakeStats(TEST_UID1, 0, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
-    populateFakeStats(TEST_UID1, UINT_MAX, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
-
-    // TODO: Mutate counterSet and enlarge TEST_MAP_SIZE if overflow on counterSet is possible.
-
-    std::vector<stats_line> lines;
-    std::vector<std::string> ifaces;
-    ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL, mFakeStatsMap,
-                                                    mFakeIfaceIndexNameMap));
-    ASSERT_EQ((size_t) 8, lines.size());
-
-    // Uid 0 first
-    expectStatsLineEqual(value1, IFACE_NAME1, 0, TEST_COUNTERSET0, TEST_TAG, lines[0]);
-
-    // Test uid, mutate tag.
-    expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, 0, lines[1]);
-    expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, INT_MAX, lines[2]);
-    expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, INT_MIN, lines[3]);
-    expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, UINT_MAX, lines[4]);
-
-    // Mutate uid.
-    expectStatsLineEqual(value1, IFACE_NAME1, INT_MAX, TEST_COUNTERSET0, TEST_TAG, lines[5]);
-    expectStatsLineEqual(value1, IFACE_NAME1, INT_MIN, TEST_COUNTERSET0, TEST_TAG, lines[6]);
-    expectStatsLineEqual(value1, IFACE_NAME1, UINT_MAX, TEST_COUNTERSET0, TEST_TAG, lines[7]);
-    lines.clear();
-}
-}  // namespace bpf
-}  // namespace android
diff --git a/libnetdbpf/include/netdbpf/BpfNetworkStats.h b/libnetdbpf/include/netdbpf/BpfNetworkStats.h
deleted file mode 100644
index 8ab7e25..0000000
--- a/libnetdbpf/include/netdbpf/BpfNetworkStats.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _BPF_NETWORKSTATS_H
-#define _BPF_NETWORKSTATS_H
-
-#include <bpf/BpfMap.h>
-#include "bpf_shared.h"
-
-namespace android {
-namespace bpf {
-
-// TODO: set this to a proper value based on the map size;
-constexpr int TAG_STATS_MAP_SOFT_LIMIT = 3;
-constexpr int UID_ALL = -1;
-constexpr int TAG_ALL = -1;
-constexpr int TAG_NONE = 0;
-constexpr int SET_ALL = -1;
-constexpr int SET_DEFAULT = 0;
-constexpr int SET_FOREGROUND = 1;
-
-// The limit for stats received by a unknown interface;
-constexpr const int64_t MAX_UNKNOWN_IFACE_BYTES = 100 * 1000;
-
-// This is used by
-// frameworks/base/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
-// make sure it is consistent with the JNI code before changing this.
-struct stats_line {
-    char iface[32];
-    uint32_t uid;
-    uint32_t set;
-    uint32_t tag;
-    int64_t rxBytes;
-    int64_t rxPackets;
-    int64_t txBytes;
-    int64_t txPackets;
-
-    stats_line& operator=(const stats_line& rhs);
-    stats_line& operator+=(const stats_line& rhs);
-};
-
-bool operator==(const stats_line& lhs, const stats_line& rhs);
-bool operator<(const stats_line& lhs, const stats_line& rhs);
-
-// For test only
-int bpfGetUidStatsInternal(uid_t uid, Stats* stats,
-                           const BpfMap<uint32_t, StatsValue>& appUidStatsMap);
-// For test only
-int bpfGetIfaceStatsInternal(const char* iface, Stats* stats,
-                             const BpfMap<uint32_t, StatsValue>& ifaceStatsMap,
-                             const BpfMap<uint32_t, IfaceValue>& ifaceNameMap);
-// For test only
-int parseBpfNetworkStatsDetailInternal(std::vector<stats_line>* lines,
-                                       const std::vector<std::string>& limitIfaces, int limitTag,
-                                       int limitUid, const BpfMap<StatsKey, StatsValue>& statsMap,
-                                       const BpfMap<uint32_t, IfaceValue>& ifaceMap);
-// For test only
-int cleanStatsMapInternal(const base::unique_fd& cookieTagMap, const base::unique_fd& tagStatsMap);
-// For test only
-template <class Key>
-int getIfaceNameFromMap(const BpfMap<uint32_t, IfaceValue>& ifaceMap,
-                        const BpfMap<Key, StatsValue>& statsMap, uint32_t ifaceIndex, char* ifname,
-                        const Key& curKey, int64_t* unknownIfaceBytesTotal) {
-    auto iface = ifaceMap.readValue(ifaceIndex);
-    if (!iface.ok()) {
-        maybeLogUnknownIface(ifaceIndex, statsMap, curKey, unknownIfaceBytesTotal);
-        return -ENODEV;
-    }
-    strlcpy(ifname, iface.value().name, sizeof(IfaceValue));
-    return 0;
-}
-
-template <class Key>
-void maybeLogUnknownIface(int ifaceIndex, const BpfMap<Key, StatsValue>& statsMap,
-                          const Key& curKey, int64_t* unknownIfaceBytesTotal) {
-    // Have we already logged an error?
-    if (*unknownIfaceBytesTotal == -1) {
-        return;
-    }
-
-    // Are we undercounting enough data to be worth logging?
-    auto statsEntry = statsMap.readValue(curKey);
-    if (!statsEntry.ok()) {
-        // No data is being undercounted.
-        return;
-    }
-
-    *unknownIfaceBytesTotal += (statsEntry.value().rxBytes + statsEntry.value().txBytes);
-    if (*unknownIfaceBytesTotal >= MAX_UNKNOWN_IFACE_BYTES) {
-        ALOGE("Unknown name for ifindex %d with more than %" PRId64 " bytes of traffic", ifaceIndex,
-              *unknownIfaceBytesTotal);
-        *unknownIfaceBytesTotal = -1;
-    }
-}
-
-// For test only
-int parseBpfNetworkStatsDevInternal(std::vector<stats_line>* lines,
-                                    const BpfMap<uint32_t, StatsValue>& statsMap,
-                                    const BpfMap<uint32_t, IfaceValue>& ifaceMap);
-
-int bpfGetUidStats(uid_t uid, Stats* stats);
-int bpfGetIfaceStats(const char* iface, Stats* stats);
-int parseBpfNetworkStatsDetail(std::vector<stats_line>* lines,
-                               const std::vector<std::string>& limitIfaces, int limitTag,
-                               int limitUid);
-
-int parseBpfNetworkStatsDev(std::vector<stats_line>* lines);
-void groupNetworkStats(std::vector<stats_line>* lines);
-int cleanStatsMap();
-}  // namespace bpf
-}  // namespace android
-
-#endif  // _BPF_NETWORKSTATS_H
diff --git a/libnetdbpf/include/netdbpf/bpf_shared.h b/libnetdbpf/include/netdbpf/bpf_shared.h
deleted file mode 100644
index 2fcb612..0000000
--- a/libnetdbpf/include/netdbpf/bpf_shared.h
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <linux/if.h>
-#include <linux/if_ether.h>
-#include <linux/in.h>
-#include <linux/in6.h>
-#include <netdutils/UidConstants.h>
-
-// This header file is shared by eBPF kernel programs (C) and netd (C++) and
-// some of the maps are also accessed directly from Java mainline module code.
-//
-// Hence: explicitly pad all relevant structures and assert that their size
-// is the sum of the sizes of their fields.
-#define STRUCT_SIZE(name, size) _Static_assert(sizeof(name) == (size), "Incorrect struct size.")
-
-typedef struct {
-    uint32_t uid;
-    uint32_t tag;
-} UidTagValue;
-STRUCT_SIZE(UidTagValue, 2 * 4);  // 8
-
-typedef struct {
-    uint32_t uid;
-    uint32_t tag;
-    uint32_t counterSet;
-    uint32_t ifaceIndex;
-} StatsKey;
-STRUCT_SIZE(StatsKey, 4 * 4);  // 16
-
-typedef struct {
-    uint64_t rxPackets;
-    uint64_t rxBytes;
-    uint64_t txPackets;
-    uint64_t txBytes;
-} StatsValue;
-STRUCT_SIZE(StatsValue, 4 * 8);  // 32
-
-typedef struct {
-    char name[IFNAMSIZ];
-} IfaceValue;
-STRUCT_SIZE(IfaceValue, 16);
-
-typedef struct {
-    uint64_t rxBytes;
-    uint64_t rxPackets;
-    uint64_t txBytes;
-    uint64_t txPackets;
-    uint64_t tcpRxPackets;
-    uint64_t tcpTxPackets;
-} Stats;
-
-// Since we cannot garbage collect the stats map since device boot, we need to make these maps as
-// large as possible. The maximum size of number of map entries we can have is depend on the rlimit
-// of MEM_LOCK granted to netd. The memory space needed by each map can be calculated by the
-// following fomula:
-//      elem_size = 40 + roundup(key_size, 8) + roundup(value_size, 8)
-//      cost = roundup_pow_of_two(max_entries) * 16 + elem_size * max_entries +
-//              elem_size * number_of_CPU
-// And the cost of each map currently used is(assume the device have 8 CPUs):
-// cookie_tag_map:      key:  8 bytes, value:  8 bytes, cost:  822592 bytes    =   823Kbytes
-// uid_counter_set_map: key:  4 bytes, value:  1 bytes, cost:  145216 bytes    =   145Kbytes
-// app_uid_stats_map:   key:  4 bytes, value: 32 bytes, cost: 1062784 bytes    =  1063Kbytes
-// uid_stats_map:       key: 16 bytes, value: 32 bytes, cost: 1142848 bytes    =  1143Kbytes
-// tag_stats_map:       key: 16 bytes, value: 32 bytes, cost: 1142848 bytes    =  1143Kbytes
-// iface_index_name_map:key:  4 bytes, value: 16 bytes, cost:   80896 bytes    =    81Kbytes
-// iface_stats_map:     key:  4 bytes, value: 32 bytes, cost:   97024 bytes    =    97Kbytes
-// dozable_uid_map:     key:  4 bytes, value:  1 bytes, cost:  145216 bytes    =   145Kbytes
-// standby_uid_map:     key:  4 bytes, value:  1 bytes, cost:  145216 bytes    =   145Kbytes
-// powersave_uid_map:   key:  4 bytes, value:  1 bytes, cost:  145216 bytes    =   145Kbytes
-// total:                                                                         4930Kbytes
-// It takes maximum 4.9MB kernel memory space if all maps are full, which requires any devices
-// running this module to have a memlock rlimit to be larger then 5MB. In the old qtaguid module,
-// we don't have a total limit for data entries but only have limitation of tags each uid can have.
-// (default is 1024 in kernel);
-
-const int COOKIE_UID_MAP_SIZE = 10000;
-const int UID_COUNTERSET_MAP_SIZE = 2000;
-const int APP_STATS_MAP_SIZE = 10000;
-const int STATS_MAP_SIZE = 5000;
-const int IFACE_INDEX_NAME_MAP_SIZE = 1000;
-const int IFACE_STATS_MAP_SIZE = 1000;
-const int CONFIGURATION_MAP_SIZE = 2;
-const int UID_OWNER_MAP_SIZE = 2000;
-
-#define BPF_PATH "/sys/fs/bpf/"
-
-#define BPF_EGRESS_PROG_PATH BPF_PATH "prog_netd_cgroupskb_egress_stats"
-#define BPF_INGRESS_PROG_PATH BPF_PATH "prog_netd_cgroupskb_ingress_stats"
-#define XT_BPF_INGRESS_PROG_PATH BPF_PATH "prog_netd_skfilter_ingress_xtbpf"
-#define XT_BPF_EGRESS_PROG_PATH BPF_PATH "prog_netd_skfilter_egress_xtbpf"
-#define XT_BPF_ALLOWLIST_PROG_PATH BPF_PATH "prog_netd_skfilter_allowlist_xtbpf"
-#define XT_BPF_DENYLIST_PROG_PATH BPF_PATH "prog_netd_skfilter_denylist_xtbpf"
-#define CGROUP_SOCKET_PROG_PATH BPF_PATH "prog_netd_cgroupsock_inet_create"
-
-#define COOKIE_TAG_MAP_PATH BPF_PATH "map_netd_cookie_tag_map"
-#define UID_COUNTERSET_MAP_PATH BPF_PATH "map_netd_uid_counterset_map"
-#define APP_UID_STATS_MAP_PATH BPF_PATH "map_netd_app_uid_stats_map"
-#define STATS_MAP_A_PATH BPF_PATH "map_netd_stats_map_A"
-#define STATS_MAP_B_PATH BPF_PATH "map_netd_stats_map_B"
-#define IFACE_INDEX_NAME_MAP_PATH BPF_PATH "map_netd_iface_index_name_map"
-#define IFACE_STATS_MAP_PATH BPF_PATH "map_netd_iface_stats_map"
-#define CONFIGURATION_MAP_PATH BPF_PATH "map_netd_configuration_map"
-#define UID_OWNER_MAP_PATH BPF_PATH "map_netd_uid_owner_map"
-#define UID_PERMISSION_MAP_PATH BPF_PATH "map_netd_uid_permission_map"
-
-enum UidOwnerMatchType {
-    NO_MATCH = 0,
-    HAPPY_BOX_MATCH = (1 << 0),
-    PENALTY_BOX_MATCH = (1 << 1),
-    DOZABLE_MATCH = (1 << 2),
-    STANDBY_MATCH = (1 << 3),
-    POWERSAVE_MATCH = (1 << 4),
-    RESTRICTED_MATCH = (1 << 5),
-    IIF_MATCH = (1 << 6),
-};
-
-enum BpfPermissionMatch {
-    BPF_PERMISSION_INTERNET = 1 << 2,
-    BPF_PERMISSION_UPDATE_DEVICE_STATS = 1 << 3,
-};
-// In production we use two identical stats maps to record per uid stats and
-// do swap and clean based on the configuration specified here. The statsMapType
-// value in configuration map specified which map is currently in use.
-enum StatsMapType {
-    SELECT_MAP_A,
-    SELECT_MAP_B,
-};
-
-// TODO: change the configuration object from an 8-bit bitmask to an object with clearer
-// semantics, like a struct.
-typedef uint8_t BpfConfig;
-const BpfConfig DEFAULT_CONFIG = 0;
-
-typedef struct {
-    // Allowed interface index. Only applicable if IIF_MATCH is set in the rule bitmask above.
-    uint32_t iif;
-    // A bitmask of enum values in UidOwnerMatchType.
-    uint32_t rule;
-} UidOwnerValue;
-STRUCT_SIZE(UidOwnerValue, 2 * 4);  // 8
-
-#define UID_RULES_CONFIGURATION_KEY 1
-#define CURRENT_STATS_MAP_CONFIGURATION_KEY 2
-
-#define CLAT_INGRESS6_PROG_RAWIP_NAME "prog_clatd_schedcls_ingress6_clat_rawip"
-#define CLAT_INGRESS6_PROG_ETHER_NAME "prog_clatd_schedcls_ingress6_clat_ether"
-
-#define CLAT_INGRESS6_PROG_RAWIP_PATH BPF_PATH CLAT_INGRESS6_PROG_RAWIP_NAME
-#define CLAT_INGRESS6_PROG_ETHER_PATH BPF_PATH CLAT_INGRESS6_PROG_ETHER_NAME
-
-#define CLAT_INGRESS6_MAP_PATH BPF_PATH "map_clatd_clat_ingress6_map"
-
-typedef struct {
-    uint32_t iif;            // The input interface index
-    struct in6_addr pfx96;   // The source /96 nat64 prefix, bottom 32 bits must be 0
-    struct in6_addr local6;  // The full 128-bits of the destination IPv6 address
-} ClatIngress6Key;
-STRUCT_SIZE(ClatIngress6Key, 4 + 2 * 16);  // 36
-
-typedef struct {
-    uint32_t oif;           // The output interface to redirect to (0 means don't redirect)
-    struct in_addr local4;  // The destination IPv4 address
-} ClatIngress6Value;
-STRUCT_SIZE(ClatIngress6Value, 4 + 4);  // 8
-
-#define CLAT_EGRESS4_PROG_RAWIP_NAME "prog_clatd_schedcls_egress4_clat_rawip"
-#define CLAT_EGRESS4_PROG_ETHER_NAME "prog_clatd_schedcls_egress4_clat_ether"
-
-#define CLAT_EGRESS4_PROG_RAWIP_PATH BPF_PATH CLAT_EGRESS4_PROG_RAWIP_NAME
-#define CLAT_EGRESS4_PROG_ETHER_PATH BPF_PATH CLAT_EGRESS4_PROG_ETHER_NAME
-
-#define CLAT_EGRESS4_MAP_PATH BPF_PATH "map_clatd_clat_egress4_map"
-
-typedef struct {
-    uint32_t iif;           // The input interface index
-    struct in_addr local4;  // The source IPv4 address
-} ClatEgress4Key;
-STRUCT_SIZE(ClatEgress4Key, 4 + 4);  // 8
-
-typedef struct {
-    uint32_t oif;            // The output interface to redirect to
-    struct in6_addr local6;  // The full 128-bits of the source IPv6 address
-    struct in6_addr pfx96;   // The destination /96 nat64 prefix, bottom 32 bits must be 0
-    bool oifIsEthernet;      // Whether the output interface requires ethernet header
-    uint8_t pad[3];
-} ClatEgress4Value;
-STRUCT_SIZE(ClatEgress4Value, 4 + 2 * 16 + 1 + 3);  // 40
-
-#undef STRUCT_SIZE
diff --git a/libnetdutils/Android.bp b/libnetdutils/Android.bp
deleted file mode 100644
index 31f2c53..0000000
--- a/libnetdutils/Android.bp
+++ /dev/null
@@ -1,70 +0,0 @@
-package {
-    // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "system_netd_license"
-    // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
-    default_applicable_licenses: ["system_netd_license"],
-}
-
-cc_library {
-    name: "libnetdutils",
-    srcs: [
-        "DumpWriter.cpp",
-        "Fd.cpp",
-        "InternetAddresses.cpp",
-        "Log.cpp",
-        "Netfilter.cpp",
-        "Netlink.cpp",
-        "Slice.cpp",
-        "Socket.cpp",
-        "SocketOption.cpp",
-        "Status.cpp",
-        "Syscalls.cpp",
-        "UniqueFd.cpp",
-        "UniqueFile.cpp",
-    ],
-    defaults: ["netd_defaults"],
-    cflags: ["-Wall", "-Werror"],
-    shared_libs: [
-        "libbase",
-        "liblog",
-    ],
-    export_shared_lib_headers: [
-        "libbase",
-    ],
-    export_include_dirs: ["include"],
-    sanitize: {
-        cfi: true,
-    },
-
-    apex_available: [
-        "//apex_available:platform",
-        "com.android.resolv",
-    ],
-    min_sdk_version: "29",
-}
-
-cc_test {
-    name: "netdutils_test",
-    srcs: [
-        "BackoffSequenceTest.cpp",
-        "FdTest.cpp",
-        "InternetAddressesTest.cpp",
-        "LogTest.cpp",
-        "MemBlockTest.cpp",
-        "SliceTest.cpp",
-        "StatusTest.cpp",
-        "SyscallsTest.cpp",
-        "ThreadUtilTest.cpp",
-    ],
-    defaults: ["netd_defaults"],
-    test_suites: ["device-tests"],
-    static_libs: [
-        "libgmock",
-        "libnetdutils",
-    ],
-    shared_libs: [
-        "libbase",
-    ],
-}
diff --git a/libnetdutils/BackoffSequenceTest.cpp b/libnetdutils/BackoffSequenceTest.cpp
deleted file mode 100644
index b6653fe..0000000
--- a/libnetdutils/BackoffSequenceTest.cpp
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <gtest/gtest.h>
-
-#include "netdutils/BackoffSequence.h"
-
-namespace android {
-namespace netdutils {
-
-TEST(BackoffSequence, defaults) {
-    BackoffSequence<uint32_t> backoff;
-
-    EXPECT_TRUE(backoff.hasNextTimeout());
-    EXPECT_EQ(0x00000001U, backoff.getNextTimeout());
-    EXPECT_EQ(0x00000002U, backoff.getNextTimeout());
-    EXPECT_EQ(0x00000004U, backoff.getNextTimeout());
-    EXPECT_EQ(0x00000008U, backoff.getNextTimeout());
-    EXPECT_EQ(0x00000010U, backoff.getNextTimeout());
-    EXPECT_EQ(0x00000020U, backoff.getNextTimeout());
-    EXPECT_EQ(0x00000040U, backoff.getNextTimeout());
-    EXPECT_EQ(0x00000080U, backoff.getNextTimeout());
-    EXPECT_EQ(0x00000100U, backoff.getNextTimeout());
-    EXPECT_EQ(0x00000200U, backoff.getNextTimeout());
-    EXPECT_EQ(0x00000400U, backoff.getNextTimeout());
-    EXPECT_EQ(0x00000800U, backoff.getNextTimeout());
-    EXPECT_EQ(0x00001000U, backoff.getNextTimeout());
-    EXPECT_EQ(0x00002000U, backoff.getNextTimeout());
-    EXPECT_EQ(0x00004000U, backoff.getNextTimeout());
-    EXPECT_EQ(0x00008000U, backoff.getNextTimeout());
-    EXPECT_EQ(0x00010000U, backoff.getNextTimeout());
-    EXPECT_EQ(0x00020000U, backoff.getNextTimeout());
-    EXPECT_EQ(0x00040000U, backoff.getNextTimeout());
-    EXPECT_EQ(0x00080000U, backoff.getNextTimeout());
-    EXPECT_EQ(0x00100000U, backoff.getNextTimeout());
-    EXPECT_EQ(0x00200000U, backoff.getNextTimeout());
-    EXPECT_EQ(0x00400000U, backoff.getNextTimeout());
-    EXPECT_EQ(0x00800000U, backoff.getNextTimeout());
-    EXPECT_EQ(0x01000000U, backoff.getNextTimeout());
-    EXPECT_EQ(0x02000000U, backoff.getNextTimeout());
-    EXPECT_EQ(0x04000000U, backoff.getNextTimeout());
-    EXPECT_EQ(0x08000000U, backoff.getNextTimeout());
-    EXPECT_EQ(0x10000000U, backoff.getNextTimeout());
-    EXPECT_EQ(0x20000000U, backoff.getNextTimeout());
-    EXPECT_EQ(0x40000000U, backoff.getNextTimeout());
-    EXPECT_EQ(0x80000000U, backoff.getNextTimeout());
-    // Maxes out, and stays there, ad infinitum.
-    for (int i = 0; i < 10; i++) {
-        EXPECT_TRUE(backoff.hasNextTimeout());
-        EXPECT_EQ(0xffffffffU, backoff.getNextTimeout());
-    }
-}
-
-TEST(BackoffSequence, backoffToOncePerHour) {
-    auto backoff = BackoffSequence<uint32_t>::Builder()
-            .withInitialRetransmissionTime(1)
-            .withMaximumRetransmissionTime(3600)
-            .build();
-
-    EXPECT_TRUE(backoff.hasNextTimeout());
-    EXPECT_EQ(0x00000001U, backoff.getNextTimeout());
-    EXPECT_EQ(0x00000002U, backoff.getNextTimeout());
-    EXPECT_EQ(0x00000004U, backoff.getNextTimeout());
-    EXPECT_EQ(0x00000008U, backoff.getNextTimeout());
-    EXPECT_EQ(0x00000010U, backoff.getNextTimeout());
-    EXPECT_EQ(0x00000020U, backoff.getNextTimeout());
-    EXPECT_EQ(0x00000040U, backoff.getNextTimeout());
-    EXPECT_EQ(0x00000080U, backoff.getNextTimeout());
-    EXPECT_EQ(0x00000100U, backoff.getNextTimeout());
-    EXPECT_EQ(0x00000200U, backoff.getNextTimeout());
-    EXPECT_EQ(0x00000400U, backoff.getNextTimeout());
-    EXPECT_EQ(0x00000800U, backoff.getNextTimeout());
-    // Maxes out, and stays there, ad infinitum.
-    for (int i = 0; i < 10; i++) {
-        EXPECT_TRUE(backoff.hasNextTimeout());
-        EXPECT_EQ(3600U, backoff.getNextTimeout());
-    }
-}
-
-TEST(BackoffSequence, simpleMaxRetransCount) {
-    auto backoff = BackoffSequence<uint32_t>::Builder()
-            .withInitialRetransmissionTime(3)
-            .withMaximumRetransmissionCount(7)
-            .build();
-
-    EXPECT_TRUE(backoff.hasNextTimeout());
-    EXPECT_EQ(0x00000003U, backoff.getNextTimeout());
-    EXPECT_EQ(0x00000006U, backoff.getNextTimeout());
-    EXPECT_EQ(0x0000000cU, backoff.getNextTimeout());
-    EXPECT_EQ(0x00000018U, backoff.getNextTimeout());
-    EXPECT_EQ(0x00000030U, backoff.getNextTimeout());
-    EXPECT_EQ(0x00000060U, backoff.getNextTimeout());
-    EXPECT_EQ(0x000000c0U, backoff.getNextTimeout());
-
-    for (int i = 0; i < 10; i++) {
-        EXPECT_FALSE(backoff.hasNextTimeout());
-        EXPECT_EQ(backoff.getEndOfSequenceIndicator(), backoff.getNextTimeout());
-    }
-}
-
-TEST(BackoffSequence, simpleMaxDuration) {
-    auto backoff = BackoffSequence<int>::Builder()
-            .withInitialRetransmissionTime(3)
-            .withMaximumRetransmissionDuration(7)
-            .withEndOfSequenceIndicator(-1)
-            .build();
-
-    EXPECT_TRUE(backoff.hasNextTimeout());
-    EXPECT_EQ(0x00000003, backoff.getNextTimeout());
-    EXPECT_EQ(0x00000004, backoff.getNextTimeout());
-
-    for (int i = 0; i < 10; i++) {
-        EXPECT_FALSE(backoff.hasNextTimeout());
-        EXPECT_EQ(backoff.getEndOfSequenceIndicator(), backoff.getNextTimeout());
-        EXPECT_EQ(-1, backoff.getNextTimeout());
-    }
-}
-
-TEST(PathologicalBackoffSequence, ZeroInitialRetransTime) {
-    auto backoff = BackoffSequence<std::chrono::seconds>::Builder()
-            .withInitialRetransmissionTime(std::chrono::seconds(0))
-            .build();
-
-    for (int i = 0; i < 10; i++) {
-        // TODO: Decide whether this needs fixing, and how.
-        EXPECT_TRUE(backoff.hasNextTimeout());
-        EXPECT_EQ(backoff.getEndOfSequenceIndicator(), backoff.getNextTimeout());
-    }
-}
-
-TEST(PathologicalBackoffSequence, MaxRetransDurationGreaterThanInitialRetransTime) {
-    auto backoff = BackoffSequence<std::chrono::milliseconds>::Builder()
-            .withInitialRetransmissionTime(std::chrono::milliseconds(5))
-            .withMaximumRetransmissionDuration(std::chrono::milliseconds(3))
-            .build();
-
-    EXPECT_EQ(std::chrono::milliseconds(3), backoff.getNextTimeout());
-    for (int i = 0; i < 10; i++) {
-        EXPECT_FALSE(backoff.hasNextTimeout());
-        EXPECT_EQ(backoff.getEndOfSequenceIndicator(), backoff.getNextTimeout());
-    }
-}
-
-TEST(PathologicalBackoffSequence, MaxRetransDurationEqualsInitialRetransTime) {
-    auto backoff = BackoffSequence<std::chrono::hours>::Builder()
-            .withInitialRetransmissionTime(std::chrono::hours(5))
-            .withMaximumRetransmissionDuration(std::chrono::hours(5))
-            .build();
-
-    EXPECT_EQ(std::chrono::hours(5), backoff.getNextTimeout());
-    for (int i = 0; i < 10; i++) {
-        EXPECT_FALSE(backoff.hasNextTimeout());
-        EXPECT_EQ(backoff.getEndOfSequenceIndicator(), backoff.getNextTimeout());
-    }
-}
-
-TEST(PathologicalBackoffSequence, MaxRetransTimeAndDurationGreaterThanInitialRetransTime) {
-    auto backoff = BackoffSequence<std::chrono::nanoseconds>::Builder()
-            .withInitialRetransmissionTime(std::chrono::nanoseconds(7))
-            .withMaximumRetransmissionTime(std::chrono::nanoseconds(3))
-            .withMaximumRetransmissionDuration(std::chrono::nanoseconds(5))
-            .build();
-
-    EXPECT_EQ(std::chrono::nanoseconds(3), backoff.getNextTimeout());
-    EXPECT_EQ(std::chrono::nanoseconds(2), backoff.getNextTimeout());
-    for (int i = 0; i < 10; i++) {
-        EXPECT_FALSE(backoff.hasNextTimeout());
-        EXPECT_EQ(backoff.getEndOfSequenceIndicator(), backoff.getNextTimeout());
-    }
-}
-
-}  // namespace netdutils
-}  // namespace android
diff --git a/libnetdutils/DumpWriter.cpp b/libnetdutils/DumpWriter.cpp
deleted file mode 100644
index 092ddba..0000000
--- a/libnetdutils/DumpWriter.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "netdutils/DumpWriter.h"
-
-#include <unistd.h>
-#include <limits>
-
-#include <android-base/stringprintf.h>
-#include <utils/String8.h>
-
-using android::base::StringAppendV;
-
-namespace android {
-namespace netdutils {
-
-namespace {
-
-const char kIndentString[] = "  ";
-const size_t kIndentStringLen = strlen(kIndentString);
-
-}  // namespace
-
-DumpWriter::DumpWriter(int fd) : mIndentLevel(0), mFd(fd) {}
-
-void DumpWriter::incIndent() {
-    if (mIndentLevel < std::numeric_limits<decltype(mIndentLevel)>::max()) {
-        mIndentLevel++;
-    }
-}
-
-void DumpWriter::decIndent() {
-    if (mIndentLevel > std::numeric_limits<decltype(mIndentLevel)>::min()) {
-        mIndentLevel--;
-    }
-}
-
-void DumpWriter::println(const std::string& line) {
-    if (!line.empty()) {
-        for (int i = 0; i < mIndentLevel; i++) {
-            ::write(mFd, kIndentString, kIndentStringLen);
-        }
-        ::write(mFd, line.c_str(), line.size());
-    }
-    ::write(mFd, "\n", 1);
-}
-
-// NOLINTNEXTLINE(cert-dcl50-cpp): Grandfathered C-style variadic function.
-void DumpWriter::println(const char* fmt, ...) {
-    std::string line;
-    va_list ap;
-    va_start(ap, fmt);
-    StringAppendV(&line, fmt, ap);
-    va_end(ap);
-    println(line);
-}
-
-}  // namespace netdutils
-}  // namespace android
diff --git a/libnetdutils/Fd.cpp b/libnetdutils/Fd.cpp
deleted file mode 100644
index 2651f90..0000000
--- a/libnetdutils/Fd.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "netdutils/Fd.h"
-
-namespace android {
-namespace netdutils {
-
-std::ostream& operator<<(std::ostream& os, const Fd& fd) {
-    return os << "Fd[" << fd.get() << "]";
-}
-
-}  // namespace netdutils
-}  // namespace android
diff --git a/libnetdutils/FdTest.cpp b/libnetdutils/FdTest.cpp
deleted file mode 100644
index 7080f83..0000000
--- a/libnetdutils/FdTest.cpp
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <cstdint>
-
-#include <gtest/gtest.h>
-
-#include "netdutils/MockSyscalls.h"
-#include "netdutils/Status.h"
-#include "netdutils/Syscalls.h"
-
-using testing::Mock;
-using testing::Return;
-using testing::StrictMock;
-
-namespace android {
-namespace netdutils {
-namespace {
-
-// Force implicit conversion from UniqueFd -> Fd
-inline Fd toFd(const UniqueFd& fd) {
-    return fd;
-}
-
-}  // namespace
-
-TEST(Fd, smoke) {
-    // Expect the following lines to compile
-    Fd fd1(1);
-    Fd fd2(fd1);
-    Fd fd3 = fd2;
-    const Fd fd4(8);
-    const Fd fd5(fd4);
-    const Fd fd6 = fd5;
-    EXPECT_TRUE(isWellFormed(fd3));
-    EXPECT_TRUE(isWellFormed(fd6));
-
-    // Corner case
-    Fd zero(0);
-    EXPECT_TRUE(isWellFormed(zero));
-
-    // Invalid file descriptors
-    Fd bad(-1);
-    Fd weird(-9);
-    EXPECT_FALSE(isWellFormed(bad));
-    EXPECT_FALSE(isWellFormed(weird));
-
-    // Default constructor
-    EXPECT_EQ(Fd(-1), Fd());
-    std::stringstream ss;
-    ss << fd3 << " " << fd6 << " " << bad << " " << weird;
-    EXPECT_EQ("Fd[1] Fd[8] Fd[-1] Fd[-9]", ss.str());
-}
-
-class UniqueFdTest : public testing::Test {
-  protected:
-    StrictMock<ScopedMockSyscalls> mSyscalls;
-};
-
-TEST_F(UniqueFdTest, operatorOstream) {
-    UniqueFd u(97);
-    EXPECT_CALL(mSyscalls, close(toFd(u))).WillOnce(Return(status::ok));
-    std::stringstream ss;
-    ss << u;
-    EXPECT_EQ("UniqueFd[Fd[97]]", ss.str());
-    u.reset();
-}
-
-TEST_F(UniqueFdTest, destructor) {
-    {
-        UniqueFd u(98);
-        EXPECT_CALL(mSyscalls, close(toFd(u))).WillOnce(Return(status::ok));
-    }
-    // Expectation above should be upon leaving nested scope
-    Mock::VerifyAndClearExpectations(&mSyscalls);
-}
-
-TEST_F(UniqueFdTest, reset) {
-    UniqueFd u(99);
-    EXPECT_CALL(mSyscalls, close(toFd(u))).WillOnce(Return(status::ok));
-    u.reset();
-
-    // Expectation above should be upon reset
-    Mock::VerifyAndClearExpectations(&mSyscalls);
-}
-
-TEST_F(UniqueFdTest, moveConstructor) {
-    constexpr Fd kFd(101);
-    UniqueFd u1(kFd);
-    {
-        UniqueFd u2(std::move(u1));
-        // NOLINTNEXTLINE bugprone-use-after-move
-        EXPECT_FALSE(isWellFormed(u1));
-        EXPECT_TRUE(isWellFormed(u2));
-        EXPECT_CALL(mSyscalls, close(kFd)).WillOnce(Return(status::ok));
-    }
-    // Expectation above should be upon leaving nested scope
-    Mock::VerifyAndClearExpectations(&mSyscalls);
-}
-
-TEST_F(UniqueFdTest, moveAssignment) {
-    constexpr Fd kFd(102);
-    UniqueFd u1(kFd);
-    {
-        UniqueFd u2 = std::move(u1);
-        // NOLINTNEXTLINE bugprone-use-after-move
-        EXPECT_FALSE(isWellFormed(u1));
-        EXPECT_TRUE(isWellFormed(u2));
-        UniqueFd u3;
-        u3 = std::move(u2);
-        // NOLINTNEXTLINE bugprone-use-after-move
-        EXPECT_FALSE(isWellFormed(u2));
-        EXPECT_TRUE(isWellFormed(u3));
-        EXPECT_CALL(mSyscalls, close(kFd)).WillOnce(Return(status::ok));
-    }
-    // Expectation above should be upon leaving nested scope
-    Mock::VerifyAndClearExpectations(&mSyscalls);
-}
-
-TEST_F(UniqueFdTest, constConstructor) {
-    constexpr Fd kFd(103);
-    const UniqueFd u(kFd);
-    EXPECT_CALL(mSyscalls, close(toFd(u))).WillOnce(Return(status::ok));
-}
-
-TEST_F(UniqueFdTest, closeFailure) {
-    constexpr Fd kFd(103);
-    UniqueFd u(kFd);
-    EXPECT_CALL(mSyscalls, close(toFd(u))).WillOnce(Return(statusFromErrno(EINTR, "test")));
-    EXPECT_DEBUG_DEATH(u.reset(), "");
-}
-
-}  // namespace netdutils
-}  // namespace android
diff --git a/libnetdutils/InternetAddresses.cpp b/libnetdutils/InternetAddresses.cpp
deleted file mode 100644
index 322f1b1..0000000
--- a/libnetdutils/InternetAddresses.cpp
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "netdutils/InternetAddresses.h"
-
-#include <string>
-
-#include <android-base/stringprintf.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-
-namespace android {
-
-using base::StringPrintf;
-
-namespace netdutils {
-
-std::string IPAddress::toString() const noexcept {
-    char repr[INET6_ADDRSTRLEN] = "\0";
-
-    switch (mData.family) {
-        case AF_UNSPEC:
-            return "<unspecified>";
-        case AF_INET: {
-            const in_addr v4 = mData.ip.v4;
-            inet_ntop(AF_INET, &v4, repr, sizeof(repr));
-            break;
-        }
-        case AF_INET6: {
-            const in6_addr v6 = mData.ip.v6;
-            inet_ntop(AF_INET6, &v6, repr, sizeof(repr));
-            break;
-        }
-        default:
-            return "<unknown_family>";
-    }
-
-    if (mData.family == AF_INET6 && mData.scope_id > 0) {
-        return StringPrintf("%s%%%u", repr, mData.scope_id);
-    }
-
-    return repr;
-}
-
-bool IPAddress::forString(const std::string& repr, IPAddress* ip) {
-    const addrinfo hints = {
-            .ai_flags = AI_NUMERICHOST | AI_NUMERICSERV,
-    };
-    addrinfo* res;
-    const int ret = getaddrinfo(repr.c_str(), nullptr, &hints, &res);
-    ScopedAddrinfo res_cleanup(res);
-    if (ret != 0) {
-        return false;
-    }
-
-    bool rval = true;
-    switch (res[0].ai_family) {
-        case AF_INET: {
-            sockaddr_in* sin = (sockaddr_in*) res[0].ai_addr;
-            if (ip) *ip = IPAddress(sin->sin_addr);
-            break;
-        }
-        case AF_INET6: {
-            sockaddr_in6* sin6 = (sockaddr_in6*) res[0].ai_addr;
-            if (ip) *ip = IPAddress(sin6->sin6_addr, sin6->sin6_scope_id);
-            break;
-        }
-        default:
-            rval = false;
-            break;
-    }
-
-    return rval;
-}
-
-IPPrefix::IPPrefix(const IPAddress& ip, int length) : IPPrefix(ip) {
-    // Silently treat CIDR lengths like "-1" as meaning the full bit length
-    // appropriate to the address family.
-    if (length < 0) return;
-    if (length >= mData.cidrlen) return;
-
-    switch (mData.family) {
-        case AF_UNSPEC:
-            break;
-        case AF_INET: {
-            const in_addr_t mask = (length > 0) ? (~0U) << (IPV4_ADDR_BITS - length) : 0U;
-            mData.ip.v4.s_addr &= htonl(mask);
-            mData.cidrlen = static_cast<uint8_t>(length);
-            break;
-        }
-        case AF_INET6: {
-            // The byte in which this CIDR length falls.
-            const int which = length / 8;
-            const int mask = (length % 8 == 0) ? 0 : 0xff << (8 - length % 8);
-            mData.ip.v6.s6_addr[which] &= mask;
-            for (int i = which + 1; i < IPV6_ADDR_LEN; i++) {
-                mData.ip.v6.s6_addr[i] = 0U;
-            }
-            mData.cidrlen = static_cast<uint8_t>(length);
-            break;
-        }
-        default:
-            // TODO: Complain bitterly about possible data corruption?
-            return;
-    }
-}
-
-bool IPPrefix::isUninitialized() const noexcept {
-    static const internal_::compact_ipdata empty{};
-    return mData == empty;
-}
-
-bool IPPrefix::forString(const std::string& repr, IPPrefix* prefix) {
-    size_t index = repr.find('/');
-    if (index == std::string::npos) return false;
-
-    // Parse the IP address.
-    IPAddress ip;
-    if (!IPAddress::forString(repr.substr(0, index), &ip)) return false;
-
-    // Parse the prefix length. Can't use base::ParseUint because it accepts non-base 10 input.
-    const char* prefixString = repr.c_str() + index + 1;
-    if (!isdigit(*prefixString)) return false;
-    char* endptr;
-    unsigned long prefixlen = strtoul(prefixString, &endptr, 10);
-    if (*endptr != '\0') return false;
-
-    uint8_t maxlen = (ip.family() == AF_INET) ? 32 : 128;
-    if (prefixlen > maxlen) return false;
-
-    *prefix = IPPrefix(ip, prefixlen);
-    return true;
-}
-
-std::string IPPrefix::toString() const noexcept {
-    return StringPrintf("%s/%d", ip().toString().c_str(), mData.cidrlen);
-}
-
-std::string IPSockAddr::toString() const noexcept {
-    switch (mData.family) {
-        case AF_INET6:
-            return StringPrintf("[%s]:%u", ip().toString().c_str(), mData.port);
-        default:
-            return StringPrintf("%s:%u", ip().toString().c_str(), mData.port);
-    }
-}
-
-}  // namespace netdutils
-}  // namespace android
diff --git a/libnetdutils/InternetAddressesTest.cpp b/libnetdutils/InternetAddressesTest.cpp
deleted file mode 100644
index f75fa76..0000000
--- a/libnetdutils/InternetAddressesTest.cpp
+++ /dev/null
@@ -1,541 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <cstdint>
-#include <limits>
-#include <sstream>
-#include <string>
-#include <vector>
-
-#include <android-base/macros.h>
-#include <gtest/gtest.h>
-
-#include "netdutils/InternetAddresses.h"
-
-namespace android {
-namespace netdutils {
-namespace {
-
-enum Relation { EQ, LT };
-
-std::ostream& operator<<(std::ostream& os, Relation relation) {
-    switch (relation) {
-        case EQ: os << "eq"; break;
-        case LT: os << "lt"; break;
-        default: os << "?!"; break;
-    }
-    return os;
-}
-
-template <typename T>
-struct OperatorExpectation {
-    const Relation relation;
-    const T obj1;
-    const T obj2;
-
-    std::string toString() const {
-        std::stringstream output;
-        output << obj1 << " " << relation << " " << obj2;
-        return output.str();
-    }
-};
-
-template <typename T>
-void testGamutOfOperators(const OperatorExpectation<T>& expectation) {
-    switch (expectation.relation) {
-        case EQ:
-            EXPECT_TRUE(expectation.obj1 == expectation.obj2);
-            EXPECT_TRUE(expectation.obj1 <= expectation.obj2);
-            EXPECT_TRUE(expectation.obj1 >= expectation.obj2);
-            EXPECT_FALSE(expectation.obj1 != expectation.obj2);
-            EXPECT_FALSE(expectation.obj1 < expectation.obj2);
-            EXPECT_FALSE(expectation.obj1 > expectation.obj2);
-            break;
-
-        case LT:
-            EXPECT_TRUE(expectation.obj1 < expectation.obj2);
-            EXPECT_TRUE(expectation.obj1 <= expectation.obj2);
-            EXPECT_TRUE(expectation.obj1 != expectation.obj2);
-            EXPECT_FALSE(expectation.obj1 > expectation.obj2);
-            EXPECT_FALSE(expectation.obj1 >= expectation.obj2);
-            EXPECT_FALSE(expectation.obj1 == expectation.obj2);
-            break;
-
-        default:
-            FAIL() << "Unknown relation given in test expectation";
-    }
-}
-
-const in_addr IPV4_ANY{htonl(INADDR_ANY)};
-const in_addr IPV4_LOOPBACK{htonl(INADDR_LOOPBACK)};
-const in_addr IPV4_ONES{~0U};
-const in6_addr IPV6_ANY = IN6ADDR_ANY_INIT;
-const in6_addr IPV6_LOOPBACK = IN6ADDR_LOOPBACK_INIT;
-const in6_addr FE80{{{0xfe,0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}};
-const in6_addr FE80_1{{{0xfe,0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,1}}};
-const in6_addr FE80_2{{{0xfe,0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,2}}};
-const uint8_t ff = std::numeric_limits<uint8_t>::max();
-const in6_addr IPV6_ONES{{{ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff}}};
-
-TEST(IPAddressTest, GamutOfOperators) {
-    const std::vector<OperatorExpectation<IPAddress>> kExpectations{
-            {EQ, IPAddress(), IPAddress()},
-            {EQ, IPAddress(IPV4_ONES), IPAddress(IPV4_ONES)},
-            {EQ, IPAddress(IPV6_ONES), IPAddress(IPV6_ONES)},
-            {EQ, IPAddress(FE80_1), IPAddress(FE80_1)},
-            {EQ, IPAddress(FE80_2), IPAddress(FE80_2)},
-            {LT, IPAddress(), IPAddress(IPV4_ANY)},
-            {LT, IPAddress(), IPAddress(IPV4_ONES)},
-            {LT, IPAddress(), IPAddress(IPV6_ANY)},
-            {LT, IPAddress(), IPAddress(IPV6_ONES)},
-            {LT, IPAddress(IPV4_ANY), IPAddress(IPV4_ONES)},
-            {LT, IPAddress(IPV4_ANY), IPAddress(IPV6_ANY)},
-            {LT, IPAddress(IPV4_ONES), IPAddress(IPV6_ANY)},
-            {LT, IPAddress(IPV4_ONES), IPAddress(IPV6_ONES)},
-            {LT, IPAddress(IPV6_ANY), IPAddress(IPV6_LOOPBACK)},
-            {LT, IPAddress(IPV6_ANY), IPAddress(IPV6_ONES)},
-            {LT, IPAddress(IPV6_LOOPBACK), IPAddress(IPV6_ONES)},
-            {LT, IPAddress(FE80_1), IPAddress(FE80_2)},
-            {LT, IPAddress(FE80_1), IPAddress(IPV6_ONES)},
-            {LT, IPAddress(FE80_2), IPAddress(IPV6_ONES)},
-            // Sort by scoped_id within the same address.
-            {LT, IPAddress(FE80_1), IPAddress(FE80_1, 1)},
-            {LT, IPAddress(FE80_1, 1), IPAddress(FE80_1, 2)},
-            // Sort by address first, scope_id second.
-            {LT, IPAddress(FE80_1, 2), IPAddress(FE80_2, 1)},
-    };
-
-    size_t tests_run = 0;
-    for (const auto& expectation : kExpectations) {
-        SCOPED_TRACE(expectation.toString());
-        EXPECT_NO_FATAL_FAILURE(testGamutOfOperators(expectation));
-        tests_run++;
-    }
-    EXPECT_EQ(kExpectations.size(), tests_run);
-}
-
-TEST(IPAddressTest, ScopeIds) {
-    // Scope IDs ignored for IPv4 addresses.
-    const IPAddress ones(IPV4_ONES);
-    EXPECT_EQ(0U, ones.scope_id());
-    const IPAddress ones22(ones, 22);
-    EXPECT_EQ(0U, ones22.scope_id());
-    EXPECT_EQ(ones, ones22);
-    const IPAddress ones23(ones, 23);
-    EXPECT_EQ(0U, ones23.scope_id());
-    EXPECT_EQ(ones22, ones23);
-
-    EXPECT_EQ("fe80::1%22", IPAddress(FE80_1, 22).toString());
-    EXPECT_EQ("fe80::2%23", IPAddress(FE80_2, 23).toString());
-
-    // Verify that given an IPAddress with a scope_id an address without a
-    // scope_id can be constructed (just in case it's useful).
-    const IPAddress fe80_intf22(FE80_1, 22);
-    EXPECT_EQ(22U, fe80_intf22.scope_id());
-    EXPECT_EQ(fe80_intf22, IPAddress(fe80_intf22));
-    EXPECT_EQ(IPAddress(FE80_1), IPAddress(fe80_intf22, 0));
-}
-
-TEST(IPAddressTest, forString) {
-    IPAddress ip;
-
-    EXPECT_FALSE(IPAddress::forString("not_an_ip", &ip));
-    EXPECT_FALSE(IPAddress::forString("not_an_ip", nullptr));
-    EXPECT_EQ(IPAddress(), IPAddress::forString("not_an_ip"));
-
-    EXPECT_EQ(IPAddress(IPV4_ANY), IPAddress::forString("0.0.0.0"));
-    EXPECT_EQ(IPAddress(IPV4_ONES), IPAddress::forString("255.255.255.255"));
-    EXPECT_EQ(IPAddress(IPV4_LOOPBACK), IPAddress::forString("127.0.0.1"));
-
-    EXPECT_EQ(IPAddress(IPV6_ANY), IPAddress::forString("::"));
-    EXPECT_EQ(IPAddress(IPV6_ANY), IPAddress::forString("::0"));
-    EXPECT_EQ(IPAddress(IPV6_ANY), IPAddress::forString("0::"));
-    EXPECT_EQ(IPAddress(IPV6_LOOPBACK), IPAddress::forString("::1"));
-    EXPECT_EQ(IPAddress(IPV6_LOOPBACK), IPAddress::forString("0::1"));
-    EXPECT_EQ(IPAddress(FE80_1), IPAddress::forString("fe80::1"));
-    EXPECT_EQ(IPAddress(FE80_1, 22), IPAddress::forString("fe80::1%22"));
-    // This relies upon having a loopback interface named "lo" with ifindex 1.
-    EXPECT_EQ(IPAddress(FE80_1, 1), IPAddress::forString("fe80::1%lo"));
-}
-
-TEST(IPPrefixTest, forString) {
-    IPPrefix prefix;
-
-    EXPECT_FALSE(IPPrefix::forString("", &prefix));
-    EXPECT_FALSE(IPPrefix::forString("invalid", &prefix));
-    EXPECT_FALSE(IPPrefix::forString("192.0.2.0", &prefix));
-    EXPECT_FALSE(IPPrefix::forString("2001::db8::", &prefix));
-
-    EXPECT_FALSE(IPPrefix::forString("2001:db8::/", &prefix));
-    EXPECT_FALSE(IPPrefix::forString("2001:db8:://32", &prefix));
-    EXPECT_FALSE(IPPrefix::forString("2001:db8::/32z", &prefix));
-    EXPECT_FALSE(IPPrefix::forString("2001:db8::/32/", &prefix));
-    EXPECT_FALSE(IPPrefix::forString("2001:db8::/0x20", &prefix));
-    EXPECT_FALSE(IPPrefix::forString("2001:db8:: /32", &prefix));
-    EXPECT_FALSE(IPPrefix::forString("2001:db8::/ 32", &prefix));
-    EXPECT_FALSE(IPPrefix::forString(" 2001:db8::/32", &prefix));
-    EXPECT_FALSE(IPPrefix::forString("2001:db8::/32 ", &prefix));
-    EXPECT_FALSE(IPPrefix::forString("2001:db8::/+32", &prefix));
-
-    EXPECT_FALSE(IPPrefix::forString("192.0.2.0/33", &prefix));
-    EXPECT_FALSE(IPPrefix::forString("2001:db8::/129", &prefix));
-    EXPECT_FALSE(IPPrefix::forString("192.0.2.0/-1", &prefix));
-    EXPECT_FALSE(IPPrefix::forString("2001:db8::/-1", &prefix));
-
-    EXPECT_TRUE(IPPrefix::forString("2001:db8::/32", &prefix));
-    EXPECT_EQ("2001:db8::/32", prefix.toString());
-    EXPECT_EQ(IPPrefix(IPAddress::forString("2001:db8::"), 32), prefix);
-
-    EXPECT_EQ(IPPrefix(), IPPrefix::forString("invalid"));
-
-    EXPECT_EQ("0.0.0.0/0", IPPrefix::forString("0.0.0.0/0").toString());
-    EXPECT_EQ("::/0", IPPrefix::forString("::/0").toString());
-    EXPECT_EQ("192.0.2.128/25", IPPrefix::forString("192.0.2.131/25").toString());
-    EXPECT_EQ("2001:db8:1:2:3:4:5:4/126",
-              IPPrefix::forString("2001:db8:1:2:3:4:5:6/126").toString());
-}
-
-TEST(IPPrefixTest, IPv4Truncation) {
-    const auto prefixStr = [](int length) -> std::string {
-        return IPPrefix(IPAddress(IPV4_ONES), length).toString();
-    };
-
-    EXPECT_EQ("0.0.0.0/0", prefixStr(0));
-
-    EXPECT_EQ("128.0.0.0/1", prefixStr(1));
-    EXPECT_EQ("192.0.0.0/2", prefixStr(2));
-    EXPECT_EQ("224.0.0.0/3", prefixStr(3));
-    EXPECT_EQ("240.0.0.0/4", prefixStr(4));
-    EXPECT_EQ("248.0.0.0/5", prefixStr(5));
-    EXPECT_EQ("252.0.0.0/6", prefixStr(6));
-    EXPECT_EQ("254.0.0.0/7", prefixStr(7));
-    EXPECT_EQ("255.0.0.0/8", prefixStr(8));
-
-    EXPECT_EQ("255.128.0.0/9", prefixStr(9));
-    EXPECT_EQ("255.192.0.0/10", prefixStr(10));
-    EXPECT_EQ("255.224.0.0/11", prefixStr(11));
-    EXPECT_EQ("255.240.0.0/12", prefixStr(12));
-    EXPECT_EQ("255.248.0.0/13", prefixStr(13));
-    EXPECT_EQ("255.252.0.0/14", prefixStr(14));
-    EXPECT_EQ("255.254.0.0/15", prefixStr(15));
-    EXPECT_EQ("255.255.0.0/16", prefixStr(16));
-
-    EXPECT_EQ("255.255.128.0/17", prefixStr(17));
-    EXPECT_EQ("255.255.192.0/18", prefixStr(18));
-    EXPECT_EQ("255.255.224.0/19", prefixStr(19));
-    EXPECT_EQ("255.255.240.0/20", prefixStr(20));
-    EXPECT_EQ("255.255.248.0/21", prefixStr(21));
-    EXPECT_EQ("255.255.252.0/22", prefixStr(22));
-    EXPECT_EQ("255.255.254.0/23", prefixStr(23));
-    EXPECT_EQ("255.255.255.0/24", prefixStr(24));
-
-    EXPECT_EQ("255.255.255.128/25", prefixStr(25));
-    EXPECT_EQ("255.255.255.192/26", prefixStr(26));
-    EXPECT_EQ("255.255.255.224/27", prefixStr(27));
-    EXPECT_EQ("255.255.255.240/28", prefixStr(28));
-    EXPECT_EQ("255.255.255.248/29", prefixStr(29));
-    EXPECT_EQ("255.255.255.252/30", prefixStr(30));
-    EXPECT_EQ("255.255.255.254/31", prefixStr(31));
-    EXPECT_EQ("255.255.255.255/32", prefixStr(32));
-}
-
-TEST(IPPrefixTest, IPv6Truncation) {
-    const auto prefixStr = [](int length) -> std::string {
-        return IPPrefix(IPAddress(IPV6_ONES), length).toString();
-    };
-
-    EXPECT_EQ("::/0", prefixStr(0));
-
-    EXPECT_EQ("8000::/1", prefixStr(1));
-    EXPECT_EQ("c000::/2", prefixStr(2));
-    EXPECT_EQ("e000::/3", prefixStr(3));
-    EXPECT_EQ("f000::/4", prefixStr(4));
-    EXPECT_EQ("f800::/5", prefixStr(5));
-    EXPECT_EQ("fc00::/6", prefixStr(6));
-    EXPECT_EQ("fe00::/7", prefixStr(7));
-    EXPECT_EQ("ff00::/8", prefixStr(8));
-
-    EXPECT_EQ("ff80::/9", prefixStr(9));
-    EXPECT_EQ("ffc0::/10", prefixStr(10));
-    EXPECT_EQ("ffe0::/11", prefixStr(11));
-    EXPECT_EQ("fff0::/12", prefixStr(12));
-    EXPECT_EQ("fff8::/13", prefixStr(13));
-    EXPECT_EQ("fffc::/14", prefixStr(14));
-    EXPECT_EQ("fffe::/15", prefixStr(15));
-    EXPECT_EQ("ffff::/16", prefixStr(16));
-
-    EXPECT_EQ("ffff:8000::/17", prefixStr(17));
-    EXPECT_EQ("ffff:c000::/18", prefixStr(18));
-    EXPECT_EQ("ffff:e000::/19", prefixStr(19));
-    EXPECT_EQ("ffff:f000::/20", prefixStr(20));
-    EXPECT_EQ("ffff:f800::/21", prefixStr(21));
-    EXPECT_EQ("ffff:fc00::/22", prefixStr(22));
-    EXPECT_EQ("ffff:fe00::/23", prefixStr(23));
-    EXPECT_EQ("ffff:ff00::/24", prefixStr(24));
-
-    EXPECT_EQ("ffff:ff80::/25", prefixStr(25));
-    EXPECT_EQ("ffff:ffc0::/26", prefixStr(26));
-    EXPECT_EQ("ffff:ffe0::/27", prefixStr(27));
-    EXPECT_EQ("ffff:fff0::/28", prefixStr(28));
-    EXPECT_EQ("ffff:fff8::/29", prefixStr(29));
-    EXPECT_EQ("ffff:fffc::/30", prefixStr(30));
-    EXPECT_EQ("ffff:fffe::/31", prefixStr(31));
-    EXPECT_EQ("ffff:ffff::/32", prefixStr(32));
-
-    EXPECT_EQ("ffff:ffff:8000::/33", prefixStr(33));
-    EXPECT_EQ("ffff:ffff:c000::/34", prefixStr(34));
-    EXPECT_EQ("ffff:ffff:e000::/35", prefixStr(35));
-    EXPECT_EQ("ffff:ffff:f000::/36", prefixStr(36));
-    EXPECT_EQ("ffff:ffff:f800::/37", prefixStr(37));
-    EXPECT_EQ("ffff:ffff:fc00::/38", prefixStr(38));
-    EXPECT_EQ("ffff:ffff:fe00::/39", prefixStr(39));
-    EXPECT_EQ("ffff:ffff:ff00::/40", prefixStr(40));
-
-    EXPECT_EQ("ffff:ffff:ff80::/41", prefixStr(41));
-    EXPECT_EQ("ffff:ffff:ffc0::/42", prefixStr(42));
-    EXPECT_EQ("ffff:ffff:ffe0::/43", prefixStr(43));
-    EXPECT_EQ("ffff:ffff:fff0::/44", prefixStr(44));
-    EXPECT_EQ("ffff:ffff:fff8::/45", prefixStr(45));
-    EXPECT_EQ("ffff:ffff:fffc::/46", prefixStr(46));
-    EXPECT_EQ("ffff:ffff:fffe::/47", prefixStr(47));
-    EXPECT_EQ("ffff:ffff:ffff::/48", prefixStr(48));
-
-    EXPECT_EQ("ffff:ffff:ffff:8000::/49", prefixStr(49));
-    EXPECT_EQ("ffff:ffff:ffff:c000::/50", prefixStr(50));
-    EXPECT_EQ("ffff:ffff:ffff:e000::/51", prefixStr(51));
-    EXPECT_EQ("ffff:ffff:ffff:f000::/52", prefixStr(52));
-    EXPECT_EQ("ffff:ffff:ffff:f800::/53", prefixStr(53));
-    EXPECT_EQ("ffff:ffff:ffff:fc00::/54", prefixStr(54));
-    EXPECT_EQ("ffff:ffff:ffff:fe00::/55", prefixStr(55));
-    EXPECT_EQ("ffff:ffff:ffff:ff00::/56", prefixStr(56));
-
-    EXPECT_EQ("ffff:ffff:ffff:ff80::/57", prefixStr(57));
-    EXPECT_EQ("ffff:ffff:ffff:ffc0::/58", prefixStr(58));
-    EXPECT_EQ("ffff:ffff:ffff:ffe0::/59", prefixStr(59));
-    EXPECT_EQ("ffff:ffff:ffff:fff0::/60", prefixStr(60));
-    EXPECT_EQ("ffff:ffff:ffff:fff8::/61", prefixStr(61));
-    EXPECT_EQ("ffff:ffff:ffff:fffc::/62", prefixStr(62));
-    EXPECT_EQ("ffff:ffff:ffff:fffe::/63", prefixStr(63));
-    EXPECT_EQ("ffff:ffff:ffff:ffff::/64", prefixStr(64));
-
-    EXPECT_EQ("ffff:ffff:ffff:ffff:8000::/65", prefixStr(65));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:c000::/66", prefixStr(66));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:e000::/67", prefixStr(67));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:f000::/68", prefixStr(68));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:f800::/69", prefixStr(69));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:fc00::/70", prefixStr(70));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:fe00::/71", prefixStr(71));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ff00::/72", prefixStr(72));
-
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ff80::/73", prefixStr(73));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffc0::/74", prefixStr(74));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffe0::/75", prefixStr(75));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:fff0::/76", prefixStr(76));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:fff8::/77", prefixStr(77));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:fffc::/78", prefixStr(78));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:fffe::/79", prefixStr(79));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff::/80", prefixStr(80));
-
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:8000::/81", prefixStr(81));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:c000::/82", prefixStr(82));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:e000::/83", prefixStr(83));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:f000::/84", prefixStr(84));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:f800::/85", prefixStr(85));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:fc00::/86", prefixStr(86));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:fe00::/87", prefixStr(87));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ff00::/88", prefixStr(88));
-
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ff80::/89", prefixStr(89));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffc0::/90", prefixStr(90));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffe0::/91", prefixStr(91));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:fff0::/92", prefixStr(92));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:fff8::/93", prefixStr(93));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:fffc::/94", prefixStr(94));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:fffe::/95", prefixStr(95));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff::/96", prefixStr(96));
-
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:8000:0/97", prefixStr(97));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:c000:0/98", prefixStr(98));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:e000:0/99", prefixStr(99));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:f000:0/100", prefixStr(100));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:f800:0/101", prefixStr(101));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:fc00:0/102", prefixStr(102));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:fe00:0/103", prefixStr(103));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ff00:0/104", prefixStr(104));
-
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ff80:0/105", prefixStr(105));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffc0:0/106", prefixStr(106));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffe0:0/107", prefixStr(107));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:fff0:0/108", prefixStr(108));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:fff8:0/109", prefixStr(109));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:fffc:0/110", prefixStr(110));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:fffe:0/111", prefixStr(111));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:0/112", prefixStr(112));
-
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:8000/113", prefixStr(113));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:c000/114", prefixStr(114));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:e000/115", prefixStr(115));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:f000/116", prefixStr(116));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:f800/117", prefixStr(117));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fc00/118", prefixStr(118));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fe00/119", prefixStr(119));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff00/120", prefixStr(120));
-
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff80/121", prefixStr(121));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffc0/122", prefixStr(122));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffe0/123", prefixStr(123));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fff0/124", prefixStr(124));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fff8/125", prefixStr(125));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffc/126", prefixStr(126));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe/127", prefixStr(127));
-    EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128", prefixStr(128));
-}
-
-TEST(IPPrefixTest, TruncationOther) {
-    const struct {
-        const char* ip;
-        const int cidrLen;
-        const char* ipTruncated;
-    } testExpectations[] = {
-            {"192.0.2.0", 24, "192.0.2.0"},
-            {"192.0.2.0", 23, "192.0.2.0"},
-            {"192.0.2.0", 22, "192.0.0.0"},
-            {"192.0.2.0", 1, "128.0.0.0"},
-            {"2001:db8:cafe:d00d::", 56, "2001:db8:cafe:d000::"},
-            {"2001:db8:cafe:d00d::", 48, "2001:db8:cafe::"},
-            {"2001:db8:cafe:d00d::", 47, "2001:db8:cafe::"},
-            {"2001:db8:cafe:d00d::", 46, "2001:db8:cafc::"},
-    };
-
-    for (const auto& expectation : testExpectations) {
-        IPAddress ip;
-        EXPECT_TRUE(IPAddress::forString(expectation.ip, &ip))
-                << "Failed to parse IP address " << expectation.ip;
-
-        IPAddress ipTruncated;
-        EXPECT_TRUE(IPAddress::forString(expectation.ipTruncated, &ipTruncated))
-                << "Failed to parse IP address " << expectation.ipTruncated;
-
-        IPPrefix prefix(ip, expectation.cidrLen);
-
-        EXPECT_EQ(expectation.cidrLen, prefix.length())
-                << "Unexpected cidrLen " << expectation.cidrLen;
-        EXPECT_EQ(ipTruncated, prefix.ip())
-                << "Unexpected IP truncation: " << prefix.ip() << ", expected: " << ipTruncated;
-    }
-}
-
-TEST(IPPrefixTest, GamutOfOperators) {
-    const std::vector<OperatorExpectation<IPPrefix>> kExpectations{
-            {EQ, IPPrefix(), IPPrefix()},
-            {EQ, IPPrefix(IPAddress(IPV4_ANY), 0), IPPrefix(IPAddress(IPV4_ANY), 0)},
-            {EQ, IPPrefix(IPAddress(IPV4_ANY), IPV4_ADDR_BITS), IPPrefix(IPAddress(IPV4_ANY))},
-            {EQ, IPPrefix(IPAddress(IPV6_ANY), 0), IPPrefix(IPAddress(IPV6_ANY), 0)},
-            {EQ, IPPrefix(IPAddress(IPV6_ANY), IPV6_ADDR_BITS), IPPrefix(IPAddress(IPV6_ANY))},
-            // Needlessly fully-specified IPv6 link-local address.
-            {EQ, IPPrefix(IPAddress(FE80_1)), IPPrefix(IPAddress(FE80_1, 0), IPV6_ADDR_BITS)},
-            // Different IPv6 link-local addresses within the same /64, no scoped_id: same /64.
-            {EQ, IPPrefix(IPAddress(FE80_1), 64), IPPrefix(IPAddress(FE80_2), 64)},
-            // Different IPv6 link-local address within the same /64, same scoped_id: same /64.
-            {EQ, IPPrefix(IPAddress(FE80_1, 17), 64), IPPrefix(IPAddress(FE80_2, 17), 64)},
-            // Unspecified < IPv4.
-            {LT, IPPrefix(), IPPrefix(IPAddress(IPV4_ANY), 0)},
-            // Same IPv4 base address sorts by prefix length.
-            {LT, IPPrefix(IPAddress(IPV4_ANY), 0), IPPrefix(IPAddress(IPV4_ANY), 1)},
-            {LT, IPPrefix(IPAddress(IPV4_ANY), 1), IPPrefix(IPAddress(IPV4_ANY), IPV4_ADDR_BITS)},
-            // Truncation means each base IPv4 address is different.
-            {LT, IPPrefix(IPAddress(IPV4_ONES), 0), IPPrefix(IPAddress(IPV4_ONES), 1)},
-            {LT, IPPrefix(IPAddress(IPV4_ONES), 1), IPPrefix(IPAddress(IPV4_ONES), IPV4_ADDR_BITS)},
-            // Sort by base IPv4 addresses first.
-            {LT, IPPrefix(IPAddress(IPV4_ANY), 0), IPPrefix(IPAddress::forString("0.0.0.1"))},
-            {LT, IPPrefix(IPAddress(IPV4_ANY), 1), IPPrefix(IPAddress::forString("0.0.0.1"))},
-            {LT, IPPrefix(IPAddress(IPV4_ANY), 24), IPPrefix(IPAddress::forString("0.0.0.1"))},
-            // IPv4 < IPv6.
-            {LT, IPPrefix(IPAddress(IPV4_ANY), 0), IPPrefix(IPAddress(IPV6_ANY), 0)},
-            {LT, IPPrefix(IPAddress(IPV4_ONES)), IPPrefix(IPAddress(IPV6_ANY))},
-            // Unspecified < IPv6.
-            {LT, IPPrefix(), IPPrefix(IPAddress(IPV6_ANY), 0)},
-            // Same IPv6 base address sorts by prefix length.
-            {LT, IPPrefix(IPAddress(IPV6_ANY), 0), IPPrefix(IPAddress(IPV6_ANY), 1)},
-            {LT, IPPrefix(IPAddress(IPV6_ANY), 1), IPPrefix(IPAddress(IPV6_ANY), IPV6_ADDR_BITS)},
-            // Truncation means each base IPv6 address is different.
-            {LT, IPPrefix(IPAddress(IPV6_ONES), 0), IPPrefix(IPAddress(IPV6_ONES), 1)},
-            {LT, IPPrefix(IPAddress(IPV6_ONES), 1), IPPrefix(IPAddress(IPV6_ONES), IPV6_ADDR_BITS)},
-            // Different IPv6 link-local address in same /64, different scoped_id: different /64.
-            {LT, IPPrefix(IPAddress(FE80_1, 17), 64), IPPrefix(IPAddress(FE80_2, 22), 64)},
-            {LT, IPPrefix(IPAddress(FE80_1, 17), 64), IPPrefix(IPAddress(FE80_1, 18), 64)},
-            {LT, IPPrefix(IPAddress(FE80_1, 18), 64), IPPrefix(IPAddress(FE80_1, 19), 64)},
-    };
-
-    size_t tests_run = 0;
-    for (const auto& expectation : kExpectations) {
-        SCOPED_TRACE(expectation.toString());
-        EXPECT_NO_FATAL_FAILURE(testGamutOfOperators(expectation));
-        tests_run++;
-    }
-    EXPECT_EQ(kExpectations.size(), tests_run);
-}
-
-TEST(IPSockAddrTest, GamutOfOperators) {
-    const std::vector<OperatorExpectation<IPSockAddr>> kExpectations{
-            {EQ, IPSockAddr(), IPSockAddr()},
-            {EQ, IPSockAddr(IPAddress(IPV4_ANY)), IPSockAddr(IPAddress(IPV4_ANY), 0)},
-            {EQ, IPSockAddr(IPAddress(IPV6_ANY)), IPSockAddr(IPAddress(IPV6_ANY), 0)},
-            {EQ, IPSockAddr(IPAddress(FE80_1), 80), IPSockAddr(IPAddress(FE80_1), 80)},
-            {EQ, IPSockAddr(IPAddress(FE80_1, 17)), IPSockAddr(IPAddress(FE80_1, 17), 0)},
-            {LT, IPSockAddr(IPAddress(IPV4_ANY), 0), IPSockAddr(IPAddress(IPV4_ANY), 1)},
-            {LT, IPSockAddr(IPAddress(IPV4_ANY), 53), IPSockAddr(IPAddress(IPV4_ANY), 123)},
-            {LT, IPSockAddr(IPAddress(IPV4_ONES), 123), IPSockAddr(IPAddress(IPV6_ANY), 53)},
-            {LT, IPSockAddr(IPAddress(IPV6_ANY), 0), IPSockAddr(IPAddress(IPV6_ANY), 1)},
-            {LT, IPSockAddr(IPAddress(IPV6_ANY), 53), IPSockAddr(IPAddress(IPV6_ANY), 123)},
-            {LT, IPSockAddr(IPAddress(FE80_1), 80), IPSockAddr(IPAddress(FE80_1, 17), 80)},
-            {LT, IPSockAddr(IPAddress(FE80_1, 17), 80), IPSockAddr(IPAddress(FE80_1, 22), 80)},
-    };
-
-    size_t tests_run = 0;
-    for (const auto& expectation : kExpectations) {
-        SCOPED_TRACE(expectation.toString());
-        EXPECT_NO_FATAL_FAILURE(testGamutOfOperators(expectation));
-        tests_run++;
-    }
-    EXPECT_EQ(kExpectations.size(), tests_run);
-}
-
-TEST(IPSockAddrTest, toString) {
-    EXPECT_EQ("<unspecified>:0", IPSockAddr().toString());
-    EXPECT_EQ("0.0.0.0:0", IPSockAddr(IPAddress(IPV4_ANY)).toString());
-    EXPECT_EQ("255.255.255.255:67", IPSockAddr(IPAddress(IPV4_ONES), 67).toString());
-    EXPECT_EQ("[::]:0", IPSockAddr(IPAddress(IPV6_ANY)).toString());
-    EXPECT_EQ("[::1]:53", IPSockAddr(IPAddress(IPV6_LOOPBACK), 53).toString());
-    EXPECT_EQ("[fe80::1]:0", IPSockAddr(IPAddress(FE80_1)).toString());
-    EXPECT_EQ("[fe80::2%17]:123", IPSockAddr(IPAddress(FE80_2, 17), 123).toString());
-}
-
-TEST(CompatIPDataTest, ConversionsClearUnneededValues) {
-    const uint32_t idx = 17;
-    const IPSockAddr linkLocalNtpSockaddr(IPAddress(FE80_2, idx), 123);
-    EXPECT_EQ(IPAddress(FE80_2, idx), linkLocalNtpSockaddr.ip());
-    // IPSockAddr(IPSockaddr.ip()) see the port cleared.
-    EXPECT_EQ(0, IPSockAddr(linkLocalNtpSockaddr.ip()).port());
-    const IPPrefix linkLocalPrefix(linkLocalNtpSockaddr.ip(), 64);
-    EXPECT_EQ(IPAddress(FE80, idx), linkLocalPrefix.ip());
-    // IPPrefix(IPPrefix.ip()) see the CIDR length cleared.
-    EXPECT_EQ(IPV6_ADDR_BITS, IPPrefix(linkLocalPrefix.ip()).length());
-}
-
-}  // namespace
-}  // namespace netdutils
-}  // namespace android
diff --git a/libnetdutils/Log.cpp b/libnetdutils/Log.cpp
deleted file mode 100644
index d2ce98f..0000000
--- a/libnetdutils/Log.cpp
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "netdutils/Log.h"
-#include "netdutils/Slice.h"
-
-#include <chrono>
-#include <ctime>
-#include <iomanip>
-#include <mutex>
-#include <sstream>
-
-#include <android-base/strings.h>
-#include <log/log.h>
-
-using ::android::base::Join;
-using ::android::base::StringPrintf;
-
-namespace android {
-namespace netdutils {
-
-namespace {
-
-std::string makeTimestampedEntry(const std::string& entry) {
-    using ::std::chrono::duration_cast;
-    using ::std::chrono::milliseconds;
-    using ::std::chrono::system_clock;
-
-    std::stringstream tsEntry;
-    const auto now = system_clock::now();
-    const auto time_sec = system_clock::to_time_t(now);
-    tsEntry << std::put_time(std::localtime(&time_sec), "%m-%d %H:%M:%S.") << std::setw(3)
-            << std::setfill('0')
-            << duration_cast<milliseconds>(now - system_clock::from_time_t(time_sec)).count() << " "
-            << entry;
-
-    return tsEntry.str();
-}
-
-}  // namespace
-
-std::string LogEntry::toString() const {
-    std::vector<std::string> text;
-
-    if (!mMsg.empty()) text.push_back(mMsg);
-    if (!mFunc.empty()) {
-        text.push_back(StringPrintf("%s(%s)", mFunc.c_str(), Join(mArgs, ", ").c_str()));
-    }
-    if (!mReturns.empty()) {
-        text.push_back("->");
-        text.push_back(StringPrintf("(%s)", Join(mReturns, ", ").c_str()));
-    }
-    if (!mUid.empty()) text.push_back(mUid);
-    if (!mDuration.empty()) text.push_back(StringPrintf("(%s)", mDuration.c_str()));
-
-    return Join(text, " ");
-}
-
-LogEntry& LogEntry::message(const std::string& message) {
-    mMsg = message;
-    return *this;
-}
-
-LogEntry& LogEntry::function(const std::string& function_name) {
-    mFunc = function_name;
-    return *this;
-}
-
-LogEntry& LogEntry::prettyFunction(const std::string& pretty_function) {
-    // __PRETTY_FUNCTION__ generally seems to be of the form:
-    //
-    //     qualifed::returnType qualified::function(args...)
-    //
-    // where the qualified forms include "(anonymous namespace)" in the
-    // "::"-delimited list and keywords like "virtual" (where applicable).
-    //
-    // Here we try to convert strings like:
-    //
-    //     virtual binder::Status android::net::NetdNativeService::isAlive(bool *)
-    //     netdutils::LogEntry android::netd::(anonymous namespace)::AAA::BBB::function()
-    //
-    // into just "NetdNativeService::isAlive" or "BBB::function". Note that
-    // without imposing convention, how to easily identify any namespace/class
-    // name boundary is not obvious.
-    const size_t endFuncName = pretty_function.rfind('(');
-    const size_t precedingSpace = pretty_function.rfind(' ', endFuncName);
-    size_t substrStart = (precedingSpace != std::string::npos) ? precedingSpace + 1 : 0;
-
-    const size_t beginFuncName = pretty_function.rfind("::", endFuncName);
-    if (beginFuncName != std::string::npos && substrStart < beginFuncName) {
-        const size_t previousNameBoundary = pretty_function.rfind("::", beginFuncName - 1);
-        if (previousNameBoundary < beginFuncName && substrStart < previousNameBoundary) {
-            substrStart = previousNameBoundary + 2;
-        } else {
-            substrStart = beginFuncName + 2;
-        }
-    }
-
-    mFunc = pretty_function.substr(substrStart, endFuncName - substrStart);
-    return *this;
-}
-
-LogEntry& LogEntry::arg(const std::string& val) {
-    mArgs.push_back(val.empty() ? "\"\"" : val);
-    return *this;
-}
-
-template <>
-LogEntry& LogEntry::arg<>(bool val) {
-    mArgs.push_back(val ? "true" : "false");
-    return *this;
-}
-
-LogEntry& LogEntry::arg(const std::vector<int32_t>& val) {
-    mArgs.push_back(StringPrintf("[%s]", Join(val, ", ").c_str()));
-    return *this;
-}
-
-LogEntry& LogEntry::arg(const std::vector<uint8_t>& val) {
-    mArgs.push_back('{' + toHex(makeSlice(val)) + '}');
-    return *this;
-}
-
-LogEntry& LogEntry::arg(const std::vector<std::string>& val) {
-    mArgs.push_back(StringPrintf("[%s]", Join(val, ", ").c_str()));
-    return *this;
-}
-
-LogEntry& LogEntry::returns(const std::string& rval) {
-    mReturns.push_back(rval);
-    return *this;
-}
-
-LogEntry& LogEntry::returns(bool rval) {
-    mReturns.push_back(rval ? "true" : "false");
-    return *this;
-}
-
-LogEntry& LogEntry::returns(const Status& status) {
-    mReturns.push_back(status.msg());
-    return *this;
-}
-
-LogEntry& LogEntry::withUid(uid_t uid) {
-    mUid = StringPrintf("(uid=%d)", uid);
-    return *this;
-}
-
-LogEntry& LogEntry::withAutomaticDuration() {
-    using ms = std::chrono::duration<float, std::ratio<1, 1000>>;
-
-    const std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
-    std::stringstream duration;
-    duration << std::setprecision(1) << std::chrono::duration_cast<ms>(end - mStart).count()
-             << "ms";
-    mDuration = duration.str();
-    return *this;
-}
-
-LogEntry& LogEntry::withDuration(const std::string& duration) {
-    mDuration = duration;
-    return *this;
-}
-
-Log::~Log() {
-    // TODO: dump the last N entries to the android log for possible posterity.
-    info(LogEntry().function(__FUNCTION__));
-}
-
-void Log::forEachEntry(const std::function<void(const std::string&)>& perEntryFn) const {
-    // We make a (potentially expensive) copy of the log buffer (including
-    // all strings), in case the |perEntryFn| takes its sweet time.
-    std::deque<std::string> entries;
-    {
-        std::shared_lock<std::shared_mutex> guard(mLock);
-        entries.assign(mEntries.cbegin(), mEntries.cend());
-    }
-
-    for (const std::string& entry : entries) perEntryFn(entry);
-}
-
-void Log::record(Log::Level lvl, const std::string& entry) {
-    switch (lvl) {
-        case Level::LOG:
-            break;
-        case Level::INFO:
-            ALOG(LOG_INFO, mTag.c_str(), "%s", entry.c_str());
-            break;
-        case Level::WARN:
-            ALOG(LOG_WARN, mTag.c_str(), "%s", entry.c_str());
-            break;
-        case Level::ERROR:
-            ALOG(LOG_ERROR, mTag.c_str(), "%s", entry.c_str());
-            break;
-    }
-
-    std::lock_guard guard(mLock);
-    mEntries.push_back(makeTimestampedEntry(entry));
-    while (mEntries.size() > mMaxEntries) mEntries.pop_front();
-}
-
-}  // namespace netdutils
-}  // namespace android
diff --git a/libnetdutils/LogTest.cpp b/libnetdutils/LogTest.cpp
deleted file mode 100644
index 1270560..0000000
--- a/libnetdutils/LogTest.cpp
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <gtest/gtest.h>
-
-#include "netdutils/Log.h"
-
-android::netdutils::LogEntry globalFunctionName() {
-    return android::netdutils::LogEntry().function(__FUNCTION__);
-}
-
-android::netdutils::LogEntry globalPrettyFunctionName() {
-    return android::netdutils::LogEntry().prettyFunction(__PRETTY_FUNCTION__);
-}
-
-namespace android {
-namespace netdutils {
-
-namespace {
-
-LogEntry functionName() {
-    return LogEntry().function(__FUNCTION__);
-}
-
-LogEntry prettyFunctionName() {
-    return LogEntry().prettyFunction(__PRETTY_FUNCTION__);
-}
-
-}  // namespace
-
-class AAA {
-  public:
-    AAA() = default;
-
-    LogEntry functionName() {
-        return LogEntry().function(__FUNCTION__);
-    }
-
-    LogEntry prettyFunctionName() {
-        return LogEntry().prettyFunction(__PRETTY_FUNCTION__);
-    }
-
-    class BBB {
-      public:
-        BBB() = default;
-
-        LogEntry functionName() {
-            return LogEntry().function(__FUNCTION__);
-        }
-
-        LogEntry prettyFunctionName() {
-            return LogEntry().prettyFunction(__PRETTY_FUNCTION__);
-        }
-    };
-};
-
-TEST(LogEntryTest, Empty) {
-    LogEntry empty;
-    EXPECT_EQ("", empty.toString());
-}
-
-TEST(LogEntryTest, GlobalFunction) {
-    EXPECT_EQ("globalFunctionName()", ::globalFunctionName().toString());
-}
-
-TEST(LogEntryTest, GlobalPrettyFunction) {
-    EXPECT_EQ("globalPrettyFunctionName()", ::globalPrettyFunctionName().toString());
-}
-
-TEST(LogEntryTest, UnnamedNamespaceFunction) {
-    const LogEntry entry = functionName();
-    EXPECT_EQ("functionName()", entry.toString());
-}
-
-TEST(LogEntryTest, UnnamedNamespacePrettyFunction) {
-    const LogEntry entry = prettyFunctionName();
-    EXPECT_EQ("prettyFunctionName()", entry.toString());
-}
-
-TEST(LogEntryTest, ClassFunction) {
-    const LogEntry entry = AAA().functionName();
-    EXPECT_EQ("functionName()", entry.toString());
-}
-
-TEST(LogEntryTest, ClassPrettyFunction) {
-    const LogEntry entry = AAA().prettyFunctionName();
-    EXPECT_EQ("AAA::prettyFunctionName()", entry.toString());
-}
-
-TEST(LogEntryTest, InnerClassFunction) {
-    const LogEntry entry = AAA::BBB().functionName();
-    EXPECT_EQ("functionName()", entry.toString());
-}
-
-TEST(LogEntryTest, InnerClassPrettyFunction) {
-    const LogEntry entry = AAA::BBB().prettyFunctionName();
-    EXPECT_EQ("BBB::prettyFunctionName()", entry.toString());
-}
-
-TEST(LogEntryTest, PrintChainedArguments) {
-    const LogEntry entry = LogEntry()
-            .function("testFunc")
-            .arg("hello")
-            .arg(42)
-            .arg(true);
-    EXPECT_EQ("testFunc(hello, 42, true)", entry.toString());
-}
-
-TEST(LogEntryTest, PrintIntegralTypes) {
-    const LogEntry entry = LogEntry()
-            .function("testFunc")
-            .arg('A')
-            .arg(100U)
-            .arg(-1000LL);
-    EXPECT_EQ("testFunc(65, 100, -1000)", entry.toString());
-}
-
-TEST(LogEntryTest, PrintHex) {
-    const std::vector<uint8_t> buf{0xDE, 0xAD, 0xBE, 0xEF};
-    const LogEntry entry = LogEntry().function("testFunc").arg(buf);
-    EXPECT_EQ("testFunc({deadbeef})", entry.toString());
-}
-
-TEST(LogEntryTest, PrintArgumentPack) {
-    const LogEntry entry = LogEntry().function("testFunc").args("hello", 42, false);
-    EXPECT_EQ("testFunc(hello, 42, false)", entry.toString());
-}
-
-}  // namespace netdutils
-}  // namespace android
diff --git a/libnetdutils/MemBlockTest.cpp b/libnetdutils/MemBlockTest.cpp
deleted file mode 100644
index 6455a7e..0000000
--- a/libnetdutils/MemBlockTest.cpp
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <algorithm>
-#include <cstdint>
-#include <utility>
-
-#include <gtest/gtest.h>
-
-#include "netdutils/MemBlock.h"
-#include "netdutils/Slice.h"
-
-namespace android {
-namespace netdutils {
-
-namespace {
-
-constexpr unsigned DNS_PACKET_SIZE = 512;
-constexpr int ARBITRARY_VALUE = 0x55;
-
-MemBlock makeArbitraryMemBlock(size_t len) {
-    MemBlock result(len);
-    // Do some fictional work before returning.
-    for (Slice slice = result.get(); !slice.empty(); slice = drop(slice, 1)) {
-        slice.base()[0] = ARBITRARY_VALUE;
-    }
-    return result;
-}
-
-void checkAllZeros(Slice slice) {
-    for (; !slice.empty(); slice = drop(slice, 1)) {
-        EXPECT_EQ(0U, slice.base()[0]);
-    }
-}
-
-void checkArbitraryMemBlock(const MemBlock& block, size_t expectedSize) {
-    Slice slice = block.get();
-    EXPECT_EQ(expectedSize, slice.size());
-    EXPECT_NE(nullptr, slice.base());
-    for (; !slice.empty(); slice = drop(slice, 1)) {
-        EXPECT_EQ(ARBITRARY_VALUE, slice.base()[0]);
-    }
-}
-
-void checkHelloMello(Slice dest, Slice src) {
-    EXPECT_EQ('h', dest.base()[0]);
-    EXPECT_EQ('e', dest.base()[1]);
-    EXPECT_EQ('l', dest.base()[2]);
-    EXPECT_EQ('l', dest.base()[3]);
-    EXPECT_EQ('o', dest.base()[4]);
-
-    src.base()[0] = 'm';
-    EXPECT_EQ('h', dest.base()[0]);
-}
-
-}  // namespace
-
-TEST(MemBlockTest, Empty) {
-    MemBlock empty;
-    EXPECT_TRUE(empty.get().empty());
-    EXPECT_EQ(nullptr, empty.get().base());
-}
-
-TEST(MemBlockTest, ExplicitZero) {
-    MemBlock zero(0);
-    EXPECT_TRUE(zero.get().empty());
-    EXPECT_EQ(nullptr, zero.get().base());
-}
-
-TEST(MemBlockTest, BasicAllocation) {
-    MemBlock dnsPacket(DNS_PACKET_SIZE);
-    Slice slice = dnsPacket.get();
-    EXPECT_EQ(DNS_PACKET_SIZE, slice.size());
-    // Verify the space is '\0'-initialized.
-    ASSERT_NO_FATAL_FAILURE(checkAllZeros(slice));
-    EXPECT_NE(nullptr, slice.base());
-}
-
-TEST(MemBlockTest, MoveConstruction) {
-    MemBlock block(makeArbitraryMemBlock(DNS_PACKET_SIZE));
-    ASSERT_NO_FATAL_FAILURE(checkArbitraryMemBlock(block, DNS_PACKET_SIZE));
-}
-
-TEST(MemBlockTest, MoveAssignmentOrConstruction) {
-    MemBlock block = makeArbitraryMemBlock(DNS_PACKET_SIZE);
-    ASSERT_NO_FATAL_FAILURE(checkArbitraryMemBlock(block, DNS_PACKET_SIZE));
-}
-
-TEST(MemBlockTest, StdMoveAssignment) {
-    constexpr unsigned SIZE = 10;
-
-    MemBlock block;
-    EXPECT_TRUE(block.get().empty());
-    EXPECT_EQ(nullptr, block.get().base());
-
-    {
-        MemBlock block2 = makeArbitraryMemBlock(SIZE);
-        EXPECT_EQ(SIZE, block2.get().size());
-        // More fictional work.
-        for (unsigned i = 0; i < SIZE; i++) {
-            block2.get().base()[i] = i;
-        }
-        block = std::move(block2);
-    }
-
-    EXPECT_EQ(SIZE, block.get().size());
-    for (unsigned i = 0; i < SIZE; i++) {
-        EXPECT_EQ(i, block.get().base()[i]);
-    }
-}
-
-TEST(MemBlockTest, ConstructionFromSlice) {
-    uint8_t data[] = {'h', 'e', 'l', 'l', 'o'};
-    Slice dataSlice(Slice(data, sizeof(data) / sizeof(data[0])));
-
-    MemBlock dataCopy(dataSlice);
-    ASSERT_NO_FATAL_FAILURE(checkHelloMello(dataCopy.get(), dataSlice));
-}
-
-TEST(MemBlockTest, ImplicitCastToSlice) {
-    uint8_t data[] = {'h', 'e', 'l', 'l', 'o'};
-    Slice dataSlice(Slice(data, sizeof(data) / sizeof(data[0])));
-
-    MemBlock dataCopy(dataSlice.size());
-    // NOTE: no explicit MemBlock::get().
-    // Verify the space is '\0'-initialized.
-    ASSERT_NO_FATAL_FAILURE(checkAllZeros(dataCopy));
-    copy(dataCopy, dataSlice);
-    ASSERT_NO_FATAL_FAILURE(checkHelloMello(dataCopy, dataSlice));
-}
-
-}  // namespace netdutils
-}  // namespace android
diff --git a/libnetdutils/Netfilter.cpp b/libnetdutils/Netfilter.cpp
deleted file mode 100644
index bb43de0..0000000
--- a/libnetdutils/Netfilter.cpp
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <arpa/inet.h>
-#include <linux/netfilter.h>
-#include <linux/netfilter/nfnetlink.h>
-#include <linux/netlink.h>
-#include <ios>
-
-#include "netdutils/Netfilter.h"
-
-std::ostream& operator<<(std::ostream& os, const nfgenmsg& msg) {
-    return os << std::hex << "nfgenmsg["
-              << "family: 0x" << static_cast<int>(msg.nfgen_family) << ", version: 0x"
-              << static_cast<int>(msg.version) << ", res_id: 0x" << ntohs(msg.res_id) << "]"
-              << std::dec;
-}
diff --git a/libnetdutils/Netlink.cpp b/libnetdutils/Netlink.cpp
deleted file mode 100644
index 824c0f2..0000000
--- a/libnetdutils/Netlink.cpp
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <ios>
-#include <linux/netlink.h>
-
-#include "netdutils/Math.h"
-#include "netdutils/Netlink.h"
-
-namespace android {
-namespace netdutils {
-
-void forEachNetlinkMessage(const Slice buf,
-                           const std::function<void(const nlmsghdr&, const Slice)>& onMsg) {
-    Slice tail = buf;
-    while (tail.size() >= sizeof(nlmsghdr)) {
-        nlmsghdr hdr = {};
-        extract(tail, hdr);
-        const auto len = std::max<size_t>(hdr.nlmsg_len, sizeof(hdr));
-        onMsg(hdr, drop(take(tail, len), sizeof(hdr)));
-        tail = drop(tail, align(len, 2));
-    }
-}
-
-void forEachNetlinkAttribute(const Slice buf,
-                             const std::function<void(const nlattr&, const Slice)>& onAttr) {
-    Slice tail = buf;
-    while (tail.size() >= sizeof(nlattr)) {
-        nlattr hdr = {};
-        extract(tail, hdr);
-        const auto len = std::max<size_t>(hdr.nla_len, sizeof(hdr));
-        onAttr(hdr, drop(take(tail, len), sizeof(hdr)));
-        tail = drop(tail, align(len, 2));
-    }
-}
-
-}  // namespace netdutils
-}  // namespace android
-
-bool operator==(const sockaddr_nl& lhs, const sockaddr_nl& rhs) {
-    return (lhs.nl_family == rhs.nl_family) && (lhs.nl_pid == rhs.nl_pid) &&
-           (lhs.nl_groups == rhs.nl_groups);
-}
-
-bool operator!=(const sockaddr_nl& lhs, const sockaddr_nl& rhs) {
-    return !(lhs == rhs);
-}
-
-std::ostream& operator<<(std::ostream& os, const nlmsghdr& hdr) {
-    return os << std::hex << "nlmsghdr["
-              << "len: 0x" << hdr.nlmsg_len << ", type: 0x" << hdr.nlmsg_type << ", flags: 0x"
-              << hdr.nlmsg_flags << ", seq: 0x" << hdr.nlmsg_seq << ", pid: 0x" << hdr.nlmsg_pid
-              << "]" << std::dec;
-}
-
-std::ostream& operator<<(std::ostream& os, const nlattr& attr) {
-    return os << std::hex << "nlattr["
-              << "len: 0x" << attr.nla_len << ", type: 0x" << attr.nla_type << "]" << std::dec;
-}
-
-std::ostream& operator<<(std::ostream& os, const sockaddr_nl& addr) {
-    return os << std::hex << "sockaddr_nl["
-              << "family: " << addr.nl_family << ", pid: " << addr.nl_pid
-              << ", groups: " << addr.nl_groups << "]" << std::dec;
-}
diff --git a/libnetdutils/Slice.cpp b/libnetdutils/Slice.cpp
deleted file mode 100644
index 7a07d47..0000000
--- a/libnetdutils/Slice.cpp
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <sstream>
-
-#include "netdutils/Slice.h"
-
-namespace android {
-namespace netdutils {
-namespace {
-
-// Convert one byte to a two character hexadecimal string
-const std::string toHex(uint8_t byte) {
-    const std::array<char, 16> kLookup = {
-        {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}};
-    return {kLookup[byte >> 4], kLookup[byte & 0xf]};
-}
-
-}  // namespace
-
-std::string toString(const Slice s) {
-    return std::string(reinterpret_cast<char*>(s.base()), s.size());
-}
-
-std::string toHex(const Slice s, int wrap) {
-    Slice tail = s;
-    int count = 0;
-    std::stringstream ss;
-    while (!tail.empty()) {
-        uint8_t byte = 0;
-        extract(tail, byte);
-        ss << toHex(byte);
-        if ((++count % wrap) == 0) {
-            ss << "\n";
-        }
-        tail = drop(tail, 1);
-    }
-    return ss.str();
-}
-
-std::ostream& operator<<(std::ostream& os, const Slice& slice) {
-    return os << std::hex << "Slice[base: " << reinterpret_cast<void*>(slice.base())
-              << ", limit: " << reinterpret_cast<void*>(slice.limit()) << ", size: 0x"
-              << slice.size() << "]" << std::dec;
-}
-
-}  // namespace netdutils
-}  // namespace android
diff --git a/libnetdutils/SliceTest.cpp b/libnetdutils/SliceTest.cpp
deleted file mode 100644
index a496933..0000000
--- a/libnetdutils/SliceTest.cpp
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <array>
-#include <cstdint>
-
-#include <gtest/gtest.h>
-
-#include "netdutils/Slice.h"
-#include "netdutils/Status.h"
-#include "netdutils/StatusOr.h"
-
-namespace android {
-namespace netdutils {
-
-class SliceTest : public testing::Test {
-  protected:
-    std::array<char, 256> mRaw = {};
-};
-
-TEST_F(SliceTest, smoke) {
-    Slice s1 = makeSlice(mRaw);
-    Slice s2 = makeSlice(mRaw);
-    auto p = split(s1, 14);
-    s2 = p.first; // avoid warn-unused error
-    std::stringstream ss;
-    ss << Slice();
-    EXPECT_EQ("Slice[base: 0x0, limit: 0x0, size: 0x0]", ss.str());
-    constexpr size_t kBytes = 14;
-    EXPECT_EQ(s1.base(), take(s1, kBytes).base());
-    EXPECT_EQ(kBytes, take(s1, kBytes).size());
-    EXPECT_EQ(s1.base() + kBytes, drop(s1, kBytes).base());
-    EXPECT_EQ(s1.size() - kBytes, drop(s1, kBytes).size());
-    double a = 0;
-    double b = 0;
-    int c = 0;
-    EXPECT_EQ(sizeof(a), extract(s1, a));
-    EXPECT_EQ(sizeof(a) + sizeof(b), extract(s1, a, b));
-    EXPECT_EQ(sizeof(a) + sizeof(b) + sizeof(c), extract(s1, a, b, c));
-}
-
-TEST_F(SliceTest, constructor) {
-    // Expect the following lines to compile
-    Slice s1 = makeSlice(mRaw);
-    Slice s2(s1);
-    Slice s3 = s2;
-    const Slice s4(s3);
-    const Slice s5 = s4;
-    s3 = s5;
-    Slice s6(mRaw.data(), mRaw.size());
-    Slice s7(mRaw.data(), mRaw.data() + mRaw.size());
-    struct {
-      int a;
-      double b;
-      float c;
-    } anon;
-    makeSlice(anon);
-    EXPECT_EQ(reinterpret_cast<uint8_t*>(mRaw.data()), s1.base());
-    EXPECT_EQ(reinterpret_cast<uint8_t*>(mRaw.data()) + mRaw.size(), s1.limit());
-    EXPECT_EQ(mRaw.size(), s1.size());
-    EXPECT_FALSE(mRaw.empty());
-    EXPECT_TRUE(Slice().empty());
-    EXPECT_TRUE(Slice(nullptr, static_cast<size_t>(0)).empty());
-    EXPECT_TRUE(Slice(nullptr, nullptr).empty());
-}
-
-TEST_F(SliceTest, extract) {
-    struct A {
-        int a, b;
-        bool operator==(const A& other) const { return a == other.a && b == other.b; }
-    };
-    struct B {
-        char str[12];
-        bool b;
-        int i;
-        bool operator==(const B& other) const {
-            return b == other.b && i == other.i && 0 == strncmp(str, other.str, 12);
-        }
-    };
-
-    A origA1 = {1, 2};
-    A origA2 = {3, 4};
-    B origB = {"hello world", true, 1234};
-
-    // Populate buffer for extracting.
-    Slice buffer = makeSlice(mRaw);
-    copy(buffer, makeSlice(origA1));
-    copy(drop(buffer, sizeof(origA1)), makeSlice(origB));
-    copy(drop(buffer, sizeof(origA1) + sizeof(origB)), makeSlice(origA2));
-
-    {
-        // Non-variadic extract
-        A a1{};
-        size_t len = extract(buffer, a1);
-        EXPECT_EQ(sizeof(A), len);
-        EXPECT_EQ(origA1, a1);
-    }
-
-    {
-        // Variadic extract, 2 destinations
-        A a1{};
-        B b{};
-        size_t len = extract(buffer, a1, b);
-        EXPECT_EQ(sizeof(A) + sizeof(B), len);
-        EXPECT_EQ(origA1, a1);
-        EXPECT_EQ(origB, b);
-    }
-
-    {
-        // Variadic extract, 3 destinations
-        A a1{}, a2{};
-        B b{};
-        size_t len = extract(buffer, a1, b, a2);
-        EXPECT_EQ(2 * sizeof(A) + sizeof(B), len);
-        EXPECT_EQ(origA1, a1);
-        EXPECT_EQ(origB, b);
-        EXPECT_EQ(origA2, a2);
-    }
-}
-
-}  // namespace netdutils
-}  // namespace android
diff --git a/libnetdutils/Socket.cpp b/libnetdutils/Socket.cpp
deleted file mode 100644
index e962b6e..0000000
--- a/libnetdutils/Socket.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <arpa/inet.h>
-
-#include "netdutils/Slice.h"
-#include "netdutils/Socket.h"
-
-namespace android {
-namespace netdutils {
-
-StatusOr<std::string> toString(const in6_addr& addr) {
-    std::array<char, INET6_ADDRSTRLEN> out = {};
-    auto* rv = inet_ntop(AF_INET6, &addr, out.data(), out.size());
-    if (rv == nullptr) {
-        return statusFromErrno(errno, "inet_ntop() failed");
-    }
-    return std::string(out.data());
-}
-
-}  // namespace netdutils
-}  // namespace android
diff --git a/libnetdutils/SocketOption.cpp b/libnetdutils/SocketOption.cpp
deleted file mode 100644
index 023df6e..0000000
--- a/libnetdutils/SocketOption.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "netdutils/SocketOption.h"
-
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <sys/socket.h>
-#include <utility>
-
-#include "netdutils/Syscalls.h"
-
-namespace android {
-namespace netdutils {
-
-Status enableSockopt(Fd sock, int level, int optname) {
-    auto& sys = sSyscalls.get();
-    const int on = 1;
-    return sys.setsockopt(sock, level, optname, &on, sizeof(on));
-}
-
-Status enableTcpKeepAlives(Fd sock, unsigned idleTime, unsigned numProbes, unsigned probeInterval) {
-    RETURN_IF_NOT_OK(enableSockopt(sock, SOL_SOCKET, SO_KEEPALIVE));
-
-    auto& sys = sSyscalls.get();
-    if (idleTime != 0) {
-        RETURN_IF_NOT_OK(sys.setsockopt(sock, SOL_TCP, TCP_KEEPIDLE, &idleTime, sizeof(idleTime)));
-    }
-    if (numProbes != 0) {
-        RETURN_IF_NOT_OK(sys.setsockopt(sock, SOL_TCP, TCP_KEEPCNT, &numProbes, sizeof(numProbes)));
-    }
-    if (probeInterval != 0) {
-        RETURN_IF_NOT_OK(sys.setsockopt(sock, SOL_TCP, TCP_KEEPINTVL, &probeInterval,
-                sizeof(probeInterval)));
-    }
-
-    return status::ok;
-}
-
-}  // namespace netdutils
-}  // namespace android
diff --git a/libnetdutils/Status.cpp b/libnetdutils/Status.cpp
deleted file mode 100644
index acd8f11..0000000
--- a/libnetdutils/Status.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "netdutils/Status.h"
-
-#include <sstream>
-
-#include "android-base/stringprintf.h"
-
-namespace android {
-namespace netdutils {
-
-Status statusFromErrno(int err, const std::string& msg) {
-    return Status(err, base::StringPrintf("[%s] : %s", strerror(err), msg.c_str()));
-}
-
-bool equalToErrno(const Status& status, int err) {
-    return status.code() == err;
-}
-
-std::string toString(const Status& status) {
-    std::stringstream ss;
-    ss << status;
-    return ss.str();
-}
-
-std::ostream& operator<<(std::ostream& os, const Status& s) {
-    return os << "Status[code: " << s.code() << ", msg: \"" << s.msg() << "\"]";
-}
-
-}  // namespace netdutils
-}  // namespace android
diff --git a/libnetdutils/StatusTest.cpp b/libnetdutils/StatusTest.cpp
deleted file mode 100644
index 4cfc3bb..0000000
--- a/libnetdutils/StatusTest.cpp
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "netdutils/Status.h"
-#include "netdutils/StatusOr.h"
-
-#include <sstream>
-
-#include <gtest/gtest.h>
-
-namespace android {
-namespace netdutils {
-namespace {
-
-TEST(StatusTest, valueSemantics) {
-    // Default constructor
-    EXPECT_EQ(status::ok, Status());
-
-    // Copy constructor
-    Status status1(1);
-    Status status2(status1);  // NOLINT(performance-unnecessary-copy-initialization)
-    EXPECT_EQ(1, status2.code());
-
-    // Copy assignment
-    Status status3;
-    status3 = status2;
-    EXPECT_EQ(1, status3.code());
-
-    // Same with const objects
-    const Status status4(4);
-    const Status status5(status4);  // NOLINT(performance-unnecessary-copy-initialization)
-    Status status6;
-    status6 = status5;
-    EXPECT_EQ(4, status6.code());
-}
-
-TEST(StatusTest, errorMessages) {
-    Status s(42, "for tea too");
-    EXPECT_EQ(42, s.code());
-    EXPECT_FALSE(s.ok());
-    EXPECT_EQ(s.msg(), "for tea too");
-}
-
-TEST(StatusOrTest, moveSemantics) {
-    // Status objects should be cheaply movable.
-    EXPECT_TRUE(std::is_nothrow_move_constructible<Status>::value);
-    EXPECT_TRUE(std::is_nothrow_move_assignable<Status>::value);
-
-    // Should move from a temporary Status (twice)
-    Status s(Status(Status(42, "move me")));
-    EXPECT_EQ(42, s.code());
-    EXPECT_EQ(s.msg(), "move me");
-
-    Status s2(666, "EDAEMON");
-    EXPECT_NE(s, s2);
-    s = s2;  // Invokes the move-assignment operator.
-    EXPECT_EQ(666, s.code());
-    EXPECT_EQ(s.msg(), "EDAEMON");
-    EXPECT_EQ(s, s2);
-
-    // A moved-from Status can be re-used.
-    s2 = s;
-
-    // Now both objects are valid.
-    EXPECT_EQ(666, s.code());
-    EXPECT_EQ(s.msg(), "EDAEMON");
-    EXPECT_EQ(s, s2);
-}
-
-TEST(StatusTest, ignoredStatus) {
-    statusFromErrno(ENOTTY, "Not a typewriter, what did you expect?").ignoreError();
-}
-
-TEST(StatusOrTest, ostream) {
-    {
-      StatusOr<int> so(11);
-      std::stringstream ss;
-      ss << so;
-      // TODO: Fix StatusOr to optionally output "value:".
-      EXPECT_EQ("StatusOr[status: Status[code: 0, msg: \"\"]]", ss.str());
-    }
-    {
-      StatusOr<int> err(status::undefined);
-      std::stringstream ss;
-      ss << err;
-      EXPECT_EQ("StatusOr[status: Status[code: 2147483647, msg: \"undefined\"]]", ss.str());
-    }
-}
-
-}  // namespace
-}  // namespace netdutils
-}  // namespace android
diff --git a/libnetdutils/Syscalls.cpp b/libnetdutils/Syscalls.cpp
deleted file mode 100644
index 9f653f7..0000000
--- a/libnetdutils/Syscalls.cpp
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "netdutils/Syscalls.h"
-
-#include <atomic>
-#include <type_traits>
-#include <utility>
-
-namespace android {
-namespace netdutils {
-namespace {
-
-// Retry syscall fn as long as it returns -1 with errno == EINTR
-template <typename FnT, typename... Params>
-typename std::result_of<FnT(Params...)>::type syscallRetry(FnT fn, Params&&... params) {
-    auto rv = fn(std::forward<Params>(params)...);
-    while ((rv == -1) && (errno == EINTR)) {
-        rv = fn(std::forward<Params>(params)...);
-    }
-    return rv;
-}
-
-}  // namespace
-
-// Production implementation of Syscalls that forwards to libc syscalls.
-class RealSyscalls final : public Syscalls {
-  public:
-    ~RealSyscalls() override = default;
-
-    StatusOr<UniqueFd> open(const std::string& pathname, int flags, mode_t mode) const override {
-        UniqueFd fd(::open(pathname.c_str(), flags, mode));
-        if (!isWellFormed(fd)) {
-            return statusFromErrno(errno, "open(\"" + pathname + "\"...) failed");
-        }
-        return fd;
-    }
-
-    StatusOr<UniqueFd> socket(int domain, int type, int protocol) const override {
-        UniqueFd sock(::socket(domain, type, protocol));
-        if (!isWellFormed(sock)) {
-            return statusFromErrno(errno, "socket() failed");
-        }
-        return sock;
-    }
-
-    Status getsockname(Fd sock, sockaddr* addr, socklen_t* addrlen) const override {
-        auto rv = ::getsockname(sock.get(), addr, addrlen);
-        if (rv == -1) {
-            return statusFromErrno(errno, "getsockname() failed");
-        }
-        return status::ok;
-    }
-
-    Status getsockopt(Fd sock, int level, int optname, void* optval,
-                      socklen_t* optlen) const override {
-        auto rv = ::getsockopt(sock.get(), level, optname, optval, optlen);
-        if (rv == -1) {
-            return statusFromErrno(errno, "getsockopt() failed");
-        }
-        return status::ok;
-    }
-
-    Status setsockopt(Fd sock, int level, int optname, const void* optval,
-                      socklen_t optlen) const override {
-        auto rv = ::setsockopt(sock.get(), level, optname, optval, optlen);
-        if (rv == -1) {
-            return statusFromErrno(errno, "setsockopt() failed");
-        }
-        return status::ok;
-    }
-
-    Status bind(Fd sock, const sockaddr* addr, socklen_t addrlen) const override {
-        auto rv = ::bind(sock.get(), addr, addrlen);
-        if (rv == -1) {
-            return statusFromErrno(errno, "bind() failed");
-        }
-        return status::ok;
-    }
-
-    Status connect(Fd sock, const sockaddr* addr, socklen_t addrlen) const override {
-        auto rv = syscallRetry(::connect, sock.get(), addr, addrlen);
-        if (rv == -1) {
-            return statusFromErrno(errno, "connect() failed");
-        }
-        return status::ok;
-    }
-
-    StatusOr<ifreq> ioctl(Fd sock, unsigned long request, ifreq* ifr) const override {
-        auto rv = ::ioctl(sock.get(), request, ifr);
-        if (rv == -1) {
-            return statusFromErrno(errno, "ioctl() failed");
-        }
-        return *ifr;
-    }
-
-    StatusOr<UniqueFd> eventfd(unsigned int initval, int flags) const override {
-        UniqueFd fd(::eventfd(initval, flags));
-        if (!isWellFormed(fd)) {
-            return statusFromErrno(errno, "eventfd() failed");
-        }
-        return fd;
-    }
-
-    StatusOr<int> ppoll(pollfd* fds, nfds_t nfds, double timeout) const override {
-        timespec ts = {};
-        ts.tv_sec = timeout;
-        ts.tv_nsec = (timeout - ts.tv_sec) * 1e9;
-        auto rv = syscallRetry(::ppoll, fds, nfds, &ts, nullptr);
-        if (rv == -1) {
-            return statusFromErrno(errno, "ppoll() failed");
-        }
-        return rv;
-    }
-
-    StatusOr<size_t> writev(Fd fd, const std::vector<iovec>& iov) const override {
-        auto rv = syscallRetry(::writev, fd.get(), iov.data(), iov.size());
-        if (rv == -1) {
-            return statusFromErrno(errno, "writev() failed");
-        }
-        return rv;
-    }
-
-    StatusOr<size_t> write(Fd fd, const Slice buf) const override {
-        auto rv = syscallRetry(::write, fd.get(), buf.base(), buf.size());
-        if (rv == -1) {
-            return statusFromErrno(errno, "write() failed");
-        }
-        return static_cast<size_t>(rv);
-    }
-
-    StatusOr<Slice> read(Fd fd, const Slice buf) const override {
-        auto rv = syscallRetry(::read, fd.get(), buf.base(), buf.size());
-        if (rv == -1) {
-            return statusFromErrno(errno, "read() failed");
-        }
-        return Slice(buf.base(), rv);
-    }
-
-    StatusOr<size_t> sendto(Fd sock, const Slice buf, int flags, const sockaddr* dst,
-                            socklen_t dstlen) const override {
-        auto rv = syscallRetry(::sendto, sock.get(), buf.base(), buf.size(), flags, dst, dstlen);
-        if (rv == -1) {
-            return statusFromErrno(errno, "sendto() failed");
-        }
-        return static_cast<size_t>(rv);
-    }
-
-    StatusOr<Slice> recvfrom(Fd sock, const Slice dst, int flags, sockaddr* src,
-                             socklen_t* srclen) const override {
-        auto rv = syscallRetry(::recvfrom, sock.get(), dst.base(), dst.size(), flags, src, srclen);
-        if (rv == -1) {
-            return statusFromErrno(errno, "recvfrom() failed");
-        }
-        if (rv == 0) {
-            return status::eof;
-        }
-        return take(dst, rv);
-    }
-
-    Status shutdown(Fd fd, int how) const override {
-        auto rv = ::shutdown(fd.get(), how);
-        if (rv == -1) {
-            return statusFromErrno(errno, "shutdown() failed");
-        }
-        return status::ok;
-    }
-
-    Status close(Fd fd) const override {
-        auto rv = ::close(fd.get());
-        if (rv == -1) {
-            return statusFromErrno(errno, "close() failed");
-        }
-        return status::ok;
-    }
-
-    StatusOr<UniqueFile> fopen(const std::string& path, const std::string& mode) const override {
-        UniqueFile file(::fopen(path.c_str(), mode.c_str()));
-        if (file == nullptr) {
-            return statusFromErrno(errno, "fopen(\"" + path + "\", \"" + mode + "\") failed");
-        }
-        return file;
-    }
-
-    StatusOr<pid_t> fork() const override {
-        pid_t rv = ::fork();
-        if (rv == -1) {
-            return statusFromErrno(errno, "fork() failed");
-        }
-        return rv;
-    }
-
-    StatusOr<int> vfprintf(FILE* file, const char* format, va_list ap) const override {
-        auto rv = ::vfprintf(file, format, ap);
-        if (rv == -1) {
-            return statusFromErrno(errno, "vfprintf() failed");
-        }
-        return rv;
-    }
-
-    StatusOr<int> vfscanf(FILE* file, const char* format, va_list ap) const override {
-        auto rv = ::vfscanf(file, format, ap);
-        if (rv == -1) {
-            return statusFromErrno(errno, "vfscanf() failed");
-        }
-        return rv;
-    }
-
-    Status fclose(FILE* file) const override {
-        auto rv = ::fclose(file);
-        if (rv == -1) {
-            return statusFromErrno(errno, "fclose() failed");
-        }
-        return status::ok;
-    }
-};
-
-SyscallsHolder::~SyscallsHolder() {
-    delete &get();
-}
-
-Syscalls& SyscallsHolder::get() {
-    while (true) {
-        // memory_order_relaxed gives the compiler and hardware more
-        // freedom. If we get a stale value (this should only happen
-        // early in the execution of a program) the exchange code below
-        // will loop until we get the most current value.
-        auto* syscalls = mSyscalls.load(std::memory_order_relaxed);
-        // Common case returns existing syscalls
-        if (syscalls) {
-            return *syscalls;
-        }
-
-        // This code will execute on first get()
-        std::unique_ptr<Syscalls> tmp(new RealSyscalls());
-        Syscalls* expected = nullptr;
-        bool success = mSyscalls.compare_exchange_strong(expected, tmp.get());
-        if (success) {
-            // Ownership was transferred to mSyscalls already, must release()
-            return *tmp.release();
-        }
-    }
-}
-
-Syscalls& SyscallsHolder::swap(Syscalls& syscalls) {
-    return *mSyscalls.exchange(&syscalls);
-}
-
-SyscallsHolder sSyscalls;
-
-}  // namespace netdutils
-}  // namespace android
diff --git a/libnetdutils/SyscallsTest.cpp b/libnetdutils/SyscallsTest.cpp
deleted file mode 100644
index 78ffab5..0000000
--- a/libnetdutils/SyscallsTest.cpp
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <array>
-#include <cstdint>
-#include <memory>
-
-#include <gtest/gtest.h>
-
-#include "netdutils/Handle.h"
-#include "netdutils/Math.h"
-#include "netdutils/MockSyscalls.h"
-#include "netdutils/Netfilter.h"
-#include "netdutils/Netlink.h"
-#include "netdutils/Slice.h"
-#include "netdutils/Status.h"
-#include "netdutils/StatusOr.h"
-#include "netdutils/Syscalls.h"
-
-using testing::_;
-using testing::ByMove;
-using testing::Invoke;
-using testing::Return;
-using testing::StrictMock;
-
-namespace android {
-namespace netdutils {
-
-class SyscallsTest : public testing::Test {
-  protected:
-    StrictMock<ScopedMockSyscalls> mSyscalls;
-};
-
-TEST(syscalls, scopedMock) {
-    auto& old = sSyscalls.get();
-    {
-        StrictMock<ScopedMockSyscalls> s;
-        EXPECT_EQ(&s, &sSyscalls.get());
-    }
-    EXPECT_EQ(&old, &sSyscalls.get());
-}
-
-TEST_F(SyscallsTest, open) {
-    const char kPath[] = "/test/path/please/ignore";
-    constexpr Fd kFd(40);
-    constexpr int kFlags = 883;
-    constexpr mode_t kMode = 37373;
-    const auto& sys = sSyscalls.get();
-    EXPECT_CALL(mSyscalls, open(kPath, kFlags, kMode)).WillOnce(Return(ByMove(UniqueFd(kFd))));
-    EXPECT_CALL(mSyscalls, close(kFd)).WillOnce(Return(status::ok));
-    auto result = sys.open(kPath, kFlags, kMode);
-    EXPECT_EQ(status::ok, result.status());
-    EXPECT_EQ(kFd, result.value());
-}
-
-TEST_F(SyscallsTest, getsockname) {
-    constexpr Fd kFd(40);
-    sockaddr_nl expected = {};
-    auto& sys = sSyscalls.get();
-
-    // Success
-    EXPECT_CALL(mSyscalls, getsockname(kFd, _, _))
-        .WillOnce(Invoke([expected](Fd, sockaddr* addr, socklen_t* addrlen) {
-            memcpy(addr, &expected, sizeof(expected));
-            EXPECT_EQ(*addrlen, static_cast<socklen_t>(sizeof(expected)));
-            return status::ok;
-        }));
-    const auto result = sys.getsockname<sockaddr_nl>(kFd);
-    EXPECT_TRUE(isOk(result));
-    EXPECT_EQ(expected, result.value());
-
-    // Failure
-    const Status kError = statusFromErrno(EINVAL, "test");
-    EXPECT_CALL(mSyscalls, getsockname(kFd, _, _)).WillOnce(Return(kError));
-    EXPECT_EQ(kError, sys.getsockname<sockaddr_nl>(kFd).status());
-}
-
-TEST_F(SyscallsTest, setsockopt) {
-    constexpr Fd kFd(40);
-    constexpr int kLevel = 50;
-    constexpr int kOptname = 70;
-    sockaddr_nl expected = {};
-    auto& sys = sSyscalls.get();
-
-    // Success
-    EXPECT_CALL(mSyscalls, setsockopt(kFd, kLevel, kOptname, &expected, sizeof(expected)))
-        .WillOnce(Return(status::ok));
-    EXPECT_EQ(status::ok, sys.setsockopt(kFd, kLevel, kOptname, expected));
-
-    // Failure
-    const Status kError = statusFromErrno(EINVAL, "test");
-    EXPECT_CALL(mSyscalls, setsockopt(kFd, kLevel, kOptname, &expected, sizeof(expected)))
-        .WillOnce(Return(kError));
-    EXPECT_EQ(kError, sys.setsockopt(kFd, kLevel, kOptname, expected));
-}
-
-TEST_F(SyscallsTest, getsockopt) {
-    constexpr Fd kFd(40);
-    constexpr int kLevel = 50;
-    constexpr int kOptname = 70;
-    sockaddr_nl expected = {};
-    socklen_t optLen = 0;
-    auto& sys = sSyscalls.get();
-
-    // Success
-    EXPECT_CALL(mSyscalls, getsockopt(kFd, kLevel, kOptname, &expected, &optLen))
-        .WillOnce(Return(status::ok));
-    EXPECT_EQ(status::ok, sys.getsockopt(kFd, kLevel, kOptname, &expected, &optLen));
-
-    // Failure
-    const Status kError = statusFromErrno(EINVAL, "test");
-    EXPECT_CALL(mSyscalls, getsockopt(kFd, kLevel, kOptname, &expected, &optLen))
-        .WillOnce(Return(kError));
-    EXPECT_EQ(kError, sys.getsockopt(kFd, kLevel, kOptname, &expected, &optLen));
-}
-
-TEST_F(SyscallsTest, bind) {
-    constexpr Fd kFd(40);
-    sockaddr_nl expected = {};
-    auto& sys = sSyscalls.get();
-
-    // Success
-    EXPECT_CALL(mSyscalls, bind(kFd, asSockaddrPtr(&expected), sizeof(expected)))
-        .WillOnce(Return(status::ok));
-    EXPECT_EQ(status::ok, sys.bind(kFd, expected));
-
-    // Failure
-    const Status kError = statusFromErrno(EINVAL, "test");
-    EXPECT_CALL(mSyscalls, bind(kFd, asSockaddrPtr(&expected), sizeof(expected)))
-        .WillOnce(Return(kError));
-    EXPECT_EQ(kError, sys.bind(kFd, expected));
-}
-
-TEST_F(SyscallsTest, connect) {
-    constexpr Fd kFd(40);
-    sockaddr_nl expected = {};
-    auto& sys = sSyscalls.get();
-
-    // Success
-    EXPECT_CALL(mSyscalls, connect(kFd, asSockaddrPtr(&expected), sizeof(expected)))
-        .WillOnce(Return(status::ok));
-    EXPECT_EQ(status::ok, sys.connect(kFd, expected));
-
-    // Failure
-    const Status kError = statusFromErrno(EINVAL, "test");
-    EXPECT_CALL(mSyscalls, connect(kFd, asSockaddrPtr(&expected), sizeof(expected)))
-        .WillOnce(Return(kError));
-    EXPECT_EQ(kError, sys.connect(kFd, expected));
-}
-
-TEST_F(SyscallsTest, sendto) {
-    constexpr Fd kFd(40);
-    constexpr int kFlags = 0;
-    std::array<char, 10> payload;
-    const auto slice = makeSlice(payload);
-    sockaddr_nl expected = {};
-    auto& sys = sSyscalls.get();
-
-    // Success
-    EXPECT_CALL(mSyscalls, sendto(kFd, slice, kFlags, asSockaddrPtr(&expected), sizeof(expected)))
-        .WillOnce(Return(slice.size()));
-    EXPECT_EQ(status::ok, sys.sendto(kFd, slice, kFlags, expected));
-}
-
-TEST_F(SyscallsTest, recvfrom) {
-    constexpr Fd kFd(40);
-    constexpr int kFlags = 0;
-    std::array<char, 10> payload;
-    const auto dst = makeSlice(payload);
-    const auto used = take(dst, 8);
-    sockaddr_nl expected = {};
-    auto& sys = sSyscalls.get();
-
-    // Success
-    EXPECT_CALL(mSyscalls, recvfrom(kFd, dst, kFlags, _, _))
-            .WillOnce(Invoke(
-                    [expected, used](Fd, const Slice, int, sockaddr* src, socklen_t* srclen) {
-                        *srclen = sizeof(expected);
-                        memcpy(src, &expected, *srclen);
-                        return used;
-                    }));
-    auto result = sys.recvfrom<sockaddr_nl>(kFd, dst, kFlags);
-    EXPECT_EQ(status::ok, result.status());
-    EXPECT_EQ(used, result.value().first);
-    EXPECT_EQ(expected, result.value().second);
-}
-
-}  // namespace netdutils
-}  // namespace android
diff --git a/libnetdutils/ThreadUtilTest.cpp b/libnetdutils/ThreadUtilTest.cpp
deleted file mode 100644
index 8fad8b8..0000000
--- a/libnetdutils/ThreadUtilTest.cpp
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <string>
-
-#include <android-base/expected.h>
-#include <gtest/gtest.h>
-#include <netdutils/ThreadUtil.h>
-
-namespace android::netdutils {
-
-namespace {
-
-android::base::expected<std::string, int> getThreadName() {
-    char name[16] = {};
-    if (const int ret = pthread_getname_np(pthread_self(), name, sizeof(name)); ret != 0) {
-        return android::base::unexpected(ret);
-    }
-    return std::string(name);
-}
-
-class NoopRun {
-  public:
-    explicit NoopRun(const std::string& name = "") : mName(name) { instanceNum++; }
-
-    // Destructor happens in the thread.
-    ~NoopRun() {
-        if (checkName) {
-            auto expected = getThreadName();
-            EXPECT_TRUE(expected.has_value());
-            EXPECT_EQ(mExpectedName, expected.value());
-        }
-        instanceNum--;
-    }
-
-    void run() {}
-
-    std::string threadName() { return mName; }
-
-    // Set the expected thread name which will be used to check if it matches the actual thread
-    // name which is returned from the system call. The check will happen in the destructor.
-    void setExpectedName(const std::string& expectedName) {
-        checkName = true;
-        mExpectedName = expectedName;
-    }
-
-    static bool waitForAllReleased(int timeoutMs) {
-        constexpr int intervalMs = 20;
-        int limit = timeoutMs / intervalMs;
-        for (int i = 1; i < limit; i++) {
-            if (instanceNum == 0) {
-                return true;
-            }
-            usleep(intervalMs * 1000);
-        }
-        return false;
-    }
-
-    // To track how many instances are alive.
-    static std::atomic<int> instanceNum;
-
-  private:
-    std::string mName;
-    std::string mExpectedName;
-    bool checkName = false;
-};
-
-std::atomic<int> NoopRun::instanceNum;
-
-}  // namespace
-
-TEST(ThreadUtilTest, objectReleased) {
-    NoopRun::instanceNum = 0;
-    NoopRun* obj = new NoopRun();
-    EXPECT_EQ(1, NoopRun::instanceNum);
-    threadLaunch(obj);
-
-    // Wait for the object released along with the thread exited.
-    EXPECT_TRUE(NoopRun::waitForAllReleased(1000));
-    EXPECT_EQ(0, NoopRun::instanceNum);
-}
-
-TEST(ThreadUtilTest, SetThreadName) {
-    NoopRun::instanceNum = 0;
-
-    // Test thread name empty.
-    NoopRun* obj1 = new NoopRun();
-    obj1->setExpectedName("");
-
-    // Test normal case.
-    NoopRun* obj2 = new NoopRun("TestName");
-    obj2->setExpectedName("TestName");
-
-    // Test thread name too long.
-    std::string name("TestNameTooooLong");
-    NoopRun* obj3 = new NoopRun(name);
-    obj3->setExpectedName(name.substr(0, 15));
-
-    // Thread names are examined in their destructors.
-    EXPECT_EQ(3, NoopRun::instanceNum);
-    threadLaunch(obj1);
-    threadLaunch(obj2);
-    threadLaunch(obj3);
-
-    EXPECT_TRUE(NoopRun::waitForAllReleased(1000));
-    EXPECT_EQ(0, NoopRun::instanceNum);
-}
-
-}  // namespace android::netdutils
diff --git a/libnetdutils/UniqueFd.cpp b/libnetdutils/UniqueFd.cpp
deleted file mode 100644
index 1cb30ed..0000000
--- a/libnetdutils/UniqueFd.cpp
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <algorithm>
-
-#include "netdutils/UniqueFd.h"
-#include "netdutils/Syscalls.h"
-
-namespace android {
-namespace netdutils {
-
-void UniqueFd::reset(Fd fd) {
-    auto& sys = sSyscalls.get();
-    std::swap(fd, mFd);
-    if (isWellFormed(fd)) {
-        expectOk(sys.close(fd));
-    }
-}
-
-std::ostream& operator<<(std::ostream& os, const UniqueFd& fd) {
-    return os << "UniqueFd[" << static_cast<Fd>(fd) << "]";
-}
-
-}  // namespace netdutils
-}  // namespace android
diff --git a/libnetdutils/UniqueFile.cpp b/libnetdutils/UniqueFile.cpp
deleted file mode 100644
index 21e8779..0000000
--- a/libnetdutils/UniqueFile.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <algorithm>
-
-#include "netdutils/Syscalls.h"
-#include "netdutils/UniqueFile.h"
-
-namespace android {
-namespace netdutils {
-
-void UniqueFileDtor::operator()(FILE* file) const {
-    const auto& sys = sSyscalls.get();
-    sys.fclose(file).ignoreError();
-}
-
-}  // namespace netdutils
-}  // namespace android
diff --git a/libnetdutils/include/netdutils/BackoffSequence.h b/libnetdutils/include/netdutils/BackoffSequence.h
deleted file mode 100644
index a52e72d..0000000
--- a/libnetdutils/include/netdutils/BackoffSequence.h
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NETDUTILS_BACKOFFSEQUENCE_H
-#define NETDUTILS_BACKOFFSEQUENCE_H
-
-#include <stdint.h>
-#include <algorithm>
-#include <chrono>
-#include <limits>
-
-namespace android {
-namespace netdutils {
-
-// Encapsulate some RFC 3315 section 14 -style backoff mechanics.
-//
-//     https://tools.ietf.org/html/rfc3315#section-14
-template<typename time_type = std::chrono::seconds, typename counter_type = uint32_t>
-class BackoffSequence {
-  public:
-    struct Parameters {
-        time_type initialRetransTime{TIME_UNITY};
-        counter_type maxRetransCount{0U};
-        time_type maxRetransTime{TIME_ZERO};
-        time_type maxRetransDuration{TIME_ZERO};
-        time_type endOfSequenceIndicator{TIME_ZERO};
-    };
-
-    BackoffSequence() : BackoffSequence(Parameters{}) {}
-    BackoffSequence(const BackoffSequence &) = default;
-    BackoffSequence(BackoffSequence &&) = default;
-    BackoffSequence& operator=(const BackoffSequence &) = default;
-    BackoffSequence& operator=(BackoffSequence &&) = default;
-
-    bool hasNextTimeout() const noexcept {
-        return !maxRetransCountExceed() && !maxRetransDurationExceeded();
-    }
-
-    // Returns 0 when the sequence is exhausted.
-    time_type getNextTimeout() {
-        if (!hasNextTimeout()) return getEndOfSequenceIndicator();
-
-        mRetransTime = getNextTimeoutAfter(mRetransTime);
-
-        mRetransCount++;
-        mTotalRetransDuration += mRetransTime;
-        return mRetransTime;
-    }
-
-    time_type getEndOfSequenceIndicator() const noexcept {
-        return mParams.endOfSequenceIndicator;
-    }
-
-    class Builder {
-      public:
-        Builder() {}
-
-        constexpr Builder& withInitialRetransmissionTime(time_type irt) {
-            mParams.initialRetransTime = irt;
-            return *this;
-        }
-        constexpr Builder& withMaximumRetransmissionCount(counter_type mrc) {
-            mParams.maxRetransCount = mrc;
-            return *this;
-        }
-        constexpr Builder& withMaximumRetransmissionTime(time_type mrt) {
-            mParams.maxRetransTime = mrt;
-            return *this;
-        }
-        constexpr Builder& withMaximumRetransmissionDuration(time_type mrd) {
-            mParams.maxRetransDuration = mrd;
-            return *this;
-        }
-        constexpr Builder& withEndOfSequenceIndicator(time_type eos) {
-            mParams.endOfSequenceIndicator = eos;
-            return *this;
-        }
-
-        constexpr BackoffSequence build() const {
-            return BackoffSequence(mParams);
-        }
-
-      private:
-        Parameters mParams;
-    };
-
-  private:
-    static constexpr int PER_ITERATION_SCALING_FACTOR = 2;
-    static constexpr time_type TIME_ZERO = time_type();
-    static constexpr time_type TIME_UNITY = time_type(1);
-
-    constexpr BackoffSequence(const struct Parameters &params)
-            : mParams(params),
-              mRetransCount(0),
-              mRetransTime(TIME_ZERO),
-              mTotalRetransDuration(TIME_ZERO) {}
-
-    constexpr bool maxRetransCountExceed() const {
-        return (mParams.maxRetransCount > 0) && (mRetransCount >= mParams.maxRetransCount);
-    }
-
-    constexpr bool maxRetransDurationExceeded() const {
-        return (mParams.maxRetransDuration > TIME_ZERO) &&
-               (mTotalRetransDuration >= mParams.maxRetransDuration);
-    }
-
-    time_type getNextTimeoutAfter(time_type lastTimeout) const {
-        // TODO: Support proper random jitter. Also, consider supporting some
-        // per-iteration scaling factor other than doubling.
-        time_type nextTimeout = (lastTimeout > TIME_ZERO)
-                ? PER_ITERATION_SCALING_FACTOR * lastTimeout
-                : mParams.initialRetransTime;
-
-        // Check if overflow occurred.
-        if (nextTimeout < lastTimeout) {
-            nextTimeout = std::numeric_limits<time_type>::max();
-        }
-
-        // Cap to maximum allowed, if necessary.
-        if (mParams.maxRetransTime > TIME_ZERO) {
-            nextTimeout = std::min(nextTimeout, mParams.maxRetransTime);
-        }
-
-        // Don't overflow the maximum total duration.
-        if (mParams.maxRetransDuration > TIME_ZERO) {
-            nextTimeout = std::min(nextTimeout, mParams.maxRetransDuration - lastTimeout);
-        }
-        return nextTimeout;
-    }
-
-    const Parameters mParams;
-    counter_type mRetransCount;
-    time_type mRetransTime;
-    time_type mTotalRetransDuration;
-};
-
-}  // namespace netdutils
-}  // namespace android
-
-#endif /* NETDUTILS_BACKOFFSEQUENCE_H */
diff --git a/libnetdutils/include/netdutils/DumpWriter.h b/libnetdutils/include/netdutils/DumpWriter.h
deleted file mode 100644
index a50b5e6..0000000
--- a/libnetdutils/include/netdutils/DumpWriter.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NETDUTILS_DUMPWRITER_H_
-#define NETDUTILS_DUMPWRITER_H_
-
-#include <string>
-
-namespace android {
-namespace netdutils {
-
-class DumpWriter {
-  public:
-    DumpWriter(int fd);
-
-    void incIndent();
-    void decIndent();
-
-    void println(const std::string& line);
-    template <size_t n>
-    void println(const char line[n]) {
-        println(std::string(line));
-    }
-    // Hint to the compiler that it should apply printf validation of
-    // arguments (beginning at position 3) of the format (specified in
-    // position 2). Note that position 1 is the implicit "this" argument.
-    void println(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3)));
-    void blankline() { println(""); }
-
-  private:
-    uint8_t mIndentLevel;
-    int mFd;
-};
-
-class ScopedIndent {
-  public:
-    ScopedIndent() = delete;
-    ScopedIndent(const ScopedIndent&) = delete;
-    ScopedIndent(ScopedIndent&&) = delete;
-    explicit ScopedIndent(DumpWriter& dw) : mDw(dw) { mDw.incIndent(); }
-    ~ScopedIndent() { mDw.decIndent(); }
-    ScopedIndent& operator=(const ScopedIndent&) = delete;
-    ScopedIndent& operator=(ScopedIndent&&) = delete;
-
-    // TODO: consider additional {inc,dec}Indent methods and a counter that
-    // can be used to unwind all pending increments on exit.
-
-  private:
-    DumpWriter& mDw;
-};
-
-}  // namespace netdutils
-}  // namespace android
-
-#endif  // NETDUTILS_DUMPWRITER_H_
diff --git a/libnetdutils/include/netdutils/Fd.h b/libnetdutils/include/netdutils/Fd.h
deleted file mode 100644
index 7db4087..0000000
--- a/libnetdutils/include/netdutils/Fd.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NETUTILS_FD_H
-#define NETUTILS_FD_H
-
-#include <ostream>
-
-#include "netdutils/Status.h"
-
-namespace android {
-namespace netdutils {
-
-// Strongly typed wrapper for file descriptors with value semantics.
-// This class should typically hold unowned file descriptors.
-class Fd {
-  public:
-    constexpr Fd() = default;
-
-    constexpr Fd(int fd) : mFd(fd) {}
-
-    int get() const { return mFd; }
-
-    bool operator==(const Fd& other) const { return get() == other.get(); }
-    bool operator!=(const Fd& other) const { return get() != other.get(); }
-
-  private:
-    int mFd = -1;
-};
-
-// Return true if fd appears valid (non-negative)
-inline bool isWellFormed(const Fd fd) {
-    return fd.get() >= 0;
-}
-
-std::ostream& operator<<(std::ostream& os, const Fd& fd);
-
-}  // namespace netdutils
-}  // namespace android
-
-#endif /* NETUTILS_FD_H */
diff --git a/libnetdutils/include/netdutils/Handle.h b/libnetdutils/include/netdutils/Handle.h
deleted file mode 100644
index 82083d4..0000000
--- a/libnetdutils/include/netdutils/Handle.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NETUTILS_HANDLE_H
-#define NETUTILS_HANDLE_H
-
-#include <ostream>
-
-namespace android {
-namespace netdutils {
-
-// Opaque, strongly typed wrapper for integer-like handles.
-// Explicitly avoids implementing arithmetic operations.
-//
-// This class is intended to avoid common errors when reordering
-// arguments to functions, typos and other cases where plain integer
-// types would silently cover up the mistake.
-//
-// usage:
-// DEFINE_HANDLE(ProductId, uint64_t);
-// DEFINE_HANDLE(ThumbnailHash, uint64_t);
-// void foo(ProductId p, ThumbnailHash th) {...}
-//
-// void test() {
-//     ProductId p(88);
-//     ThumbnailHash th1(100), th2(200);
-//
-//     foo(p, th1);        <- ok!
-//     foo(th1, p);        <- disallowed!
-//     th1 += 10;          <- disallowed!
-//     p = th2;            <- disallowed!
-//     assert(th1 != th2); <- ok!
-// }
-template <typename T, typename TagT>
-class Handle {
-  public:
-    constexpr Handle() = default;
-    constexpr Handle(const T& value) : mValue(value) {}
-
-    const T get() const { return mValue; }
-
-    bool operator==(const Handle& that) const { return get() == that.get(); }
-    bool operator!=(const Handle& that) const { return get() != that.get(); }
-
-  private:
-    T mValue;
-};
-
-#define DEFINE_HANDLE(name, type) \
-    struct _##name##Tag {};       \
-    using name = ::android::netdutils::Handle<type, _##name##Tag>;
-
-template <typename T, typename TagT>
-inline std::ostream& operator<<(std::ostream& os, const Handle<T, TagT>& handle) {
-    return os << handle.get();
-}
-
-}  // namespace netdutils
-}  // namespace android
-
-#endif /* NETUTILS_HANDLE_H */
diff --git a/libnetdutils/include/netdutils/InternetAddresses.h b/libnetdutils/include/netdutils/InternetAddresses.h
deleted file mode 100644
index d5cbe2b..0000000
--- a/libnetdutils/include/netdutils/InternetAddresses.h
+++ /dev/null
@@ -1,325 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <netdb.h>
-#include <netinet/in.h>
-#include <stdint.h>
-#include <cstring>
-#include <limits>
-#include <string>
-
-#include "netdutils/NetworkConstants.h"
-
-namespace android {
-namespace netdutils {
-
-namespace internal_ {
-
-// A structure to hold data for dealing with Internet addresses (IPAddress) and
-// related types such as IPSockAddr and IPPrefix.
-struct compact_ipdata {
-    uint8_t family{AF_UNSPEC};
-    uint8_t cidrlen{0U};  // written and read in host-byte order
-    in_port_t port{0U};   // written and read in host-byte order
-    uint32_t scope_id{0U};
-    union {
-        in_addr v4;
-        in6_addr v6;
-    } ip{.v6 = IN6ADDR_ANY_INIT};  // written and read in network-byte order
-
-    // Classes that use compact_ipdata and this method should be sure to clear
-    // (i.e. zero or make uniform) any fields not relevant to the class.
-    friend bool operator==(const compact_ipdata& a, const compact_ipdata& b) {
-        if ((a.family != b.family) || (a.cidrlen != b.cidrlen) || (a.port != b.port) ||
-            (a.scope_id != b.scope_id)) {
-            return false;
-        }
-        switch (a.family) {
-            case AF_UNSPEC:
-                // After the above checks, two AF_UNSPEC objects can be
-                // considered equal, for convenience.
-                return true;
-            case AF_INET: {
-                const in_addr v4a = a.ip.v4;
-                const in_addr v4b = b.ip.v4;
-                return (v4a.s_addr == v4b.s_addr);
-            }
-            case AF_INET6: {
-                const in6_addr v6a = a.ip.v6;
-                const in6_addr v6b = b.ip.v6;
-                return IN6_ARE_ADDR_EQUAL(&v6a, &v6b);
-            }
-        }
-        return false;
-    }
-
-    // Classes that use compact_ipdata and this method should be sure to clear
-    // (i.e. zero or make uniform) any fields not relevant to the class.
-    friend bool operator!=(const compact_ipdata& a, const compact_ipdata& b) { return !(a == b); }
-
-    // Classes that use compact_ipdata and this method should be sure to clear
-    // (i.e. zero or make uniform) any fields not relevant to the class.
-    friend bool operator<(const compact_ipdata& a, const compact_ipdata& b) {
-        if (a.family != b.family) return (a.family < b.family);
-        switch (a.family) {
-            case AF_INET: {
-                const in_addr v4a = a.ip.v4;
-                const in_addr v4b = b.ip.v4;
-                if (v4a.s_addr != v4b.s_addr) return (ntohl(v4a.s_addr) < ntohl(v4b.s_addr));
-                break;
-            }
-            case AF_INET6: {
-                const in6_addr v6a = a.ip.v6;
-                const in6_addr v6b = b.ip.v6;
-                const int cmp = std::memcmp(v6a.s6_addr, v6b.s6_addr, IPV6_ADDR_LEN);
-                if (cmp != 0) return cmp < 0;
-                break;
-            }
-        }
-        if (a.cidrlen != b.cidrlen) return (a.cidrlen < b.cidrlen);
-        if (a.port != b.port) return (a.port < b.port);
-        return (a.scope_id < b.scope_id);
-    }
-};
-
-static_assert(AF_UNSPEC <= std::numeric_limits<uint8_t>::max(), "AF_UNSPEC value too large");
-static_assert(AF_INET <= std::numeric_limits<uint8_t>::max(), "AF_INET value too large");
-static_assert(AF_INET6 <= std::numeric_limits<uint8_t>::max(), "AF_INET6 value too large");
-static_assert(sizeof(compact_ipdata) == 24U, "compact_ipdata unexpectedly large");
-
-}  // namespace internal_
-
-struct AddrinfoDeleter {
-    void operator()(struct addrinfo* p) const {
-        if (p != nullptr) {
-            freeaddrinfo(p);
-        }
-    }
-};
-
-typedef std::unique_ptr<struct addrinfo, struct AddrinfoDeleter> ScopedAddrinfo;
-
-inline bool usesScopedIds(const in6_addr& ipv6) {
-    return (IN6_IS_ADDR_LINKLOCAL(&ipv6) || IN6_IS_ADDR_MC_LINKLOCAL(&ipv6));
-}
-
-class IPPrefix;
-class IPSockAddr;
-
-class IPAddress {
-  public:
-    static bool forString(const std::string& repr, IPAddress* ip);
-    static IPAddress forString(const std::string& repr) {
-        IPAddress ip;
-        if (!forString(repr, &ip)) return IPAddress();
-        return ip;
-    }
-
-    IPAddress() = default;
-    IPAddress(const IPAddress&) = default;
-    IPAddress(IPAddress&&) = default;
-
-    explicit IPAddress(const in_addr& ipv4)
-        : mData({AF_INET, IPV4_ADDR_BITS, 0U, 0U, {.v4 = ipv4}}) {}
-    explicit IPAddress(const in6_addr& ipv6)
-        : mData({AF_INET6, IPV6_ADDR_BITS, 0U, 0U, {.v6 = ipv6}}) {}
-    IPAddress(const in6_addr& ipv6, uint32_t scope_id)
-        : mData({AF_INET6,
-                 IPV6_ADDR_BITS,
-                 0U,
-                 // Sanity check: scoped_ids only for link-local addresses.
-                 usesScopedIds(ipv6) ? scope_id : 0U,
-                 {.v6 = ipv6}}) {}
-    IPAddress(const IPAddress& ip, uint32_t scope_id) : IPAddress(ip) {
-        mData.scope_id = (family() == AF_INET6 && usesScopedIds(mData.ip.v6)) ? scope_id : 0U;
-    }
-
-    IPAddress& operator=(const IPAddress&) = default;
-    IPAddress& operator=(IPAddress&&) = default;
-
-    constexpr sa_family_t family() const noexcept { return mData.family; }
-    constexpr uint32_t scope_id() const noexcept { return mData.scope_id; }
-
-    std::string toString() const noexcept;
-
-    friend std::ostream& operator<<(std::ostream& os, const IPAddress& ip) {
-        os << ip.toString();
-        return os;
-    }
-    friend bool operator==(const IPAddress& a, const IPAddress& b) { return (a.mData == b.mData); }
-    friend bool operator!=(const IPAddress& a, const IPAddress& b) { return (a.mData != b.mData); }
-    friend bool operator<(const IPAddress& a, const IPAddress& b) { return (a.mData < b.mData); }
-    friend bool operator>(const IPAddress& a, const IPAddress& b) { return (b.mData < a.mData); }
-    friend bool operator<=(const IPAddress& a, const IPAddress& b) { return (a < b) || (a == b); }
-    friend bool operator>=(const IPAddress& a, const IPAddress& b) { return (b < a) || (a == b); }
-
-  private:
-    friend class IPPrefix;
-    friend class IPSockAddr;
-
-    explicit IPAddress(const internal_::compact_ipdata& ipdata) : mData(ipdata) {
-        mData.port = 0U;
-        switch (mData.family) {
-            case AF_INET:
-                mData.cidrlen = IPV4_ADDR_BITS;
-                mData.scope_id = 0U;
-                break;
-            case AF_INET6:
-                mData.cidrlen = IPV6_ADDR_BITS;
-                if (usesScopedIds(ipdata.ip.v6)) mData.scope_id = ipdata.scope_id;
-                break;
-            default:
-                mData.cidrlen = 0U;
-                mData.scope_id = 0U;
-                break;
-        }
-    }
-
-    internal_::compact_ipdata mData{};
-};
-
-class IPPrefix {
-  public:
-    static bool forString(const std::string& repr, IPPrefix* prefix);
-    static IPPrefix forString(const std::string& repr) {
-        IPPrefix prefix;
-        if (!forString(repr, &prefix)) return IPPrefix();
-        return prefix;
-    }
-
-    IPPrefix() = default;
-    IPPrefix(const IPPrefix&) = default;
-    IPPrefix(IPPrefix&&) = default;
-
-    explicit IPPrefix(const IPAddress& ip) : mData(ip.mData) {}
-
-    // Truncate the IP address |ip| at length |length|. Lengths greater than
-    // the address-family-relevant maximum, along with negative values, are
-    // interpreted as if the address-family-relevant maximum had been given.
-    IPPrefix(const IPAddress& ip, int length);
-
-    IPPrefix& operator=(const IPPrefix&) = default;
-    IPPrefix& operator=(IPPrefix&&) = default;
-
-    constexpr sa_family_t family() const noexcept { return mData.family; }
-    IPAddress ip() const noexcept { return IPAddress(mData); }
-    in_addr addr4() const noexcept { return mData.ip.v4; }
-    in6_addr addr6() const noexcept { return mData.ip.v6; }
-    constexpr int length() const noexcept { return mData.cidrlen; }
-
-    bool isUninitialized() const noexcept;
-    std::string toString() const noexcept;
-
-    friend std::ostream& operator<<(std::ostream& os, const IPPrefix& prefix) {
-        os << prefix.toString();
-        return os;
-    }
-    friend bool operator==(const IPPrefix& a, const IPPrefix& b) { return (a.mData == b.mData); }
-    friend bool operator!=(const IPPrefix& a, const IPPrefix& b) { return (a.mData != b.mData); }
-    friend bool operator<(const IPPrefix& a, const IPPrefix& b) { return (a.mData < b.mData); }
-    friend bool operator>(const IPPrefix& a, const IPPrefix& b) { return (b.mData < a.mData); }
-    friend bool operator<=(const IPPrefix& a, const IPPrefix& b) { return (a < b) || (a == b); }
-    friend bool operator>=(const IPPrefix& a, const IPPrefix& b) { return (b < a) || (a == b); }
-
-  private:
-    internal_::compact_ipdata mData{};
-};
-
-// An Internet socket address.
-//
-// Cannot represent other types of socket addresses (e.g. UNIX socket address, et cetera).
-class IPSockAddr {
-  public:
-    // TODO: static forString
-
-    static IPSockAddr toIPSockAddr(const std::string& repr, in_port_t port) {
-        return IPSockAddr(IPAddress::forString(repr), port);
-    }
-    static IPSockAddr toIPSockAddr(const sockaddr& sa) {
-        switch (sa.sa_family) {
-            case AF_INET:
-                return IPSockAddr(*reinterpret_cast<const sockaddr_in*>(&sa));
-            case AF_INET6:
-                return IPSockAddr(*reinterpret_cast<const sockaddr_in6*>(&sa));
-            default:
-                return IPSockAddr();
-        }
-    }
-    static IPSockAddr toIPSockAddr(const sockaddr_storage& ss) {
-        return toIPSockAddr(*reinterpret_cast<const sockaddr*>(&ss));
-    }
-
-    IPSockAddr() = default;
-    IPSockAddr(const IPSockAddr&) = default;
-    IPSockAddr(IPSockAddr&&) = default;
-
-    explicit IPSockAddr(const IPAddress& ip) : mData(ip.mData) {}
-    IPSockAddr(const IPAddress& ip, in_port_t port) : mData(ip.mData) { mData.port = port; }
-    explicit IPSockAddr(const sockaddr_in& ipv4sa)
-        : IPSockAddr(IPAddress(ipv4sa.sin_addr), ntohs(ipv4sa.sin_port)) {}
-    explicit IPSockAddr(const sockaddr_in6& ipv6sa)
-        : IPSockAddr(IPAddress(ipv6sa.sin6_addr, ipv6sa.sin6_scope_id), ntohs(ipv6sa.sin6_port)) {}
-
-    IPSockAddr& operator=(const IPSockAddr&) = default;
-    IPSockAddr& operator=(IPSockAddr&&) = default;
-
-    constexpr sa_family_t family() const noexcept { return mData.family; }
-    IPAddress ip() const noexcept { return IPAddress(mData); }
-    constexpr in_port_t port() const noexcept { return mData.port; }
-
-    // Implicit conversion to sockaddr_storage.
-    operator sockaddr_storage() const noexcept {
-        sockaddr_storage ss;
-        ss.ss_family = mData.family;
-        switch (mData.family) {
-            case AF_INET:
-                reinterpret_cast<sockaddr_in*>(&ss)->sin_addr = mData.ip.v4;
-                reinterpret_cast<sockaddr_in*>(&ss)->sin_port = htons(mData.port);
-                break;
-            case AF_INET6:
-                reinterpret_cast<sockaddr_in6*>(&ss)->sin6_addr = mData.ip.v6;
-                reinterpret_cast<sockaddr_in6*>(&ss)->sin6_port = htons(mData.port);
-                reinterpret_cast<sockaddr_in6*>(&ss)->sin6_scope_id = mData.scope_id;
-                break;
-        }
-        return ss;
-    }
-
-    std::string toString() const noexcept;
-
-    friend std::ostream& operator<<(std::ostream& os, const IPSockAddr& prefix) {
-        os << prefix.toString();
-        return os;
-    }
-    friend bool operator==(const IPSockAddr& a, const IPSockAddr& b) {
-        return (a.mData == b.mData);
-    }
-    friend bool operator!=(const IPSockAddr& a, const IPSockAddr& b) {
-        return (a.mData != b.mData);
-    }
-    friend bool operator<(const IPSockAddr& a, const IPSockAddr& b) { return (a.mData < b.mData); }
-    friend bool operator>(const IPSockAddr& a, const IPSockAddr& b) { return (b.mData < a.mData); }
-    friend bool operator<=(const IPSockAddr& a, const IPSockAddr& b) { return (a < b) || (a == b); }
-    friend bool operator>=(const IPSockAddr& a, const IPSockAddr& b) { return (b < a) || (a == b); }
-
-  private:
-    internal_::compact_ipdata mData{};
-};
-
-}  // namespace netdutils
-}  // namespace android
diff --git a/libnetdutils/include/netdutils/Log.h b/libnetdutils/include/netdutils/Log.h
deleted file mode 100644
index 77ae649..0000000
--- a/libnetdutils/include/netdutils/Log.h
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NETUTILS_LOG_H
-#define NETUTILS_LOG_H
-
-#include <chrono>
-#include <deque>
-#include <shared_mutex>
-#include <string>
-#include <type_traits>
-#include <vector>
-
-#include <android-base/stringprintf.h>
-#include <android-base/thread_annotations.h>
-
-#include <netdutils/Status.h>
-
-namespace android {
-namespace netdutils {
-
-class LogEntry {
-  public:
-    LogEntry() = default;
-    LogEntry(const LogEntry&) = default;
-    LogEntry(LogEntry&&) = default;
-    ~LogEntry() = default;
-    LogEntry& operator=(const LogEntry&) = default;
-    LogEntry& operator=(LogEntry&&) = default;
-
-    std::string toString() const;
-
-    ///
-    // Helper methods that make it easy to build up a LogEntry message.
-    // If performance becomes a factor the implementations could be inlined.
-    ///
-    LogEntry& message(const std::string& message);
-
-    // For calling with __FUNCTION__.
-    LogEntry& function(const std::string& function_name);
-    // For calling with __PRETTY_FUNCTION__.
-    LogEntry& prettyFunction(const std::string& pretty_function);
-
-    // Convenience methods for each of the common types of function arguments.
-    LogEntry& arg(const std::string& val);
-    // Intended for binary buffers, formats as hex
-    LogEntry& arg(const std::vector<uint8_t>& val);
-    LogEntry& arg(const std::vector<int32_t>& val);
-    LogEntry& arg(const std::vector<std::string>& val);
-    template <typename IntT, typename = std::enable_if_t<std::is_arithmetic_v<IntT>>>
-    LogEntry& arg(IntT val) {
-        mArgs.push_back(std::to_string(val));
-        return *this;
-    }
-    // Not using a plain overload here to avoid the implicit conversion from
-    // any pointer to bool, which causes string literals to print as 'true'.
-    template <>
-    LogEntry& arg<>(bool val);
-
-    template <typename... Args>
-    LogEntry& args(const Args&... a) {
-        // Cleverness ahead: we throw away the initializer_list filled with
-        // zeroes, all we care about is calling arg() for each argument.
-        (void) std::initializer_list<int>{(arg(a), 0)...};
-        return *this;
-    }
-
-    // Some things can return more than one value, or have multiple output
-    // parameters, so each of these adds to the mReturns vector.
-    LogEntry& returns(const std::string& rval);
-    LogEntry& returns(const Status& status);
-    LogEntry& returns(bool rval);
-    template <class T>
-    LogEntry& returns(T val) {
-        mReturns.push_back(std::to_string(val));
-        return *this;
-    }
-
-    LogEntry& withUid(uid_t uid);
-
-    // Append the duration computed since the creation of this instance.
-    LogEntry& withAutomaticDuration();
-    // Append the string-ified duration computed by some other means.
-    LogEntry& withDuration(const std::string& duration);
-
-  private:
-    std::chrono::steady_clock::time_point mStart = std::chrono::steady_clock::now();
-    std::string mMsg{};
-    std::string mFunc{};
-    std::vector<std::string> mArgs{};
-    std::vector<std::string> mReturns{};
-    std::string mUid{};
-    std::string mDuration{};
-};
-
-class Log {
-  public:
-    Log() = delete;
-    Log(const std::string& tag) : Log(tag, MAX_ENTRIES) {}
-    Log(const std::string& tag, size_t maxEntries) : mTag(tag), mMaxEntries(maxEntries) {}
-    Log(const Log&) = delete;
-    Log(Log&&) = delete;
-    ~Log();
-    Log& operator=(const Log&) = delete;
-    Log& operator=(Log&&) = delete;
-
-    LogEntry newEntry() const { return LogEntry(); }
-
-    // Record a log entry in internal storage only.
-    void log(const std::string& entry) { record(Level::LOG, entry); }
-    template <size_t n>
-    void log(const char entry[n]) { log(std::string(entry)); }
-    void log(const LogEntry& entry) { log(entry.toString()); }
-    void log(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) {
-        using ::android::base::StringAppendV;
-        std::string result;
-        va_list ap;
-        va_start(ap, fmt);
-        StringAppendV(&result, fmt, ap);
-        va_end(ap);
-        log(result);
-    }
-
-    // Record a log entry in internal storage and to ALOGI as well.
-    void info(const std::string& entry) { record(Level::INFO, entry); }
-    template <size_t n>
-    void info(const char entry[n]) { info(std::string(entry)); }
-    void info(const LogEntry& entry) { info(entry.toString()); }
-    void info(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) {
-        using ::android::base::StringAppendV;
-        std::string result;
-        va_list ap;
-        va_start(ap, fmt);
-        StringAppendV(&result, fmt, ap);
-        va_end(ap);
-        info(result);
-    }
-
-    // Record a log entry in internal storage and to ALOGW as well.
-    void warn(const std::string& entry) { record(Level::WARN, entry); }
-    template <size_t n>
-    void warn(const char entry[n]) { warn(std::string(entry)); }
-    void warn(const LogEntry& entry) { warn(entry.toString()); }
-    void warn(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) {
-        using ::android::base::StringAppendV;
-        std::string result;
-        va_list ap;
-        va_start(ap, fmt);
-        StringAppendV(&result, fmt, ap);
-        va_end(ap);
-        warn(result);
-    }
-
-    // Record a log entry in internal storage and to ALOGE as well.
-    void error(const std::string& entry) { record(Level::ERROR, entry); }
-    template <size_t n>
-    void error(const char entry[n]) { error(std::string(entry)); }
-    void error(const LogEntry& entry) { error(entry.toString()); }
-    void error(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) {
-        using ::android::base::StringAppendV;
-        std::string result;
-        va_list ap;
-        va_start(ap, fmt);
-        StringAppendV(&result, fmt, ap);
-        va_end(ap);
-        error(result);
-    }
-
-    // Iterates over every entry in the log in chronological order. Operates
-    // on a copy of the log entries, and so perEntryFn may itself call one of
-    // the logging functions if needed.
-    void forEachEntry(const std::function<void(const std::string&)>& perEntryFn) const;
-
-  private:
-    static constexpr const size_t MAX_ENTRIES = 750U;
-    const std::string mTag;
-    const size_t mMaxEntries;
-
-    // The LOG level adds an entry to mEntries but does not output the message
-    // to the system log. All other levels append to mEntries and output to the
-    // the system log.
-    enum class Level {
-        LOG,
-        INFO,
-        WARN,
-        ERROR,
-    };
-
-    void record(Level lvl, const std::string& entry);
-
-    mutable std::shared_mutex mLock;
-    std::deque<const std::string> mEntries;  // GUARDED_BY(mLock), when supported
-};
-
-}  // namespace netdutils
-}  // namespace android
-
-#endif /* NETUTILS_LOG_H */
diff --git a/libnetdutils/include/netdutils/Math.h b/libnetdutils/include/netdutils/Math.h
deleted file mode 100644
index c41fbf5..0000000
--- a/libnetdutils/include/netdutils/Math.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NETUTILS_MATH_H
-#define NETUTILS_MATH_H
-
-#include <algorithm>
-#include <cstdint>
-
-namespace android {
-namespace netdutils {
-
-template <class T>
-inline constexpr const T mask(const int shift) {
-    return (1 << shift) - 1;
-}
-
-// Align x up to the nearest integer multiple of 2^shift
-template <class T>
-inline constexpr const T align(const T& x, const int shift) {
-    return (x + mask<T>(shift)) & ~mask<T>(shift);
-}
-
-}  // namespace netdutils
-}  // namespace android
-
-#endif /* NETUTILS_MATH_H */
diff --git a/libnetdutils/include/netdutils/MemBlock.h b/libnetdutils/include/netdutils/MemBlock.h
deleted file mode 100644
index fd4d612..0000000
--- a/libnetdutils/include/netdutils/MemBlock.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NETUTILS_MEMBLOCK_H
-#define NETUTILS_MEMBLOCK_H
-
-#include <memory>
-#include "netdutils/Slice.h"
-
-namespace android {
-namespace netdutils {
-
-// A class to encapsulate self-deleting byte arrays while preserving access
-// to the underlying length (without the length being part of the type, e.g.
-// std::array<>). By design, the only interface to the underlying bytes is
-// via Slice, to encourage safer memory access usage.
-//
-// No thread-safety guarantees whatsoever.
-class MemBlock {
-  public:
-    MemBlock() : MemBlock(0U) {}
-    explicit MemBlock(size_t len)
-            : mData((len > 0U) ? new uint8_t[len]{} : nullptr),
-              mLen(len) {}
-    // Allocate memory of size src.size() and copy src into this MemBlock.
-    explicit MemBlock(Slice src) : MemBlock(src.size()) {
-        copy(get(), src);
-    }
-
-    // No copy construction or assignment.
-    MemBlock(const MemBlock&) = delete;
-    MemBlock& operator=(const MemBlock&) = delete;
-
-    // Move construction and assignment are okay.
-    MemBlock(MemBlock&&) = default;
-    MemBlock& operator=(MemBlock&&) = default;
-
-    // Even though this method is const, the memory wrapped by the
-    // returned Slice is mutable.
-    Slice get() const noexcept { return Slice(mData.get(), mLen); }
-
-    // Implicit cast to Slice.
-    // NOLINTNEXTLINE(google-explicit-constructor)
-    operator const Slice() const noexcept { return get(); }
-
-  private:
-    std::unique_ptr<uint8_t[]> mData;
-    size_t mLen;
-};
-
-}  // namespace netdutils
-}  // namespace android
-
-#endif /* NETUTILS_MEMBLOCK_H */
diff --git a/libnetdutils/include/netdutils/Misc.h b/libnetdutils/include/netdutils/Misc.h
deleted file mode 100644
index d344f81..0000000
--- a/libnetdutils/include/netdutils/Misc.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NETUTILS_MISC_H
-#define NETUTILS_MISC_H
-
-#include <map>
-
-namespace android {
-namespace netdutils {
-
-// Lookup key in map, returing a default value if key is not found
-template <typename U, typename V>
-inline const V& findWithDefault(const std::map<U, V>& map, const U& key, const V& dflt) {
-    auto it = map.find(key);
-    return (it == map.end()) ? dflt : it->second;
-}
-
-// Movable, copiable, scoped lambda (or std::function) runner. Useful
-// for running arbitrary cleanup or logging code when exiting a scope.
-//
-// Compare to defer in golang.
-template <typename FnT>
-class Cleanup {
-  public:
-    Cleanup() = delete;
-    explicit Cleanup(FnT fn) : mFn(fn) {}
-    ~Cleanup() { if (!mReleased) mFn(); }
-
-    void release() { mReleased = true; }
-
-  private:
-    bool mReleased{false};
-    FnT mFn;
-};
-
-// Helper to make a new Cleanup. Avoids complex or impossible syntax
-// when wrapping lambdas.
-//
-// Usage:
-// auto cleanup = makeCleanup([](){ your_code_here; });
-template <typename FnT>
-Cleanup<FnT> makeCleanup(FnT fn) {
-    return Cleanup<FnT>(fn);
-}
-
-}  // namespace netdutils
-}  // namespace android
-
-#endif /* NETUTILS_MISC_H */
diff --git a/libnetdutils/include/netdutils/MockSyscalls.h b/libnetdutils/include/netdutils/MockSyscalls.h
deleted file mode 100644
index f57b55c..0000000
--- a/libnetdutils/include/netdutils/MockSyscalls.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NETUTILS_MOCK_SYSCALLS_H
-#define NETUTILS_MOCK_SYSCALLS_H
-
-#include <atomic>
-#include <cassert>
-#include <memory>
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include "netdutils/Syscalls.h"
-
-namespace android {
-namespace netdutils {
-
-class MockSyscalls : public Syscalls {
-  public:
-    virtual ~MockSyscalls() = default;
-    // Use Return(ByMove(...)) to deal with movable return types.
-    MOCK_CONST_METHOD3(open,
-                       StatusOr<UniqueFd>(const std::string& pathname, int flags, mode_t mode));
-    MOCK_CONST_METHOD3(socket, StatusOr<UniqueFd>(int domain, int type, int protocol));
-    MOCK_CONST_METHOD3(getsockname, Status(Fd sock, sockaddr* addr, socklen_t* addrlen));
-    MOCK_CONST_METHOD5(getsockopt, Status(Fd sock, int level, int optname, void* optval,
-                                          socklen_t *optlen));
-    MOCK_CONST_METHOD5(setsockopt, Status(Fd sock, int level, int optname, const void* optval,
-                                          socklen_t optlen));
-
-    MOCK_CONST_METHOD3(bind, Status(Fd sock, const sockaddr* addr, socklen_t addrlen));
-    MOCK_CONST_METHOD3(connect, Status(Fd sock, const sockaddr* addr, socklen_t addrlen));
-    MOCK_CONST_METHOD3(ioctl, StatusOr<ifreq>(Fd sock, unsigned long request, ifreq* ifr));
-
-    // Use Return(ByMove(...)) to deal with movable return types.
-    MOCK_CONST_METHOD2(eventfd, StatusOr<UniqueFd>(unsigned int initval, int flags));
-    MOCK_CONST_METHOD3(ppoll, StatusOr<int>(pollfd* fds, nfds_t nfds, double timeout));
-
-    MOCK_CONST_METHOD2(writev, StatusOr<size_t>(Fd fd, const std::vector<iovec>& iov));
-    MOCK_CONST_METHOD2(write, StatusOr<size_t>(Fd fd, const Slice buf));
-    MOCK_CONST_METHOD2(read, StatusOr<Slice>(Fd fd, const Slice buf));
-    MOCK_CONST_METHOD5(sendto, StatusOr<size_t>(Fd sock, const Slice buf, int flags,
-                                                const sockaddr* dst, socklen_t dstlen));
-    MOCK_CONST_METHOD5(recvfrom, StatusOr<Slice>(Fd sock, const Slice dst, int flags, sockaddr* src,
-                                                 socklen_t* srclen));
-    MOCK_CONST_METHOD2(shutdown, Status(Fd fd, int how));
-    MOCK_CONST_METHOD1(close, Status(Fd fd));
-
-    MOCK_CONST_METHOD2(fopen,
-                       StatusOr<UniqueFile>(const std::string& path, const std::string& mode));
-    MOCK_CONST_METHOD3(vfprintf, StatusOr<int>(FILE* file, const char* format, va_list ap));
-    MOCK_CONST_METHOD3(vfscanf, StatusOr<int>(FILE* file, const char* format, va_list ap));
-    MOCK_CONST_METHOD1(fclose, Status(FILE* file));
-    MOCK_CONST_METHOD0(fork, StatusOr<pid_t>());
-};
-
-// For the lifetime of this mock, replace the contents of sSyscalls
-// with a pointer to this mock. Behavior is undefined if multiple
-// ScopedMockSyscalls instances exist concurrently.
-class ScopedMockSyscalls : public MockSyscalls {
-  public:
-    ScopedMockSyscalls() : mOld(sSyscalls.swap(*this)) { assert((mRefcount++) == 1); }
-    virtual ~ScopedMockSyscalls() {
-        sSyscalls.swap(mOld);
-        assert((mRefcount--) == 0);
-    }
-
-  private:
-    std::atomic<int> mRefcount{0};
-    Syscalls& mOld;
-};
-
-}  // namespace netdutils
-}  // namespace android
-
-#endif /* NETUTILS_MOCK_SYSCALLS_H */
diff --git a/libnetdutils/include/netdutils/Netfilter.h b/libnetdutils/include/netdutils/Netfilter.h
deleted file mode 100644
index 22736f1..0000000
--- a/libnetdutils/include/netdutils/Netfilter.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NETUTILS_NETFILTER_H
-#define NETUTILS_NETFILTER_H
-
-#include <ostream>
-
-#include <linux/netfilter.h>
-#include <linux/netfilter/nfnetlink.h>
-#include <linux/netlink.h>
-
-std::ostream& operator<<(std::ostream& os, const nfgenmsg& msg);
-
-#endif /* NETUTILS_NETFILTER_H */
diff --git a/libnetdutils/include/netdutils/Netlink.h b/libnetdutils/include/netdutils/Netlink.h
deleted file mode 100644
index ee5183a..0000000
--- a/libnetdutils/include/netdutils/Netlink.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NETUTILS_NETLINK_H
-#define NETUTILS_NETLINK_H
-
-#include <functional>
-#include <ostream>
-#include <linux/netlink.h>
-
-#include "netdutils/Slice.h"
-
-namespace android {
-namespace netdutils {
-
-// Invoke onMsg once for each netlink message in buf. onMsg will be
-// invoked with an aligned and deserialized header along with a Slice
-// containing the message payload.
-//
-// Assume that the first message begins at offset zero within buf.
-void forEachNetlinkMessage(const Slice buf,
-                           const std::function<void(const nlmsghdr&, const Slice)>& onMsg);
-
-// Invoke onAttr once for each netlink attribute in buf. onAttr will be
-// invoked with an aligned and deserialized header along with a Slice
-// containing the attribute payload.
-//
-// Assume that the first attribute begins at offset zero within buf.
-void forEachNetlinkAttribute(const Slice buf,
-                             const std::function<void(const nlattr&, const Slice)>& onAttr);
-
-}  // namespace netdutils
-}  // namespace android
-
-bool operator==(const sockaddr_nl& lhs, const sockaddr_nl& rhs);
-bool operator!=(const sockaddr_nl& lhs, const sockaddr_nl& rhs);
-
-std::ostream& operator<<(std::ostream& os, const nlmsghdr& hdr);
-std::ostream& operator<<(std::ostream& os, const nlattr& attr);
-std::ostream& operator<<(std::ostream& os, const sockaddr_nl& addr);
-
-#endif /* NETUTILS_NETLINK_H */
diff --git a/libnetdutils/include/netdutils/NetworkConstants.h b/libnetdutils/include/netdutils/NetworkConstants.h
deleted file mode 100644
index dead9a1..0000000
--- a/libnetdutils/include/netdutils/NetworkConstants.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-namespace android {
-namespace netdutils {
-
-// See also NetworkConstants.java in frameworks/base.
-constexpr int IPV4_ADDR_LEN = 4;
-constexpr int IPV4_ADDR_BITS = 32;
-constexpr int IPV6_ADDR_LEN = 16;
-constexpr int IPV6_ADDR_BITS = 128;
-
-// Referred from SHA256_DIGEST_LENGTH in boringssl
-constexpr size_t SHA256_SIZE = 32;
-
-}  // namespace netdutils
-}  // namespace android
diff --git a/libnetdutils/include/netdutils/ResponseCode.h b/libnetdutils/include/netdutils/ResponseCode.h
deleted file mode 100644
index c170684..0000000
--- a/libnetdutils/include/netdutils/ResponseCode.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NETDUTILS_RESPONSECODE_H
-#define NETDUTILS_RESPONSECODE_H
-
-namespace android {
-namespace netdutils {
-
-class ResponseCode {
-    // Keep in sync with
-    // frameworks/base/services/java/com/android/server/NetworkManagementService.java
-  public:
-    // 100 series - Requestion action was initiated; expect another reply
-    // before proceeding with a new command.
-    // clang-format off
-    static constexpr int ActionInitiated                = 100;
-    static constexpr int InterfaceListResult            = 110;
-    static constexpr int TetherInterfaceListResult      = 111;
-    static constexpr int TetherDnsFwdTgtListResult      = 112;
-    static constexpr int TtyListResult                  = 113;
-    static constexpr int TetheringStatsListResult       = 114;
-    static constexpr int TetherDnsFwdNetIdResult        = 115;
-
-    // 200 series - Requested action has been successfully completed
-    static constexpr int CommandOkay                    = 200;
-    static constexpr int TetherStatusResult             = 210;
-    static constexpr int IpFwdStatusResult              = 211;
-    static constexpr int InterfaceGetCfgResult          = 213;
-    // Formerly: int SoftapStatusResult                 = 214;
-    static constexpr int UsbRNDISStatusResult           = 215;
-    static constexpr int InterfaceRxCounterResult       = 216;
-    static constexpr int InterfaceTxCounterResult       = 217;
-    static constexpr int InterfaceRxThrottleResult      = 218;
-    static constexpr int InterfaceTxThrottleResult      = 219;
-    static constexpr int QuotaCounterResult             = 220;
-    static constexpr int TetheringStatsResult           = 221;
-    // NOTE: keep synced with bionic/libc/dns/net/gethnamaddr.c
-    static constexpr int DnsProxyQueryResult            = 222;
-    static constexpr int ClatdStatusResult              = 223;
-
-    // 400 series - The command was accepted but the requested action
-    // did not take place.
-    static constexpr int OperationFailed                = 400;
-    static constexpr int DnsProxyOperationFailed        = 401;
-    static constexpr int ServiceStartFailed             = 402;
-    static constexpr int ServiceStopFailed              = 403;
-
-    // 500 series - The command was not accepted and the requested
-    // action did not take place.
-    static constexpr int CommandSyntaxError             = 500;
-    static constexpr int CommandParameterError          = 501;
-
-    // 600 series - Unsolicited broadcasts
-    static constexpr int InterfaceChange                = 600;
-    static constexpr int BandwidthControl               = 601;
-    static constexpr int ServiceDiscoveryFailed         = 602;
-    static constexpr int ServiceDiscoveryServiceAdded   = 603;
-    static constexpr int ServiceDiscoveryServiceRemoved = 604;
-    static constexpr int ServiceRegistrationFailed      = 605;
-    static constexpr int ServiceRegistrationSucceeded   = 606;
-    static constexpr int ServiceResolveFailed           = 607;
-    static constexpr int ServiceResolveSuccess          = 608;
-    static constexpr int ServiceSetHostnameFailed       = 609;
-    static constexpr int ServiceSetHostnameSuccess      = 610;
-    static constexpr int ServiceGetAddrInfoFailed       = 611;
-    static constexpr int ServiceGetAddrInfoSuccess      = 612;
-    static constexpr int InterfaceClassActivity         = 613;
-    static constexpr int InterfaceAddressChange         = 614;
-    static constexpr int InterfaceDnsInfo               = 615;
-    static constexpr int RouteChange                    = 616;
-    static constexpr int StrictCleartext                = 617;
-    // clang-format on
-};
-
-}  // namespace netdutils
-}  // namespace android
-
-#endif  // NETDUTILS_RESPONSECODE_H
diff --git a/libnetdutils/include/netdutils/Slice.h b/libnetdutils/include/netdutils/Slice.h
deleted file mode 100644
index 717fbd1..0000000
--- a/libnetdutils/include/netdutils/Slice.h
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NETUTILS_SLICE_H
-#define NETUTILS_SLICE_H
-
-#include <algorithm>
-#include <array>
-#include <cstring>
-#include <ostream>
-#include <tuple>
-#include <vector>
-
-namespace android {
-namespace netdutils {
-
-// Immutable wrapper for a linear region of unowned bytes.
-// Slice represents memory as a half-closed interval [base, limit).
-//
-// Note that without manually invoking the Slice() constructor, it is
-// impossible to increase the size of a slice. This guarantees that
-// applications that properly use the slice API will never access
-// memory outside of a slice.
-//
-// Note that const Slice still wraps mutable memory, however copy
-// assignment and move assignment to slice are disabled.
-class Slice {
-  public:
-    Slice() = default;
-
-    // Create a slice beginning at base and continuing to but not including limit
-    Slice(void* base, void* limit) : mBase(toUint8(base)), mLimit(toUint8(limit)) {}
-
-    // Create a slice beginning at base and continuing for size bytes
-    Slice(void* base, size_t size) : Slice(base, toUint8(base) + size) {}
-
-    // Return the address of the first byte in this slice
-    uint8_t* base() const { return mBase; }
-
-    // Return the address of the first byte following this slice
-    uint8_t* limit() const { return mLimit; }
-
-    // Return the size of this slice in bytes
-    size_t size() const { return limit() - base(); }
-
-    // Return true if size() == 0
-    bool empty() const { return base() == limit(); }
-
-  private:
-    static uint8_t* toUint8(void* ptr) { return reinterpret_cast<uint8_t*>(ptr); }
-
-    uint8_t* mBase = nullptr;
-    uint8_t* mLimit = nullptr;
-};
-
-// Return slice representation of ref which must be a POD type
-template <typename T>
-inline const Slice makeSlice(const T& ref) {
-    static_assert(std::is_pod<T>::value, "value must be a POD type");
-    static_assert(!std::is_pointer<T>::value, "value must not be a pointer type");
-    return {const_cast<T*>(&ref), sizeof(ref)};
-}
-
-// Return slice representation of string data()
-inline const Slice makeSlice(const std::string& s) {
-    using ValueT = std::string::value_type;
-    return {const_cast<ValueT*>(s.data()), s.size() * sizeof(ValueT)};
-}
-
-// Return slice representation of vector data()
-template <typename T>
-inline const Slice makeSlice(const std::vector<T>& v) {
-    return {const_cast<T*>(v.data()), v.size() * sizeof(T)};
-}
-
-// Return slice representation of array data()
-template <typename U, size_t V>
-inline const Slice makeSlice(const std::array<U, V>& a) {
-    return {const_cast<U*>(a.data()), a.size() * sizeof(U)};
-}
-
-// Return prefix and suffix of Slice s ending and starting at position cut
-inline std::pair<const Slice, const Slice> split(const Slice s, size_t cut) {
-    const size_t tmp = std::min(cut, s.size());
-    return {{s.base(), s.base() + tmp}, {s.base() + tmp, s.limit()}};
-}
-
-// Return prefix of Slice s ending at position cut
-inline const Slice take(const Slice s, size_t cut) {
-    return std::get<0>(split(s, cut));
-}
-
-// Return suffix of Slice s starting at position cut
-inline const Slice drop(const Slice s, size_t cut) {
-    return std::get<1>(split(s, cut));
-}
-
-// Copy from src into dst. Bytes copied is the lesser of dst.size() and src.size()
-inline size_t copy(const Slice dst, const Slice src) {
-    const auto min = std::min(dst.size(), src.size());
-    memcpy(dst.base(), src.base(), min);
-    return min;
-}
-
-// Base case for variadic extract below
-template <typename Head>
-inline size_t extract(const Slice src, Head& head) {
-    return copy(makeSlice(head), src);
-}
-
-// Copy from src into one or more pointers to POD data.  If src.size()
-// is less than the sum of all data pointers a suffix of data will be
-// left unmodified. Return the number of bytes copied.
-template <typename Head, typename... Tail>
-inline size_t extract(const Slice src, Head& head, Tail&... tail) {
-    const auto extracted = extract(src, head);
-    return extracted + extract(drop(src, extracted), tail...);
-}
-
-// Return a string containing a copy of the contents of s
-std::string toString(const Slice s);
-
-// Return a string containing a hexadecimal representation of the contents of s.
-// This function inserts a newline into its output every wrap bytes.
-std::string toHex(const Slice s, int wrap = INT_MAX);
-
-inline bool operator==(const Slice& lhs, const Slice& rhs) {
-    return (lhs.base() == rhs.base()) && (lhs.limit() == rhs.limit());
-}
-
-inline bool operator!=(const Slice& lhs, const Slice& rhs) {
-    return !(lhs == rhs);
-}
-
-std::ostream& operator<<(std::ostream& os, const Slice& slice);
-
-// Return suffix of Slice s starting at the first match of byte c. If no matched
-// byte, return an empty Slice.
-inline const Slice findFirstMatching(const Slice s, uint8_t c) {
-    uint8_t* match = (uint8_t*)memchr(s.base(), c, s.size());
-    if (!match) return Slice();
-    return drop(s, match - s.base());
-}
-
-}  // namespace netdutils
-}  // namespace android
-
-#endif /* NETUTILS_SLICE_H */
diff --git a/libnetdutils/include/netdutils/Socket.h b/libnetdutils/include/netdutils/Socket.h
deleted file mode 100644
index e5aaab9..0000000
--- a/libnetdutils/include/netdutils/Socket.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NETDUTILS_SOCKET_H
-#define NETDUTILS_SOCKET_H
-
-#include <netinet/in.h>
-#include <sys/socket.h>
-#include <string>
-
-#include "netdutils/StatusOr.h"
-
-namespace android {
-namespace netdutils {
-
-inline sockaddr* asSockaddrPtr(void* addr) {
-    return reinterpret_cast<sockaddr*>(addr);
-}
-
-inline const sockaddr* asSockaddrPtr(const void* addr) {
-    return reinterpret_cast<const sockaddr*>(addr);
-}
-
-// Return a string representation of addr or Status if there was a
-// failure during conversion.
-StatusOr<std::string> toString(const in6_addr& addr);
-
-}  // namespace netdutils
-}  // namespace android
-
-#endif /* NETDUTILS_SOCKET_H */
diff --git a/libnetdutils/include/netdutils/SocketOption.h b/libnetdutils/include/netdutils/SocketOption.h
deleted file mode 100644
index 3b0aab7..0000000
--- a/libnetdutils/include/netdutils/SocketOption.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NETDUTILS_SOCKETOPTION_H
-#define NETDUTILS_SOCKETOPTION_H
-
-#include <netinet/in.h>
-#include <sys/socket.h>
-#include <string>
-
-#include "netdutils/Fd.h"
-#include "netdutils/Status.h"
-
-namespace android {
-namespace netdutils {
-
-// Turn on simple "boolean" socket options.
-//
-// This is simple wrapper for options that are enabled via code of the form:
-//
-//     int on = 1;
-//     setsockopt(..., &on, sizeof(on));
-Status enableSockopt(Fd sock, int level, int optname);
-
-// Turn on TCP keepalives, and set keepalive parameters for this socket.
-//
-// A parameter value of zero does not set that parameter.
-//
-// Typical system defaults are:
-//
-//     idleTime (in seconds)
-//     $ cat /proc/sys/net/ipv4/tcp_keepalive_time
-//     7200
-//
-//     numProbes
-//     $ cat /proc/sys/net/ipv4/tcp_keepalive_probes
-//     9
-//
-//     probeInterval (in seconds)
-//     $ cat /proc/sys/net/ipv4/tcp_keepalive_intvl
-//     75
-Status enableTcpKeepAlives(Fd sock, unsigned idleTime, unsigned numProbes, unsigned probeInterval);
-
-}  // namespace netdutils
-}  // namespace android
-
-#endif /* NETDUTILS_SOCKETOPTION_H */
diff --git a/libnetdutils/include/netdutils/Status.h b/libnetdutils/include/netdutils/Status.h
deleted file mode 100644
index bc347d5..0000000
--- a/libnetdutils/include/netdutils/Status.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NETUTILS_STATUS_H
-#define NETUTILS_STATUS_H
-
-#include <cassert>
-#include <limits>
-#include <ostream>
-
-#include <android-base/result.h>
-
-namespace android {
-namespace netdutils {
-
-// Simple status implementation suitable for use on the stack in low
-// or moderate performance code. This can definitely be improved but
-// for now short string optimization is expected to keep the common
-// success case fast.
-//
-// Status is implicitly movable via the default noexcept move constructor
-// and noexcept move-assignment operator.
-class [[nodiscard]] Status {
-  public:
-    Status() = default;
-    explicit Status(int code) : mCode(code) {}
-
-    // Constructs an error Status, |code| must be non-zero.
-    Status(int code, std::string msg) : mCode(code), mMsg(std::move(msg)) { assert(!ok()); }
-
-    Status(android::base::Result<void> result)
-        : mCode(result.ok() ? 0 : result.error().code()),
-          mMsg(result.ok() ? "" : result.error().message()) {}
-
-    int code() const { return mCode; }
-
-    bool ok() const { return code() == 0; }
-
-    const std::string& msg() const { return mMsg; }
-
-    // Explicitly ignores the Status without triggering [[nodiscard]] errors.
-    void ignoreError() const {}
-
-    bool operator==(const Status& other) const { return code() == other.code(); }
-    bool operator!=(const Status& other) const { return !(*this == other); }
-
-  private:
-    int mCode = 0;
-    std::string mMsg;
-};
-
-namespace status {
-
-const Status ok{0};
-// EOF is not part of errno space, we'll place it far above the
-// highest existing value.
-const Status eof{0x10001, "end of file"};
-const Status undefined{std::numeric_limits<int>::max(), "undefined"};
-
-}  // namespace status
-
-// Return true if status is "OK". This is sometimes preferable to
-// status.ok() when we want to check the state of Status-like objects
-// that implicitly cast to Status.
-inline bool isOk(const Status& status) {
-    return status.ok();
-}
-
-// For use only in tests. Used for both Status and Status-like objects. See also isOk().
-#define EXPECT_OK(status) EXPECT_TRUE(isOk(status))
-#define ASSERT_OK(status) ASSERT_TRUE(isOk(status))
-
-// Documents that status is expected to be ok. This function may log
-// (or assert when running in debug mode) if status has an unexpected value.
-inline void expectOk(const Status& /*status*/) {
-    // TODO: put something here, for now this function serves solely as documentation.
-}
-
-// Convert POSIX errno to a Status object.
-// If Status is extended to have more features, this mapping may
-// become more complex.
-Status statusFromErrno(int err, const std::string& msg);
-
-// Helper that checks Status-like object (notably StatusOr) against a
-// value in the errno space.
-bool equalToErrno(const Status& status, int err);
-
-// Helper that converts Status-like object (notably StatusOr) to a
-// message.
-std::string toString(const Status& status);
-
-std::ostream& operator<<(std::ostream& os, const Status& s);
-
-// Evaluate 'stmt' to a Status object and if it results in an error, return that
-// error.  Use 'tmp' as a variable name to avoid shadowing any variables named
-// tmp.
-#define RETURN_IF_NOT_OK_IMPL(tmp, stmt)           \
-    do {                                           \
-        ::android::netdutils::Status tmp = (stmt); \
-        if (!isOk(tmp)) {                          \
-            return tmp;                            \
-        }                                          \
-    } while (false)
-
-// Create a unique variable name to avoid shadowing local variables.
-#define RETURN_IF_NOT_OK_CONCAT(line, stmt) RETURN_IF_NOT_OK_IMPL(__CONCAT(_status_, line), stmt)
-
-// Macro to allow exception-like handling of error return values.
-//
-// If the evaluation of stmt results in an error, return that error
-// from current function.
-//
-// Example usage:
-// Status bar() { ... }
-//
-// RETURN_IF_NOT_OK(status);
-// RETURN_IF_NOT_OK(bar());
-#define RETURN_IF_NOT_OK(stmt) RETURN_IF_NOT_OK_CONCAT(__LINE__, stmt)
-
-}  // namespace netdutils
-}  // namespace android
-
-#endif /* NETUTILS_STATUS_H */
diff --git a/libnetdutils/include/netdutils/StatusOr.h b/libnetdutils/include/netdutils/StatusOr.h
deleted file mode 100644
index c7aa4e4..0000000
--- a/libnetdutils/include/netdutils/StatusOr.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NETUTILS_STATUSOR_H
-#define NETUTILS_STATUSOR_H
-
-#include <cassert>
-#include "netdutils/Status.h"
-
-namespace android {
-namespace netdutils {
-
-// Wrapper around a combination of Status and application value type.
-// T may be any copyable or movable type.
-template <typename T>
-class [[nodiscard]] StatusOr {
-  public:
-    // Constructs a new StatusOr with status::undefined status.
-    // This is marked 'explicit' to try to catch cases like 'return {};',
-    // where people think StatusOr<std::vector<int>> will be initialized
-    // with an empty vector, instead of a status::undefined.
-    explicit StatusOr() = default;
-
-    // Implicit copy constructor and construction from T.
-    // NOLINTNEXTLINE(google-explicit-constructor)
-    StatusOr(Status status) : mStatus(std::move(status)) { assert(!isOk(mStatus)); }
-
-    // Implicit construction from T. It is convenient and sensible to be able
-    // to do 'return T()' when the return type is StatusOr<T>.
-    // NOLINTNEXTLINE(google-explicit-constructor)
-    StatusOr(const T& value) : mStatus(status::ok), mValue(value) {}
-    // NOLINTNEXTLINE(google-explicit-constructor)
-    StatusOr(T&& value) : mStatus(status::ok), mValue(std::move(value)) {}
-
-    // Move constructor ok (if T supports move)
-    StatusOr(StatusOr&&) noexcept = default;
-    // Move assignment ok (if T supports move)
-    StatusOr& operator=(StatusOr&&) noexcept = default;
-    // Copy constructor ok (if T supports copy)
-    StatusOr(const StatusOr&) = default;
-    // Copy assignment ok (if T supports copy)
-    StatusOr& operator=(const StatusOr&) = default;
-
-    // Returns a const reference to wrapped type.
-    // It is an error to call value() when !isOk(status())
-    const T& value() const & { return mValue; }
-    const T&& value() const && { return mValue; }
-
-    // Returns an rvalue reference to wrapped type
-    // It is an error to call value() when !isOk(status())
-    //
-    // If T is expensive to copy but supports efficient move, it can be moved
-    // out of a StatusOr as follows:
-    //   T value = std::move(statusor).value();
-    T& value() & { return mValue; }
-    T&& value() && { return mValue; }
-
-    // Returns the Status object assigned at construction time.
-    const Status status() const { return mStatus; }
-
-    // Explicitly ignores the Status without triggering [[nodiscard]] errors.
-    void ignoreError() const {}
-
-    // Implicit cast to Status.
-    // NOLINTNEXTLINE(google-explicit-constructor)
-    operator Status() const { return status(); }
-
-  private:
-    Status mStatus = status::undefined;
-    T mValue;
-};
-
-template <typename T>
-inline std::ostream& operator<<(std::ostream& os, const StatusOr<T>& s) {
-    return os << "StatusOr[status: " << s.status() << "]";
-}
-
-#define ASSIGN_OR_RETURN_IMPL(tmp, lhs, stmt) \
-    auto tmp = (stmt);                        \
-    RETURN_IF_NOT_OK(tmp);                    \
-    lhs = std::move(tmp.value());
-
-#define ASSIGN_OR_RETURN_CONCAT(line, lhs, stmt) \
-    ASSIGN_OR_RETURN_IMPL(__CONCAT(_status_or_, line), lhs, stmt)
-
-// Macro to allow exception-like handling of error return values.
-//
-// If the evaluation of stmt results in an error, return that error
-// from the current function. Otherwise, assign the result to lhs.
-//
-// This macro supports both move and copy assignment operators. lhs
-// may be either a new local variable or an existing non-const
-// variable accessible in the current scope.
-//
-// Example usage:
-// StatusOr<MyType> foo() { ... }
-//
-// ASSIGN_OR_RETURN(auto myVar, foo());
-// ASSIGN_OR_RETURN(myExistingVar, foo());
-// ASSIGN_OR_RETURN(myMemberVar, foo());
-#define ASSIGN_OR_RETURN(lhs, stmt) ASSIGN_OR_RETURN_CONCAT(__LINE__, lhs, stmt)
-
-}  // namespace netdutils
-}  // namespace android
-
-#endif /* NETUTILS_STATUSOR_H */
diff --git a/libnetdutils/include/netdutils/Stopwatch.h b/libnetdutils/include/netdutils/Stopwatch.h
deleted file mode 100644
index e7b4326..0000000
--- a/libnetdutils/include/netdutils/Stopwatch.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NETDUTILS_STOPWATCH_H
-#define NETDUTILS_STOPWATCH_H
-
-#include <chrono>
-
-namespace android {
-namespace netdutils {
-
-class Stopwatch {
-  private:
-    using clock = std::chrono::steady_clock;
-    using time_point = std::chrono::time_point<clock>;
-
-  public:
-    Stopwatch() : mStart(clock::now()) {}
-    virtual ~Stopwatch() = default;
-
-    int64_t timeTakenUs() const { return getElapsedUs(clock::now()); }
-    int64_t getTimeAndResetUs() {
-        const auto& now = clock::now();
-        int64_t elapsed = getElapsedUs(now);
-        mStart = now;
-        return elapsed;
-    }
-
-  private:
-    time_point mStart;
-
-    int64_t getElapsedUs(const time_point& now) const {
-        return (std::chrono::duration_cast<std::chrono::microseconds>(now - mStart)).count();
-    }
-};
-
-}  // namespace netdutils
-}  // namespace android
-
-#endif  // NETDUTILS_STOPWATCH_H
diff --git a/libnetdutils/include/netdutils/Syscalls.h b/libnetdutils/include/netdutils/Syscalls.h
deleted file mode 100644
index 36fcd85..0000000
--- a/libnetdutils/include/netdutils/Syscalls.h
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NETDUTILS_SYSCALLS_H
-#define NETDUTILS_SYSCALLS_H
-
-#include <memory>
-
-#include <net/if.h>
-#include <poll.h>
-#include <sys/eventfd.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/uio.h>
-#include <unistd.h>
-
-#include "netdutils/Fd.h"
-#include "netdutils/Slice.h"
-#include "netdutils/Socket.h"
-#include "netdutils/Status.h"
-#include "netdutils/StatusOr.h"
-#include "netdutils/UniqueFd.h"
-#include "netdutils/UniqueFile.h"
-
-namespace android {
-namespace netdutils {
-
-class Syscalls {
-  public:
-    virtual ~Syscalls() = default;
-
-    virtual StatusOr<UniqueFd> open(const std::string& pathname, int flags,
-                                    mode_t mode = 0) const = 0;
-
-    virtual StatusOr<UniqueFd> socket(int domain, int type, int protocol) const = 0;
-
-    virtual Status getsockname(Fd sock, sockaddr* addr, socklen_t* addrlen) const = 0;
-
-    virtual Status getsockopt(Fd sock, int level, int optname, void *optval,
-                              socklen_t *optlen) const = 0;
-
-    virtual Status setsockopt(Fd sock, int level, int optname, const void* optval,
-                              socklen_t optlen) const = 0;
-
-    virtual Status bind(Fd sock, const sockaddr* addr, socklen_t addrlen) const = 0;
-
-    virtual Status connect(Fd sock, const sockaddr* addr, socklen_t addrlen) const = 0;
-
-    virtual StatusOr<ifreq> ioctl(Fd sock, unsigned long request, ifreq* ifr) const = 0;
-
-    virtual StatusOr<UniqueFd> eventfd(unsigned int initval, int flags) const = 0;
-
-    virtual StatusOr<int> ppoll(pollfd* fds, nfds_t nfds, double timeout) const = 0;
-
-    virtual StatusOr<size_t> writev(Fd fd, const std::vector<iovec>& iov) const = 0;
-
-    virtual StatusOr<size_t> write(Fd fd, const Slice buf) const = 0;
-
-    virtual StatusOr<Slice> read(Fd fd, const Slice buf) const = 0;
-
-    virtual StatusOr<size_t> sendto(Fd sock, const Slice buf, int flags, const sockaddr* dst,
-                                    socklen_t dstlen) const = 0;
-
-    virtual StatusOr<Slice> recvfrom(Fd sock, const Slice dst, int flags, sockaddr* src,
-                                     socklen_t* srclen) const = 0;
-
-    virtual Status shutdown(Fd fd, int how) const = 0;
-
-    virtual Status close(Fd fd) const = 0;
-
-    virtual StatusOr<UniqueFile> fopen(const std::string& path, const std::string& mode) const = 0;
-
-    virtual StatusOr<int> vfprintf(FILE* file, const char* format, va_list ap) const = 0;
-
-    virtual StatusOr<int> vfscanf(FILE* file, const char* format, va_list ap) const = 0;
-
-    virtual Status fclose(FILE* file) const = 0;
-
-    virtual StatusOr<pid_t> fork() const = 0;
-
-    // va_args helpers
-    // va_start doesn't work when the preceding argument is a reference
-    // type so we're forced to use const char*.
-    StatusOr<int> fprintf(FILE* file, const char* format, ...) const {
-        va_list ap;
-        va_start(ap, format);
-        auto result = vfprintf(file, format, ap);
-        va_end(ap);
-        return result;
-    }
-
-    // va_start doesn't work when the preceding argument is a reference
-    // type so we're forced to use const char*.
-    StatusOr<int> fscanf(FILE* file, const char* format, ...) const {
-        va_list ap;
-        va_start(ap, format);
-        auto result = vfscanf(file, format, ap);
-        va_end(ap);
-        return result;
-    }
-
-    // Templated helpers that forward directly to methods declared above
-    template <typename SockaddrT>
-    StatusOr<SockaddrT> getsockname(Fd sock) const {
-        SockaddrT addr = {};
-        socklen_t addrlen = sizeof(addr);
-        RETURN_IF_NOT_OK(getsockname(sock, asSockaddrPtr(&addr), &addrlen));
-        return addr;
-    }
-
-    template <typename SockoptT>
-    Status getsockopt(Fd sock, int level, int optname, void* optval, socklen_t* optlen) const {
-        return getsockopt(sock, level, optname, optval, optlen);
-    }
-
-    template <typename SockoptT>
-    Status setsockopt(Fd sock, int level, int optname, const SockoptT& opt) const {
-        return setsockopt(sock, level, optname, &opt, sizeof(opt));
-    }
-
-    template <typename SockaddrT>
-    Status bind(Fd sock, const SockaddrT& addr) const {
-        return bind(sock, asSockaddrPtr(&addr), sizeof(addr));
-    }
-
-    template <typename SockaddrT>
-    Status connect(Fd sock, const SockaddrT& addr) const {
-        return connect(sock, asSockaddrPtr(&addr), sizeof(addr));
-    }
-
-    template <size_t size>
-    StatusOr<std::array<uint16_t, size>> ppoll(const std::array<Fd, size>& fds, uint16_t events,
-                                               double timeout) const {
-        std::array<pollfd, size> tmp;
-        for (size_t i = 0; i < size; ++i) {
-            tmp[i].fd = fds[i].get();
-            tmp[i].events = events;
-            tmp[i].revents = 0;
-        }
-        RETURN_IF_NOT_OK(ppoll(tmp.data(), tmp.size(), timeout).status());
-        std::array<uint16_t, size> out;
-        for (size_t i = 0; i < size; ++i) {
-            out[i] = tmp[i].revents;
-        }
-        return out;
-    }
-
-    template <typename SockaddrT>
-    StatusOr<size_t> sendto(Fd sock, const Slice buf, int flags, const SockaddrT& dst) const {
-        return sendto(sock, buf, flags, asSockaddrPtr(&dst), sizeof(dst));
-    }
-
-    // Ignore src sockaddr
-    StatusOr<Slice> recvfrom(Fd sock, const Slice dst, int flags) const {
-        return recvfrom(sock, dst, flags, nullptr, nullptr);
-    }
-
-    template <typename SockaddrT>
-    StatusOr<std::pair<Slice, SockaddrT>> recvfrom(Fd sock, const Slice dst, int flags) const {
-        SockaddrT addr = {};
-        socklen_t addrlen = sizeof(addr);
-        ASSIGN_OR_RETURN(auto used, recvfrom(sock, dst, flags, asSockaddrPtr(&addr), &addrlen));
-        return std::make_pair(used, addr);
-    }
-};
-
-// Specialized singleton that supports zero initialization and runtime
-// override of contained pointer.
-class SyscallsHolder {
-  public:
-    ~SyscallsHolder();
-
-    // Return a pointer to an unowned instance of Syscalls.
-    Syscalls& get();
-
-    // Testing only: set the value returned by getSyscalls. Return the old value.
-    // Callers are responsible for restoring the previous value returned
-    // by getSyscalls to avoid leaks.
-    Syscalls& swap(Syscalls& syscalls);
-
-  private:
-    std::atomic<Syscalls*> mSyscalls{nullptr};
-};
-
-// Syscalls instance used throughout netdutils
-extern SyscallsHolder sSyscalls;
-
-}  // namespace netdutils
-}  // namespace android
-
-#endif /* NETDUTILS_SYSCALLS_H */
diff --git a/libnetdutils/include/netdutils/ThreadUtil.h b/libnetdutils/include/netdutils/ThreadUtil.h
deleted file mode 100644
index 62e6f70..0000000
--- a/libnetdutils/include/netdutils/ThreadUtil.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NETDUTILS_THREADUTIL_H
-#define NETDUTILS_THREADUTIL_H
-
-#include <pthread.h>
-#include <memory>
-
-#include <android-base/logging.h>
-
-namespace android {
-namespace netdutils {
-
-struct scoped_pthread_attr {
-    scoped_pthread_attr() { pthread_attr_init(&attr); }
-    ~scoped_pthread_attr() { pthread_attr_destroy(&attr); }
-
-    int detach() { return -pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); }
-
-    pthread_attr_t attr;
-};
-
-inline void setThreadName(std::string name) {
-    // MAX_TASK_COMM_LEN=16 is not exported by bionic.
-    const size_t MAX_TASK_COMM_LEN = 16;
-
-    // Crop name to 16 bytes including the NUL byte, as required by pthread_setname_np()
-    if (name.size() >= MAX_TASK_COMM_LEN) name.resize(MAX_TASK_COMM_LEN - 1);
-
-    if (int ret = pthread_setname_np(pthread_self(), name.c_str()); ret != 0) {
-        LOG(WARNING) << "Unable to set thread name to " << name << ": " << strerror(ret);
-    }
-}
-
-template <typename T>
-inline void* runAndDelete(void* obj) {
-    std::unique_ptr<T> handler(reinterpret_cast<T*>(obj));
-    setThreadName(handler->threadName().c_str());
-    handler->run();
-    return nullptr;
-}
-
-template <typename T>
-inline int threadLaunch(T* obj) {
-    if (obj == nullptr) {
-        return -EINVAL;
-    }
-
-    scoped_pthread_attr scoped_attr;
-
-    int rval = scoped_attr.detach();
-    if (rval != 0) {
-        return rval;
-    }
-
-    pthread_t thread;
-    rval = pthread_create(&thread, &scoped_attr.attr, &runAndDelete<T>, obj);
-    if (rval != 0) {
-        LOG(WARNING) << __func__ << ": pthread_create failed: " << rval;
-        return -rval;
-    }
-
-    return rval;
-}
-
-}  // namespace netdutils
-}  // namespace android
-
-#endif  // NETDUTILS_THREADUTIL_H
diff --git a/libnetdutils/include/netdutils/UidConstants.h b/libnetdutils/include/netdutils/UidConstants.h
deleted file mode 100644
index 42c1090..0000000
--- a/libnetdutils/include/netdutils/UidConstants.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NETDUTILS_UID_CONSTANTS_H
-#define NETDUTILS_UID_CONSTANTS_H
-
-// These are used by both eBPF kernel programs and netd, we cannot put them in NetdConstant.h since
-// we have to minimize the number of headers included by the BPF kernel program.
-#define MIN_SYSTEM_UID 0
-#define MAX_SYSTEM_UID 9999
-
-#define PER_USER_RANGE 100000
-
-#endif  // NETDUTILS_UID_CONSTANTS_H
diff --git a/libnetdutils/include/netdutils/UniqueFd.h b/libnetdutils/include/netdutils/UniqueFd.h
deleted file mode 100644
index 61101f9..0000000
--- a/libnetdutils/include/netdutils/UniqueFd.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NETUTILS_UNIQUEFD_H
-#define NETUTILS_UNIQUEFD_H
-
-#include <unistd.h>
-#include <ostream>
-
-#include "netdutils/Fd.h"
-
-namespace android {
-namespace netdutils {
-
-// Stricter unique_fd implementation that:
-// *) Does not implement release()
-// *) Does not implicitly cast to int
-// *) Uses a strongly typed wrapper (Fd) for the underlying file descriptor
-//
-// Users of UniqueFd should endeavor to treat this as a completely
-// opaque object. The only code that should interpret the wrapped
-// value is in Syscalls.h
-class UniqueFd {
-  public:
-    UniqueFd() = default;
-
-    UniqueFd(Fd fd) : mFd(fd) {}
-
-    ~UniqueFd() { reset(); }
-
-    // Disallow copy
-    UniqueFd(const UniqueFd&) = delete;
-    UniqueFd& operator=(const UniqueFd&) = delete;
-
-    // Allow move
-    UniqueFd(UniqueFd&& other) { std::swap(mFd, other.mFd); }
-    UniqueFd& operator=(UniqueFd&& other) {
-        std::swap(mFd, other.mFd);
-        return *this;
-    }
-
-    // Cleanup any currently owned Fd, replacing it with the optional
-    // parameter fd
-    void reset(Fd fd = Fd());
-
-    // Implict cast to Fd
-    operator const Fd &() const { return mFd; }
-
-  private:
-    Fd mFd;
-};
-
-std::ostream& operator<<(std::ostream& os, const UniqueFd& fd);
-
-}  // namespace netdutils
-}  // namespace android
-
-#endif /* NETUTILS_UNIQUEFD_H */
diff --git a/libnetdutils/include/netdutils/UniqueFile.h b/libnetdutils/include/netdutils/UniqueFile.h
deleted file mode 100644
index 6dd6d67..0000000
--- a/libnetdutils/include/netdutils/UniqueFile.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NETDUTILS_UNIQUEFILE_H
-#define NETDUTILS_UNIQUEFILE_H
-
-#include <stdio.h>
-#include <memory>
-
-namespace android {
-namespace netdutils {
-
-struct UniqueFileDtor {
-    void operator()(FILE* file) const;
-};
-
-using UniqueFile = std::unique_ptr<FILE, UniqueFileDtor>;
-
-}  // namespace netdutils
-}  // namespace android
-
-#endif /* NETDUTILS_UNIQUEFILE_H */
diff --git a/server/Android.bp b/server/Android.bp
index 9c89041..d008919 100644
--- a/server/Android.bp
+++ b/server/Android.bp
@@ -7,148 +7,6 @@
     default_applicable_licenses: ["system_netd_license"],
 }
 
-java_library {
-    name: "netd_aidl_interface-lateststable-java",
-    sdk_version: "system_current",
-    min_sdk_version: "29",
-    static_libs: [
-        "netd_aidl_interface-V7-java",
-    ],
-    apex_available: [
-        "//apex_available:platform", // used from services.net
-        "com.android.bluetooth.updatable",
-        "com.android.tethering",
-        "com.android.wifi",
-    ],
-}
-
-cc_library_static {
-    name: "netd_event_listener_interface-lateststable-ndk_platform",
-    whole_static_libs: [
-        "netd_event_listener_interface-V1-ndk_platform",
-    ],
-    apex_available: [
-        "com.android.resolv",
-    ],
-    min_sdk_version: "29",
-}
-
-cc_library_static {
-    name: "netd_aidl_interface-lateststable-ndk_platform",
-    whole_static_libs: [
-        "netd_aidl_interface-V7-ndk_platform",
-    ],
-    apex_available: [
-        "com.android.resolv",
-    ],
-    min_sdk_version: "29",
-}
-
-cc_library_static {
-    name: "netd_aidl_interface-lateststable-cpp",
-    whole_static_libs: [
-        "netd_aidl_interface-V7-cpp",
-    ],
-}
-
-aidl_interface {
-    name: "netd_aidl_interface",
-    local_include_dir: "binder",
-    srcs: [
-        "binder/android/net/INetd.aidl",
-        // AIDL interface that callers can implement to receive networking events from netd.
-        "binder/android/net/INetdUnsolicitedEventListener.aidl",
-        "binder/android/net/InterfaceConfigurationParcel.aidl",
-        "binder/android/net/MarkMaskParcel.aidl",
-        "binder/android/net/NativeNetworkConfig.aidl",
-        "binder/android/net/NativeNetworkType.aidl",
-        "binder/android/net/NativeVpnType.aidl",
-        "binder/android/net/RouteInfoParcel.aidl",
-        "binder/android/net/TetherConfigParcel.aidl",
-        "binder/android/net/TetherOffloadRuleParcel.aidl",
-        "binder/android/net/TetherStatsParcel.aidl",
-        "binder/android/net/UidRangeParcel.aidl",
-        // Add new AIDL classes in android.net.netd.aidl to consist with other network modules.
-        "binder/android/net/netd/aidl/**/*.aidl",
-    ],
-    backend: {
-        cpp: {
-            gen_log: true,
-        },
-        java: {
-            // TODO: Remove apex_available and restrict visibility to only mainline modules that are
-            // either outside the system server or use jarjar to rename the generated AIDL classes.
-            apex_available: [
-                "//apex_available:platform", // used from services.net
-                "com.android.bluetooth.updatable",
-                "com.android.tethering",
-                "com.android.wifi",
-            ],
-            // this is part of updatable modules(NetworkStack) which targets 29(Q)
-            min_sdk_version: "29",
-        },
-        ndk: {
-            apex_available: [
-                "//apex_available:platform",
-            ],
-            // This is necessary for the DnsResovler tests to run in Android Q.
-            // Soong would recognize this value and produce the Q compatible aidl library.
-            min_sdk_version: "29",
-        },
-    },
-    versions: [
-        "1",
-        "2",
-        "3",
-        "4",
-        "5",
-        "6",
-        "7",
-    ],
-}
-
-java_library {
-    name: "netd_event_listener_interface-lateststable-java",
-    sdk_version: "system_current",
-    min_sdk_version: "29",
-    static_libs: [
-        "netd_event_listener_interface-V1-java",
-    ],
-    apex_available: [
-        "//apex_available:platform",
-        "com.android.bluetooth.updatable",
-        "com.android.wifi",
-        "com.android.tethering",
-    ],
-}
-
-aidl_interface {
-    name: "netd_event_listener_interface",
-    local_include_dir: "binder",
-    srcs: [
-        "binder/android/net/metrics/INetdEventListener.aidl",
-    ],
-    versions: ["1"],
-    backend: {
-        ndk: {
-            apex_available: [
-                "//apex_available:platform",
-                "com.android.resolv",
-            ],
-            min_sdk_version: "29",
-        },
-        java: {
-            apex_available: [
-                "//apex_available:platform",
-                "com.android.bluetooth.updatable",
-                "com.android.wifi",
-                "com.android.tethering",
-            ],
-            min_sdk_version: "29",
-        },
-    },
-}
-
 aidl_interface {
     // This interface is for OEM calls to netd and vice versa that do not exist in AOSP.
     // Those calls cannot be part of INetd.aidl and INetdUnsolicitedEventListener.aidl
@@ -171,25 +29,25 @@
         "NetdConstants.cpp",
         "InterfaceController.cpp",
         "NetlinkCommands.cpp",
-        "NetlinkListener.cpp",
-        "OffloadUtils.cpp",
         "SockDiag.cpp",
         "XfrmController.cpp",
-        "TrafficController.cpp",
     ],
 }
 
 // Modules common to both netd and netd_unit_test
 cc_library_static {
     name: "libnetd_server",
-    defaults: ["netd_defaults"],
+    defaults: [
+        "netd_aidl_interface_lateststable_cpp_shared",
+        "netd_defaults",
+    ],
     include_dirs: [
         "system/netd/include",
         "system/netd/server/binder",
     ],
+    header_libs: ["bpf_connectivity_headers"],
     srcs: [
         "BandwidthController.cpp",
-        "ClatdController.cpp",
         "Controllers.cpp",
         "NetdConstants.cpp",
         "FirewallController.cpp",
@@ -198,33 +56,30 @@
         "IptablesRestoreController.cpp",
         "NFLogListener.cpp",
         "NetlinkCommands.cpp",
-        "NetlinkListener.cpp",
         "NetlinkManager.cpp",
-        "OffloadUtils.cpp",
         "RouteController.cpp",
         "SockDiag.cpp",
         "StrictController.cpp",
         "TcpSocketMonitor.cpp",
         "TetherController.cpp",
-        "TrafficController.cpp",
         "UidRanges.cpp",
         "WakeupController.cpp",
         "XfrmController.cpp",
     ],
     shared_libs: [
-        "libbpf_android",
         "libbase",
         "libbinder",
-        "libnetdbpf",
         "libnetutils",
         "libnetdutils",
         "libpcap",
-        "libqtaguid",
         "libssl",
         "libsysutils",
-        "netd_aidl_interface-V7-cpp",
         "netd_event_listener_interface-V1-cpp",
     ],
+    static_libs: [
+        "libip_checksum",
+        "libtcutils",
+    ],
     aidl: {
         export_aidl_headers: true,
         local_include_dirs: ["binder"],
@@ -233,7 +88,10 @@
 
 cc_binary {
     name: "netd",
-    defaults: ["netd_defaults"],
+    defaults: [
+        "netd_aidl_interface_lateststable_cpp_shared",
+        "netd_defaults",
+    ],
     include_dirs: [
         "external/mdnsresponder/mDNSShared",
         "system/netd/include",
@@ -241,43 +99,44 @@
     init_rc: ["netd.rc"],
     required: [
         "bpfloader",
-        "clatd.o",
-        "netd.o",
     ],
+    header_libs: ["bpf_connectivity_headers"],
     shared_libs: [
         "android.system.net.netd@1.0",
         "android.system.net.netd@1.1",
         "libbase",
         "libbinder",
-        "libbpf_android",
         "libcutils",
         "libdl",
         "libhidlbase",
         "liblog",
         "libmdnssd",
+        "libnetd_updatable",
         "libnetd_resolv",
-        "libnetdbpf",
         "libnetdutils",
         "libnetutils",
         "libpcap",
         "libprocessgroup",
-        "libqtaguid",
         "libselinux",
         "libsysutils",
         "libutils",
-        "netd_aidl_interface-V7-cpp",
+        "mdns_aidl_interface-V1-cpp",
         "netd_event_listener_interface-V1-cpp",
         "oemnetd_aidl_interface-cpp",
     ],
     static_libs: [
+        "libip_checksum",
         "libnetd_server",
+        "libtcutils",
     ],
     srcs: [
         "DummyNetwork.cpp",
         "EventReporter.cpp",
         "FwmarkServer.cpp",
         "LocalNetwork.cpp",
+        "MDnsEventReporter.cpp",
         "MDnsSdListener.cpp",
+        "MDnsService.cpp",
         "NetdCommand.cpp",
         "NetdHwService.cpp",
         "NetdNativeService.cpp",
@@ -295,12 +154,16 @@
     ],
     sanitize: {
         cfi: true,
+        memtag_heap: true,
     },
 }
 
 cc_binary {
     name: "ndc",
-    defaults: ["netd_defaults"],
+    defaults: [
+        "netd_aidl_interface_lateststable_cpp_shared",
+        "netd_defaults",
+    ],
     include_dirs: [
         "system/netd/include",
     ],
@@ -316,7 +179,6 @@
         "libutils",
         "libbinder",
         "dnsresolver_aidl_interface-V7-cpp",
-        "netd_aidl_interface-V6-cpp",
     ],
     srcs: [
         "ndc.cpp",
@@ -331,7 +193,10 @@
 
 cc_test {
     name: "netd_unit_test",
-    defaults: ["netd_defaults"],
+    defaults: [
+        "netd_aidl_interface_lateststable_cpp_static",
+        "netd_defaults",
+    ],
     test_suites: ["device-tests"],
     require_root: true,
     include_dirs: [
@@ -339,9 +204,14 @@
         "system/netd/server/binder",
         "system/netd/tests",
     ],
+    header_libs: ["bpf_connectivity_headers"],
+    tidy_timeout_srcs: [
+        "BandwidthControllerTest.cpp",
+        "InterfaceControllerTest.cpp",
+        "XfrmControllerTest.cpp",
+    ],
     srcs: [
         "BandwidthControllerTest.cpp",
-        "ClatdControllerTest.cpp",
         "ControllersTest.cpp",
         "FirewallControllerTest.cpp",
         "IdletimerControllerTest.cpp",
@@ -349,31 +219,27 @@
         "IptablesBaseTest.cpp",
         "IptablesRestoreControllerTest.cpp",
         "NFLogListenerTest.cpp",
-        "OffloadUtilsTest.cpp",
         "RouteControllerTest.cpp",
         "SockDiagTest.cpp",
         "StrictControllerTest.cpp",
         "TetherControllerTest.cpp",
-        "TrafficControllerTest.cpp",
         "XfrmControllerTest.cpp",
         "WakeupControllerTest.cpp",
     ],
     static_libs: [
         "libgmock",
+        "libip_checksum",
         "libnetd_server",
         "libnetd_test_tun_interface",
-        "libqtaguid",
-        "netd_aidl_interface-V7-cpp",
+        "libtcutils",
         "netd_event_listener_interface-V1-cpp",
     ],
     shared_libs: [
         "libbase",
         "libbinder",
-        "libbpf_android",
         "libcrypto",
         "libcutils",
         "liblog",
-        "libnetdbpf",
         "libnetdutils",
         "libnetutils",
         "libsysutils",
diff --git a/server/BandwidthController.cpp b/server/BandwidthController.cpp
index 1b46234..96a82e2 100644
--- a/server/BandwidthController.cpp
+++ b/server/BandwidthController.cpp
@@ -55,7 +55,6 @@
 #include "FirewallController.h" /* For makeCriticalCommands */
 #include "Fwmark.h"
 #include "NetdConstants.h"
-#include "TrafficController.h"
 #include "bpf/BpfUtils.h"
 
 /* Alphabetical */
@@ -67,6 +66,9 @@
 const char BandwidthController::LOCAL_MANGLE_POSTROUTING[] = "bw_mangle_POSTROUTING";
 const char BandwidthController::LOCAL_GLOBAL_ALERT[] = "bw_global_alert";
 
+// Sync from packages/modules/Connectivity/bpf_progs/clatd.c
+#define CLAT_MARK 0xdeadc1a7
+
 auto BandwidthController::iptablesRestoreFunction = execIptablesRestoreWithOutput;
 
 using android::base::Join;
@@ -74,8 +76,6 @@
 using android::base::StringAppendF;
 using android::base::StringPrintf;
 using android::net::FirewallController;
-using android::net::gCtls;
-using android::netdutils::Status;
 using android::netdutils::StatusOr;
 using android::netdutils::UniqueFile;
 
@@ -227,6 +227,8 @@
             "COMMIT",
 
             "*raw",
+            // Drop duplicate ingress clat packets
+            StringPrintf("-A bw_raw_PREROUTING -m mark --mark 0x%x -j DROP", CLAT_MARK),
             // Prevents IPSec double counting (Tunnel mode and Transport mode,
             // respectively)
             ("-A bw_raw_PREROUTING -i " IPSEC_IFACE_PREFIX "+ -j RETURN"),
@@ -236,9 +238,7 @@
             // interface and later correct for overhead (+20 bytes/packet).
             //
             // Note: eBPF offloaded packets never hit base interface's ip6tables, and non
-            // offloaded packets (which when using xt_qtaguid means all packets, because
-            // clat eBPF offload does not work on xt_qtaguid devices) are dropped in
-            // clat_raw_PREROUTING.
+            // offloaded packets are dropped up above due to being marked with CLAT_MARK
             //
             // Hence we will never double count and additional corrections are not needed.
             // We can simply take the sum of base and stacked (+20B/pkt) interface counts.
@@ -252,9 +252,6 @@
             "-A bw_mangle_POSTROUTING -m policy --pol ipsec --dir out -j RETURN",
             // Clear the uid billing done (egress) mark before sending this packet
             StringPrintf("-A bw_mangle_POSTROUTING -j MARK --set-mark 0x0/0x%x", uidBillingMask),
-            // Packets from the clat daemon have already been counted on egress through the
-            // stacked v4-* interface.
-            "-A bw_mangle_POSTROUTING -m owner --uid-owner clat -j RETURN",
             // This is egress interface accounting: we account 464xlat traffic only on
             // the clat interface (as offloaded packets never hit base interface's ip6tables)
             // and later sum base and stacked with overhead (+20B/pkt) in higher layers
@@ -323,31 +320,6 @@
     return ret;
 }
 
-int BandwidthController::addNaughtyApps(const std::vector<uint32_t>& appUids) {
-    return manipulateSpecialApps(appUids, PENALTY_BOX_MATCH, IptOpInsert);
-}
-
-int BandwidthController::removeNaughtyApps(const std::vector<uint32_t>& appUids) {
-    return manipulateSpecialApps(appUids, PENALTY_BOX_MATCH, IptOpDelete);
-}
-
-int BandwidthController::addNiceApps(const std::vector<uint32_t>& appUids) {
-    return manipulateSpecialApps(appUids, HAPPY_BOX_MATCH, IptOpInsert);
-}
-
-int BandwidthController::removeNiceApps(const std::vector<uint32_t>& appUids) {
-    return manipulateSpecialApps(appUids, HAPPY_BOX_MATCH, IptOpDelete);
-}
-
-int BandwidthController::manipulateSpecialApps(const std::vector<uint32_t>& appUids,
-                                               UidOwnerMatchType matchType, IptOp op) {
-    Status status = gCtls->trafficCtrl.updateUidOwnerMap(appUids, matchType, op);
-    if (!isOk(status)) {
-        ALOGE("unable to update the Bandwidth Uid Map: %s", toString(status).c_str());
-    }
-    return status.code();
-}
-
 int BandwidthController::setInterfaceSharedQuota(const std::string& iface, int64_t maxBytes) {
     int res = 0;
     std::string quotaCmd;
diff --git a/server/BandwidthController.h b/server/BandwidthController.h
index 414e91b..2a3b4bd 100644
--- a/server/BandwidthController.h
+++ b/server/BandwidthController.h
@@ -24,7 +24,6 @@
 #include <mutex>
 
 #include "NetdConstants.h"
-#include "netdbpf/bpf_shared.h"
 
 class BandwidthController {
 public:
@@ -90,9 +89,6 @@
 
     std::string makeDataSaverCommand(IptablesTarget target, bool enable);
 
-    int manipulateSpecialApps(const std::vector<uint32_t>& appStrUids, UidOwnerMatchType matchType,
-                              IptOp appOp);
-
     int runIptablesAlertCmd(IptOp op, const std::string& alertName, int64_t bytes);
     int runIptablesAlertFwdCmd(IptOp op, const std::string& alertName, int64_t bytes);
 
diff --git a/server/BandwidthControllerTest.cpp b/server/BandwidthControllerTest.cpp
index d635daf..e7d29d2 100644
--- a/server/BandwidthControllerTest.cpp
+++ b/server/BandwidthControllerTest.cpp
@@ -34,8 +34,7 @@
 #include "BandwidthController.h"
 #include "Fwmark.h"
 #include "IptablesBaseTest.h"
-#include "bpf/BpfUtils.h"
-#include "netdbpf/bpf_shared.h"
+#include "bpf_shared.h"
 #include "tun_interface.h"
 
 using ::testing::_;
@@ -188,6 +187,7 @@
             "-I bw_happy_box -m bpf --object-pinned " XT_BPF_ALLOWLIST_PROG_PATH " -j RETURN\n"
             "COMMIT\n"
             "*raw\n"
+            "-A bw_raw_PREROUTING -m mark --mark 0xdeadc1a7 -j DROP\n"
             "-A bw_raw_PREROUTING -i ipsec+ -j RETURN\n"
             "-A bw_raw_PREROUTING -m policy --pol ipsec --dir in -j RETURN\n"
             "-A bw_raw_PREROUTING -m bpf --object-pinned " XT_BPF_INGRESS_PROG_PATH "\n"
@@ -196,7 +196,6 @@
             "-A bw_mangle_POSTROUTING -o ipsec+ -j RETURN\n"
             "-A bw_mangle_POSTROUTING -m policy --pol ipsec --dir out -j RETURN\n"
             "-A bw_mangle_POSTROUTING -j MARK --set-mark 0x0/0x100000\n"
-            "-A bw_mangle_POSTROUTING -m owner --uid-owner clat -j RETURN\n"
             "-A bw_mangle_POSTROUTING -m bpf --object-pinned " XT_BPF_EGRESS_PROG_PATH "\n"
             "COMMIT\n";
     // clang-format on
diff --git a/server/ClatdController.cpp b/server/ClatdController.cpp
deleted file mode 100644
index 847a6db..0000000
--- a/server/ClatdController.cpp
+++ /dev/null
@@ -1,669 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <map>
-#include <string>
-
-#include <arpa/inet.h>
-#include <errno.h>
-#include <linux/if_tun.h>
-#include <linux/ioctl.h>
-#include <net/if.h>
-#include <netinet/in.h>
-#include <spawn.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#define LOG_TAG "ClatdController"
-#include <log/log.h>
-
-#include "ClatdController.h"
-#include "InterfaceController.h"
-
-#include "android-base/properties.h"
-#include "android-base/scopeguard.h"
-#include "android-base/stringprintf.h"
-#include "android-base/unique_fd.h"
-#include "bpf/BpfMap.h"
-#include "netdbpf/bpf_shared.h"
-#include "netdutils/DumpWriter.h"
-
-extern "C" {
-#include "netutils/checksum.h"
-}
-
-#include "Fwmark.h"
-#include "NetdConstants.h"
-#include "NetworkController.h"
-#include "OffloadUtils.h"
-#include "netid_client.h"
-
-static const char* kClatdPath = "/system/bin/clatd";
-
-// For historical reasons, start with 192.0.0.4, and after that, use all subsequent addresses in
-// 192.0.0.0/29 (RFC 7335).
-static const char* kV4AddrString = "192.0.0.4";
-static const in_addr kV4Addr = {inet_addr(kV4AddrString)};
-static const int kV4AddrLen = 29;
-
-using android::base::Result;
-using android::base::StringPrintf;
-using android::base::unique_fd;
-using android::bpf::BpfMap;
-using android::netdutils::DumpWriter;
-using android::netdutils::ScopedIndent;
-
-namespace android {
-namespace net {
-
-void ClatdController::init(void) {
-    std::lock_guard guard(mutex);
-
-    int rv = getClatEgress4MapFd();
-    if (rv < 0) {
-        ALOGE("getClatEgress4MapFd() failure: %s", strerror(-rv));
-        return;
-    }
-    mClatEgress4Map.reset(rv);
-
-    rv = getClatIngress6MapFd();
-    if (rv < 0) {
-        ALOGE("getClatIngress6MapFd() failure: %s", strerror(-rv));
-        mClatEgress4Map.reset(-1);
-        return;
-    }
-    mClatIngress6Map.reset(rv);
-
-    mClatEgress4Map.clear();
-    mClatIngress6Map.clear();
-}
-
-bool ClatdController::isIpv4AddressFree(in_addr_t addr) {
-    int s = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
-    if (s == -1) {
-        return 0;
-    }
-
-    // Attempt to connect to the address. If the connection succeeds and getsockname returns the
-    // same then the address is already assigned to the system and we can't use it.
-    struct sockaddr_in sin = {
-            .sin_family = AF_INET,
-            .sin_port = htons(53),
-            .sin_addr = {addr},
-    };
-    socklen_t len = sizeof(sin);
-    bool inuse = connect(s, (struct sockaddr*)&sin, sizeof(sin)) == 0 &&
-                 getsockname(s, (struct sockaddr*)&sin, &len) == 0 && (size_t)len >= sizeof(sin) &&
-                 sin.sin_addr.s_addr == addr;
-
-    close(s);
-    return !inuse;
-}
-
-// Picks a free IPv4 address, starting from ip and trying all addresses in the prefix in order.
-//   ip        - the IP address from the configuration file
-//   prefixlen - the length of the prefix from which addresses may be selected.
-//   returns: the IPv4 address, or INADDR_NONE if no addresses were available
-in_addr_t ClatdController::selectIpv4Address(const in_addr ip, int16_t prefixlen) {
-    // Don't accept prefixes that are too large because we scan addresses one by one.
-    if (prefixlen < 16 || prefixlen > 32) {
-        return INADDR_NONE;
-    }
-
-    // All these are in host byte order.
-    in_addr_t mask = 0xffffffff >> (32 - prefixlen) << (32 - prefixlen);
-    in_addr_t ipv4 = ntohl(ip.s_addr);
-    in_addr_t first_ipv4 = ipv4;
-    in_addr_t prefix = ipv4 & mask;
-
-    // Pick the first IPv4 address in the pool, wrapping around if necessary.
-    // So, for example, 192.0.0.4 -> 192.0.0.5 -> 192.0.0.6 -> 192.0.0.7 -> 192.0.0.0.
-    do {
-        if (isIpv4AddressFreeFunc(htonl(ipv4))) {
-            return htonl(ipv4);
-        }
-        ipv4 = prefix | ((ipv4 + 1) & ~mask);
-    } while (ipv4 != first_ipv4);
-
-    return INADDR_NONE;
-}
-
-// Alters the bits in the IPv6 address to make them checksum neutral with v4 and nat64Prefix.
-void ClatdController::makeChecksumNeutral(in6_addr* v6, const in_addr v4,
-                                          const in6_addr& nat64Prefix) {
-    // Fill last 8 bytes of IPv6 address with random bits.
-    arc4random_buf(&v6->s6_addr[8], 8);
-
-    // Make the IID checksum-neutral. That is, make it so that:
-    //   checksum(Local IPv4 | Remote IPv4) = checksum(Local IPv6 | Remote IPv6)
-    // in other words (because remote IPv6 = NAT64 prefix | Remote IPv4):
-    //   checksum(Local IPv4) = checksum(Local IPv6 | NAT64 prefix)
-    // Do this by adjusting the two bytes in the middle of the IID.
-
-    uint16_t middlebytes = (v6->s6_addr[11] << 8) + v6->s6_addr[12];
-
-    uint32_t c1 = ip_checksum_add(0, &v4, sizeof(v4));
-    uint32_t c2 = ip_checksum_add(0, &nat64Prefix, sizeof(nat64Prefix)) +
-                  ip_checksum_add(0, v6, sizeof(*v6));
-
-    uint16_t delta = ip_checksum_adjust(middlebytes, c1, c2);
-    v6->s6_addr[11] = delta >> 8;
-    v6->s6_addr[12] = delta & 0xff;
-}
-
-// Picks a random interface ID that is checksum neutral with the IPv4 address and the NAT64 prefix.
-int ClatdController::generateIpv6Address(const char* iface, const in_addr v4,
-                                         const in6_addr& nat64Prefix, in6_addr* v6) {
-    unique_fd s(socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0));
-    if (s == -1) return -errno;
-
-    if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, iface, strlen(iface) + 1) == -1) {
-        return -errno;
-    }
-
-    sockaddr_in6 sin6 = {.sin6_family = AF_INET6, .sin6_addr = nat64Prefix};
-    if (connect(s, reinterpret_cast<struct sockaddr*>(&sin6), sizeof(sin6)) == -1) {
-        return -errno;
-    }
-
-    socklen_t len = sizeof(sin6);
-    if (getsockname(s, reinterpret_cast<struct sockaddr*>(&sin6), &len) == -1) {
-        return -errno;
-    }
-
-    *v6 = sin6.sin6_addr;
-
-    if (IN6_IS_ADDR_UNSPECIFIED(v6) || IN6_IS_ADDR_LOOPBACK(v6) || IN6_IS_ADDR_LINKLOCAL(v6) ||
-        IN6_IS_ADDR_SITELOCAL(v6) || IN6_IS_ADDR_ULA(v6)) {
-        return -ENETUNREACH;
-    }
-
-    makeChecksumNeutral(v6, v4, nat64Prefix);
-
-    return 0;
-}
-
-void ClatdController::maybeStartBpf(const ClatdTracker& tracker) {
-    auto isEthernet = android::net::isEthernet(tracker.iface);
-    if (!isEthernet.ok()) {
-        ALOGE("isEthernet(%s[%d]) failure: %s", tracker.iface, tracker.ifIndex,
-              isEthernet.error().message().c_str());
-        return;
-    }
-
-    // This program will be attached to the v4-* interface which is a TUN and thus always rawip.
-    int rv = getClatEgress4ProgFd(RAWIP);
-    if (rv < 0) {
-        ALOGE("getClatEgress4ProgFd(RAWIP) failure: %s", strerror(-rv));
-        return;
-    }
-    unique_fd txRawIpProgFd(rv);
-
-    rv = getClatIngress6ProgFd(isEthernet.value());
-    if (rv < 0) {
-        ALOGE("getClatIngress6ProgFd(%d) failure: %s", isEthernet.value(), strerror(-rv));
-        return;
-    }
-    unique_fd rxProgFd(rv);
-
-    ClatEgress4Key txKey = {
-            .iif = tracker.v4ifIndex,
-            .local4 = tracker.v4,
-    };
-    ClatEgress4Value txValue = {
-            .oif = tracker.ifIndex,
-            .local6 = tracker.v6,
-            .pfx96 = tracker.pfx96,
-            .oifIsEthernet = isEthernet.value(),
-    };
-
-    auto ret = mClatEgress4Map.writeValue(txKey, txValue, BPF_ANY);
-    if (!ret.ok()) {
-        ALOGE("mClatEgress4Map.writeValue failure: %s", strerror(ret.error().code()));
-        return;
-    }
-
-    ClatIngress6Key rxKey = {
-            .iif = tracker.ifIndex,
-            .pfx96 = tracker.pfx96,
-            .local6 = tracker.v6,
-    };
-    ClatIngress6Value rxValue = {
-            // TODO: move all the clat code to eBPF and remove the tun interface entirely.
-            .oif = tracker.v4ifIndex,
-            .local4 = tracker.v4,
-    };
-
-    ret = mClatIngress6Map.writeValue(rxKey, rxValue, BPF_ANY);
-    if (!ret.ok()) {
-        ALOGE("mClatIngress6Map.writeValue failure: %s", strerror(ret.error().code()));
-        ret = mClatEgress4Map.deleteValue(txKey);
-        if (!ret.ok())
-            ALOGE("mClatEgress4Map.deleteValue failure: %s", strerror(ret.error().code()));
-        return;
-    }
-
-    // We do tc setup *after* populating the maps, so scanning through them
-    // can always be used to tell us what needs cleanup.
-
-    // Usually the clsact will be added in RouteController::addInterfaceToPhysicalNetwork.
-    // But clat is started before the v4- interface is added to the network. The clat startup have
-    // to add clsact of v4- tun interface first for adding bpf filter in maybeStartBpf.
-    // TODO: move "qdisc add clsact" of v4- tun interface out from ClatdController.
-    rv = tcQdiscAddDevClsact(tracker.v4ifIndex);
-    if (rv) {
-        ALOGE("tcQdiscAddDevClsact(%d[%s]) failure: %s", tracker.v4ifIndex, tracker.v4iface,
-              strerror(-rv));
-        ret = mClatEgress4Map.deleteValue(txKey);
-        if (!ret.ok())
-            ALOGE("mClatEgress4Map.deleteValue failure: %s", strerror(ret.error().code()));
-        ret = mClatIngress6Map.deleteValue(rxKey);
-        if (!ret.ok())
-            ALOGE("mClatIngress6Map.deleteValue failure: %s", strerror(ret.error().code()));
-        return;
-    }
-
-    rv = tcFilterAddDevEgressClatIpv4(tracker.v4ifIndex, txRawIpProgFd, RAWIP);
-    if (rv) {
-        ALOGE("tcFilterAddDevEgressClatIpv4(%d[%s], RAWIP) failure: %s", tracker.v4ifIndex,
-              tracker.v4iface, strerror(-rv));
-
-        // The v4- interface clsact is not deleted for unwinding error because once it is created
-        // with interface addition, the lifetime is till interface deletion. Moreover, the clsact
-        // has no clat filter now. It should not break anything.
-
-        ret = mClatEgress4Map.deleteValue(txKey);
-        if (!ret.ok())
-            ALOGE("mClatEgress4Map.deleteValue failure: %s", strerror(ret.error().code()));
-        ret = mClatIngress6Map.deleteValue(rxKey);
-        if (!ret.ok())
-            ALOGE("mClatIngress6Map.deleteValue failure: %s", strerror(ret.error().code()));
-        return;
-    }
-
-    rv = tcFilterAddDevIngressClatIpv6(tracker.ifIndex, rxProgFd, isEthernet.value());
-    if (rv) {
-        ALOGE("tcFilterAddDevIngressClatIpv6(%d[%s], %d) failure: %s", tracker.ifIndex,
-              tracker.iface, isEthernet.value(), strerror(-rv));
-        rv = tcFilterDelDevEgressClatIpv4(tracker.v4ifIndex);
-        if (rv) {
-            ALOGE("tcFilterDelDevEgressClatIpv4(%d[%s]) failure: %s", tracker.v4ifIndex,
-                  tracker.v4iface, strerror(-rv));
-        }
-
-        // The v4- interface clsact is not deleted. See the reason in the error unwinding code of
-        // the egress filter attaching of v4- tun interface.
-
-        ret = mClatEgress4Map.deleteValue(txKey);
-        if (!ret.ok())
-            ALOGE("mClatEgress4Map.deleteValue failure: %s", strerror(ret.error().code()));
-        ret = mClatIngress6Map.deleteValue(rxKey);
-        if (!ret.ok())
-            ALOGE("mClatIngress6Map.deleteValue failure: %s", strerror(ret.error().code()));
-        return;
-    }
-
-    // success
-}
-
-void ClatdController::setIptablesDropRule(bool add, const char* iface, const char* pfx96Str,
-                                          const char* v6Str) {
-    std::string cmd = StringPrintf(
-            "*raw\n"
-            "%s %s -i %s -s %s/96 -d %s -j DROP\n"
-            "COMMIT\n",
-            (add ? "-A" : "-D"), LOCAL_RAW_PREROUTING, iface, pfx96Str, v6Str);
-
-    iptablesRestoreFunction(V6, cmd);
-}
-
-void ClatdController::maybeStopBpf(const ClatdTracker& tracker) {
-    int rv = tcFilterDelDevIngressClatIpv6(tracker.ifIndex);
-    if (rv < 0) {
-        ALOGE("tcFilterDelDevIngressClatIpv6(%d[%s]) failure: %s", tracker.ifIndex, tracker.iface,
-              strerror(-rv));
-    }
-
-    rv = tcFilterDelDevEgressClatIpv4(tracker.v4ifIndex);
-    if (rv < 0) {
-        ALOGE("tcFilterDelDevEgressClatIpv4(%d[%s]) failure: %s", tracker.v4ifIndex,
-              tracker.v4iface, strerror(-rv));
-    }
-
-    // We cleanup the maps last, so scanning through them can be used to
-    // determine what still needs cleanup.
-
-    ClatEgress4Key txKey = {
-            .iif = tracker.v4ifIndex,
-            .local4 = tracker.v4,
-    };
-
-    auto ret = mClatEgress4Map.deleteValue(txKey);
-    if (!ret.ok()) ALOGE("mClatEgress4Map.deleteValue failure: %s", strerror(ret.error().code()));
-
-    ClatIngress6Key rxKey = {
-            .iif = tracker.ifIndex,
-            .pfx96 = tracker.pfx96,
-            .local6 = tracker.v6,
-    };
-
-    ret = mClatIngress6Map.deleteValue(rxKey);
-    if (!ret.ok()) ALOGE("mClatIngress6Map.deleteValue failure: %s", strerror(ret.error().code()));
-}
-
-// Finds the tracker of the clatd running on interface |interface|, or nullptr if clatd has not been
-// started  on |interface|.
-ClatdController::ClatdTracker* ClatdController::getClatdTracker(const std::string& interface) {
-    auto it = mClatdTrackers.find(interface);
-    return (it == mClatdTrackers.end() ? nullptr : &it->second);
-}
-
-// Initializes a ClatdTracker for the specified interface.
-int ClatdController::ClatdTracker::init(unsigned networkId, const std::string& interface,
-                                        const std::string& v4interface,
-                                        const std::string& nat64Prefix) {
-    fwmark.netId = networkId;
-    fwmark.explicitlySelected = true;
-    fwmark.protectedFromVpn = true;
-    fwmark.permission = PERMISSION_SYSTEM;
-
-    snprintf(fwmarkString, sizeof(fwmarkString), "0x%x", fwmark.intValue);
-    strlcpy(iface, interface.c_str(), sizeof(iface));
-    ifIndex = if_nametoindex(iface);
-    strlcpy(v4iface, v4interface.c_str(), sizeof(v4iface));
-    v4ifIndex = if_nametoindex(v4iface);
-
-    // Pass in everything that clatd needs: interface, a fwmark for outgoing packets, the NAT64
-    // prefix, and the IPv4 and IPv6 addresses.
-    // Validate the prefix and strip off the prefix length.
-    uint8_t family;
-    uint8_t prefixLen;
-    int res = parsePrefix(nat64Prefix.c_str(), &family, &pfx96, sizeof(pfx96), &prefixLen);
-    // clatd only supports /96 prefixes.
-    if (res != sizeof(pfx96)) return res;
-    if (family != AF_INET6) return -EAFNOSUPPORT;
-    if (prefixLen != 96) return -EINVAL;
-    if (!inet_ntop(AF_INET6, &pfx96, pfx96String, sizeof(pfx96String))) return -errno;
-
-    // Pick an IPv4 address.
-    // TODO: this picks the address based on other addresses that are assigned to interfaces, but
-    // the address is only actually assigned to an interface once clatd starts up. So we could end
-    // up with two clatd instances with the same IPv4 address.
-    // Stop doing this and instead pick a free one from the kV4Addr pool.
-    v4 = {selectIpv4Address(kV4Addr, kV4AddrLen)};
-    if (v4.s_addr == INADDR_NONE) {
-        ALOGE("No free IPv4 address in %s/%d", kV4AddrString, kV4AddrLen);
-        return -EADDRNOTAVAIL;
-    }
-    if (!inet_ntop(AF_INET, &v4, v4Str, sizeof(v4Str))) return -errno;
-
-    // Generate a checksum-neutral IID.
-    if (generateIpv6Address(iface, v4, pfx96, &v6)) {
-        ALOGE("Unable to find global source address on %s for %s", iface, pfx96String);
-        return -EADDRNOTAVAIL;
-    }
-    if (!inet_ntop(AF_INET6, &v6, v6Str, sizeof(v6Str))) return -errno;
-
-    ALOGD("starting clatd on %s v4=%s v6=%s pfx96=%s", iface, v4Str, v6Str, pfx96String);
-    return 0;
-}
-
-int ClatdController::startClatd(const std::string& interface, const std::string& nat64Prefix,
-                                std::string* v6Str) {
-    std::lock_guard guard(mutex);
-
-    // 1. fail if pre-existing tracker already exists
-    ClatdTracker* existing = getClatdTracker(interface);
-    if (existing != nullptr) {
-        ALOGE("clatd pid=%d already started on %s", existing->pid, interface.c_str());
-        return -EBUSY;
-    }
-
-    // 2. get network id associated with this external interface
-    unsigned networkId = mNetCtrl->getNetworkForInterface(interface.c_str());
-    if (networkId == NETID_UNSET) {
-        ALOGE("Interface %s not assigned to any netId", interface.c_str());
-        return -ENODEV;
-    }
-
-    // 3. open the tun device in non blocking mode as required by clatd
-    int res = open("/dev/net/tun", O_RDWR | O_NONBLOCK | O_CLOEXEC);
-    if (res == -1) {
-        res = errno;
-        ALOGE("open of tun device failed (%s)", strerror(res));
-        return -res;
-    }
-    unique_fd tmpTunFd(res);
-
-    // 4. create the v4-... tun interface
-    std::string v4interface("v4-");
-    v4interface += interface;
-
-    struct ifreq ifr = {
-            .ifr_flags = IFF_TUN,
-    };
-    strlcpy(ifr.ifr_name, v4interface.c_str(), sizeof(ifr.ifr_name));
-
-    res = ioctl(tmpTunFd, TUNSETIFF, &ifr, sizeof(ifr));
-    if (res == -1) {
-        res = errno;
-        ALOGE("ioctl(TUNSETIFF) failed (%s)", strerror(res));
-        return -res;
-    }
-
-    // disable IPv6 on it - failing to do so is not a critical error
-    res = InterfaceController::setEnableIPv6(v4interface.c_str(), 0);
-    if (res) ALOGE("setEnableIPv6 %s failed (%s)", v4interface.c_str(), strerror(res));
-
-    // 5. initialize tracker object
-    ClatdTracker tracker;
-    int ret = tracker.init(networkId, interface, v4interface, nat64Prefix);
-    if (ret) return ret;
-
-    // 6. create a throwaway socket to reserve a file descriptor number
-    res = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
-    if (res == -1) {
-        res = errno;
-        ALOGE("socket(ipv6/udp) failed (%s)", strerror(res));
-        return -res;
-    }
-    unique_fd passedTunFd(res);
-
-    // 7. this is the FD we'll pass to clatd on the cli, so need it as a string
-    char passedTunFdStr[INT32_STRLEN];
-    snprintf(passedTunFdStr, sizeof(passedTunFdStr), "%d", passedTunFd.get());
-
-    // 8. we're going to use this as argv[0] to clatd to make ps output more useful
-    std::string progname("clatd-");
-    progname += tracker.iface;
-
-    // clang-format off
-    const char* args[] = {progname.c_str(),
-                          "-i", tracker.iface,
-                          "-m", tracker.fwmarkString,
-                          "-p", tracker.pfx96String,
-                          "-4", tracker.v4Str,
-                          "-6", tracker.v6Str,
-                          "-t", passedTunFdStr,
-                          nullptr};
-    // clang-format on
-
-    // 9. register vfork requirement
-    posix_spawnattr_t attr;
-    res = posix_spawnattr_init(&attr);
-    if (res) {
-        ALOGE("posix_spawnattr_init failed (%s)", strerror(res));
-        return -res;
-    }
-    const android::base::ScopeGuard attrGuard = [&] { posix_spawnattr_destroy(&attr); };
-    res = posix_spawnattr_setflags(&attr, POSIX_SPAWN_USEVFORK);
-    if (res) {
-        ALOGE("posix_spawnattr_setflags failed (%s)", strerror(res));
-        return -res;
-    }
-
-    // 10. register dup2() action: this is what 'clears' the CLOEXEC flag
-    // on the tun fd that we want the child clatd process to inherit
-    // (this will happen after the vfork, and before the execve)
-    posix_spawn_file_actions_t fa;
-    res = posix_spawn_file_actions_init(&fa);
-    if (res) {
-        ALOGE("posix_spawn_file_actions_init failed (%s)", strerror(res));
-        return -res;
-    }
-    const android::base::ScopeGuard faGuard = [&] { posix_spawn_file_actions_destroy(&fa); };
-    res = posix_spawn_file_actions_adddup2(&fa, tmpTunFd, passedTunFd);
-    if (res) {
-        ALOGE("posix_spawn_file_actions_adddup2 failed (%s)", strerror(res));
-        return -res;
-    }
-
-    // 11. add the drop rule for iptables.
-    setIptablesDropRule(true, tracker.iface, tracker.pfx96String, tracker.v6Str);
-
-    // 12. actually perform vfork/dup2/execve
-    res = posix_spawn(&tracker.pid, kClatdPath, &fa, &attr, (char* const*)args, nullptr);
-    if (res) {
-        ALOGE("posix_spawn failed (%s)", strerror(res));
-        return -res;
-    }
-
-    // 13. configure eBPF offload - if possible
-    maybeStartBpf(tracker);
-
-    mClatdTrackers[interface] = tracker;
-    ALOGD("clatd started on %s", interface.c_str());
-
-    *v6Str = tracker.v6Str;
-    return 0;
-}
-
-int ClatdController::stopClatd(const std::string& interface) {
-    std::lock_guard guard(mutex);
-    ClatdTracker* tracker = getClatdTracker(interface);
-
-    if (tracker == nullptr) {
-        ALOGE("clatd already stopped");
-        return -ENODEV;
-    }
-
-    ALOGD("Stopping clatd pid=%d on %s", tracker->pid, interface.c_str());
-
-    maybeStopBpf(*tracker);
-
-    kill(tracker->pid, SIGTERM);
-    waitpid(tracker->pid, nullptr, 0);
-
-    setIptablesDropRule(false, tracker->iface, tracker->pfx96String, tracker->v6Str);
-    mClatdTrackers.erase(interface);
-
-    ALOGD("clatd on %s stopped", interface.c_str());
-
-    return 0;
-}
-
-void ClatdController::dumpEgress(DumpWriter& dw) {
-    if (!mClatEgress4Map.isValid()) return;  // if unsupported just don't dump anything
-
-    ScopedIndent bpfIndent(dw);
-    dw.println("BPF egress map: iif(iface) v4Addr -> v6Addr nat64Prefix oif(iface)");
-
-    ScopedIndent bpfDetailIndent(dw);
-    const auto printClatMap = [&dw](const ClatEgress4Key& key, const ClatEgress4Value& value,
-                                    const BpfMap<ClatEgress4Key, ClatEgress4Value>&) {
-        char iifStr[IFNAMSIZ] = "?";
-        char local4Str[INET_ADDRSTRLEN] = "?";
-        char local6Str[INET6_ADDRSTRLEN] = "?";
-        char pfx96Str[INET6_ADDRSTRLEN] = "?";
-        char oifStr[IFNAMSIZ] = "?";
-
-        if_indextoname(key.iif, iifStr);
-        inet_ntop(AF_INET, &key.local4, local4Str, sizeof(local4Str));
-        inet_ntop(AF_INET6, &value.local6, local6Str, sizeof(local6Str));
-        inet_ntop(AF_INET6, &value.pfx96, pfx96Str, sizeof(pfx96Str));
-        if_indextoname(value.oif, oifStr);
-
-        dw.println("%u(%s) %s -> %s %s/96 %u(%s) %s", key.iif, iifStr, local4Str, local6Str,
-                   pfx96Str, value.oif, oifStr, value.oifIsEthernet ? "ether" : "rawip");
-        return Result<void>();
-    };
-    auto res = mClatEgress4Map.iterateWithValue(printClatMap);
-    if (!res.ok()) {
-        dw.println("Error printing BPF map: %s", res.error().message().c_str());
-    }
-}
-
-void ClatdController::dumpIngress(DumpWriter& dw) {
-    if (!mClatIngress6Map.isValid()) return;  // if unsupported just don't dump anything
-
-    ScopedIndent bpfIndent(dw);
-    dw.println("BPF ingress map: iif(iface) nat64Prefix v6Addr -> v4Addr oif(iface)");
-
-    ScopedIndent bpfDetailIndent(dw);
-    const auto printClatMap = [&dw](const ClatIngress6Key& key, const ClatIngress6Value& value,
-                                    const BpfMap<ClatIngress6Key, ClatIngress6Value>&) {
-        char iifStr[IFNAMSIZ] = "?";
-        char pfx96Str[INET6_ADDRSTRLEN] = "?";
-        char local6Str[INET6_ADDRSTRLEN] = "?";
-        char local4Str[INET_ADDRSTRLEN] = "?";
-        char oifStr[IFNAMSIZ] = "?";
-
-        if_indextoname(key.iif, iifStr);
-        inet_ntop(AF_INET6, &key.pfx96, pfx96Str, sizeof(pfx96Str));
-        inet_ntop(AF_INET6, &key.local6, local6Str, sizeof(local6Str));
-        inet_ntop(AF_INET, &value.local4, local4Str, sizeof(local4Str));
-        if_indextoname(value.oif, oifStr);
-
-        dw.println("%u(%s) %s/96 %s -> %s %u(%s)", key.iif, iifStr, pfx96Str, local6Str, local4Str,
-                   value.oif, oifStr);
-        return Result<void>();
-    };
-    auto res = mClatIngress6Map.iterateWithValue(printClatMap);
-    if (!res.ok()) {
-        dw.println("Error printing BPF map: %s", res.error().message().c_str());
-    }
-}
-
-void ClatdController::dumpTrackers(DumpWriter& dw) {
-    ScopedIndent trackerIndent(dw);
-    dw.println("Trackers: iif[iface] nat64Prefix v6Addr -> v4Addr v4iif[v4iface] [fwmark]");
-
-    ScopedIndent trackerDetailIndent(dw);
-    for (const auto& pair : mClatdTrackers) {
-        const ClatdTracker& tracker = pair.second;
-        dw.println("%u[%s] %s/96 %s -> %s %u[%s] [%s]", tracker.ifIndex, tracker.iface,
-                   tracker.pfx96String, tracker.v6Str, tracker.v4Str, tracker.v4ifIndex,
-                   tracker.v4iface, tracker.fwmarkString);
-    }
-}
-
-void ClatdController::dump(DumpWriter& dw) {
-    std::lock_guard guard(mutex);
-
-    ScopedIndent clatdIndent(dw);
-    dw.println("ClatdController");
-
-    dumpTrackers(dw);
-    dumpIngress(dw);
-    dumpEgress(dw);
-}
-
-auto ClatdController::isIpv4AddressFreeFunc = isIpv4AddressFree;
-auto ClatdController::iptablesRestoreFunction = execIptablesRestore;
-
-}  // namespace net
-}  // namespace android
diff --git a/server/ClatdController.h b/server/ClatdController.h
deleted file mode 100644
index 4b7c60b..0000000
--- a/server/ClatdController.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _CLATD_CONTROLLER_H
-#define _CLATD_CONTROLLER_H
-
-#include <map>
-#include <mutex>
-#include <string>
-
-#include <linux/if.h>
-#include <netinet/in.h>
-
-#include <android-base/thread_annotations.h>
-
-#include "Fwmark.h"
-#include "NetdConstants.h"
-#include "bpf/BpfMap.h"
-#include "netdbpf/bpf_shared.h"
-#include "netdutils/DumpWriter.h"
-
-namespace android {
-namespace net {
-
-class NetworkController;
-
-class ClatdController {
-  public:
-    explicit ClatdController(NetworkController* controller) EXCLUDES(mutex)
-        : mNetCtrl(controller){};
-    virtual ~ClatdController() EXCLUDES(mutex){};
-
-    /* First thing init/startClatd/stopClatd/dump do is grab the mutex. */
-    void init(void) EXCLUDES(mutex);
-
-    int startClatd(const std::string& interface, const std::string& nat64Prefix,
-                   std::string* v6Addr) EXCLUDES(mutex);
-    int stopClatd(const std::string& interface) EXCLUDES(mutex);
-
-    void dump(netdutils::DumpWriter& dw) EXCLUDES(mutex);
-
-    static constexpr const char LOCAL_RAW_PREROUTING[] = "clat_raw_PREROUTING";
-
-  private:
-    struct ClatdTracker {
-        pid_t pid = -1;
-        unsigned ifIndex;
-        char iface[IFNAMSIZ];
-        unsigned v4ifIndex;
-        char v4iface[IFNAMSIZ];
-        Fwmark fwmark;
-        char fwmarkString[UINT32_STRLEN];
-        in_addr v4;
-        char v4Str[INET_ADDRSTRLEN];
-        in6_addr v6;
-        char v6Str[INET6_ADDRSTRLEN];
-        in6_addr pfx96;
-        char pfx96String[INET6_ADDRSTRLEN];
-
-        int init(unsigned networkId, const std::string& interface, const std::string& v4interface,
-                 const std::string& nat64Prefix);
-    };
-
-    std::mutex mutex;
-
-    const NetworkController* mNetCtrl GUARDED_BY(mutex);
-    std::map<std::string, ClatdTracker> mClatdTrackers GUARDED_BY(mutex);
-    ClatdTracker* getClatdTracker(const std::string& interface) REQUIRES(mutex);
-
-    void dumpEgress(netdutils::DumpWriter& dw) REQUIRES(mutex);
-    void dumpIngress(netdutils::DumpWriter& dw) REQUIRES(mutex);
-    void dumpTrackers(netdutils::DumpWriter& dw) REQUIRES(mutex);
-
-    static in_addr_t selectIpv4Address(const in_addr ip, int16_t prefixlen);
-    static int generateIpv6Address(const char* iface, const in_addr v4, const in6_addr& nat64Prefix,
-                                   in6_addr* v6);
-    static void makeChecksumNeutral(in6_addr* v6, const in_addr v4, const in6_addr& nat64Prefix);
-
-    bpf::BpfMap<ClatEgress4Key, ClatEgress4Value> mClatEgress4Map GUARDED_BY(mutex);
-    bpf::BpfMap<ClatIngress6Key, ClatIngress6Value> mClatIngress6Map GUARDED_BY(mutex);
-
-    void maybeStartBpf(const ClatdTracker& tracker) REQUIRES(mutex);
-    void maybeStopBpf(const ClatdTracker& tracker) REQUIRES(mutex);
-    void setIptablesDropRule(bool add, const char* iface, const char* pfx96Str, const char* v6Str)
-            REQUIRES(mutex);
-
-    // For testing.
-    friend class ClatdControllerTest;
-
-    static bool (*isIpv4AddressFreeFunc)(in_addr_t);
-    static bool isIpv4AddressFree(in_addr_t addr);
-    static int (*iptablesRestoreFunction)(IptablesTarget target, const std::string& commands);
-};
-
-}  // namespace net
-}  // namespace android
-
-#endif
diff --git a/server/ClatdControllerTest.cpp b/server/ClatdControllerTest.cpp
deleted file mode 100644
index d3a2aa7..0000000
--- a/server/ClatdControllerTest.cpp
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * ClatdControllerTest.cpp - unit tests for ClatdController.cpp
- */
-
-#include <arpa/inet.h>
-#include <netinet/in.h>
-#include <string>
-
-#include <gtest/gtest.h>
-
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-#include <netutils/ifc.h>
-
-extern "C" {
-#include <netutils/checksum.h>
-}
-
-#include "ClatdController.h"
-#include "IptablesBaseTest.h"
-#include "NetworkController.h"
-#include "tun_interface.h"
-
-static const char kIPv4LocalAddr[] = "192.0.0.4";
-
-namespace android {
-namespace net {
-
-using android::base::StringPrintf;
-
-// Mock functions for isIpv4AddressFree.
-bool neverFree(in_addr_t /* addr */) {
-    return 0;
-}
-bool alwaysFree(in_addr_t /* addr */) {
-    return 1;
-}
-bool only2Free(in_addr_t addr) {
-    return (ntohl(addr) & 0xff) == 2;
-}
-bool over6Free(in_addr_t addr) {
-    return (ntohl(addr) & 0xff) >= 6;
-}
-bool only10Free(in_addr_t addr) {
-    return (ntohl(addr) & 0xff) == 10;
-}
-
-class ClatdControllerTest : public IptablesBaseTest {
-  public:
-    ClatdControllerTest() : mClatdCtrl(nullptr) {
-        ClatdController::iptablesRestoreFunction = fakeExecIptablesRestore;
-    }
-
-    void SetUp() { resetIpv4AddressFreeFunc(); }
-
-  protected:
-    ClatdController mClatdCtrl;
-    void setIptablesDropRule(bool a, const char* b, const char* c, const char* d) {
-        std::lock_guard guard(mClatdCtrl.mutex);
-        return mClatdCtrl.setIptablesDropRule(a, b, c, d);
-    }
-    void setIpv4AddressFreeFunc(bool (*func)(in_addr_t)) {
-        ClatdController::isIpv4AddressFreeFunc = func;
-    }
-    void resetIpv4AddressFreeFunc() {
-        ClatdController::isIpv4AddressFreeFunc = ClatdController::isIpv4AddressFree;
-    }
-    in_addr_t selectIpv4Address(const in_addr a, int16_t b) {
-        return ClatdController::selectIpv4Address(a, b);
-    }
-    void makeChecksumNeutral(in6_addr* a, const in_addr b, const in6_addr& c) {
-        ClatdController::makeChecksumNeutral(a, b, c);
-    }
-};
-
-TEST_F(ClatdControllerTest, SelectIpv4Address) {
-    struct in_addr addr;
-
-    inet_pton(AF_INET, kIPv4LocalAddr, &addr);
-
-    // If no addresses are free, return INADDR_NONE.
-    setIpv4AddressFreeFunc(neverFree);
-    EXPECT_EQ(INADDR_NONE, selectIpv4Address(addr, 29));
-    EXPECT_EQ(INADDR_NONE, selectIpv4Address(addr, 16));
-
-    // If the configured address is free, pick that. But a prefix that's too big is invalid.
-    setIpv4AddressFreeFunc(alwaysFree);
-    EXPECT_EQ(inet_addr(kIPv4LocalAddr), selectIpv4Address(addr, 29));
-    EXPECT_EQ(inet_addr(kIPv4LocalAddr), selectIpv4Address(addr, 20));
-    EXPECT_EQ(INADDR_NONE, selectIpv4Address(addr, 15));
-
-    // A prefix length of 32 works, but anything above it is invalid.
-    EXPECT_EQ(inet_addr(kIPv4LocalAddr), selectIpv4Address(addr, 32));
-    EXPECT_EQ(INADDR_NONE, selectIpv4Address(addr, 33));
-
-    // If another address is free, pick it.
-    setIpv4AddressFreeFunc(over6Free);
-    EXPECT_EQ(inet_addr("192.0.0.6"), selectIpv4Address(addr, 29));
-
-    // Check that we wrap around to addresses that are lower than the first address.
-    setIpv4AddressFreeFunc(only2Free);
-    EXPECT_EQ(inet_addr("192.0.0.2"), selectIpv4Address(addr, 29));
-    EXPECT_EQ(INADDR_NONE, selectIpv4Address(addr, 30));
-
-    // If a free address exists outside the prefix, we don't pick it.
-    setIpv4AddressFreeFunc(only10Free);
-    EXPECT_EQ(INADDR_NONE, selectIpv4Address(addr, 29));
-    EXPECT_EQ(inet_addr("192.0.0.10"), selectIpv4Address(addr, 24));
-
-    // Now try using the real function which sees if IP addresses are free using bind().
-    // Assume that the machine running the test has the address 127.0.0.1, but not 8.8.8.8.
-    resetIpv4AddressFreeFunc();
-    addr.s_addr = inet_addr("8.8.8.8");
-    EXPECT_EQ(inet_addr("8.8.8.8"), selectIpv4Address(addr, 29));
-
-    addr.s_addr = inet_addr("127.0.0.1");
-    EXPECT_EQ(inet_addr("127.0.0.2"), selectIpv4Address(addr, 29));
-}
-
-TEST_F(ClatdControllerTest, MakeChecksumNeutral) {
-    // We can't test generateIPv6Address here since it requires manipulating routing, which we can't
-    // do without talking to the real netd on the system.
-    uint32_t rand = arc4random_uniform(0xffffffff);
-    uint16_t rand1 = rand & 0xffff;
-    uint16_t rand2 = (rand >> 16) & 0xffff;
-    std::string v6PrefixStr = StringPrintf("2001:db8:%x:%x", rand1, rand2);
-    std::string v6InterfaceAddrStr = StringPrintf("%s::%x:%x", v6PrefixStr.c_str(), rand2, rand1);
-    std::string nat64PrefixStr = StringPrintf("2001:db8:%x:%x::", rand2, rand1);
-
-    in_addr v4 = {inet_addr(kIPv4LocalAddr)};
-    in6_addr v6InterfaceAddr;
-    ASSERT_TRUE(inet_pton(AF_INET6, v6InterfaceAddrStr.c_str(), &v6InterfaceAddr));
-    in6_addr nat64Prefix;
-    ASSERT_TRUE(inet_pton(AF_INET6, nat64PrefixStr.c_str(), &nat64Prefix));
-
-    // Generate a boatload of random IIDs.
-    int onebits = 0;
-    uint64_t prev_iid = 0;
-    for (int i = 0; i < 100000; i++) {
-        in6_addr v6 = v6InterfaceAddr;
-        makeChecksumNeutral(&v6, v4, nat64Prefix);
-
-        // Check the generated IP address is in the same prefix as the interface IPv6 address.
-        EXPECT_EQ(0, memcmp(&v6, &v6InterfaceAddr, 8));
-
-        // Check that consecutive IIDs are not the same.
-        uint64_t iid = *(uint64_t*)(&v6.s6_addr[8]);
-        ASSERT_TRUE(iid != prev_iid)
-                << "Two consecutive random IIDs are the same: " << std::showbase << std::hex << iid
-                << "\n";
-        prev_iid = iid;
-
-        // Check that the IID is checksum-neutral with the NAT64 prefix and the
-        // local prefix.
-        uint16_t c1 = ip_checksum_finish(ip_checksum_add(0, &v4, sizeof(v4)));
-        uint16_t c2 = ip_checksum_finish(ip_checksum_add(0, &nat64Prefix, sizeof(nat64Prefix)) +
-                                         ip_checksum_add(0, &v6, sizeof(v6)));
-
-        if (c1 != c2) {
-            char v6Str[INET6_ADDRSTRLEN];
-            inet_ntop(AF_INET6, &v6, v6Str, sizeof(v6Str));
-            FAIL() << "Bad IID: " << v6Str << " not checksum-neutral with " << kIPv4LocalAddr
-                   << " and " << nat64PrefixStr.c_str() << std::showbase << std::hex
-                   << "\n  IPv4 checksum: " << c1 << "\n  IPv6 checksum: " << c2 << "\n";
-        }
-
-        // Check that IIDs are roughly random and use all the bits by counting the
-        // total number of bits set to 1 in a random sample of 100000 generated IIDs.
-        onebits += __builtin_popcountll(*(uint64_t*)&iid);
-    }
-    EXPECT_LE(3190000, onebits);
-    EXPECT_GE(3210000, onebits);
-}
-
-TEST_F(ClatdControllerTest, AddIptablesRule) {
-    setIptablesDropRule(true, "wlan0", "64:ff9b::", "2001:db8::1:2:3:4");
-    expectIptablesRestoreCommands((ExpectedIptablesCommands){
-            {V6,
-             "*raw\n"
-             "-A clat_raw_PREROUTING -i wlan0 -s 64:ff9b::/96 -d 2001:db8::1:2:3:4 -j DROP\n"
-             "COMMIT\n"}});
-}
-
-TEST_F(ClatdControllerTest, RemoveIptablesRule) {
-    setIptablesDropRule(false, "wlan0", "64:ff9b::", "2001:db8::a:b:c:d");
-    expectIptablesRestoreCommands((ExpectedIptablesCommands){
-            {V6,
-             "*raw\n"
-             "-D clat_raw_PREROUTING -i wlan0 -s 64:ff9b::/96 -d 2001:db8::a:b:c:d -j DROP\n"
-             "COMMIT\n"}});
-}
-
-}  // namespace net
-}  // namespace android
diff --git a/server/Controllers.cpp b/server/Controllers.cpp
index 1f2bac2..0df6b0e 100644
--- a/server/Controllers.cpp
+++ b/server/Controllers.cpp
@@ -74,9 +74,8 @@
 };
 
 static const std::vector<const char*> RAW_PREROUTING = {
-        ClatdController::LOCAL_RAW_PREROUTING,
-        BandwidthController::LOCAL_RAW_PREROUTING,
         IdletimerController::LOCAL_RAW_PREROUTING,
+        BandwidthController::LOCAL_RAW_PREROUTING,
         TetherController::LOCAL_RAW_PREROUTING,
 };
 
@@ -192,8 +191,7 @@
 }
 
 Controllers::Controllers()
-    : clatdCtrl(&netCtrl),
-      wakeupCtrl(
+    : wakeupCtrl(
               [this](const WakeupController::ReportArgs& args) {
                   const auto listener = eventReporter.getNetdEventListener();
                   if (listener == nullptr) {
@@ -279,21 +277,6 @@
     initIptablesRules();
     Stopwatch s;
 
-    clatdCtrl.init();
-    gLog.info("Initializing ClatdController: %" PRId64 "us", s.getTimeAndResetUs());
-
-    netdutils::Status tcStatus = trafficCtrl.start();
-    if (!isOk(tcStatus)) {
-        gLog.error("Failed to start trafficcontroller: (%s)", toString(tcStatus).c_str());
-        gLog.error("CRITICAL: sleeping 60 seconds, netd exiting with failure, crash loop likely!");
-        // The expected reason we get here is a major kernel or other code bug, as such
-        // the probability that things will succeed on restart of netd is pretty small.
-        // So, let's wait a minute to at least try to limit the log spam a little bit.
-        sleep(60);
-        exit(1);
-    }
-    gLog.info("Initializing traffic control: %" PRId64 "us", s.getTimeAndResetUs());
-
     bandwidthCtrl.enableBandwidthControl();
     gLog.info("Enabling bandwidth control: %" PRId64 "us", s.getTimeAndResetUs());
 
diff --git a/server/Controllers.h b/server/Controllers.h
index fbd9bf1..8b51ddf 100644
--- a/server/Controllers.h
+++ b/server/Controllers.h
@@ -18,7 +18,6 @@
 #define _CONTROLLERS_H__
 
 #include "BandwidthController.h"
-#include "ClatdController.h"
 #include "EventReporter.h"
 #include "FirewallController.h"
 #include "IdletimerController.h"
@@ -29,7 +28,6 @@
 #include "StrictController.h"
 #include "TcpSocketMonitor.h"
 #include "TetherController.h"
-#include "TrafficController.h"
 #include "WakeupController.h"
 #include "XfrmController.h"
 #include "netdutils/Log.h"
@@ -47,13 +45,11 @@
     BandwidthController bandwidthCtrl;
     IdletimerController idletimerCtrl;
     FirewallController firewallCtrl;
-    ClatdController clatdCtrl;
     StrictController strictCtrl;
     EventReporter eventReporter;
     IptablesRestoreController iptablesRestoreCtrl;
     WakeupController wakeupCtrl;
     XfrmController xfrmCtrl;
-    TrafficController trafficCtrl;
     TcpSocketMonitor tcpSocketMonitor;
 
     void init();
diff --git a/server/ControllersTest.cpp b/server/ControllersTest.cpp
index ebaa38f..9033a1d 100644
--- a/server/ControllersTest.cpp
+++ b/server/ControllersTest.cpp
@@ -96,12 +96,10 @@
              "*raw\n"
              ":PREROUTING -\n"
              "-F PREROUTING\n"
-             ":clat_raw_PREROUTING -\n"
-             "-A PREROUTING -j clat_raw_PREROUTING\n"
-             ":bw_raw_PREROUTING -\n"
-             "-A PREROUTING -j bw_raw_PREROUTING\n"
              ":idletimer_raw_PREROUTING -\n"
              "-A PREROUTING -j idletimer_raw_PREROUTING\n"
+             ":bw_raw_PREROUTING -\n"
+             "-A PREROUTING -j bw_raw_PREROUTING\n"
              ":tetherctrl_raw_PREROUTING -\n"
              "-A PREROUTING -j tetherctrl_raw_PREROUTING\n"
              "COMMIT\n"},
diff --git a/server/FirewallController.cpp b/server/FirewallController.cpp
index 35fd1e2..b3c6b02 100644
--- a/server/FirewallController.cpp
+++ b/server/FirewallController.cpp
@@ -37,23 +37,8 @@
 #include "bpf/BpfUtils.h"
 
 using android::base::Join;
-using android::base::ReadFileToString;
-using android::base::Split;
 using android::base::StringAppendF;
 using android::base::StringPrintf;
-using android::net::gCtls;
-
-namespace {
-
-// Default maximum valid uid in a normal root user namespace. The maximum valid uid is used in
-// rules that exclude all possible UIDs in the namespace in order to match packets that have
-// no socket associated with them.
-constexpr const uid_t kDefaultMaximumUid = UID_MAX - 1;  // UID_MAX defined as UINT_MAX
-
-// Proc file containing the uid mapping for the user namespace of the current process.
-const char kUidMapProcFile[] = "/proc/self/uid_map";
-
-}  // namespace
 
 namespace android {
 namespace net {
@@ -66,11 +51,6 @@
 const char* FirewallController::LOCAL_OUTPUT = "fw_OUTPUT";
 const char* FirewallController::LOCAL_FORWARD = "fw_FORWARD";
 
-const char* FirewallController::LOCAL_DOZABLE = "fw_dozable";
-const char* FirewallController::LOCAL_STANDBY = "fw_standby";
-const char* FirewallController::LOCAL_POWERSAVE = "fw_powersave";
-const char* FirewallController::LOCAL_RESTRICTED = "fw_restricted";
-
 // ICMPv6 types that are required for any form of IPv6 connectivity to work. Note that because the
 // fw_dozable chain is called from both INPUT and OUTPUT, this includes both packets that we need
 // to be able to send (e.g., RS, NS), and packets that we need to receive (e.g., RA, NA).
@@ -83,25 +63,14 @@
     "redirect",
 };
 
-FirewallController::FirewallController(void) : mMaxUid(discoverMaximumValidUid(kUidMapProcFile)) {
+FirewallController::FirewallController(void) {
     // If no rules are set, it's in DENYLIST mode
     mFirewallType = DENYLIST;
     mIfaceRules = {};
 }
 
 int FirewallController::setupIptablesHooks(void) {
-    int res = flushRules();
-
-    // mUseBpfOwnerMatch should be removed, but it is still depended upon by test code.
-    mUseBpfOwnerMatch = true;
-    if (mUseBpfOwnerMatch) {
-        return res;
-    }
-    res |= createChain(LOCAL_DOZABLE, getFirewallType(DOZABLE));
-    res |= createChain(LOCAL_STANDBY, getFirewallType(STANDBY));
-    res |= createChain(LOCAL_POWERSAVE, getFirewallType(POWERSAVE));
-    res |= createChain(LOCAL_RESTRICTED, getFirewallType(RESTRICTED));
-    return res;
+    return flushRules();
 }
 
 int FirewallController::setFirewallType(FirewallType ftype) {
@@ -145,39 +114,6 @@
     return flushRules();
 }
 
-int FirewallController::enableChildChains(ChildChain chain, bool enable) {
-    int res = 0;
-    const char* name;
-    switch(chain) {
-        case DOZABLE:
-            name = LOCAL_DOZABLE;
-            break;
-        case STANDBY:
-            name = LOCAL_STANDBY;
-            break;
-        case POWERSAVE:
-            name = LOCAL_POWERSAVE;
-            break;
-        case RESTRICTED:
-            name = LOCAL_RESTRICTED;
-            break;
-        default:
-            return res;
-    }
-
-    if (mUseBpfOwnerMatch) {
-        return gCtls->trafficCtrl.toggleUidOwnerMap(chain, enable);
-    }
-
-    std::string command = "*filter\n";
-    for (const char *parent : { LOCAL_INPUT, LOCAL_OUTPUT }) {
-        StringAppendF(&command, "%s %s -j %s\n", (enable ? "-A" : "-D"), parent, name);
-    }
-    StringAppendF(&command, "COMMIT\n");
-
-    return execIptablesRestore(V4V6, command);
-}
-
 int FirewallController::isFirewallEnabled(void) {
     // TODO: verify that rules are still in place near top
     return -1;
@@ -217,77 +153,6 @@
     return (execIptablesRestore(V4V6, command) == 0) ? 0 : -EREMOTEIO;
 }
 
-FirewallType FirewallController::getFirewallType(ChildChain chain) {
-    switch(chain) {
-        case DOZABLE:
-            return ALLOWLIST;
-        case STANDBY:
-            return DENYLIST;
-        case POWERSAVE:
-            return ALLOWLIST;
-        case RESTRICTED:
-            return ALLOWLIST;
-        case NONE:
-            return mFirewallType;
-        default:
-            return DENYLIST;
-    }
-}
-
-int FirewallController::setUidRule(ChildChain chain, int uid, FirewallRule rule) {
-    const char* op;
-    const char* target;
-    FirewallType firewallType = getFirewallType(chain);
-    if (firewallType == ALLOWLIST) {
-        target = "RETURN";
-        // When adding, insert RETURN rules at the front, before the catch-all DROP at the end.
-        op = (rule == ALLOW)? "-I" : "-D";
-    } else {  // DENYLIST mode
-        target = "DROP";
-        // When adding, append DROP rules at the end, after the RETURN rule that matches TCP RSTs.
-        op = (rule == DENY)? "-A" : "-D";
-    }
-
-    std::vector<std::string> chainNames;
-    switch(chain) {
-        case DOZABLE:
-            chainNames = {LOCAL_DOZABLE};
-            break;
-        case STANDBY:
-            chainNames = {LOCAL_STANDBY};
-            break;
-        case POWERSAVE:
-            chainNames = {LOCAL_POWERSAVE};
-            break;
-        case RESTRICTED:
-            chainNames = {LOCAL_RESTRICTED};
-            break;
-        case NONE:
-            chainNames = {LOCAL_INPUT, LOCAL_OUTPUT};
-            break;
-        default:
-            ALOGW("Unknown child chain: %d", chain);
-            return -EINVAL;
-    }
-    if (mUseBpfOwnerMatch) {
-        return gCtls->trafficCtrl.changeUidOwnerRule(chain, uid, rule, firewallType);
-    }
-
-    std::string command = "*filter\n";
-    for (const std::string& chainName : chainNames) {
-        StringAppendF(&command, "%s %s -m owner --uid-owner %d -j %s\n",
-                      op, chainName.c_str(), uid, target);
-    }
-    StringAppendF(&command, "COMMIT\n");
-
-    return (execIptablesRestore(V4V6, command) == 0) ? 0 : -EREMOTEIO;
-}
-
-int FirewallController::createChain(const char* chain, FirewallType type) {
-    static const std::vector<int32_t> NO_UIDS;
-    return replaceUidChain(chain, type == ALLOWLIST, NO_UIDS);
-}
-
 /* static */
 std::string FirewallController::makeCriticalCommands(IptablesTarget target, const char* chainName) {
     // Allow ICMPv6 packets necessary to make IPv6 connectivity work. http://b/23158230 .
@@ -301,112 +166,5 @@
     return commands;
 }
 
-std::string FirewallController::makeUidRules(IptablesTarget target, const char* name,
-                                             bool isAllowlist, const std::vector<int32_t>& uids) {
-    std::string commands;
-    StringAppendF(&commands, "*filter\n:%s -\n", name);
-
-    // Allowlist chains have UIDs at the beginning, and new UIDs are added with '-I'.
-    if (isAllowlist) {
-        for (auto uid : uids) {
-            StringAppendF(&commands, "-A %s -m owner --uid-owner %d -j RETURN\n", name, uid);
-        }
-
-        // Always allowlist system UIDs.
-        StringAppendF(&commands,
-                "-A %s -m owner --uid-owner %d-%d -j RETURN\n", name, 0, MAX_SYSTEM_UID);
-
-        // This rule inverts the match for all UIDs; ie, if there is no UID match here,
-        // there is no socket to be found
-        StringAppendF(&commands,
-                "-A %s -m owner ! --uid-owner %d-%u -j RETURN\n", name, 0, mMaxUid);
-
-        // Always allowlist traffic with protocol ESP, or no known socket - required for IPSec
-        StringAppendF(&commands, "-A %s -p esp -j RETURN\n", name);
-    }
-
-    // Always allow networking on loopback.
-    StringAppendF(&commands, "-A %s -i lo -j RETURN\n", name);
-    StringAppendF(&commands, "-A %s -o lo -j RETURN\n", name);
-
-    // Allow TCP RSTs so we can cleanly close TCP connections of apps that no longer have network
-    // access. Both incoming and outgoing RSTs are allowed.
-    StringAppendF(&commands, "-A %s -p tcp --tcp-flags RST RST -j RETURN\n", name);
-
-    if (isAllowlist) {
-        commands.append(makeCriticalCommands(target, name));
-    }
-
-    // Denylist chains have UIDs at the end, and new UIDs are added with '-A'.
-    if (!isAllowlist) {
-        for (auto uid : uids) {
-            StringAppendF(&commands, "-A %s -m owner --uid-owner %d -j DROP\n", name, uid);
-        }
-    }
-
-    // If it's an allowlist chain, add a default DROP at the end. This is not necessary for a
-    // denylist chain, because all user-defined chains implicitly RETURN at the end.
-    if (isAllowlist) {
-        StringAppendF(&commands, "-A %s -j DROP\n", name);
-    }
-
-    StringAppendF(&commands, "COMMIT\n");
-
-    return commands;
-}
-
-int FirewallController::replaceUidChain(const std::string& name, bool isAllowlist,
-                                        const std::vector<int32_t>& uids) {
-    if (mUseBpfOwnerMatch) {
-        return gCtls->trafficCtrl.replaceUidOwnerMap(name, isAllowlist, uids);
-    }
-    std::string commands4 = makeUidRules(V4, name.c_str(), isAllowlist, uids);
-    std::string commands6 = makeUidRules(V6, name.c_str(), isAllowlist, uids);
-    return execIptablesRestore(V4, commands4.c_str()) | execIptablesRestore(V6, commands6.c_str());
-}
-
-/* static */
-uid_t FirewallController::discoverMaximumValidUid(const std::string& fileName) {
-    std::string content;
-    if (!ReadFileToString(fileName, &content, false)) {
-        // /proc/self/uid_map only exists if a uid mapping has been set.
-        ALOGD("Could not read %s, max uid defaulting to %u", fileName.c_str(), kDefaultMaximumUid);
-        return kDefaultMaximumUid;
-    }
-
-    std::vector<std::string> lines = Split(content, "\n");
-    if (lines.empty()) {
-        ALOGD("%s was empty, max uid defaulting to %u", fileName.c_str(), kDefaultMaximumUid);
-        return kDefaultMaximumUid;
-    }
-
-    uint32_t maxUid = 0;
-    for (const auto& line : lines) {
-        if (line.empty()) {
-            continue;
-        }
-
-        // Choose the end of the largest range found in the file.
-        uint32_t start;
-        uint32_t ignored;
-        uint32_t rangeLength;
-        int items = sscanf(line.c_str(), "%u %u %u", &start, &ignored, &rangeLength);
-        if (items != 3) {
-            // uid_map lines must have 3 items, see the man page of 'user_namespaces' for details.
-            ALOGD("Format of %s unrecognized, max uid defaulting to %u", fileName.c_str(),
-                  kDefaultMaximumUid);
-            return kDefaultMaximumUid;
-        }
-        maxUid = std::max(maxUid, start + rangeLength - 1);
-    }
-
-    if (maxUid == 0) {
-        ALOGD("No max uid found, max uid defaulting to %u", kDefaultMaximumUid);
-        return kDefaultMaximumUid;
-    }
-
-    return maxUid;
-}
-
 }  // namespace net
 }  // namespace android
diff --git a/server/FirewallController.h b/server/FirewallController.h
index 6de1b45..6d6f48f 100644
--- a/server/FirewallController.h
+++ b/server/FirewallController.h
@@ -23,30 +23,12 @@
 #include <string>
 #include <vector>
 
-#include "android/net/INetd.h"
-
 #include "NetdConstants.h"
 #include "bpf/BpfUtils.h"
 
 namespace android {
 namespace net {
 
-enum FirewallRule { ALLOW = INetd::FIREWALL_RULE_ALLOW, DENY = INetd::FIREWALL_RULE_DENY };
-
-// ALLOWLIST means the firewall denies all by default, uids must be explicitly ALLOWed
-// DENYLIST means the firewall allows all by default, uids must be explicitly DENYed
-
-enum FirewallType { ALLOWLIST = INetd::FIREWALL_ALLOWLIST, DENYLIST = INetd::FIREWALL_DENYLIST };
-
-enum ChildChain {
-    NONE = INetd::FIREWALL_CHAIN_NONE,
-    DOZABLE = INetd::FIREWALL_CHAIN_DOZABLE,
-    STANDBY = INetd::FIREWALL_CHAIN_STANDBY,
-    POWERSAVE = INetd::FIREWALL_CHAIN_POWERSAVE,
-    RESTRICTED = INetd::FIREWALL_CHAIN_RESTRICTED,
-    INVALID_CHAIN
-};
-
 /*
  * Simple firewall that drops all packets except those matching explicitly
  * defined ALLOW rules.
@@ -72,10 +54,7 @@
 
   int enableChildChains(ChildChain, bool);
 
-  int replaceUidChain(const std::string&, bool, const std::vector<int32_t>&);
-
   static std::string makeCriticalCommands(IptablesTarget target, const char* chainName);
-  static uid_t discoverMaximumValidUid(const std::string& fileName);
 
   static const char* TABLE;
 
@@ -83,36 +62,18 @@
   static const char* LOCAL_OUTPUT;
   static const char* LOCAL_FORWARD;
 
-  static const char* LOCAL_DOZABLE;
-  static const char* LOCAL_STANDBY;
-  static const char* LOCAL_POWERSAVE;
-  static const char* LOCAL_RESTRICTED;
-
   static const char* ICMPV6_TYPES[];
 
   std::mutex lock;
 
 protected:
   friend class FirewallControllerTest;
-  std::string makeUidRules(IptablesTarget target, const char* name, bool isAllowlist,
-                           const std::vector<int32_t>& uids);
   static int (*execIptablesRestore)(IptablesTarget target, const std::string& commands);
 
 private:
-  // Netd supports two cases, in both of which mMaxUid that derives from the uid mapping is const:
-  //  - netd runs in a root namespace which contains all UIDs.
-  //  - netd runs in a user namespace where the uid mapping is written once before netd starts.
-  //    In that case, an attempt to write more than once to a uid_map file in a user namespace
-  //    fails with EPERM. Netd can therefore assumes the max valid uid to be const.
-  const uid_t mMaxUid;
   FirewallType mFirewallType;
-  bool mUseBpfOwnerMatch;
   std::set<std::string> mIfaceRules;
   int flushRules(void);
-  int attachChain(const char*, const char*);
-  int detachChain(const char*, const char*);
-  int createChain(const char*, FirewallType);
-  FirewallType getFirewallType(ChildChain);
 };
 
 }  // namespace net
diff --git a/server/FirewallControllerTest.cpp b/server/FirewallControllerTest.cpp
index 1f199af..a7aee47 100644
--- a/server/FirewallControllerTest.cpp
+++ b/server/FirewallControllerTest.cpp
@@ -22,16 +22,9 @@
 
 #include <gtest/gtest.h>
 
-#include <android-base/file.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-
 #include "FirewallController.h"
 #include "IptablesBaseTest.h"
 
-using android::base::Join;
-using android::base::WriteStringToFile;
-
 namespace android {
 namespace net {
 
@@ -39,192 +32,10 @@
 protected:
     FirewallControllerTest() {
         FirewallController::execIptablesRestore = fakeExecIptablesRestore;
-        // This unit test currently doesn't cover the eBPF owner match case so
-        // we have to manually turn eBPF support off.
-        // TODO: find a way to unit test the eBPF code path.
-        mFw.mUseBpfOwnerMatch = false;
     }
     FirewallController mFw;
-
-    std::string makeUidRules(IptablesTarget a, const char* b, bool c,
-                             const std::vector<int32_t>& d) {
-        return mFw.makeUidRules(a, b, c, d);
-    }
-
-    int createChain(const char* a, FirewallType b) {
-        return mFw.createChain(a, b);
-    }
 };
 
-TEST_F(FirewallControllerTest, TestCreateAllowlistChain) {
-    std::vector<std::string> expectedRestore4 = {
-            "*filter",
-            ":fw_allowlist -",
-            "-A fw_allowlist -m owner --uid-owner 0-9999 -j RETURN",
-            "-A fw_allowlist -m owner ! --uid-owner 0-4294967294 -j RETURN",
-            "-A fw_allowlist -p esp -j RETURN",
-            "-A fw_allowlist -i lo -j RETURN",
-            "-A fw_allowlist -o lo -j RETURN",
-            "-A fw_allowlist -p tcp --tcp-flags RST RST -j RETURN",
-            "-A fw_allowlist -j DROP",
-            "COMMIT\n"};
-    std::vector<std::string> expectedRestore6 = {
-            "*filter",
-            ":fw_allowlist -",
-            "-A fw_allowlist -m owner --uid-owner 0-9999 -j RETURN",
-            "-A fw_allowlist -m owner ! --uid-owner 0-4294967294 -j RETURN",
-            "-A fw_allowlist -p esp -j RETURN",
-            "-A fw_allowlist -i lo -j RETURN",
-            "-A fw_allowlist -o lo -j RETURN",
-            "-A fw_allowlist -p tcp --tcp-flags RST RST -j RETURN",
-            "-A fw_allowlist -p icmpv6 --icmpv6-type packet-too-big -j RETURN",
-            "-A fw_allowlist -p icmpv6 --icmpv6-type router-solicitation -j RETURN",
-            "-A fw_allowlist -p icmpv6 --icmpv6-type router-advertisement -j RETURN",
-            "-A fw_allowlist -p icmpv6 --icmpv6-type neighbour-solicitation -j RETURN",
-            "-A fw_allowlist -p icmpv6 --icmpv6-type neighbour-advertisement -j RETURN",
-            "-A fw_allowlist -p icmpv6 --icmpv6-type redirect -j RETURN",
-            "-A fw_allowlist -j DROP",
-            "COMMIT\n"};
-    std::vector<std::pair<IptablesTarget, std::string>> expectedRestoreCommands = {
-            {V4, Join(expectedRestore4, '\n')},
-            {V6, Join(expectedRestore6, '\n')},
-    };
-
-    createChain("fw_allowlist", ALLOWLIST);
-    expectIptablesRestoreCommands(expectedRestoreCommands);
-}
-
-TEST_F(FirewallControllerTest, TestCreateDenylistChain) {
-    std::vector<std::string> expectedRestore = {
-            "*filter",
-            ":fw_denylist -",
-            "-A fw_denylist -i lo -j RETURN",
-            "-A fw_denylist -o lo -j RETURN",
-            "-A fw_denylist -p tcp --tcp-flags RST RST -j RETURN",
-            "COMMIT\n"};
-    std::vector<std::pair<IptablesTarget, std::string>> expectedRestoreCommands = {
-            {V4, Join(expectedRestore, '\n')},
-            {V6, Join(expectedRestore, '\n')},
-    };
-
-    createChain("fw_denylist", DENYLIST);
-    expectIptablesRestoreCommands(expectedRestoreCommands);
-}
-
-TEST_F(FirewallControllerTest, TestSetStandbyRule) {
-    ExpectedIptablesCommands expected = {
-        { V4V6, "*filter\n-D fw_standby -m owner --uid-owner 12345 -j DROP\nCOMMIT\n" }
-    };
-    mFw.setUidRule(STANDBY, 12345, ALLOW);
-    expectIptablesRestoreCommands(expected);
-
-    expected = {
-        { V4V6, "*filter\n-A fw_standby -m owner --uid-owner 12345 -j DROP\nCOMMIT\n" }
-    };
-    mFw.setUidRule(STANDBY, 12345, DENY);
-    expectIptablesRestoreCommands(expected);
-}
-
-TEST_F(FirewallControllerTest, TestSetDozeRule) {
-    ExpectedIptablesCommands expected = {
-        { V4V6, "*filter\n-I fw_dozable -m owner --uid-owner 54321 -j RETURN\nCOMMIT\n" }
-    };
-    mFw.setUidRule(DOZABLE, 54321, ALLOW);
-    expectIptablesRestoreCommands(expected);
-
-    expected = {
-        { V4V6, "*filter\n-D fw_dozable -m owner --uid-owner 54321 -j RETURN\nCOMMIT\n" }
-    };
-    mFw.setUidRule(DOZABLE, 54321, DENY);
-    expectIptablesRestoreCommands(expected);
-}
-
-TEST_F(FirewallControllerTest, TestSetFirewallRule) {
-    ExpectedIptablesCommands expected = {
-        { V4V6, "*filter\n"
-                "-A fw_INPUT -m owner --uid-owner 54321 -j DROP\n"
-                "-A fw_OUTPUT -m owner --uid-owner 54321 -j DROP\n"
-                "COMMIT\n" }
-    };
-    mFw.setUidRule(NONE, 54321, DENY);
-    expectIptablesRestoreCommands(expected);
-
-    expected = {
-        { V4V6, "*filter\n"
-                "-D fw_INPUT -m owner --uid-owner 54321 -j DROP\n"
-                "-D fw_OUTPUT -m owner --uid-owner 54321 -j DROP\n"
-                "COMMIT\n" }
-    };
-    mFw.setUidRule(NONE, 54321, ALLOW);
-    expectIptablesRestoreCommands(expected);
-}
-
-TEST_F(FirewallControllerTest, TestReplaceAllowlistUidRule) {
-    std::string expected =
-            "*filter\n"
-            ":FW_allowchain -\n"
-            "-A FW_allowchain -m owner --uid-owner 10023 -j RETURN\n"
-            "-A FW_allowchain -m owner --uid-owner 10059 -j RETURN\n"
-            "-A FW_allowchain -m owner --uid-owner 10124 -j RETURN\n"
-            "-A FW_allowchain -m owner --uid-owner 10111 -j RETURN\n"
-            "-A FW_allowchain -m owner --uid-owner 110122 -j RETURN\n"
-            "-A FW_allowchain -m owner --uid-owner 210153 -j RETURN\n"
-            "-A FW_allowchain -m owner --uid-owner 210024 -j RETURN\n"
-            "-A FW_allowchain -m owner --uid-owner 0-9999 -j RETURN\n"
-            "-A FW_allowchain -m owner ! --uid-owner 0-4294967294 -j RETURN\n"
-            "-A FW_allowchain -p esp -j RETURN\n"
-            "-A FW_allowchain -i lo -j RETURN\n"
-            "-A FW_allowchain -o lo -j RETURN\n"
-            "-A FW_allowchain -p tcp --tcp-flags RST RST -j RETURN\n"
-            "-A FW_allowchain -p icmpv6 --icmpv6-type packet-too-big -j RETURN\n"
-            "-A FW_allowchain -p icmpv6 --icmpv6-type router-solicitation -j RETURN\n"
-            "-A FW_allowchain -p icmpv6 --icmpv6-type router-advertisement -j RETURN\n"
-            "-A FW_allowchain -p icmpv6 --icmpv6-type neighbour-solicitation -j RETURN\n"
-            "-A FW_allowchain -p icmpv6 --icmpv6-type neighbour-advertisement -j RETURN\n"
-            "-A FW_allowchain -p icmpv6 --icmpv6-type redirect -j RETURN\n"
-            "-A FW_allowchain -j DROP\n"
-            "COMMIT\n";
-
-    std::vector<int32_t> uids = { 10023, 10059, 10124, 10111, 110122, 210153, 210024 };
-    EXPECT_EQ(expected, makeUidRules(V6, "FW_allowchain", true, uids));
-}
-
-TEST_F(FirewallControllerTest, TestReplaceDenylistUidRule) {
-    std::string expected =
-            "*filter\n"
-            ":FW_denychain -\n"
-            "-A FW_denychain -i lo -j RETURN\n"
-            "-A FW_denychain -o lo -j RETURN\n"
-            "-A FW_denychain -p tcp --tcp-flags RST RST -j RETURN\n"
-            "-A FW_denychain -m owner --uid-owner 10023 -j DROP\n"
-            "-A FW_denychain -m owner --uid-owner 10059 -j DROP\n"
-            "-A FW_denychain -m owner --uid-owner 10124 -j DROP\n"
-            "COMMIT\n";
-
-    std::vector<int32_t> uids = { 10023, 10059, 10124 };
-    EXPECT_EQ(expected, makeUidRules(V4, "FW_denychain", false, uids));
-}
-
-TEST_F(FirewallControllerTest, TestEnableChildChains) {
-    std::vector<std::string> expected = {
-        "*filter\n"
-        "-A fw_INPUT -j fw_dozable\n"
-        "-A fw_OUTPUT -j fw_dozable\n"
-        "COMMIT\n"
-    };
-    EXPECT_EQ(0, mFw.enableChildChains(DOZABLE, true));
-    expectIptablesRestoreCommands(expected);
-
-    expected = {
-        "*filter\n"
-        "-D fw_INPUT -j fw_powersave\n"
-        "-D fw_OUTPUT -j fw_powersave\n"
-        "COMMIT\n"
-    };
-    EXPECT_EQ(0, mFw.enableChildChains(POWERSAVE, false));
-    expectIptablesRestoreCommands(expected);
-}
-
 TEST_F(FirewallControllerTest, TestFirewall) {
     std::vector<std::string> enableCommands = {
             "*filter\n"
@@ -298,52 +109,5 @@
     expectIptablesRestoreCommands(noCommands);
 }
 
-TEST_F(FirewallControllerTest, TestDiscoverMaximumValidUid) {
-    struct {
-        const std::string description;
-        const std::string content;
-        const uint32_t expected;
-    } testCases[] = {
-            {
-                    .description = "root namespace case",
-                    .content = "         0          0 4294967295",
-                    .expected = 4294967294,
-            },
-            {
-                    .description = "container namespace case",
-                    .content = "         0     655360       5000\n"
-                               "      5000        600         50\n"
-                               "      5050     660410    1994950\n",
-                    .expected = 1999999,
-            },
-            {
-                    .description = "garbage content case",
-                    .content = "garbage",
-                    .expected = 4294967294,
-            },
-            {
-                    .description = "no content case",
-                    .content = "",
-                    .expected = 4294967294,
-            },
-    };
-
-    const std::string tempFile = "/data/local/tmp/fake_uid_mapping";
-
-    for (const auto& test : testCases) {
-        EXPECT_TRUE(WriteStringToFile(test.content, tempFile, false));
-        uint32_t got = FirewallController::discoverMaximumValidUid(tempFile);
-        EXPECT_EQ(0, remove(tempFile.c_str()));
-        if (got != test.expected) {
-            FAIL() << test.description << ":\n"
-                   << test.content << "\ngot " << got << ", but expected " << test.expected;
-        }
-    }
-
-    // Also check when the file is not defined
-    EXPECT_NE(0, access(tempFile.c_str(), F_OK));
-    EXPECT_EQ(4294967294, FirewallController::discoverMaximumValidUid(tempFile));
-}
-
 }  // namespace net
 }  // namespace android
diff --git a/server/FwmarkServer.cpp b/server/FwmarkServer.cpp
index 60981e5..1ae8ed3 100644
--- a/server/FwmarkServer.cpp
+++ b/server/FwmarkServer.cpp
@@ -32,9 +32,9 @@
 #include "FwmarkCommand.h"
 #include "NetdConstants.h"
 #include "NetworkController.h"
-#include "TrafficController.h"
 
-using android::String16;
+#include "NetdUpdatablePublic.h"
+
 using android::base::ReceiveFileDescriptorVector;
 using android::base::unique_fd;
 using android::net::metrics::INetdEventListener;
@@ -62,12 +62,10 @@
     return ret;
 }
 
-FwmarkServer::FwmarkServer(NetworkController* networkController, EventReporter* eventReporter,
-                           TrafficController* trafficCtrl)
+FwmarkServer::FwmarkServer(NetworkController* networkController, EventReporter* eventReporter)
     : SocketListener(SOCKET_NAME, true),
       mNetworkController(networkController),
       mEventReporter(eventReporter),
-      mTrafficCtrl(trafficCtrl),
       mRedirectSocketCalls(
               android::base::GetBoolProperty("ro.vendor.redirect_socket_calls", false)) {}
 
@@ -134,14 +132,6 @@
         return mNetworkController->checkUserNetworkAccess(command.uid, command.netId);
     }
 
-    if (command.cmdId == FwmarkCommand::SET_COUNTERSET) {
-        return mTrafficCtrl->setCounterSet(command.trafficCtrlInfo, command.uid, client->getUid());
-    }
-
-    if (command.cmdId == FwmarkCommand::DELETE_TAGDATA) {
-        return mTrafficCtrl->deleteTagData(command.trafficCtrlInfo, command.uid, client->getUid());
-    }
-
     if (received_fds.size() != 1) {
         LOG(ERROR) << "FwmarkServer received " << received_fds.size() << " fds from client?";
         return -EBADF;
@@ -309,13 +299,13 @@
             if (static_cast<int>(command.uid) == -1) {
                 command.uid = client->getUid();
             }
-            return mTrafficCtrl->tagSocket(*socketFd, command.trafficCtrlInfo, command.uid,
-                                           client->getUid());
+            return libnetd_updatable_tagSocket(*socketFd, command.trafficCtrlInfo, command.uid,
+                                               client->getUid());
         }
 
         case FwmarkCommand::UNTAG_SOCKET: {
             // Any process can untag a socket it has an fd for.
-            return mTrafficCtrl->untagSocket(*socketFd);
+            return libnetd_updatable_untagSocket(*socketFd);
         }
 
         default: {
diff --git a/server/FwmarkServer.h b/server/FwmarkServer.h
index 32d5791..b013582 100644
--- a/server/FwmarkServer.h
+++ b/server/FwmarkServer.h
@@ -24,12 +24,10 @@
 namespace net {
 
 class NetworkController;
-class TrafficController;
 
 class FwmarkServer : public SocketListener {
 public:
-  explicit FwmarkServer(NetworkController* networkController, EventReporter* eventReporter,
-                        TrafficController* trafficCtrl);
+  explicit FwmarkServer(NetworkController* networkController, EventReporter* eventReporter);
 
   static constexpr const char* SOCKET_NAME = "fwmarkd";
 
@@ -42,7 +40,6 @@
 
     NetworkController* const mNetworkController;
     EventReporter* mEventReporter;
-    TrafficController* mTrafficCtrl;
     bool mRedirectSocketCalls;
 };
 
diff --git a/server/InterfaceController.cpp b/server/InterfaceController.cpp
index 7504fb9..99d85fa 100644
--- a/server/InterfaceController.cpp
+++ b/server/InterfaceController.cpp
@@ -44,8 +44,6 @@
 using android::base::StringPrintf;
 using android::base::Trim;
 using android::base::WriteStringToFile;
-using android::net::INetd;
-using android::net::RouteController;
 using android::netdutils::isOk;
 using android::netdutils::makeSlice;
 using android::netdutils::sSyscalls;
@@ -416,37 +414,6 @@
     setOnAllInterfaces(ipv6_proc_path, "use_optimistic", value);
 }
 
-StatusOr<std::vector<std::string>> InterfaceController::getIfaceNames() {
-    std::vector<std::string> ifaceNames;
-    DIR* d;
-    struct dirent* de;
-
-    if (!(d = opendir("/sys/class/net"))) {
-        return statusFromErrno(errno, "Cannot open iface directory");
-    }
-    while ((de = readdir(d))) {
-        if ((de->d_type != DT_DIR) && (de->d_type != DT_LNK)) continue;
-        if (de->d_name[0] == '.') continue;
-        ifaceNames.push_back(std::string(de->d_name));
-    }
-    closedir(d);
-    return ifaceNames;
-}
-
-StatusOr<std::map<std::string, uint32_t>> InterfaceController::getIfaceList() {
-    std::map<std::string, uint32_t> ifacePairs;
-
-    ASSIGN_OR_RETURN(auto ifaceNames, getIfaceNames());
-
-    for (const auto& name : ifaceNames) {
-        uint32_t ifaceIndex = if_nametoindex(name.c_str());
-        if (ifaceIndex) {
-            ifacePairs.insert(std::pair<std::string, uint32_t>(name, ifaceIndex));
-        }
-    }
-    return ifacePairs;
-}
-
 namespace {
 
 std::string hwAddrToStr(unsigned char* hwaddr) {
diff --git a/server/InterfaceController.h b/server/InterfaceController.h
index e21c75d..e9dce01 100644
--- a/server/InterfaceController.h
+++ b/server/InterfaceController.h
@@ -59,9 +59,6 @@
     static int setParameter(const char* family, const char* which, const char* ifName,
                             const char* parameter, const char* value);
 
-    static android::netdutils::StatusOr<std::vector<std::string>> getIfaceNames();
-    static android::netdutils::StatusOr<std::map<std::string, uint32_t>> getIfaceList();
-
     static std::mutex mutex;
 
   private:
diff --git a/server/InterfaceControllerTest.cpp b/server/InterfaceControllerTest.cpp
index 78d507f..006018d 100644
--- a/server/InterfaceControllerTest.cpp
+++ b/server/InterfaceControllerTest.cpp
@@ -22,6 +22,7 @@
 #include <gtest/gtest.h>
 
 #include <netdutils/MockSyscalls.h>
+#include <netdutils/Utils.h>
 
 #include "InterfaceController.h"
 
@@ -36,14 +37,16 @@
 namespace {
 
 using netdutils::Fd;
+using netdutils::getIfaceList;
+using netdutils::getIfaceNames;
+using netdutils::makeSlice;
 using netdutils::ScopedMockSyscalls;
 using netdutils::Slice;
 using netdutils::Status;
+using netdutils::statusFromErrno;
 using netdutils::StatusOr;
 using netdutils::UniqueFd;
-using netdutils::makeSlice;
 using netdutils::status::ok;
-using netdutils::statusFromErrno;
 
 constexpr Fd kDevRandomFd(777);
 constexpr Fd kStableSecretFd(9999);
@@ -179,7 +182,7 @@
 class GetIfaceListTest : public testing::Test {};
 
 TEST_F(GetIfaceListTest, IfaceNames) {
-    StatusOr<std::vector<std::string>> ifaceNames = InterfaceController::getIfaceNames();
+    StatusOr<std::vector<std::string>> ifaceNames = getIfaceNames();
     EXPECT_EQ(ok, ifaceNames.status());
     struct ifaddrs *ifaddr, *ifa;
     EXPECT_EQ(0, getifaddrs(&ifaddr));
@@ -192,7 +195,7 @@
 }
 
 TEST_F(GetIfaceListTest, IfaceExist) {
-    StatusOr<std::map<std::string, uint32_t>> ifaceMap = InterfaceController::getIfaceList();
+    StatusOr<std::map<std::string, uint32_t>> ifaceMap = getIfaceList();
     EXPECT_EQ(ok, ifaceMap.status());
     struct ifaddrs *ifaddr, *ifa;
     EXPECT_EQ(0, getifaddrs(&ifaddr));
diff --git a/server/IptablesBaseTest.cpp b/server/IptablesBaseTest.cpp
index b3748cd..ef4d743 100644
--- a/server/IptablesBaseTest.cpp
+++ b/server/IptablesBaseTest.cpp
@@ -24,10 +24,10 @@
 
 #include <android-base/stringprintf.h>
 
+#define LOG_TAG "IptablesBaseTest"
 #include "IptablesBaseTest.h"
 #include "NetdConstants.h"
 
-#define LOG_TAG "IptablesBaseTest"
 #include <log/log.h>
 
 using android::base::StringPrintf;
diff --git a/server/IptablesRestoreController.cpp b/server/IptablesRestoreController.cpp
index 10cedfa..f7ba200 100644
--- a/server/IptablesRestoreController.cpp
+++ b/server/IptablesRestoreController.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "IptablesRestoreController"
 #include "IptablesRestoreController.h"
 
 #include <poll.h>
@@ -21,12 +22,12 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
-#define LOG_TAG "IptablesRestoreController"
 #include <android-base/logging.h>
 #include <android-base/file.h>
 #include <netdutils/Syscalls.h>
 
 #include "Controllers.h"
+#include "NetdConstants.h"
 
 using android::netdutils::StatusOr;
 using android::netdutils::sSyscalls;
@@ -44,7 +45,9 @@
 
 class IptablesProcess {
 public:
-    IptablesProcess(pid_t pid, int stdIn, int stdOut, int stdErr) :
+    IptablesProcess(const IptablesRestoreController::IptablesProcessType type,
+            pid_t pid, int stdIn, int stdOut, int stdErr) :
+        type(type),
         pid(pid),
         stdIn(stdIn),
         processTerminated(false) {
@@ -76,34 +79,13 @@
         // process was killed by something else on the system). In both cases, it's safe to send the
         // PID a SIGTERM, because the PID continues to exist until its parent (i.e., us) calls
         // waitpid on it, so there's no risk that the PID is reused.
-        int err = kill(pid, SIGTERM);
-        if (err) {
-            err = errno;
-        }
-
-        if (err == ESRCH) {
-            // This means that someone else inside netd but outside this class called waitpid(),
-            // which is a programming error. There's no point in calling waitpid() here since we
-            // know that the process is gone.
-            ALOGE("iptables child process %d unexpectedly disappeared", pid);
-            processTerminated = true;
-            return;
-        }
-
-        if (err) {
-            ALOGE("Error killing iptables child process %d: %s", pid, strerror(err));
-        }
-
-        int status;
-        if (waitpid(pid, &status, 0) == -1) {
-            ALOGE("Error waiting for iptables child process %d: %s", pid, strerror(errno));
-        } else {
-            ALOGW("iptables-restore process %d terminated status=%d", pid, status);
-        }
+        ::stopProcess(pid, (type == IptablesRestoreController::IPTABLES_PROCESS) ?
+                "iptables-restore" : "ip6tables-restore");
 
         processTerminated = true;
     }
 
+    const IptablesRestoreController::IptablesProcessType type;
     const pid_t pid;  // NOLINT(misc-non-private-member-variables-in-classes)
     const int stdIn;  // NOLINT(misc-non-private-member-variables-in-classes)
 
@@ -197,7 +179,8 @@
         ALOGW("close() failed: %s", strerror(errno));
     }
 
-    return new IptablesProcess(child_pid.value(), stdin_pipe[1], stdout_pipe[0], stderr_pipe[0]);
+    return new IptablesProcess(type,
+            child_pid.value(), stdin_pipe[1], stdout_pipe[0], stderr_pipe[0]);
 }
 
 // TODO: Return -errno on failure instead of -1.
diff --git a/server/IptablesRestoreControllerTest.cpp b/server/IptablesRestoreControllerTest.cpp
index 3881124..a05c76d 100644
--- a/server/IptablesRestoreControllerTest.cpp
+++ b/server/IptablesRestoreControllerTest.cpp
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "IptablesRestoreControllerTest"
+#include "IptablesRestoreController.h"
+
 #include <fcntl.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
@@ -25,14 +28,12 @@
 #include <iostream>
 #include <string>
 
-#define LOG_TAG "IptablesRestoreControllerTest"
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <log/log.h>
 #include <netdutils/MockSyscalls.h>
 #include <netdutils/Stopwatch.h>
 
-#include "IptablesRestoreController.h"
 #include "NetdConstants.h"
 #include "bpf/BpfUtils.h"
 
diff --git a/server/MDnsEventReporter.cpp b/server/MDnsEventReporter.cpp
new file mode 100644
index 0000000..db9021a
--- /dev/null
+++ b/server/MDnsEventReporter.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "MDnsEventReporter"
+
+#include "MDnsEventReporter.h"
+
+using android::net::mdns::aidl::IMDnsEventListener;
+
+MDnsEventReporter& MDnsEventReporter::getInstance() {
+    // It should be initialized only once.
+    static MDnsEventReporter instance;
+    return instance;
+}
+
+const MDnsEventReporter::EventListenerSet& MDnsEventReporter::getEventListeners() const {
+    return getEventListenersImpl();
+}
+
+int MDnsEventReporter::addEventListener(const android::sp<IMDnsEventListener>& listener) {
+    return addEventListenerImpl(listener);
+}
+
+int MDnsEventReporter::removeEventListener(const android::sp<IMDnsEventListener>& listener) {
+    return removeEventListenerImpl(listener);
+}
+
+const MDnsEventReporter::EventListenerSet& MDnsEventReporter::getEventListenersImpl() const {
+    std::lock_guard lock(mMutex);
+    return mEventListeners;
+}
+
+int MDnsEventReporter::addEventListenerImpl(const android::sp<IMDnsEventListener>& listener) {
+    if (listener == nullptr) {
+        ALOGE("The event listener should not be null");
+        return -EINVAL;
+    }
+
+    std::lock_guard lock(mMutex);
+
+    for (const auto& it : mEventListeners) {
+        if (android::IInterface::asBinder(it).get() ==
+            android::IInterface::asBinder(listener).get()) {
+            ALOGW("The event listener was already subscribed");
+            return -EEXIST;
+        }
+    }
+
+    // Create the death listener.
+    class DeathRecipient : public android::IBinder::DeathRecipient {
+      public:
+        DeathRecipient(MDnsEventReporter* eventReporter,
+                       const android::sp<IMDnsEventListener>& listener)
+            : mEventReporter(eventReporter), mListener(listener) {}
+        ~DeathRecipient() override = default;
+        void binderDied(const android::wp<android::IBinder>& /* who */) override {
+            mEventReporter->removeEventListenerImpl(mListener);
+        }
+
+      private:
+        MDnsEventReporter* mEventReporter;
+        android::sp<IMDnsEventListener> mListener;
+    };
+
+    android::sp<android::IBinder::DeathRecipient> deathRecipient =
+            new DeathRecipient(this, listener);
+
+    android::IInterface::asBinder(listener)->linkToDeath(deathRecipient);
+
+    mEventListeners.insert(listener);
+    return 0;
+}
+
+int MDnsEventReporter::removeEventListenerImpl(const android::sp<IMDnsEventListener>& listener) {
+    if (listener == nullptr) {
+        ALOGE("The event listener should not be null");
+        return -EINVAL;
+    }
+
+    std::lock_guard lock(mMutex);
+
+    mEventListeners.erase(listener);
+    return 0;
+}
diff --git a/server/MDnsEventReporter.h b/server/MDnsEventReporter.h
new file mode 100644
index 0000000..e49c3e3
--- /dev/null
+++ b/server/MDnsEventReporter.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/thread_annotations.h>
+#include <android/net/mdns/aidl/IMDnsEventListener.h>
+
+#include <set>
+
+class MDnsEventReporter final {
+  public:
+    MDnsEventReporter(const MDnsEventReporter&) = delete;
+    MDnsEventReporter& operator=(const MDnsEventReporter&) = delete;
+
+    using EventListenerSet = std::set<android::sp<android::net::mdns::aidl::IMDnsEventListener>>;
+
+    // Get the instance of the singleton MDnsEventReporter.
+    static MDnsEventReporter& getInstance();
+
+    // Return registered binder services from the singleton MDnsEventReporter. This method is
+    // threadsafe.
+    const EventListenerSet& getEventListeners() const;
+
+    // Add the binder to the singleton MDnsEventReporter. This method is threadsafe.
+    int addEventListener(const android::sp<android::net::mdns::aidl::IMDnsEventListener>& listener);
+
+    // Remove the binder from the singleton MDnsEventReporter. This method is threadsafe.
+    int removeEventListener(
+            const android::sp<android::net::mdns::aidl::IMDnsEventListener>& listener);
+
+  private:
+    MDnsEventReporter() = default;
+    ~MDnsEventReporter() = default;
+
+    mutable std::mutex mMutex;
+    EventListenerSet mEventListeners GUARDED_BY(mMutex);
+
+    int addEventListenerImpl(
+            const android::sp<android::net::mdns::aidl::IMDnsEventListener>& listener)
+            EXCLUDES(mMutex);
+    int removeEventListenerImpl(
+            const android::sp<android::net::mdns::aidl::IMDnsEventListener>& listener)
+            EXCLUDES(mMutex);
+    const EventListenerSet& getEventListenersImpl() const EXCLUDES(mMutex);
+    void handleEventBinderDied(const void* who) EXCLUDES(mMutex);
+};
diff --git a/server/MDnsSdListener.cpp b/server/MDnsSdListener.cpp
index 42dcddf..1636400 100644
--- a/server/MDnsSdListener.cpp
+++ b/server/MDnsSdListener.cpp
@@ -19,6 +19,7 @@
 #include <arpa/inet.h>
 #include <dirent.h>
 #include <errno.h>
+#include <inttypes.h>
 #include <linux/if.h>
 #include <netdb.h>
 #include <netinet/in.h>
@@ -36,10 +37,15 @@
 
 #include <cutils/properties.h>
 #include <log/log.h>
-#include <netdutils/ResponseCode.h>
 #include <netdutils/ThreadUtil.h>
 #include <sysutils/SocketClient.h>
 
+#include "Controllers.h"
+#include "MDnsEventReporter.h"
+#include "netid_client.h"
+
+using android::net::gCtls;
+
 #define MDNS_SERVICE_NAME "mdnsd"
 #define MDNS_SERVICE_STATUS "init.svc.mdnsd"
 
@@ -47,474 +53,312 @@
 
 constexpr char RESCAN[] = "1";
 
-using android::netdutils::ResponseCode;
+using android::net::mdns::aidl::DiscoveryInfo;
+using android::net::mdns::aidl::GetAddressInfo;
+using android::net::mdns::aidl::IMDnsEventListener;
+using android::net::mdns::aidl::RegistrationInfo;
+using android::net::mdns::aidl::ResolutionInfo;
 
-MDnsSdListener::MDnsSdListener() : FrameworkListener(SOCKET_NAME, true) {
-    Monitor *m = new Monitor();
-    registerCmd(new Handler(m, this));
-}
-
-MDnsSdListener::Handler::Handler(Monitor *m, MDnsSdListener *listener) :
-   NetdCommand("mdnssd") {
-   if (DBG) ALOGD("MDnsSdListener::Hander starting up");
-   mMonitor = m;
-   mListener = listener;
-}
-
-MDnsSdListener::Handler::~Handler() {}
-
-void MDnsSdListener::Handler::discover(SocketClient *cli,
-        const char *iface,
-        const char *regType,
-        const char *domain,
-        const int requestId,
-        const int requestFlags) {
-    if (VDBG) {
-        ALOGD("discover(%s, %s, %s, %d, %d)", iface, regType, domain, requestId,
-                requestFlags);
+static unsigned ifaceIndexToNetId(uint32_t interfaceIndex) {
+    char interfaceName[IFNAMSIZ] = {};
+    unsigned netId;
+    if (if_indextoname(interfaceIndex, interfaceName) == nullptr) {
+        ALOGE("Interface %d was not found", interfaceIndex);
+        return NETID_UNSET;
+    } else if ((netId = gCtls->netCtrl.getNetworkForInterface(interfaceName)) == NETID_UNSET) {
+        ALOGE("Network was not found for interface %s", interfaceName);
+        return NETID_UNSET;
     }
-    Context *context = new Context(requestId, mListener);
-    DNSServiceRef *ref = mMonitor->allocateServiceRef(requestId, context);
+    return netId;
+}
+
+int MDnsSdListener::discover(uint32_t ifIndex, const char* regType, const char* domain,
+                             const int requestId, const int requestFlags) {
+    if (VDBG) {
+        ALOGD("discover(%d, %s, %s, %d, %d)", ifIndex, regType, domain ? domain : "null", requestId,
+              requestFlags);
+    }
+    Context* context = new Context(requestId);
+    DNSServiceRef* ref = mMonitor.allocateServiceRef(requestId, context);
     if (ref == nullptr) {
         ALOGE("requestId %d already in use during discover call", requestId);
-        cli->sendMsg(ResponseCode::CommandParameterError,
-                "RequestId already in use during discover call", false);
-        return;
+        return -EBUSY;
     }
     if (VDBG) ALOGD("using ref %p", ref);
-    DNSServiceFlags nativeFlags = iToFlags(requestFlags);
-    int interfaceInt = ifaceNameToI(iface);
 
-    DNSServiceErrorType result = DNSServiceBrowse(ref, nativeFlags, interfaceInt, regType,
-            domain, &MDnsSdListenerDiscoverCallback, context);
+    DNSServiceErrorType result = DNSServiceBrowse(ref, requestFlags, ifIndex, regType, domain,
+                                                  &MDnsSdListenerDiscoverCallback, context);
     if (result != kDNSServiceErr_NoError) {
         ALOGE("Discover request %d got an error from DNSServiceBrowse %d", requestId, result);
-        mMonitor->freeServiceRef(requestId);
-        cli->sendMsg(ResponseCode::CommandParameterError,
-                "Discover request got an error from DNSServiceBrowse", false);
-        return;
+        mMonitor.freeServiceRef(requestId);
+        // Return kDNSServiceErr_* directly instead of transferring to an UNIX error.
+        // This can help caller to know what going wrong from mdnsresponder side.
+        return -result;
     }
-    mMonitor->startMonitoring(requestId);
+    mMonitor.startMonitoring(requestId);
     if (VDBG) ALOGD("discover successful");
-    cli->sendMsg(ResponseCode::CommandOkay, "Discover operation started", false);
-    return;
+    return 0;
 }
 
 void MDnsSdListenerDiscoverCallback(DNSServiceRef /* sdRef */, DNSServiceFlags flags,
-        uint32_t /* interfaceIndex */, DNSServiceErrorType errorCode, const char *serviceName,
-        const char *regType, const char *replyDomain, void *inContext) {
+                                    uint32_t ifIndex, DNSServiceErrorType errorCode,
+                                    const char* serviceName, const char* regType,
+                                    const char* replyDomain, void* inContext) {
     MDnsSdListener::Context *context = reinterpret_cast<MDnsSdListener::Context *>(inContext);
-    char *msg;
     int refNumber = context->mRefNumber;
+    const auto& listeners = MDnsEventReporter::getInstance().getEventListeners();
+    if (listeners.empty()) {
+        ALOGI("Discover callback not sent since no IMDnsEventListener receiver is available.");
+        return;
+    }
 
-    if (errorCode != kDNSServiceErr_NoError) {
-        asprintf(&msg, "%d %d", refNumber, errorCode);
-        context->mListener->sendBroadcast(ResponseCode::ServiceDiscoveryFailed, msg, false);
-        if (DBG) ALOGE("discover failure for %d, error= %d", refNumber, errorCode);
-    } else {
-        int respCode;
-        char *quotedServiceName = SocketClient::quoteArg(serviceName);
+    DiscoveryInfo info;
+    info.id = refNumber;
+    info.serviceName = serviceName;
+    info.registrationType = regType;
+    info.interfaceIdx = ifIndex;
+    // If the network is not found, still send the event and let
+    // the service decide what to do with a callback with an empty network
+    info.netId = ifaceIndexToNetId(ifIndex);
+    if (errorCode == kDNSServiceErr_NoError) {
         if (flags & kDNSServiceFlagsAdd) {
             if (VDBG) {
                 ALOGD("Discover found new serviceName %s, regType %s and domain %s for %d",
-                        serviceName, regType, replyDomain, refNumber);
+                      serviceName, regType, replyDomain, refNumber);
             }
-            respCode = ResponseCode::ServiceDiscoveryServiceAdded;
+            info.result = IMDnsEventListener::SERVICE_FOUND;
         } else {
             if (VDBG) {
-                ALOGD("Discover lost serviceName %s, regType %s and domain %s for %d",
-                        serviceName, regType, replyDomain, refNumber);
+                ALOGD("Discover lost serviceName %s, regType %s and domain %s for %d", serviceName,
+                      regType, replyDomain, refNumber);
             }
-            respCode = ResponseCode::ServiceDiscoveryServiceRemoved;
+            info.result = IMDnsEventListener::SERVICE_LOST;
         }
-        asprintf(&msg, "%d %s %s %s", refNumber, quotedServiceName, regType, replyDomain);
-        free(quotedServiceName);
-        context->mListener->sendBroadcast(respCode, msg, false);
+    } else {
+        if (DBG) ALOGE("discover failure for %d, error= %d", refNumber, errorCode);
+        info.result = IMDnsEventListener::SERVICE_DISCOVERY_FAILED;
     }
-    free(msg);
+
+    for (const auto& it : listeners) {
+        it->onServiceDiscoveryStatus(info);
+    }
 }
 
-void MDnsSdListener::Handler::stop(SocketClient *cli, int argc, char **argv, const char *str) {
-    if (argc != 3) {
-        char *msg;
-        asprintf(&msg, "Invalid number of arguments to %s", str);
-        cli->sendMsg(ResponseCode::CommandParameterError, msg, false);
-        free(msg);
-        return;
-    }
-    int requestId = strtol(argv[2], nullptr, 10);
-    DNSServiceRef *ref = mMonitor->lookupServiceRef(requestId);
+int MDnsSdListener::stop(int requestId) {
+    DNSServiceRef* ref = mMonitor.lookupServiceRef(requestId);
     if (ref == nullptr) {
-        if (DBG) ALOGE("%s stop used unknown requestId %d", str, requestId);
-        cli->sendMsg(ResponseCode::CommandParameterError, "Unknown requestId", false);
-        return;
+        if (DBG) ALOGE("Stop used unknown requestId %d", requestId);
+        return -ESRCH;
     }
-    if (VDBG) ALOGD("Stopping %s with ref %p", str, ref);
-    mMonitor->deallocateServiceRef(ref);
-    mMonitor->freeServiceRef(requestId);
-    char *msg;
-    asprintf(&msg, "%s stopped", str);
-    cli->sendMsg(ResponseCode::CommandOkay, msg, false);
-    free(msg);
+    if (VDBG) ALOGD("Stopping operation with ref %p", ref);
+    mMonitor.deallocateServiceRef(ref);
+    mMonitor.freeServiceRef(requestId);
+    return 0;
 }
 
-void MDnsSdListener::Handler::serviceRegister(SocketClient *cli, int requestId,
-        const char *interfaceName, const char *serviceName, const char *serviceType,
-        const char *domain, const char *host, int port, int txtLen, void *txtRecord) {
+int MDnsSdListener::serviceRegister(int requestId, const char* serviceName, const char* serviceType,
+                                    const char* domain, const char* host, int port,
+                                    const std::vector<unsigned char>& txtRecord, uint32_t ifIndex) {
     if (VDBG) {
-        ALOGD("serviceRegister(%d, %s, %s, %s, %s, %s, %d, %d, <binary>)", requestId,
-                interfaceName, serviceName, serviceType, domain, host, port, txtLen);
+        ALOGD("serviceRegister(%d, %d, %s, %s, %s, %s, %d, <binary>)", requestId, ifIndex,
+              serviceName, serviceType, domain ? domain : "null", host ? host : "null", port);
     }
-    Context *context = new Context(requestId, mListener);
-    DNSServiceRef *ref = mMonitor->allocateServiceRef(requestId, context);
-    port = htons(port);
+    Context* context = new Context(requestId);
+    DNSServiceRef* ref = mMonitor.allocateServiceRef(requestId, context);
     if (ref == nullptr) {
         ALOGE("requestId %d already in use during register call", requestId);
-        cli->sendMsg(ResponseCode::CommandParameterError,
-                "RequestId already in use during register call", false);
-        return;
+        return -EBUSY;
     }
+    port = htons(port);
     DNSServiceFlags nativeFlags = 0;
-    int interfaceInt = ifaceNameToI(interfaceName);
-    DNSServiceErrorType result = DNSServiceRegister(ref, interfaceInt, nativeFlags, serviceName,
-            serviceType, domain, host, port, txtLen, txtRecord, &MDnsSdListenerRegisterCallback,
-            context);
+    DNSServiceErrorType result = DNSServiceRegister(
+            ref, nativeFlags, ifIndex, serviceName, serviceType, domain, host, port,
+            txtRecord.size(), &txtRecord.front(), &MDnsSdListenerRegisterCallback, context);
     if (result != kDNSServiceErr_NoError) {
         ALOGE("service register request %d got an error from DNSServiceRegister %d", requestId,
                 result);
-        mMonitor->freeServiceRef(requestId);
-        cli->sendMsg(ResponseCode::CommandParameterError,
-                "serviceRegister request got an error from DNSServiceRegister", false);
-        return;
+        mMonitor.freeServiceRef(requestId);
+        // Return kDNSServiceErr_* directly instead of transferring to an UNIX error.
+        // This can help caller to know what going wrong from mdnsresponder side.
+        return -result;
     }
-    mMonitor->startMonitoring(requestId);
+    mMonitor.startMonitoring(requestId);
     if (VDBG) ALOGD("serviceRegister successful");
-    cli->sendMsg(ResponseCode::CommandOkay, "serviceRegister started", false);
-    return;
+    return 0;
 }
 
 void MDnsSdListenerRegisterCallback(DNSServiceRef /* sdRef */, DNSServiceFlags /* flags */,
-        DNSServiceErrorType errorCode, const char *serviceName, const char * /* regType */,
-        const char * /* domain */, void *inContext) {
-    MDnsSdListener::Context *context = reinterpret_cast<MDnsSdListener::Context *>(inContext);
-    char *msg;
+                                    DNSServiceErrorType errorCode, const char* serviceName,
+                                    const char* regType, const char* /* domain */,
+                                    void* inContext) {
+    MDnsSdListener::Context* context = reinterpret_cast<MDnsSdListener::Context*>(inContext);
     int refNumber = context->mRefNumber;
-    if (errorCode != kDNSServiceErr_NoError) {
-        asprintf(&msg, "%d %d", refNumber, errorCode);
-        context->mListener->sendBroadcast(ResponseCode::ServiceRegistrationFailed, msg, false);
-        if (DBG) ALOGE("register failure for %d, error= %d", refNumber, errorCode);
-    } else {
-        char *quotedServiceName = SocketClient::quoteArg(serviceName);
-        asprintf(&msg, "%d %s", refNumber, quotedServiceName);
-        free(quotedServiceName);
-        context->mListener->sendBroadcast(ResponseCode::ServiceRegistrationSucceeded, msg, false);
-        if (VDBG) ALOGD("register succeeded for %d as %s", refNumber, serviceName);
+    const auto& listeners = MDnsEventReporter::getInstance().getEventListeners();
+    if (listeners.empty()) {
+        ALOGI("Register callback not sent since no IMDnsEventListener receiver is available.");
+        return;
     }
-    free(msg);
+
+    RegistrationInfo info;
+    info.id = refNumber;
+    info.serviceName = serviceName;
+    info.registrationType = regType;
+    if (errorCode == kDNSServiceErr_NoError) {
+        if (VDBG) ALOGD("register succeeded for %d as %s", refNumber, serviceName);
+        info.result = IMDnsEventListener::SERVICE_REGISTERED;
+    } else {
+        if (DBG) ALOGE("register failure for %d, error= %d", refNumber, errorCode);
+        info.result = IMDnsEventListener::SERVICE_REGISTRATION_FAILED;
+    }
+
+    for (const auto& it : listeners) {
+        it->onServiceRegistrationStatus(info);
+    }
 }
 
-
-void MDnsSdListener::Handler::resolveService(SocketClient *cli, int requestId,
-        const char *interfaceName, const char *serviceName, const char *regType,
-        const char *domain) {
+int MDnsSdListener::resolveService(int requestId, uint32_t ifIndex, const char* serviceName,
+                                   const char* regType, const char* domain) {
     if (VDBG) {
-        ALOGD("resolveService(%d, %s, %s, %s, %s)", requestId, interfaceName,
-                serviceName, regType, domain);
+        ALOGD("resolveService(%d, %d, %s, %s, %s)", requestId, ifIndex, serviceName, regType,
+              domain);
     }
-    Context *context = new Context(requestId, mListener);
-    DNSServiceRef *ref = mMonitor->allocateServiceRef(requestId, context);
+    Context* context = new Context(requestId);
+    DNSServiceRef* ref = mMonitor.allocateServiceRef(requestId, context);
     if (ref == nullptr) {
         ALOGE("request Id %d already in use during resolve call", requestId);
-        cli->sendMsg(ResponseCode::CommandParameterError,
-                "RequestId already in use during resolve call", false);
-        return;
+        return -EBUSY;
     }
     DNSServiceFlags nativeFlags = 0;
-    int interfaceInt = ifaceNameToI(interfaceName);
-    DNSServiceErrorType result = DNSServiceResolve(ref, nativeFlags, interfaceInt, serviceName,
-            regType, domain, &MDnsSdListenerResolveCallback, context);
+    DNSServiceErrorType result = DNSServiceResolve(ref, nativeFlags, ifIndex, serviceName, regType,
+                                                   domain, &MDnsSdListenerResolveCallback, context);
     if (result != kDNSServiceErr_NoError) {
-        ALOGE("service resolve request %d got an error from DNSServiceResolve %d", requestId,
-                result);
-        mMonitor->freeServiceRef(requestId);
-        cli->sendMsg(ResponseCode::CommandParameterError,
-                "resolveService got an error from DNSServiceResolve", false);
-        return;
+        ALOGE("service resolve request %d on iface %d: got an error from DNSServiceResolve %d",
+              requestId, ifIndex, result);
+        mMonitor.freeServiceRef(requestId);
+        // Return kDNSServiceErr_* directly instead of transferring to an UNIX error.
+        // This can help caller to know what going wrong from mdnsresponder side.
+        return -result;
     }
-    mMonitor->startMonitoring(requestId);
+    mMonitor.startMonitoring(requestId);
     if (VDBG) ALOGD("resolveService successful");
-    cli->sendMsg(ResponseCode::CommandOkay, "resolveService started", false);
-    return;
+    return 0;
 }
 
 void MDnsSdListenerResolveCallback(DNSServiceRef /* sdRef */, DNSServiceFlags /* flags */,
-        uint32_t /* interface */, DNSServiceErrorType errorCode, const char *fullname,
-        const char *hosttarget, uint16_t port, uint16_t txtLen,
-        const unsigned char *txtRecord , void *inContext) {
-    MDnsSdListener::Context *context = reinterpret_cast<MDnsSdListener::Context *>(inContext);
-    char *msg;
+                                   uint32_t ifIndex, DNSServiceErrorType errorCode,
+                                   const char* fullname, const char* hosttarget, uint16_t port,
+                                   uint16_t txtLen, const unsigned char* txtRecord,
+                                   void* inContext) {
+    MDnsSdListener::Context* context = reinterpret_cast<MDnsSdListener::Context*>(inContext);
     int refNumber = context->mRefNumber;
-    port = ntohs(port);
-    if (errorCode != kDNSServiceErr_NoError) {
-        asprintf(&msg, "%d %d", refNumber, errorCode);
-        context->mListener->sendBroadcast(ResponseCode::ServiceResolveFailed, msg, false);
-        if (DBG) ALOGE("resolve failure for %d, error= %d", refNumber, errorCode);
-    } else {
-        char *quotedFullName = SocketClient::quoteArg(fullname);
-        char *quotedHostTarget = SocketClient::quoteArg(hosttarget);
-
-        // Base 64 encodes every 3 bytes into 4 characters, but then adds padding to the next
-        // multiple of 4 and a \0
-        size_t dstLength = CEIL(CEIL(txtLen * 4, 3), 4) * 4 + 1;
-
-        char *dst = (char *)malloc(dstLength);
-        b64_ntop(txtRecord, txtLen, dst, dstLength);
-
-        asprintf(&msg, "%d %s %s %d %d \"%s\"", refNumber, quotedFullName, quotedHostTarget, port,
-                 txtLen, dst);
-        free(quotedFullName);
-        free(quotedHostTarget);
-        free(dst);
-        context->mListener->sendBroadcast(ResponseCode::ServiceResolveSuccess, msg, false);
-        if (VDBG) {
-            ALOGD("resolve succeeded for %d finding %s at %s:%d with txtLen %d",
-                    refNumber, fullname, hosttarget, port, txtLen);
-        }
-    }
-    free(msg);
-}
-
-void MDnsSdListener::Handler::getAddrInfo(SocketClient *cli, int requestId,
-        const char *interfaceName, uint32_t protocol, const char *hostname) {
-    if (VDBG) ALOGD("getAddrInfo(%d, %s %d, %s)", requestId, interfaceName, protocol, hostname);
-    Context *context = new Context(requestId, mListener);
-    DNSServiceRef *ref = mMonitor->allocateServiceRef(requestId, context);
-    if (ref == nullptr) {
-        ALOGE("request ID %d already in use during getAddrInfo call", requestId);
-        cli->sendMsg(ResponseCode::CommandParameterError,
-                "RequestId already in use during getAddrInfo call", false);
+    const auto& listeners = MDnsEventReporter::getInstance().getEventListeners();
+    if (listeners.empty()) {
+        ALOGI("Resolve callback not sent since no IMDnsEventListener receiver is available.");
         return;
     }
+    port = ntohs(port);
+
+    ResolutionInfo info;
+    info.id = refNumber;
+    info.port = port;
+    info.serviceFullName = fullname;
+    info.hostname = hosttarget;
+    info.txtRecord = std::vector<unsigned char>(txtRecord, txtRecord + txtLen);
+    info.interfaceIdx = ifIndex;
+    if (errorCode == kDNSServiceErr_NoError) {
+        if (VDBG) {
+            ALOGD("resolve succeeded for %d finding %s at %s:%d with txtLen %d", refNumber,
+                  fullname, hosttarget, port, txtLen);
+        }
+        info.result = IMDnsEventListener::SERVICE_RESOLVED;
+    } else {
+        if (DBG) ALOGE("resolve failure for %d, error= %d", refNumber, errorCode);
+        info.result = IMDnsEventListener::SERVICE_RESOLUTION_FAILED;
+    }
+
+    for (const auto& it : listeners) {
+        it->onServiceResolutionStatus(info);
+    }
+}
+
+int MDnsSdListener::getAddrInfo(int requestId, uint32_t ifIndex, uint32_t protocol,
+                                const char* hostname) {
+    if (VDBG) ALOGD("getAddrInfo(%d, %u %d, %s)", requestId, ifIndex, protocol, hostname);
+    Context* context = new Context(requestId);
+    DNSServiceRef* ref = mMonitor.allocateServiceRef(requestId, context);
+    if (ref == nullptr) {
+        ALOGE("request ID %d already in use during getAddrInfo call", requestId);
+        return -EBUSY;
+    }
     DNSServiceFlags nativeFlags = 0;
-    int interfaceInt = ifaceNameToI(interfaceName);
-    DNSServiceErrorType result = DNSServiceGetAddrInfo(ref, nativeFlags, interfaceInt, protocol,
-            hostname, &MDnsSdListenerGetAddrInfoCallback, context);
+    DNSServiceErrorType result =
+            DNSServiceGetAddrInfo(ref, nativeFlags, ifIndex, protocol, hostname,
+                                  &MDnsSdListenerGetAddrInfoCallback, context);
     if (result != kDNSServiceErr_NoError) {
         ALOGE("getAddrInfo request %d got an error from DNSServiceGetAddrInfo %d", requestId,
                 result);
-        mMonitor->freeServiceRef(requestId);
-        cli->sendMsg(ResponseCode::CommandParameterError,
-                "getAddrInfo request got an error from DNSServiceGetAddrInfo", false);
-        return;
+        mMonitor.freeServiceRef(requestId);
+        // Return kDNSServiceErr_* directly instead of transferring to an UNIX error.
+        // This can help caller to know what going wrong from mdnsresponder side.
+        return -result;
     }
-    mMonitor->startMonitoring(requestId);
+    mMonitor.startMonitoring(requestId);
     if (VDBG) ALOGD("getAddrInfo successful");
-    cli->sendMsg(ResponseCode::CommandOkay, "getAddrInfo started", false);
-    return;
+    return 0;
 }
 
 void MDnsSdListenerGetAddrInfoCallback(DNSServiceRef /* sdRef */, DNSServiceFlags /* flags */,
-        uint32_t /* interface */, DNSServiceErrorType errorCode, const char *hostname,
-        const struct sockaddr *const sa, uint32_t ttl, void *inContext) {
+                                       uint32_t ifIndex, DNSServiceErrorType errorCode,
+                                       const char* hostname, const struct sockaddr* const sa,
+                                       uint32_t /* ttl */, void* inContext) {
     MDnsSdListener::Context *context = reinterpret_cast<MDnsSdListener::Context *>(inContext);
     int refNumber = context->mRefNumber;
+    const auto& listeners = MDnsEventReporter::getInstance().getEventListeners();
+    if (listeners.empty()) {
+        ALOGI("Get address callback not sent since no IMDnsEventListener receiver is available.");
+        return;
+    }
 
-    if (errorCode != kDNSServiceErr_NoError) {
-        char *msg;
-        asprintf(&msg, "%d %d", refNumber, errorCode);
-        context->mListener->sendBroadcast(ResponseCode::ServiceGetAddrInfoFailed, msg, false);
-        if (DBG) ALOGE("getAddrInfo failure for %d, error= %d", refNumber, errorCode);
-        free(msg);
-    } else {
+    GetAddressInfo info;
+    info.id = refNumber;
+    info.hostname = hostname;
+    info.interfaceIdx = ifIndex;
+    // If the network is not found, still send the event with an empty network
+    // and let the service decide what to do with it
+    info.netId = ifaceIndexToNetId(ifIndex);
+    if (errorCode == kDNSServiceErr_NoError) {
         char addr[INET6_ADDRSTRLEN];
-        char *msg;
-        char *quotedHostname = SocketClient::quoteArg(hostname);
         if (sa->sa_family == AF_INET) {
             inet_ntop(sa->sa_family, &(((struct sockaddr_in *)sa)->sin_addr), addr, sizeof(addr));
         } else {
             inet_ntop(sa->sa_family, &(((struct sockaddr_in6 *)sa)->sin6_addr), addr, sizeof(addr));
         }
-        asprintf(&msg, "%d %s %d %s", refNumber, quotedHostname, ttl, addr);
-        free(quotedHostname);
-        context->mListener->sendBroadcast(ResponseCode::ServiceGetAddrInfoSuccess, msg, false);
+        info.address = addr;
         if (VDBG) {
-            ALOGD("getAddrInfo succeeded for %d: %s", refNumber, msg);
+            ALOGD("getAddrInfo succeeded for %d:", refNumber);
         }
-        free(msg);
-    }
-}
-
-void MDnsSdListener::Handler::setHostname(SocketClient *cli, int requestId,
-        const char *hostname) {
-    if (VDBG) ALOGD("setHostname(%d, %s)", requestId, hostname);
-    Context *context = new Context(requestId, mListener);
-    DNSServiceRef *ref = mMonitor->allocateServiceRef(requestId, context);
-    if (ref == nullptr) {
-        ALOGE("request Id %d already in use during setHostname call", requestId);
-        cli->sendMsg(ResponseCode::CommandParameterError,
-                "RequestId already in use during setHostname call", false);
-        return;
-    }
-    DNSServiceFlags nativeFlags = 0;
-    DNSServiceErrorType result = DNSSetHostname(ref, nativeFlags, hostname,
-            &MDnsSdListenerSetHostnameCallback, context);
-    if (result != kDNSServiceErr_NoError) {
-        ALOGE("setHostname request %d got an error from DNSSetHostname %d", requestId, result);
-        mMonitor->freeServiceRef(requestId);
-        cli->sendMsg(ResponseCode::CommandParameterError,
-                "setHostname got an error from DNSSetHostname", false);
-        return;
-    }
-    mMonitor->startMonitoring(requestId);
-    if (VDBG) ALOGD("setHostname successful");
-    cli->sendMsg(ResponseCode::CommandOkay, "setHostname started", false);
-    return;
-}
-
-void MDnsSdListenerSetHostnameCallback(DNSServiceRef /* sdRef */, DNSServiceFlags /* flags */,
-        DNSServiceErrorType errorCode, const char *hostname, void *inContext) {
-    MDnsSdListener::Context *context = reinterpret_cast<MDnsSdListener::Context *>(inContext);
-    char *msg;
-    int refNumber = context->mRefNumber;
-    if (errorCode != kDNSServiceErr_NoError) {
-        asprintf(&msg, "%d %d", refNumber, errorCode);
-        context->mListener->sendBroadcast(ResponseCode::ServiceSetHostnameFailed, msg, false);
-        if (DBG) ALOGE("setHostname failure for %d, error= %d", refNumber, errorCode);
+        info.result = IMDnsEventListener::SERVICE_GET_ADDR_SUCCESS;
     } else {
-        char *quotedHostname = SocketClient::quoteArg(hostname);
-        asprintf(&msg, "%d %s", refNumber, quotedHostname);
-        free(quotedHostname);
-        context->mListener->sendBroadcast(ResponseCode::ServiceSetHostnameSuccess, msg, false);
-        if (VDBG) ALOGD("setHostname succeeded for %d.  Set to %s", refNumber, hostname);
+        if (DBG) ALOGE("getAddrInfo failure for %d, error= %d", refNumber, errorCode);
+        info.result = IMDnsEventListener::SERVICE_GET_ADDR_FAILED;
     }
-    free(msg);
-}
-
-
-int MDnsSdListener::Handler::ifaceNameToI(const char * /* iface */) {
-    return 0;
-}
-
-const char *MDnsSdListener::Handler::iToIfaceName(int /* i */) {
-    return nullptr;
-}
-
-DNSServiceFlags MDnsSdListener::Handler::iToFlags(int /* i */) {
-    return 0;
-}
-
-int MDnsSdListener::Handler::flagsToI(DNSServiceFlags /* flags */) {
-    return 0;
-}
-
-int MDnsSdListener::Handler::runCommand(SocketClient *cli,
-                                        int argc, char **argv) {
-    if (argc < 2) {
-        char* msg = nullptr;
-        asprintf( &msg, "Invalid number of arguments to mdnssd: %i", argc);
-        ALOGW("%s", msg);
-        cli->sendMsg(ResponseCode::CommandParameterError, msg, false);
-        free(msg);
-        return -1;
+    for (const auto& it : listeners) {
+        it->onGettingServiceAddressStatus(info);
     }
+}
 
-    char* cmd = argv[1];
+int MDnsSdListener::startDaemon() {
+    if (!mMonitor.startService()) {
+        ALOGE("Failed to start: Service already running");
+        return -EBUSY;
+    }
+    return 0;
+}
 
-    if (strcmp(cmd, "discover") == 0) {
-        if (argc != 4) {
-            cli->sendMsg(ResponseCode::CommandParameterError,
-                    "Invalid number of arguments to mdnssd discover", false);
-            return 0;
-        }
-        int requestId = strtol(argv[2], nullptr, 10);
-        char *serviceType = argv[3];
-
-        discover(cli, nullptr, serviceType, nullptr, requestId, 0);
-    } else if (strcmp(cmd, "stop-discover") == 0) {
-        stop(cli, argc, argv, "discover");
-    } else if (strcmp(cmd, "register") == 0) {
-        if (argc != 7) {
-            cli->sendMsg(ResponseCode::CommandParameterError,
-                    "Invalid number of arguments to mdnssd register", false);
-            return 0;
-        }
-        int requestId = atoi(argv[2]);
-        char *serviceName = argv[3];
-        char *serviceType = argv[4];
-        int port = strtol(argv[5], nullptr, 10);
-        char *interfaceName = nullptr; // will use all
-        char *domain = nullptr;        // will use default
-        char *host = nullptr;          // will use default hostname
-
-        // TXT record length is <= 1300, see NsdServiceInfo.setAttribute
-        char dst[1300];
-
-        int length = b64_pton(argv[6], (u_char *)dst, 1300);
-
-        if (length < 0) {
-           cli->sendMsg(ResponseCode::CommandParameterError,
-                    "Could not decode txtRecord", false);
-           return 0;
-        }
-
-        serviceRegister(cli, requestId, interfaceName, serviceName,
-                serviceType, domain, host, port, length, dst);
-    } else if (strcmp(cmd, "stop-register") == 0) {
-        stop(cli, argc, argv, "register");
-    } else if (strcmp(cmd, "resolve") == 0) {
-        if (argc != 6) {
-            cli->sendMsg(ResponseCode::CommandParameterError,
-                    "Invalid number of arguments to mdnssd resolve", false);
-            return 0;
-        }
-        int requestId = atoi(argv[2]);
-        char *interfaceName = nullptr;  // will use all
-        char *serviceName = argv[3];
-        char *regType = argv[4];
-        char *domain = argv[5];
-        resolveService(cli, requestId, interfaceName, serviceName, regType, domain);
-    } else if (strcmp(cmd, "stop-resolve") == 0) {
-        stop(cli, argc, argv, "resolve");
-    } else if (strcmp(cmd, "start-service") == 0) {
-        if (mMonitor->startService()) {
-            cli->sendMsg(ResponseCode::CommandOkay, "Service Started", false);
-        } else {
-            cli->sendMsg(ResponseCode::ServiceStartFailed, "Service already running", false);
-        }
-    } else if (strcmp(cmd, "stop-service") == 0) {
-        if (mMonitor->stopService()) {
-            cli->sendMsg(ResponseCode::CommandOkay, "Service Stopped", false);
-        } else {
-            cli->sendMsg(ResponseCode::ServiceStopFailed, "Service still in use", false);
-        }
-    } else if (strcmp(cmd, "sethostname") == 0) {
-        if (argc != 4) {
-            cli->sendMsg(ResponseCode::CommandParameterError,
-                    "Invalid number of arguments to mdnssd sethostname", false);
-            return 0;
-        }
-        int requestId = strtol(argv[2], nullptr, 10);
-        char *hostname = argv[3];
-        setHostname(cli, requestId, hostname);
-    } else if (strcmp(cmd, "stop-sethostname") == 0) {
-        stop(cli, argc, argv, "sethostname");
-    } else if (strcmp(cmd, "getaddrinfo") == 0) {
-        if (argc != 4) {
-            cli->sendMsg(ResponseCode::CommandParameterError,
-                    "Invalid number of arguments to mdnssd getaddrinfo", false);
-            return 0;
-        }
-        int requestId = atoi(argv[2]);
-        char *hostname = argv[3];
-        char *interfaceName = nullptr;  // default
-        int protocol = 0;            // intelligient heuristic (both v4 + v6)
-        getAddrInfo(cli, requestId, interfaceName, protocol, hostname);
-    } else if (strcmp(cmd, "stop-getaddrinfo") == 0) {
-        stop(cli, argc, argv, "getaddrinfo");
-    } else {
-        if (VDBG) ALOGE("Unknown cmd %s", cmd);
-        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown mdnssd cmd", false);
-        return 0;
+int MDnsSdListener::stopDaemon() {
+    if (!mMonitor.stopService()) {
+        ALOGE("Failed to stop: Service still in use");
+        return -EBUSY;
     }
     return 0;
 }
@@ -595,6 +439,7 @@
     while (1) {
         if (VDBG) ALOGD("Going to poll with pollCount %d", pollCount);
         int pollResults = poll(mPollFds, pollCount, 10000000);
+        if (VDBG) ALOGD("pollResults=%d", pollResults);
         if (pollResults < 0) {
             ALOGE("Error in poll - got %d", errno);
         } else if (pollResults > 0) {
diff --git a/server/MDnsSdListener.h b/server/MDnsSdListener.h
index 83cf23e..f9c2e87 100644
--- a/server/MDnsSdListener.h
+++ b/server/MDnsSdListener.h
@@ -26,48 +26,60 @@
 #include "NetdCommand.h"
 
 // callbacks
-void MDnsSdListenerDiscoverCallback(DNSServiceRef sdRef, DNSServiceFlags flags,
-        uint32_t interfaceIndex, DNSServiceErrorType errorCode,
-        const char *serviceName, const char *regType, const char *replyDomain,
-        void *inContext);
+void MDnsSdListenerDiscoverCallback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t ifIndex,
+                                    DNSServiceErrorType errorCode, const char* serviceName,
+                                    const char* regType, const char* replyDomain, void* inContext);
 
 void MDnsSdListenerRegisterCallback(DNSServiceRef sdRef, DNSServiceFlags flags,
         DNSServiceErrorType errorCode, const char *serviceName, const char *regType,
         const char *domain, void *inContext);
 
-void MDnsSdListenerResolveCallback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interface,
-        DNSServiceErrorType errorCode, const char *fullname, const char *hosttarget, uint16_t port,
-        uint16_t txtLen, const unsigned char *txtRecord, void *inContext);
+void MDnsSdListenerResolveCallback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t ifIndex,
+                                   DNSServiceErrorType errorCode, const char* fullname,
+                                   const char* hosttarget, uint16_t port, uint16_t txtLen,
+                                   const unsigned char* txtRecord, void* inContext);
 
 void MDnsSdListenerSetHostnameCallback(DNSServiceRef, DNSServiceFlags flags,
         DNSServiceErrorType errorCode, const char *hostname, void *inContext);
 
-void MDnsSdListenerGetAddrInfoCallback(DNSServiceRef sdRef, DNSServiceFlags flags,
-        uint32_t interface, DNSServiceErrorType errorCode, const char *hostname,
-        const struct sockaddr *const sa, uint32_t ttl, void *inContext);
+void MDnsSdListenerGetAddrInfoCallback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t ifIndex,
+                                       DNSServiceErrorType errorCode, const char* hostname,
+                                       const struct sockaddr* const sa, uint32_t ttl,
+                                       void* inContext);
 
-class MDnsSdListener : public FrameworkListener {
+class MDnsSdListener {
   public:
-    MDnsSdListener();
-    virtual ~MDnsSdListener() {}
-
     static constexpr const char* SOCKET_NAME = "mdns";
 
     class Context {
       public:
-        MDnsSdListener *mListener;
         int mRefNumber;
 
-        Context(int refNumber, MDnsSdListener *m) {
-            mRefNumber = refNumber;
-            mListener = m;
-        }
+        Context(int refNumber) { mRefNumber = refNumber; }
 
         ~Context() {
         }
     };
 
-private:
+    int stop(int requestId);
+
+    int discover(uint32_t ifIndex, const char* regType, const char* domain, const int requestId,
+                 const int requestFlags);
+
+    int serviceRegister(int requestId, const char* serviceName, const char* serviceType,
+                        const char* domain, const char* host, int port,
+                        const std::vector<unsigned char>& txtRecord, uint32_t ifIndex);
+
+    int resolveService(int requestId, uint32_t ifIndex, const char* serviceName,
+                       const char* regType, const char* domain);
+
+    int getAddrInfo(int requestId, uint32_t ifIndex, uint32_t protocol, const char* hostname);
+
+    int startDaemon();
+
+    int stopDaemon();
+
+  private:
     class Monitor {
     public:
         Monitor();
@@ -103,40 +115,7 @@
         int mCtrlSocketPair[2];
         std::mutex mMutex;
     };
-
-    class Handler : public NetdCommand {
-    public:
-        Handler(Monitor *m, MDnsSdListener *listener);
-        virtual ~Handler();
-        int runCommand(SocketClient *c, int argc, char** argv);
-
-        MDnsSdListener *mListener; // needed for broadcast purposes
-    private:
-        void stop(SocketClient *cli, int argc, char **argv, const char *str);
-
-        void discover(SocketClient *cli, const char *iface, const char *regType,
-                const char *domain, const int requestNumber,
-                const int requestFlags);
-
-        void serviceRegister(SocketClient *cli, int requestId, const char *interfaceName,
-                const char *serviceName, const char *serviceType, const char *domain,
-                const char *host, int port, int textLen, void *txtRecord);
-
-        void resolveService(SocketClient *cli, int requestId,
-                const char *interfaceName, const char *serviceName, const char *regType,
-                const char *domain);
-
-        void setHostname(SocketClient *cli, int requestId, const char *hostname);
-
-        void getAddrInfo(SocketClient *cli, int requestId, const char *interfaceName,
-                uint32_t protocol, const char *hostname);
-
-        int ifaceNameToI(const char *iface);
-        const char *iToIfaceName(int i);
-        DNSServiceFlags iToFlags(int i);
-        int flagsToI(DNSServiceFlags flags);
-        Monitor *mMonitor;
-    };
+    Monitor mMonitor;
 };
 
 #endif
diff --git a/server/MDnsService.cpp b/server/MDnsService.cpp
new file mode 100644
index 0000000..1c1dfca
--- /dev/null
+++ b/server/MDnsService.cpp
@@ -0,0 +1,120 @@
+/**
+ * Copyright (c) 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "MDnsService"
+
+#include "MDnsService.h"
+
+#include "binder_utils/BinderUtil.h"
+#include "binder_utils/NetdPermissions.h"
+
+#include <android-base/strings.h>
+#include <binder/Status.h>
+
+#include <string>
+#include <vector>
+
+using android::net::mdns::aidl::DiscoveryInfo;
+using android::net::mdns::aidl::GetAddressInfo;
+using android::net::mdns::aidl::IMDnsEventListener;
+using android::net::mdns::aidl::RegistrationInfo;
+using android::net::mdns::aidl::ResolutionInfo;
+
+namespace android::net {
+
+// TODO: DnsResolver has same macro definition but returns ScopedAStatus. Move these macros to
+// BinderUtil.h to do the same permission check.
+#define ENFORCE_ANY_PERMISSION(...)                                \
+    do {                                                           \
+        binder::Status status = checkAnyPermission({__VA_ARGS__}); \
+        if (!status.isOk()) {                                      \
+            return status;                                         \
+        }                                                          \
+    } while (0)
+
+#define ENFORCE_NETWORK_STACK_PERMISSIONS() \
+    ENFORCE_ANY_PERMISSION(PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK)
+
+status_t MDnsService::start() {
+    IPCThreadState::self()->disableBackgroundScheduling(true);
+    const status_t ret = BinderService<MDnsService>::publish();
+    if (ret != android::OK) {
+        return ret;
+    }
+    return android::OK;
+}
+
+binder::Status MDnsService::startDaemon() {
+    ENFORCE_NETWORK_STACK_PERMISSIONS();
+    int res = mListener.startDaemon();
+    return statusFromErrcode(res);
+}
+
+binder::Status MDnsService::stopDaemon() {
+    ENFORCE_NETWORK_STACK_PERMISSIONS();
+    int res = mListener.stopDaemon();
+    return statusFromErrcode(res);
+}
+
+binder::Status MDnsService::registerService(const RegistrationInfo& info) {
+    ENFORCE_NETWORK_STACK_PERMISSIONS();
+    int res = mListener.serviceRegister(
+            info.id, info.serviceName.c_str(), info.registrationType.c_str(), nullptr /* domain */,
+            nullptr /* host */, info.port, info.txtRecord, info.interfaceIdx);
+    return statusFromErrcode(res);
+}
+
+binder::Status MDnsService::discover(const DiscoveryInfo& info) {
+    ENFORCE_NETWORK_STACK_PERMISSIONS();
+    int res = mListener.discover(info.interfaceIdx, info.registrationType.c_str(),
+                                 nullptr /* domain */, info.id, 0 /* requestFlags */);
+    return statusFromErrcode(res);
+}
+
+binder::Status MDnsService::resolve(const ResolutionInfo& info) {
+    ENFORCE_NETWORK_STACK_PERMISSIONS();
+    int res = mListener.resolveService(info.id, info.interfaceIdx, info.serviceName.c_str(),
+                                       info.registrationType.c_str(), info.domain.c_str());
+    return statusFromErrcode(res);
+}
+
+binder::Status MDnsService::getServiceAddress(const GetAddressInfo& info) {
+    ENFORCE_NETWORK_STACK_PERMISSIONS();
+    int res = mListener.getAddrInfo(info.id, info.interfaceIdx, 0 /* protocol */,
+                                    info.hostname.c_str());
+    return statusFromErrcode(res);
+}
+
+binder::Status MDnsService::stopOperation(int32_t id) {
+    ENFORCE_NETWORK_STACK_PERMISSIONS();
+    int res = mListener.stop(id);
+    return statusFromErrcode(res);
+}
+
+binder::Status MDnsService::registerEventListener(const android::sp<IMDnsEventListener>& listener) {
+    ENFORCE_NETWORK_STACK_PERMISSIONS();
+    int res = MDnsEventReporter::getInstance().addEventListener(listener);
+    return statusFromErrcode(res);
+}
+
+binder::Status MDnsService::unregisterEventListener(
+        const android::sp<IMDnsEventListener>& listener) {
+    ENFORCE_NETWORK_STACK_PERMISSIONS();
+    int res = MDnsEventReporter::getInstance().removeEventListener(listener);
+    return statusFromErrcode(res);
+}
+
+}  // namespace android::net
diff --git a/server/MDnsService.h b/server/MDnsService.h
new file mode 100644
index 0000000..fc3eca6
--- /dev/null
+++ b/server/MDnsService.h
@@ -0,0 +1,50 @@
+/**
+ * Copyright (c) 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "MDnsEventReporter.h"
+#include "MDnsSdListener.h"
+
+#include <android/net/mdns/aidl/BnMDns.h>
+#include <binder/BinderService.h>
+
+namespace android::net {
+
+class MDnsService : public BinderService<MDnsService>, public android::net::mdns::aidl::BnMDns {
+  public:
+    static status_t start();
+    static char const* getServiceName() { return "mdns"; }
+
+    binder::Status startDaemon() override;
+    binder::Status stopDaemon() override;
+    binder::Status registerService(
+            const ::android::net::mdns::aidl::RegistrationInfo& info) override;
+    binder::Status discover(const ::android::net::mdns::aidl::DiscoveryInfo& info) override;
+    binder::Status resolve(const ::android::net::mdns::aidl::ResolutionInfo& info) override;
+    binder::Status getServiceAddress(
+            const ::android::net::mdns::aidl::GetAddressInfo& info) override;
+    binder::Status stopOperation(int32_t id) override;
+    binder::Status registerEventListener(
+            const android::sp<android::net::mdns::aidl::IMDnsEventListener>& listener) override;
+    binder::Status unregisterEventListener(
+            const android::sp<android::net::mdns::aidl::IMDnsEventListener>& listener) override;
+
+  private:
+    MDnsSdListener mListener;
+};
+
+}  // namespace android::net
diff --git a/server/NFLogListener.cpp b/server/NFLogListener.cpp
index 76972b6..62ac19d 100644
--- a/server/NFLogListener.cpp
+++ b/server/NFLogListener.cpp
@@ -35,6 +35,8 @@
 using netdutils::extract;
 using netdutils::findWithDefault;
 using netdutils::makeSlice;
+using netdutils::NetlinkListener;
+using netdutils::NetlinkListenerInterface;
 using netdutils::Slice;
 using netdutils::sSyscalls;
 using netdutils::Status;
diff --git a/server/NFLogListener.h b/server/NFLogListener.h
index 459b5cf..722fdd0 100644
--- a/server/NFLogListener.h
+++ b/server/NFLogListener.h
@@ -19,7 +19,7 @@
 
 #include <netdutils/Netfilter.h>
 
-#include "NetlinkListener.h"
+#include "netdutils/NetlinkListener.h"
 #include "netdutils/StatusOr.h"
 
 namespace android {
@@ -64,7 +64,7 @@
 
     // Do not invoke this constructor directly outside of tests. Use
     // makeNFLogListener() instead.
-    NFLogListener(std::shared_ptr<NetlinkListenerInterface> listener);
+    NFLogListener(std::shared_ptr<netdutils::NetlinkListenerInterface> listener);
 
     ~NFLogListener() override;
 
@@ -76,7 +76,7 @@
     netdutils::Status unsubscribe(uint16_t nfLogGroup) override;
 
   private:
-    std::shared_ptr<NetlinkListenerInterface> mListener;
+    std::shared_ptr<netdutils::NetlinkListenerInterface> mListener;
     std::mutex mMutex;
     std::map<uint16_t, DispatchFn> mDispatchMap;  // guarded by mMutex
 };
diff --git a/server/NFLogListenerTest.cpp b/server/NFLogListenerTest.cpp
index f3bd810..88ab2c6 100644
--- a/server/NFLogListenerTest.cpp
+++ b/server/NFLogListenerTest.cpp
@@ -38,9 +38,10 @@
 namespace android {
 namespace net {
 
+using netdutils::makeSlice;
+using netdutils::NetlinkListenerInterface;
 using netdutils::Slice;
 using netdutils::StatusOr;
-using netdutils::makeSlice;
 using netdutils::status::ok;
 
 constexpr int kNFLogPacketMsgType = (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_PACKET;
diff --git a/server/NdcDispatcher.cpp b/server/NdcDispatcher.cpp
index 80ad7fb..303d0dd 100644
--- a/server/NdcDispatcher.cpp
+++ b/server/NdcDispatcher.cpp
@@ -136,7 +136,6 @@
     registerCmd(new BandwidthControlCmd());
     registerCmd(new IdletimerControlCmd());
     registerCmd(new FirewallCmd());
-    registerCmd(new ClatdCmd());
     registerCmd(new NetworkCommand());
     registerCmd(new StrictCmd());
 }
@@ -844,40 +843,6 @@
     return 0;
 }
 
-NdcDispatcher::ClatdCmd::ClatdCmd() : NdcNetdCommand("clatd") {}
-
-int NdcDispatcher::ClatdCmd::runCommand(NdcClient* cli, int argc, char** argv) const {
-    int rc = 0;
-    if (argc < 3) {
-        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
-        return 0;
-    }
-
-    std::string v6Addr;
-
-    if (!strcmp(argv[1], "stop")) {
-        rc = !mNetd->clatdStop(argv[2]).isOk();
-    } else if (!strcmp(argv[1], "start")) {
-        if (argc < 4) {
-            cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
-            return 0;
-        }
-        rc = !mNetd->clatdStart(argv[2], argv[3], &v6Addr).isOk();
-    } else {
-        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown clatd cmd", false);
-        return 0;
-    }
-
-    if (!rc) {
-        cli->sendMsg(ResponseCode::CommandOkay,
-                     std::string(("Clatd operation succeeded ") + v6Addr).c_str(), false);
-    } else {
-        cli->sendMsg(ResponseCode::OperationFailed, "Clatd operation failed", false);
-    }
-
-    return 0;
-}
-
 NdcDispatcher::StrictCmd::StrictCmd() : NdcNetdCommand("strict") {}
 
 int NdcDispatcher::StrictCmd::sendGenericOkFail(NdcClient* cli, int cond) const {
diff --git a/server/NdcDispatcher.h b/server/NdcDispatcher.h
index 5732e22..2b01116 100644
--- a/server/NdcDispatcher.h
+++ b/server/NdcDispatcher.h
@@ -137,13 +137,6 @@
         static int parseChildChain(const char* arg);
     };
 
-    class ClatdCmd : public NdcNetdCommand {
-      public:
-        ClatdCmd();
-        virtual ~ClatdCmd() {}
-        int runCommand(NdcClient* cli, int argc, char** argv) const;
-    };
-
     class StrictCmd : public NdcNetdCommand {
       public:
         StrictCmd();
diff --git a/server/NetdConstants.cpp b/server/NetdConstants.cpp
index f3898f5..6de164f 100644
--- a/server/NetdConstants.cpp
+++ b/server/NetdConstants.cpp
@@ -171,3 +171,37 @@
         ALOGE("Can't set control socket %s to FD_CLOEXEC", sock);
     }
 }
+
+// SIGTERM with timeout first, if fail, SIGKILL
+void stopProcess(int pid, const char* processName) {
+    int err = kill(pid, SIGTERM);
+    if (err) {
+        err = errno;
+    }
+    if (err == ESRCH) {
+        // This means that someone else inside netd called this helper function,
+        // which is a programming error. There's no point in calling waitpid() here since we
+        // know that the process is gone.
+        ALOGE("%s child process %d unexpectedly disappeared", processName, pid);
+        return;
+    }
+    if (err) {
+        ALOGE("Error killing %s child process %d: %s", processName, pid, strerror(err));
+    }
+    int status = 0;
+    int ret = 0;
+    for (int count = 0; ret == 0 && count < 50; count++) {
+        usleep(100000); // sleep 0.1s to wait for process stop.
+        ret = waitpid(pid, &status, WNOHANG);
+    }
+    if (ret == 0) {
+        ALOGE("Failed to SIGTERM %s pid=%d, try SIGKILL", processName, pid);
+        kill(pid, SIGKILL);
+        ret = waitpid(pid, &status, 0);
+    }
+    if (ret == -1) {
+        ALOGE("Error waiting for %s child process %d: %s", processName, pid, strerror(errno));
+    } else {
+        ALOGD("%s process %d terminated status=%d", processName, pid, status);
+    }
+}
diff --git a/server/NetdConstants.h b/server/NetdConstants.h
index c273e1b..6951239 100644
--- a/server/NetdConstants.h
+++ b/server/NetdConstants.h
@@ -24,6 +24,8 @@
 #include <mutex>
 #include <string>
 
+#include "android/net/INetd.h"
+
 #include <netdutils/UidConstants.h>
 #include <private/android_filesystem_config.h>
 
@@ -39,6 +41,8 @@
 void blockSigpipe();
 void setCloseOnExec(const char *sock);
 
+void stopProcess(int pid, const char* processName);
+
 // TODO: use std::size() instead.
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
 
@@ -74,4 +78,20 @@
  */
 extern std::mutex gBigNetdLock;
 
+enum FirewallRule { ALLOW = INetd::FIREWALL_RULE_ALLOW, DENY = INetd::FIREWALL_RULE_DENY };
+
+// ALLOWLIST means the firewall denies all by default, uids must be explicitly ALLOWed
+// DENYLIST means the firewall allows all by default, uids must be explicitly DENYed
+
+enum FirewallType { ALLOWLIST = INetd::FIREWALL_ALLOWLIST, DENYLIST = INetd::FIREWALL_DENYLIST };
+
+enum ChildChain {
+    NONE = INetd::FIREWALL_CHAIN_NONE,
+    DOZABLE = INetd::FIREWALL_CHAIN_DOZABLE,
+    STANDBY = INetd::FIREWALL_CHAIN_STANDBY,
+    POWERSAVE = INetd::FIREWALL_CHAIN_POWERSAVE,
+    RESTRICTED = INetd::FIREWALL_CHAIN_RESTRICTED,
+    INVALID_CHAIN
+};
+
 }  // namespace android::net
diff --git a/server/NetdNativeService.cpp b/server/NetdNativeService.cpp
index 1f5dc97..466d8ba 100644
--- a/server/NetdNativeService.cpp
+++ b/server/NetdNativeService.cpp
@@ -32,6 +32,7 @@
 #include <cutils/properties.h>
 #include <log/log.h>
 #include <netdutils/DumpWriter.h>
+#include <netdutils/Utils.h>
 #include <utils/Errors.h>
 #include <utils/String16.h>
 
@@ -52,12 +53,11 @@
 
 using android::base::StringPrintf;
 using android::base::WriteStringToFile;
-using android::net::NativeNetworkType;
-using android::net::TetherOffloadRuleParcel;
 using android::net::TetherStatsParcel;
 using android::net::UidRangeParcel;
 using android::net::netd::aidl::NativeUidRangeConfig;
 using android::netdutils::DumpWriter;
+using android::netdutils::getIfaceNames;
 using android::netdutils::ScopedIndent;
 using android::os::ParcelFileDescriptor;
 
@@ -67,48 +67,6 @@
 namespace {
 const char OPT_SHORT[] = "--short";
 
-// The input permissions should be equivalent that this function would return ok if any of them is
-// granted.
-binder::Status checkAnyPermission(const std::vector<const char*>& permissions) {
-    pid_t pid = IPCThreadState::self()->getCallingPid();
-    uid_t uid = IPCThreadState::self()->getCallingUid();
-
-    // TODO: Do the pure permission check in this function. Have another method
-    // (e.g. checkNetworkStackPermission) to wrap AID_SYSTEM and
-    // AID_NETWORK_STACK uid check.
-    // If the caller is the system UID, don't check permissions.
-    // Otherwise, if the system server's binder thread pool is full, and all the threads are
-    // blocked on a thread that's waiting for us to complete, we deadlock. http://b/69389492
-    //
-    // From a security perspective, there is currently no difference, because:
-    // 1. The system server has the NETWORK_STACK permission, which grants access to all the
-    //    IPCs in this file.
-    // 2. AID_SYSTEM always has all permissions. See ActivityManager#checkComponentPermission.
-    if (uid == AID_SYSTEM) {
-        return binder::Status::ok();
-    }
-    // AID_NETWORK_STACK own MAINLINE_NETWORK_STACK permission, don't IPC to system server to check
-    // MAINLINE_NETWORK_STACK permission. Cross-process(netd, networkstack and system server)
-    // deadlock: http://b/149766727
-    if (uid == AID_NETWORK_STACK) {
-        for (const char* permission : permissions) {
-            if (std::strcmp(permission, PERM_MAINLINE_NETWORK_STACK) == 0) {
-                return binder::Status::ok();
-            }
-        }
-    }
-
-    for (const char* permission : permissions) {
-        if (checkPermission(String16(permission), pid, uid)) {
-            return binder::Status::ok();
-        }
-    }
-
-    auto err = StringPrintf("UID %d / PID %d does not have any of the following permissions: %s",
-                            uid, pid, android::base::Join(permissions, ',').c_str());
-    return binder::Status::fromExceptionCode(binder::Status::EX_SECURITY, err.c_str());
-}
-
 #define ENFORCE_ANY_PERMISSION(...)                                \
     do {                                                           \
         binder::Status status = checkAnyPermission({__VA_ARGS__}); \
@@ -153,13 +111,6 @@
                                                     result.error().message().c_str());
 }
 
-inline binder::Status statusFromErrcode(int ret) {
-    if (ret) {
-        return binder::Status::fromServiceSpecificError(-ret, strerror(-ret));
-    }
-    return binder::Status::ok();
-}
-
 bool contains(const Vector<String16>& words, const String16& word) {
     for (const auto& w : words) {
         if (w == word) return true;
@@ -210,27 +161,14 @@
       return NO_ERROR;
     }
 
-    if (!args.isEmpty() && args[0] == TrafficController::DUMP_KEYWORD) {
-        dw.blankline();
-        gCtls->trafficCtrl.dump(dw, true);
-        dw.blankline();
-        return NO_ERROR;
-    }
-
     process::dump(dw);
     dw.blankline();
     gCtls->netCtrl.dump(dw);
     dw.blankline();
 
-    gCtls->trafficCtrl.dump(dw, false);
-    dw.blankline();
-
     gCtls->xfrmCtrl.dump(dw);
     dw.blankline();
 
-    gCtls->clatdCtrl.dump(dw);
-    dw.blankline();
-
     gCtls->tetherCtrl.dump(dw);
     dw.blankline();
 
@@ -270,14 +208,9 @@
     return binder::Status::ok();
 }
 
-binder::Status NetdNativeService::firewallReplaceUidChain(const std::string& chainName,
-                                                          bool isAllowlist,
-                                                          const std::vector<int32_t>& uids,
-                                                          bool* ret) {
-    NETD_LOCKING_RPC(gCtls->firewallCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK);
-    int err = gCtls->firewallCtrl.replaceUidChain(chainName, isAllowlist, uids);
-    *ret = (err == 0);
-    return binder::Status::ok();
+binder::Status NetdNativeService::firewallReplaceUidChain(const std::string&, bool,
+                                                          const std::vector<int32_t>&, bool*) {
+    return binder::Status::fromExceptionCode(binder::Status::EX_UNSUPPORTED_OPERATION);
 }
 
 binder::Status NetdNativeService::bandwidthEnableDataSaver(bool enable, bool *ret) {
@@ -319,32 +252,20 @@
     return statusFromErrcode(res);
 }
 
-binder::Status NetdNativeService::bandwidthAddNaughtyApp(int32_t uid) {
-    NETD_LOCKING_RPC(gCtls->bandwidthCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK);
-    std::vector<uint32_t> appUids = {static_cast<uint32_t>(abs(uid))};
-    int res = gCtls->bandwidthCtrl.addNaughtyApps(appUids);
-    return statusFromErrcode(res);
+binder::Status NetdNativeService::bandwidthAddNaughtyApp(int32_t) {
+    return binder::Status::fromExceptionCode(binder::Status::EX_UNSUPPORTED_OPERATION);
 }
 
-binder::Status NetdNativeService::bandwidthRemoveNaughtyApp(int32_t uid) {
-    NETD_LOCKING_RPC(gCtls->bandwidthCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK);
-    std::vector<uint32_t> appUids = {static_cast<uint32_t>(abs(uid))};
-    int res = gCtls->bandwidthCtrl.removeNaughtyApps(appUids);
-    return statusFromErrcode(res);
+binder::Status NetdNativeService::bandwidthRemoveNaughtyApp(int32_t) {
+    return binder::Status::fromExceptionCode(binder::Status::EX_UNSUPPORTED_OPERATION);
 }
 
-binder::Status NetdNativeService::bandwidthAddNiceApp(int32_t uid) {
-    NETD_LOCKING_RPC(gCtls->bandwidthCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK);
-    std::vector<uint32_t> appUids = {static_cast<uint32_t>(abs(uid))};
-    int res = gCtls->bandwidthCtrl.addNiceApps(appUids);
-    return statusFromErrcode(res);
+binder::Status NetdNativeService::bandwidthAddNiceApp(int32_t) {
+    return binder::Status::fromExceptionCode(binder::Status::EX_UNSUPPORTED_OPERATION);
 }
 
-binder::Status NetdNativeService::bandwidthRemoveNiceApp(int32_t uid) {
-    NETD_LOCKING_RPC(gCtls->bandwidthCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK);
-    std::vector<uint32_t> appUids = {static_cast<uint32_t>(abs(uid))};
-    int res = gCtls->bandwidthCtrl.removeNiceApps(appUids);
-    return statusFromErrcode(res);
+binder::Status NetdNativeService::bandwidthRemoveNiceApp(int32_t) {
+    return binder::Status::fromExceptionCode(binder::Status::EX_UNSUPPORTED_OPERATION);
 }
 
 // TODO: Remove this function when there are no users. Currently, it is still used by DNS resolver
@@ -362,7 +283,8 @@
     // The value of vpnType does not matter here, because it is not used in AOSP and is only
     // implemented by OEMs. Also, the RPC is going to deprecate. Just pick a value defined in INetd
     // as default.
-    int ret = gCtls->netCtrl.createVirtualNetwork(netId, secure, NativeVpnType::LEGACY);
+    int ret = gCtls->netCtrl.createVirtualNetwork(netId, secure, NativeVpnType::LEGACY,
+                                                  false /* excludeLocalRoutes */);
     return statusFromErrcode(ret);
 }
 
@@ -373,7 +295,8 @@
         ret = gCtls->netCtrl.createPhysicalNetwork(config.netId,
                                                    convertPermission(config.permission));
     } else if (config.networkType == NativeNetworkType::VIRTUAL) {
-        ret = gCtls->netCtrl.createVirtualNetwork(config.netId, config.secure, config.vpnType);
+        ret = gCtls->netCtrl.createVirtualNetwork(config.netId, config.secure, config.vpnType,
+                                                  config.excludeLocalRoutes);
     }
     return statusFromErrcode(ret);
 }
@@ -402,7 +325,7 @@
     // NetworkController::addUsersToNetwork is thread-safe.
     ENFORCE_NETWORK_STACK_PERMISSIONS();
     int ret = gCtls->netCtrl.addUsersToNetwork(netId, UidRanges(uidRangeArray),
-                                               UidRanges::DEFAULT_SUB_PRIORITY);
+                                               UidRanges::SUB_PRIORITY_HIGHEST);
     return statusFromErrcode(ret);
 }
 
@@ -411,7 +334,7 @@
     // NetworkController::removeUsersFromNetwork is thread-safe.
     ENFORCE_NETWORK_STACK_PERMISSIONS();
     int ret = gCtls->netCtrl.removeUsersFromNetwork(netId, UidRanges(uidRangeArray),
-                                                    UidRanges::DEFAULT_SUB_PRIORITY);
+                                                    UidRanges::SUB_PRIORITY_HIGHEST);
     return statusFromErrcode(ret);
 }
 
@@ -786,8 +709,7 @@
 }
 
 binder::Status NetdNativeService::trafficSwapActiveStatsMap() {
-    ENFORCE_NETWORK_STACK_PERMISSIONS();
-    return asBinderStatus(gCtls->trafficCtrl.swapActiveStatsMap());
+    return binder::Status::fromExceptionCode(binder::Status::EX_UNSUPPORTED_OPERATION);
 }
 
 binder::Status NetdNativeService::idletimerAddInterface(const std::string& ifName, int32_t timeout,
@@ -828,17 +750,20 @@
     return statusFromErrcode(res);
 }
 
-binder::Status NetdNativeService::clatdStart(const std::string& ifName,
-                                             const std::string& nat64Prefix, std::string* v6Addr) {
+// TODO: remark @deprecated in INetd.aidl.
+binder::Status NetdNativeService::clatdStart(const std::string& /* ifName */,
+                                             const std::string& /* nat64Prefix */,
+                                             std::string* /* v6Addr */) {
     ENFORCE_ANY_PERMISSION(PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK);
-    int res = gCtls->clatdCtrl.startClatd(ifName.c_str(), nat64Prefix, v6Addr);
-    return statusFromErrcode(res);
+    // deprecated
+    return binder::Status::fromExceptionCode(binder::Status::EX_UNSUPPORTED_OPERATION);
 }
 
-binder::Status NetdNativeService::clatdStop(const std::string& ifName) {
+// TODO: remark @deprecated in INetd.aidl.
+binder::Status NetdNativeService::clatdStop(const std::string& /* ifName */) {
     ENFORCE_ANY_PERMISSION(PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK);
-    int res = gCtls->clatdCtrl.stopClatd(ifName.c_str());
-    return statusFromErrcode(res);
+    // deprecated
+    return binder::Status::fromExceptionCode(binder::Status::EX_UNSUPPORTED_OPERATION);
 }
 
 binder::Status NetdNativeService::ipfwdEnabled(bool* status) {
@@ -891,7 +816,7 @@
 
 binder::Status NetdNativeService::interfaceGetList(std::vector<std::string>* interfaceListResult) {
     NETD_LOCKING_RPC(InterfaceController::mutex, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK);
-    const auto& ifaceList = InterfaceController::getIfaceNames();
+    const auto& ifaceList = getIfaceNames();
 
     interfaceListResult->clear();
     interfaceListResult->reserve(ifaceList.value().size());
@@ -1180,11 +1105,8 @@
     return binder::Status::ok();
 }
 
-binder::Status NetdNativeService::trafficSetNetPermForUids(int32_t permission,
-                                                           const std::vector<int32_t>& uids) {
-    ENFORCE_NETWORK_STACK_PERMISSIONS();
-    gCtls->trafficCtrl.setPermissionForUids(permission, intsToUids(uids));
-    return binder::Status::ok();
+binder::Status NetdNativeService::trafficSetNetPermForUids(int32_t, const std::vector<int32_t>&) {
+    return binder::Status::fromExceptionCode(binder::Status::EX_UNSUPPORTED_OPERATION);
 }
 
 binder::Status NetdNativeService::firewallSetFirewallType(int32_t firewallType) {
@@ -1204,37 +1126,21 @@
     return statusFromErrcode(res);
 }
 
-binder::Status NetdNativeService::firewallSetUidRule(int32_t childChain, int32_t uid,
-                                                     int32_t firewallRule) {
-    NETD_LOCKING_RPC(gCtls->firewallCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK);
-    auto chain = static_cast<ChildChain>(childChain);
-    auto rule = static_cast<FirewallRule>(firewallRule);
-
-    int res = gCtls->firewallCtrl.setUidRule(chain, uid, rule);
-    return statusFromErrcode(res);
+binder::Status NetdNativeService::firewallSetUidRule(int32_t, int32_t, int32_t) {
+    return binder::Status::fromExceptionCode(binder::Status::EX_UNSUPPORTED_OPERATION);
 }
 
-binder::Status NetdNativeService::firewallEnableChildChain(int32_t childChain, bool enable) {
-    NETD_LOCKING_RPC(gCtls->firewallCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK);
-    auto chain = static_cast<ChildChain>(childChain);
-
-    int res = gCtls->firewallCtrl.enableChildChains(chain, enable);
-    return statusFromErrcode(res);
+binder::Status NetdNativeService::firewallEnableChildChain(int32_t, bool) {
+    return binder::Status::fromExceptionCode(binder::Status::EX_UNSUPPORTED_OPERATION);
 }
 
-binder::Status NetdNativeService::firewallAddUidInterfaceRules(const std::string& ifName,
-                                                               const std::vector<int32_t>& uids) {
-    ENFORCE_NETWORK_STACK_PERMISSIONS();
-
-    return asBinderStatus(gCtls->trafficCtrl.addUidInterfaceRules(
-            RouteController::getIfIndex(ifName.c_str()), uids));
+binder::Status NetdNativeService::firewallAddUidInterfaceRules(const std::string&,
+                                                               const std::vector<int32_t>&) {
+    return binder::Status::fromExceptionCode(binder::Status::EX_UNSUPPORTED_OPERATION);
 }
 
-binder::Status NetdNativeService::firewallRemoveUidInterfaceRules(
-        const std::vector<int32_t>& uids) {
-    ENFORCE_NETWORK_STACK_PERMISSIONS();
-
-    return asBinderStatus(gCtls->trafficCtrl.removeUidInterfaceRules(uids));
+binder::Status NetdNativeService::firewallRemoveUidInterfaceRules(const std::vector<int32_t>&) {
+    return binder::Status::fromExceptionCode(binder::Status::EX_UNSUPPORTED_OPERATION);
 }
 
 binder::Status NetdNativeService::tetherAddForward(const std::string& intIface,
diff --git a/server/NetlinkCommands.cpp b/server/NetlinkCommands.cpp
index acefa8e..7cb08d8 100644
--- a/server/NetlinkCommands.cpp
+++ b/server/NetlinkCommands.cpp
@@ -84,6 +84,11 @@
 // Returns -errno if there was an error or if the kernel reported an error.
 OPTNONE int sendNetlinkRequest(uint16_t action, uint16_t flags, iovec* iov, int iovlen,
                                const NetlinkDumpCallback* callback) {
+    int sock = openNetlinkSocket(NETLINK_ROUTE);
+    if (sock < 0) {
+        return sock;
+    }
+
     nlmsghdr nlmsg = {
         .nlmsg_type = action,
         .nlmsg_flags = flags,
@@ -94,14 +99,11 @@
         nlmsg.nlmsg_len += iov[i].iov_len;
     }
 
-    int sock = openNetlinkSocket(NETLINK_ROUTE);
-    if (sock < 0) {
-        return sock;
-    }
-
+    ssize_t writevRet = writev(sock, iov, iovlen);
+    // Don't let pointers to the stack escape.
+    iov[0] = {nullptr, 0};
     int ret = 0;
-
-    if (writev(sock, iov, iovlen) == -1) {
+    if (writevRet == -1) {
         ret = -errno;
         ALOGE("netlink socket connect/writev failed (%s)", strerror(-ret));
         close(sock);
diff --git a/server/NetlinkHandler.cpp b/server/NetlinkHandler.cpp
index 525bb2d..a4e05b0 100644
--- a/server/NetlinkHandler.cpp
+++ b/server/NetlinkHandler.cpp
@@ -107,18 +107,6 @@
     if (!strcmp(subsys, "net")) {
         NetlinkEvent::Action action = evt->getAction();
         const char *iface = evt->findParam("INTERFACE");
-        if ((action == NetlinkEvent::Action::kAdd) ||
-            (action == NetlinkEvent::Action::kLinkUp) ||
-            (action == NetlinkEvent::Action::kLinkDown)) {
-            const char *ifIndex = evt->findParam("IFINDEX");
-            long ifaceIndex = parseIfIndex(ifIndex);
-            if (ifaceIndex) {
-                gCtls->trafficCtrl.addInterface(iface, ifaceIndex);
-            } else {
-                ALOGE("invalid interface index: %s(%s)", iface, ifIndex);
-            }
-        }
-
         if (action == NetlinkEvent::Action::kAdd) {
             notifyInterfaceAdded(iface);
         } else if (action == NetlinkEvent::Action::kRemove) {
diff --git a/server/NetlinkListener.cpp b/server/NetlinkListener.cpp
deleted file mode 100644
index a6e427d..0000000
--- a/server/NetlinkListener.cpp
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "NetlinkListener"
-
-#include "NetlinkListener.h"
-
-#include <sstream>
-#include <vector>
-
-#include <linux/netfilter/nfnetlink.h>
-
-#include <log/log.h>
-#include <netdutils/Misc.h>
-#include <netdutils/Syscalls.h>
-
-namespace android {
-namespace net {
-
-using netdutils::Fd;
-using netdutils::Slice;
-using netdutils::Status;
-using netdutils::UniqueFd;
-using netdutils::findWithDefault;
-using netdutils::forEachNetlinkMessage;
-using netdutils::makeSlice;
-using netdutils::sSyscalls;
-using netdutils::status::ok;
-using netdutils::statusFromErrno;
-
-namespace {
-
-constexpr int kNetlinkMsgErrorType = (NFNL_SUBSYS_NONE << 8) | NLMSG_ERROR;
-
-constexpr sockaddr_nl kKernelAddr = {
-    .nl_family = AF_NETLINK, .nl_pad = 0, .nl_pid = 0, .nl_groups = 0,
-};
-
-const NetlinkListener::DispatchFn kDefaultDispatchFn = [](const nlmsghdr& nlmsg, const Slice) {
-    std::stringstream ss;
-    ss << nlmsg;
-    ALOGE("unhandled netlink message: %s", ss.str().c_str());
-};
-
-}  // namespace
-
-NetlinkListener::NetlinkListener(UniqueFd event, UniqueFd sock, const std::string& name)
-    : mEvent(std::move(event)), mSock(std::move(sock)), mThreadName(name) {
-    const auto rxErrorHandler = [](const nlmsghdr& nlmsg, const Slice msg) {
-        std::stringstream ss;
-        ss << nlmsg << " " << msg << " " << netdutils::toHex(msg, 32);
-        ALOGE("unhandled netlink message: %s", ss.str().c_str());
-    };
-    expectOk(NetlinkListener::subscribe(kNetlinkMsgErrorType, rxErrorHandler));
-
-    mErrorHandler = [& name = mThreadName](const int fd, const int err) {
-        ALOGE("Error on NetlinkListener(%s) fd=%d: %s", name.c_str(), fd, strerror(err));
-    };
-
-    // Start the thread
-    mWorker = std::thread([this]() { run().ignoreError(); });
-}
-
-NetlinkListener::~NetlinkListener() {
-    const auto& sys = sSyscalls.get();
-    const uint64_t data = 1;
-    // eventfd should never enter an error state unexpectedly
-    expectOk(sys.write(mEvent, makeSlice(data)).status());
-    mWorker.join();
-}
-
-Status NetlinkListener::send(const Slice msg) {
-    const auto& sys = sSyscalls.get();
-    ASSIGN_OR_RETURN(auto sent, sys.sendto(mSock, msg, 0, kKernelAddr));
-    if (sent != msg.size()) {
-        return statusFromErrno(EMSGSIZE, "unexpect message size");
-    }
-    return ok;
-}
-
-Status NetlinkListener::subscribe(uint16_t type, const DispatchFn& fn) {
-    std::lock_guard guard(mMutex);
-    mDispatchMap[type] = fn;
-    return ok;
-}
-
-Status NetlinkListener::unsubscribe(uint16_t type) {
-    std::lock_guard guard(mMutex);
-    mDispatchMap.erase(type);
-    return ok;
-}
-
-void NetlinkListener::registerSkErrorHandler(const SkErrorHandler& handler) {
-    mErrorHandler = handler;
-}
-
-Status NetlinkListener::run() {
-    std::vector<char> rxbuf(4096);
-
-    const auto rxHandler = [this](const nlmsghdr& nlmsg, const Slice& buf) {
-        std::lock_guard guard(mMutex);
-        const auto& fn = findWithDefault(mDispatchMap, nlmsg.nlmsg_type, kDefaultDispatchFn);
-        fn(nlmsg, buf);
-    };
-
-    if (mThreadName.length() > 0) {
-        int ret = pthread_setname_np(pthread_self(), mThreadName.c_str());
-        if (ret) {
-            ALOGE("thread name set failed, name: %s, ret: %s", mThreadName.c_str(), strerror(ret));
-        }
-    }
-    const auto& sys = sSyscalls.get();
-    const std::array<Fd, 2> fds{{{mEvent}, {mSock}}};
-    const int events = POLLIN;
-    const double timeout = 3600;
-    while (true) {
-        ASSIGN_OR_RETURN(auto revents, sys.ppoll(fds, events, timeout));
-        // After mEvent becomes readable, we should stop servicing mSock and return
-        if (revents[0] & POLLIN) {
-            break;
-        }
-        if (revents[1] & (POLLIN|POLLERR)) {
-            auto rx = sys.recvfrom(mSock, makeSlice(rxbuf), 0);
-            int err = rx.status().code();
-            if (err) {
-                // Ignore errors. The only error we expect to see here is ENOBUFS, and there's
-                // nothing we can do about that. The recvfrom above will already have cleared the
-                // error indication and ensured we won't get EPOLLERR again.
-                // TODO: Consider using NETLINK_NO_ENOBUFS.
-                mErrorHandler(((Fd) mSock).get(), err);
-                continue;
-            }
-            forEachNetlinkMessage(rx.value(), rxHandler);
-        }
-    }
-    return ok;
-}
-
-}  // namespace net
-}  // namespace android
diff --git a/server/NetlinkListener.h b/server/NetlinkListener.h
deleted file mode 100644
index 6f38829..0000000
--- a/server/NetlinkListener.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NETLINK_LISTENER_H
-#define NETLINK_LISTENER_H
-
-#include <functional>
-#include <map>
-#include <mutex>
-#include <thread>
-
-#include <android-base/thread_annotations.h>
-#include <netdutils/Netlink.h>
-#include <netdutils/Slice.h>
-#include <netdutils/Status.h>
-#include <netdutils/UniqueFd.h>
-
-namespace android {
-namespace net {
-
-class NetlinkListenerInterface {
-  public:
-    using DispatchFn = std::function<void(const nlmsghdr& nlmsg, const netdutils::Slice msg)>;
-
-    using SkErrorHandler = std::function<void(const int fd, const int err)>;
-
-    virtual ~NetlinkListenerInterface() = default;
-
-    // Send message to the kernel using the underlying netlink socket
-    virtual netdutils::Status send(const netdutils::Slice msg) = 0;
-
-    // Deliver future messages with nlmsghdr.nlmsg_type == type to fn.
-    //
-    // Threadsafe.
-    // All dispatch functions invoked on a single service thread.
-    // subscribe() and join() must not be called from the stack of fn().
-    virtual netdutils::Status subscribe(uint16_t type, const DispatchFn& fn) = 0;
-
-    // Halt delivery of future messages with nlmsghdr.nlmsg_type == type.
-    // Threadsafe.
-    virtual netdutils::Status unsubscribe(uint16_t type) = 0;
-
-    virtual void registerSkErrorHandler(const SkErrorHandler& handler) = 0;
-};
-
-// NetlinkListener manages a netlink socket and associated blocking
-// service thread.
-//
-// This class is written in a generic way to allow multiple different
-// netlink subsystems to share this common infrastructure. If multiple
-// subsystems share the same message delivery requirements (drops ok,
-// no drops) they may share a single listener by calling subscribe()
-// with multiple types.
-//
-// This class is suitable for moderate performance message
-// processing. In particular it avoids extra copies of received
-// message data and allows client code to control which message
-// attributes are processed.
-//
-// Note that NetlinkListener is capable of processing multiple batched
-// netlink messages in a single system call. This is useful to
-// netfilter extensions that allow batching of events like NFLOG.
-class NetlinkListener : public NetlinkListenerInterface {
-  public:
-    NetlinkListener(netdutils::UniqueFd event, netdutils::UniqueFd sock, const std::string& name);
-
-    ~NetlinkListener() override;
-
-    netdutils::Status send(const netdutils::Slice msg) override;
-
-    netdutils::Status subscribe(uint16_t type, const DispatchFn& fn) override EXCLUDES(mMutex);
-
-    netdutils::Status unsubscribe(uint16_t type) override EXCLUDES(mMutex);
-
-    void registerSkErrorHandler(const SkErrorHandler& handler) override;
-
-  private:
-    netdutils::Status run();
-
-    const netdutils::UniqueFd mEvent;
-    const netdutils::UniqueFd mSock;
-    const std::string mThreadName;
-    std::mutex mMutex;
-    std::map<uint16_t, DispatchFn> mDispatchMap GUARDED_BY(mMutex);
-    std::thread mWorker;
-    SkErrorHandler mErrorHandler;
-};
-
-}  // namespace net
-}  // namespace android
-
-#endif /* NETLINK_LISTENER_H */
diff --git a/server/Network.cpp b/server/Network.cpp
index 72a1545..85f942f 100644
--- a/server/Network.cpp
+++ b/server/Network.cpp
@@ -86,7 +86,7 @@
 // Check if the user has been added to this network. If yes, the highest priority of matching
 // setting is returned by subPriority. Thus caller can make choice among several matching
 // networks.
-bool Network::appliesToUser(uid_t uid, uint32_t* subPriority) const {
+bool Network::appliesToUser(uid_t uid, int32_t* subPriority) const {
     for (const auto& [priority, uidRanges] : mUidRangeMap) {
         if (uidRanges.hasUid(uid)) {
             *subPriority = priority;
@@ -96,7 +96,7 @@
     return false;
 }
 
-void Network::addToUidRangeMap(const UidRanges& uidRanges, uint32_t subPriority) {
+void Network::addToUidRangeMap(const UidRanges& uidRanges, int32_t subPriority) {
     auto iter = mUidRangeMap.find(subPriority);
     if (iter != mUidRangeMap.end()) {
         iter->second.add(uidRanges);
@@ -105,7 +105,7 @@
     }
 }
 
-void Network::removeFromUidRangeMap(const UidRanges& uidRanges, uint32_t subPriority) {
+void Network::removeFromUidRangeMap(const UidRanges& uidRanges, int32_t subPriority) {
     auto iter = mUidRangeMap.find(subPriority);
     if (iter != mUidRangeMap.end()) {
         iter->second.remove(uidRanges);
@@ -113,11 +113,11 @@
             mUidRangeMap.erase(subPriority);
         }
     } else {
-        ALOGW("uidRanges with priority %u not found", subPriority);
+        ALOGW("uidRanges with priority %d not found", subPriority);
     }
 }
 
-bool Network::canAddUidRanges(const UidRanges& uidRanges, uint32_t subPriority) const {
+bool Network::canAddUidRanges(const UidRanges& uidRanges, int32_t subPriority) const {
     if (uidRanges.overlapsSelf()) {
         ALOGE("uid range %s overlaps self", uidRanges.toString().c_str());
         return false;
@@ -125,7 +125,7 @@
 
     auto iter = mUidRangeMap.find(subPriority);
     if (iter != mUidRangeMap.end() && uidRanges.overlaps(iter->second)) {
-        ALOGE("uid range %s overlaps priority %u %s", uidRanges.toString().c_str(), subPriority,
+        ALOGE("uid range %s overlaps priority %d %s", uidRanges.toString().c_str(), subPriority,
               iter->second.toString().c_str());
         return false;
     }
diff --git a/server/Network.h b/server/Network.h
index aa1b21a..e18e1cd 100644
--- a/server/Network.h
+++ b/server/Network.h
@@ -24,7 +24,7 @@
 
 namespace android::net {
 
-typedef std::map<uint32_t, UidRanges> UidRangeMap;
+typedef std::map<int32_t, UidRanges> UidRangeMap;
 
 // A Network represents a collection of interfaces participating as a single administrative unit.
 class Network {
@@ -47,11 +47,11 @@
 
     std::string toString() const;
     std::string uidRangesToString() const;
-    bool appliesToUser(uid_t uid, uint32_t* subPriority) const;
-    [[nodiscard]] virtual int addUsers(const UidRanges&, uint32_t /*subPriority*/) {
+    bool appliesToUser(uid_t uid, int32_t* subPriority) const;
+    [[nodiscard]] virtual int addUsers(const UidRanges&, int32_t /*subPriority*/) {
         return -EINVAL;
     };
-    [[nodiscard]] virtual int removeUsers(const UidRanges&, uint32_t /*subPriority*/) {
+    [[nodiscard]] virtual int removeUsers(const UidRanges&, int32_t /*subPriority*/) {
         return -EINVAL;
     };
     bool isSecure() const;
@@ -59,18 +59,18 @@
     virtual bool isUnreachable() { return false; }
     virtual bool isVirtual() { return false; }
     virtual bool canAddUsers() { return false; }
-    virtual bool isValidSubPriority(uint32_t /*priority*/) { return false; }
-    virtual void addToUidRangeMap(const UidRanges& uidRanges, uint32_t subPriority);
-    virtual void removeFromUidRangeMap(const UidRanges& uidRanges, uint32_t subPriority);
+    virtual bool isValidSubPriority(int32_t /*priority*/) { return false; }
+    virtual void addToUidRangeMap(const UidRanges& uidRanges, int32_t subPriority);
+    virtual void removeFromUidRangeMap(const UidRanges& uidRanges, int32_t subPriority);
 
 protected:
-    explicit Network(unsigned netId, bool mSecure = false);
-    bool canAddUidRanges(const UidRanges& uidRanges, uint32_t subPriority) const;
+    explicit Network(unsigned netId, bool secure = false);
+    bool canAddUidRanges(const UidRanges& uidRanges, int32_t subPriority) const;
 
     const unsigned mNetId;
     std::set<std::string> mInterfaces;
     // Each subsidiary priority maps to a set of UID ranges of a feature.
-    std::map<uint32_t, UidRanges> mUidRangeMap;
+    std::map<int32_t, UidRanges> mUidRangeMap;
     const bool mSecure;
 
 private:
diff --git a/server/NetworkController.cpp b/server/NetworkController.cpp
index 602639c..f144139 100644
--- a/server/NetworkController.cpp
+++ b/server/NetworkController.cpp
@@ -36,17 +36,19 @@
 #include "DummyNetwork.h"
 #include "Fwmark.h"
 #include "LocalNetwork.h"
-#include "OffloadUtils.h"
 #include "PhysicalNetwork.h"
 #include "RouteController.h"
+#include "TcUtils.h"
 #include "UnreachableNetwork.h"
 #include "VirtualNetwork.h"
 #include "netdutils/DumpWriter.h"
+#include "netdutils/Utils.h"
 #include "netid_client.h"
 
 #define DBG 0
 
 using android::netdutils::DumpWriter;
+using android::netdutils::getIfaceNames;
 
 namespace android::net {
 
@@ -150,7 +152,7 @@
     // TODO: perhaps only remove the clsact on the interface which is added by
     // RouteController::addInterfaceToPhysicalNetwork. Currently, the netd only
     // attach the clsact to the interface for the physical network.
-    const auto& ifaces = InterfaceController::getIfaceNames();
+    const auto& ifaces = getIfaceNames();
     if (isOk(ifaces)) {
         for (const std::string& iface : ifaces.value()) {
             if (int ifIndex = if_nametoindex(iface.c_str())) {
@@ -437,7 +439,8 @@
     return ret;
 }
 
-int NetworkController::createVirtualNetwork(unsigned netId, bool secure, NativeVpnType vpnType) {
+int NetworkController::createVirtualNetwork(unsigned netId, bool secure, NativeVpnType vpnType,
+                                            bool excludeLocalRoutes) {
     ScopedWLock lock(mRWLock);
 
     if (!(MIN_NET_ID <= netId && netId <= MAX_NET_ID)) {
@@ -458,7 +461,7 @@
     if (int ret = modifyFallthroughLocked(netId, true)) {
         return ret;
     }
-    mNetworks[netId] = new VirtualNetwork(netId, secure);
+    mNetworks[netId] = new VirtualNetwork(netId, secure, excludeLocalRoutes);
     return 0;
 }
 
@@ -617,7 +620,7 @@
 }  // namespace
 
 int NetworkController::addUsersToNetwork(unsigned netId, const UidRanges& uidRanges,
-                                         uint32_t subPriority) {
+                                         int32_t subPriority) {
     ScopedWLock lock(mRWLock);
     Network* network = getNetworkLocked(netId);
     if (int ret = isWrongNetworkForUidRanges(netId, network)) {
@@ -627,7 +630,7 @@
 }
 
 int NetworkController::removeUsersFromNetwork(unsigned netId, const UidRanges& uidRanges,
-                                              uint32_t subPriority) {
+                                              int32_t subPriority) {
     ScopedWLock lock(mRWLock);
     Network* network = getNetworkLocked(netId);
     if (int ret = isWrongNetworkForUidRanges(netId, network)) {
@@ -768,6 +771,22 @@
     }
     dw.decIndent();
 
+    dw.blankline();
+    dw.println("Permission of users:");
+    dw.incIndent();
+    std::vector<uid_t> systemUids;
+    std::vector<uid_t> networkUids;
+    for (const auto& [uid, permission] : mUsers) {
+        if ((permission & PERMISSION_SYSTEM) == PERMISSION_SYSTEM) {
+            systemUids.push_back(uid);
+        } else if ((permission & PERMISSION_NETWORK) == PERMISSION_NETWORK) {
+            networkUids.push_back(uid);
+        }
+    }
+    dw.println("NETWORK: %s", android::base::Join(networkUids, ", ").c_str());
+    dw.println("SYSTEM: %s", android::base::Join(systemUids, ", ").c_str());
+    dw.decIndent();
+
     dw.decIndent();
 
     dw.decIndent();
@@ -783,7 +802,7 @@
 }
 
 VirtualNetwork* NetworkController::getVirtualNetworkForUserLocked(uid_t uid) const {
-    uint32_t subPriority;
+    int32_t subPriority;
     for (const auto& [_, network] : mNetworks) {
         if (network->isVirtual() && network->appliesToUser(uid, &subPriority)) {
             return static_cast<VirtualNetwork*>(network);
@@ -792,17 +811,26 @@
     return nullptr;
 }
 
-// Returns a network with the highest subsidiary priority among physical and unreachable networks
-// that applies to uid. For a single subsidiary priority, an uid should belong to only one network.
-// If the uid apply to different network with the same priority at the same time, the behavior is
-// undefined. That is a configuration error.
+// Returns the default network with the highest subsidiary priority among physical and unreachable
+// networks that applies to uid. For a single subsidiary priority, an uid should belong to only one
+// network.  If the uid apply to different network with the same priority at the same time, the
+// behavior is undefined. That is a configuration error.
 Network* NetworkController::getPhysicalOrUnreachableNetworkForUserLocked(uid_t uid) const {
     Network* bestNetwork = nullptr;
-    unsigned bestSubPriority = UidRanges::LOWEST_SUB_PRIORITY + 1;
+
+    // In this function, appliesToUser() is used to figure out if this network is the user's default
+    // network (not just if the user has access to this network). Rules at SUB_PRIORITY_NO_DEFAULT
+    // "apply to the user" but do not include a default network rule. Since their subpriority (999)
+    // is greater than SUB_PRIORITY_LOWEST (998), these rules never trump any subpriority that
+    // includes a default network rule (appliesToUser returns the "highest" (=lowest value)
+    // subPriority that includes the uid), and they get filtered out in the if-statement below.
+    int32_t bestSubPriority = UidRanges::SUB_PRIORITY_NO_DEFAULT;
     for (const auto& [netId, network] : mNetworks) {
-        uint32_t subPriority;
+        int32_t subPriority;
         if (!network->isPhysical() && !network->isUnreachable()) continue;
         if (!network->appliesToUser(uid, &subPriority)) continue;
+        if (subPriority == UidRanges::SUB_PRIORITY_NO_DEFAULT) continue;
+
         if (subPriority < bestSubPriority) {
             bestNetwork = network;
             bestSubPriority = subPriority;
@@ -836,7 +864,7 @@
         return 0;
     }
     // If the UID wants to use a VPN, it can do so if and only if the VPN applies to the UID.
-    uint32_t subPriority;
+    int32_t subPriority;
     if (network->isVirtual()) {
         return network->appliesToUser(uid, &subPriority) ? 0 : -EPERM;
     }
@@ -897,11 +925,13 @@
 
     switch (op) {
         case ROUTE_ADD:
-            return RouteController::addRoute(interface, destination, nexthop, tableType, mtu);
+            return RouteController::addRoute(interface, destination, nexthop, tableType, mtu,
+                                             0 /* priority */);
         case ROUTE_UPDATE:
             return RouteController::updateRoute(interface, destination, nexthop, tableType, mtu);
         case ROUTE_REMOVE:
-            return RouteController::removeRoute(interface, destination, nexthop, tableType);
+            return RouteController::removeRoute(interface, destination, nexthop, tableType,
+                                                0 /* priority */);
     }
     return -EINVAL;
 }
diff --git a/server/NetworkController.h b/server/NetworkController.h
index a61ac39..e9ef091 100644
--- a/server/NetworkController.h
+++ b/server/NetworkController.h
@@ -107,7 +107,8 @@
 
     [[nodiscard]] int createPhysicalNetwork(unsigned netId, Permission permission);
     [[nodiscard]] int createPhysicalOemNetwork(Permission permission, unsigned* netId);
-    [[nodiscard]] int createVirtualNetwork(unsigned netId, bool secure, NativeVpnType vpnType);
+    [[nodiscard]] int createVirtualNetwork(unsigned netId, bool secure, NativeVpnType vpnType,
+                                           bool excludeLocalRoutes);
     [[nodiscard]] int destroyNetwork(unsigned netId);
 
     [[nodiscard]] int addInterfaceToNetwork(unsigned netId, const char* interface);
@@ -120,9 +121,9 @@
                                                const std::vector<unsigned>& netIds);
 
     [[nodiscard]] int addUsersToNetwork(unsigned netId, const UidRanges& uidRanges,
-                                        uint32_t subPriority);
+                                        int32_t subPriority);
     [[nodiscard]] int removeUsersFromNetwork(unsigned netId, const UidRanges& uidRanges,
-                                             uint32_t subPriority);
+                                             int32_t subPriority);
 
     // |nexthop| can be NULL (to indicate a directly-connected route), "unreachable" (to indicate a
     // route that's blocked), "throw" (to indicate the lack of a match), or a regular IP address.
diff --git a/server/OWNERS b/server/OWNERS
new file mode 100644
index 0000000..03fedf7
--- /dev/null
+++ b/server/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 31808
+lorenzo@google.com
+maze@google.com
diff --git a/server/OffloadUtils.cpp b/server/OffloadUtils.cpp
deleted file mode 100644
index 0d9869f..0000000
--- a/server/OffloadUtils.cpp
+++ /dev/null
@@ -1,388 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "OffloadUtils.h"
-
-#include <arpa/inet.h>
-#include <linux/if.h>
-#include <linux/if_arp.h>
-#include <linux/netlink.h>
-#include <linux/pkt_cls.h>
-#include <linux/pkt_sched.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#define LOG_TAG "OffloadUtils"
-#include <log/log.h>
-
-#include "NetlinkCommands.h"
-#include "android-base/unique_fd.h"
-
-namespace android {
-namespace net {
-
-using std::max;
-
-static int doSIOCGIF(const std::string& interface, int opt) {
-    base::unique_fd ufd(socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0));
-
-    if (ufd < 0) {
-        const int err = errno;
-        ALOGE("socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0)");
-        return -err;
-    };
-
-    struct ifreq ifr = {};
-    // We use strncpy() instead of strlcpy() since kernel has to be able
-    // to handle non-zero terminated junk passed in by userspace anyway,
-    // and this way too long interface names (more than IFNAMSIZ-1 = 15
-    // characters plus terminating NULL) will not get truncated to 15
-    // characters and zero-terminated and thus potentially erroneously
-    // match a truncated interface if one were to exist.
-    strncpy(ifr.ifr_name, interface.c_str(), sizeof(ifr.ifr_name));
-
-    if (ioctl(ufd, opt, &ifr, sizeof(ifr))) return -errno;
-
-    if (opt == SIOCGIFHWADDR) return ifr.ifr_hwaddr.sa_family;
-    if (opt == SIOCGIFMTU) return ifr.ifr_mtu;
-    return -EINVAL;
-}
-
-int hardwareAddressType(const std::string& interface) {
-    return doSIOCGIF(interface, SIOCGIFHWADDR);
-}
-
-int deviceMTU(const std::string& interface) {
-    return doSIOCGIF(interface, SIOCGIFMTU);
-}
-
-base::Result<bool> isEthernet(const std::string& interface) {
-    int rv = hardwareAddressType(interface);
-    if (rv < 0) {
-        errno = -rv;
-        return ErrnoErrorf("Get hardware address type of interface {} failed", interface);
-    }
-
-    switch (rv) {
-        case ARPHRD_ETHER:
-            return true;
-        case ARPHRD_NONE:
-        case ARPHRD_RAWIP:  // in Linux 4.14+ rmnet support was upstreamed and this is 519
-        case 530:           // this is ARPHRD_RAWIP on some Android 4.9 kernels with rmnet
-            return false;
-        default:
-            errno = EAFNOSUPPORT;  // Address family not supported
-            return ErrnoErrorf("Unknown hardware address type {} on interface {}", rv, interface);
-    }
-}
-
-// TODO: use //system/netd/server/NetlinkCommands.cpp:openNetlinkSocket(protocol)
-// and //system/netd/server/SockDiag.cpp:checkError(fd)
-static int sendAndProcessNetlinkResponse(const void* req, int len) {
-    base::unique_fd fd(socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE));
-    if (fd == -1) {
-        const int err = errno;
-        ALOGE("socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE)");
-        return -err;
-    }
-
-    static constexpr int on = 1;
-    int rv = setsockopt(fd, SOL_NETLINK, NETLINK_CAP_ACK, &on, sizeof(on));
-    if (rv) ALOGE("setsockopt(fd, SOL_NETLINK, NETLINK_CAP_ACK, %d)", on);
-
-    // this is needed to get sane strace netlink parsing, it allocates the pid
-    rv = bind(fd, (const struct sockaddr*)&KERNEL_NLADDR, sizeof(KERNEL_NLADDR));
-    if (rv) {
-        const int err = errno;
-        ALOGE("bind(fd, {AF_NETLINK, 0, 0})");
-        return -err;
-    }
-
-    // we do not want to receive messages from anyone besides the kernel
-    rv = connect(fd, (const struct sockaddr*)&KERNEL_NLADDR, sizeof(KERNEL_NLADDR));
-    if (rv) {
-        const int err = errno;
-        ALOGE("connect(fd, {AF_NETLINK, 0, 0})");
-        return -err;
-    }
-
-    rv = send(fd, req, len, 0);
-    if (rv == -1) return -errno;
-    if (rv != len) return -EMSGSIZE;
-
-    struct {
-        nlmsghdr h;
-        nlmsgerr e;
-        char buf[256];
-    } resp = {};
-
-    rv = recv(fd, &resp, sizeof(resp), MSG_TRUNC);
-
-    if (rv == -1) {
-        const int err = errno;
-        ALOGE("recv() failed");
-        return -err;
-    }
-
-    if (rv < (int)NLMSG_SPACE(sizeof(struct nlmsgerr))) {
-        ALOGE("recv() returned short packet: %d", rv);
-        return -EMSGSIZE;
-    }
-
-    if (resp.h.nlmsg_len != (unsigned)rv) {
-        ALOGE("recv() returned invalid header length: %d != %d", resp.h.nlmsg_len, rv);
-        return -EBADMSG;
-    }
-
-    if (resp.h.nlmsg_type != NLMSG_ERROR) {
-        ALOGE("recv() did not return NLMSG_ERROR message: %d", resp.h.nlmsg_type);
-        return -EBADMSG;
-    }
-
-    return resp.e.error;  // returns 0 on success
-}
-
-// ADD:     nlMsgType=RTM_NEWQDISC nlMsgFlags=NLM_F_EXCL|NLM_F_CREATE
-// REPLACE: nlMsgType=RTM_NEWQDISC nlMsgFlags=NLM_F_CREATE|NLM_F_REPLACE
-// DEL:     nlMsgType=RTM_DELQDISC nlMsgFlags=0
-int doTcQdiscClsact(int ifIndex, uint16_t nlMsgType, uint16_t nlMsgFlags) {
-    // This is the name of the qdisc we are attaching.
-    // Some hoop jumping to make this compile time constant with known size,
-    // so that the structure declaration is well defined at compile time.
-#define CLSACT "clsact"
-    // sizeof() includes the terminating NULL
-    static constexpr size_t ASCIIZ_LEN_CLSACT = sizeof(CLSACT);
-
-    const struct {
-        nlmsghdr n;
-        tcmsg t;
-        struct {
-            nlattr attr;
-            char str[NLMSG_ALIGN(ASCIIZ_LEN_CLSACT)];
-        } kind;
-    } req = {
-            .n =
-                    {
-                            .nlmsg_len = sizeof(req),
-                            .nlmsg_type = nlMsgType,
-                            .nlmsg_flags = static_cast<__u16>(NETLINK_REQUEST_FLAGS | nlMsgFlags),
-                    },
-            .t =
-                    {
-                            .tcm_family = AF_UNSPEC,
-                            .tcm_ifindex = ifIndex,
-                            .tcm_handle = TC_H_MAKE(TC_H_CLSACT, 0),
-                            .tcm_parent = TC_H_CLSACT,
-                    },
-            .kind =
-                    {
-                            .attr =
-                                    {
-                                            .nla_len = NLA_HDRLEN + ASCIIZ_LEN_CLSACT,
-                                            .nla_type = TCA_KIND,
-                                    },
-                            .str = CLSACT,
-                    },
-    };
-#undef CLSACT
-
-    return sendAndProcessNetlinkResponse(&req, sizeof(req));
-}
-
-// The priority of clat hook - must be after tethering.
-constexpr uint16_t PRIO_CLAT = 4;
-
-// tc filter add dev .. in/egress prio 4 protocol ipv6/ip bpf object-pinned /sys/fs/bpf/...
-// direct-action
-int tcFilterAddDevBpf(int ifIndex, bool ingress, uint16_t proto, int bpfFd, bool ethernet) {
-    // This is the name of the filter we're attaching (ie. this is the 'bpf'
-    // packet classifier enabled by kernel config option CONFIG_NET_CLS_BPF.
-    //
-    // We go through some hoops in order to make this compile time constants
-    // so that we can define the struct further down the function with the
-    // field for this sized correctly already during the build.
-#define BPF "bpf"
-    // sizeof() includes the terminating NULL
-    static constexpr size_t ASCIIZ_LEN_BPF = sizeof(BPF);
-
-    // This is to replicate program name suffix used by 'tc' Linux cli
-    // when it attaches programs.
-#define FSOBJ_SUFFIX ":[*fsobj]"
-
-    // This macro expands (from header files) to:
-    //   prog_clatd_schedcls_ingress6_clat_rawip:[*fsobj]
-    // and is the name of the pinned ingress ebpf program for ARPHRD_RAWIP interfaces.
-    // (also compatible with anything that has 0 size L2 header)
-    static constexpr char name_clat_rx_rawip[] = CLAT_INGRESS6_PROG_RAWIP_NAME FSOBJ_SUFFIX;
-
-    // This macro expands (from header files) to:
-    //   prog_clatd_schedcls_ingress6_clat_ether:[*fsobj]
-    // and is the name of the pinned ingress ebpf program for ARPHRD_ETHER interfaces.
-    // (also compatible with anything that has standard ethernet header)
-    static constexpr char name_clat_rx_ether[] = CLAT_INGRESS6_PROG_ETHER_NAME FSOBJ_SUFFIX;
-
-    // This macro expands (from header files) to:
-    //   prog_clatd_schedcls_egress4_clat_rawip:[*fsobj]
-    // and is the name of the pinned egress ebpf program for ARPHRD_RAWIP interfaces.
-    // (also compatible with anything that has 0 size L2 header)
-    static constexpr char name_clat_tx_rawip[] = CLAT_EGRESS4_PROG_RAWIP_NAME FSOBJ_SUFFIX;
-
-    // This macro expands (from header files) to:
-    //   prog_clatd_schedcls_egress4_clat_ether:[*fsobj]
-    // and is the name of the pinned egress ebpf program for ARPHRD_ETHER interfaces.
-    // (also compatible with anything that has standard ethernet header)
-    static constexpr char name_clat_tx_ether[] = CLAT_EGRESS4_PROG_ETHER_NAME FSOBJ_SUFFIX;
-
-#undef FSOBJ_SUFFIX
-
-    // The actual name we'll use is determined at run time via 'ethernet' and 'ingress'
-    // booleans.  We need to compile time allocate enough space in the struct
-    // hence this macro magic to make sure we have enough space for either
-    // possibility.  In practice some of these are actually the same size.
-    static constexpr size_t ASCIIZ_MAXLEN_NAME = max({
-            sizeof(name_clat_rx_rawip),
-            sizeof(name_clat_rx_ether),
-            sizeof(name_clat_tx_rawip),
-            sizeof(name_clat_tx_ether),
-    });
-
-    // These are not compile time constants: 'name' is used in strncpy below
-    const char* const name_clat_rx = ethernet ? name_clat_rx_ether : name_clat_rx_rawip;
-    const char* const name_clat_tx = ethernet ? name_clat_tx_ether : name_clat_tx_rawip;
-    const char* const name = ingress ? name_clat_rx : name_clat_tx;
-
-    struct {
-        nlmsghdr n;
-        tcmsg t;
-        struct {
-            nlattr attr;
-            char str[NLMSG_ALIGN(ASCIIZ_LEN_BPF)];
-        } kind;
-        struct {
-            nlattr attr;
-            struct {
-                nlattr attr;
-                __u32 u32;
-            } fd;
-            struct {
-                nlattr attr;
-                char str[NLMSG_ALIGN(ASCIIZ_MAXLEN_NAME)];
-            } name;
-            struct {
-                nlattr attr;
-                __u32 u32;
-            } flags;
-        } options;
-    } req = {
-            .n =
-                    {
-                            .nlmsg_len = sizeof(req),
-                            .nlmsg_type = RTM_NEWTFILTER,
-                            .nlmsg_flags = NETLINK_REQUEST_FLAGS | NLM_F_EXCL | NLM_F_CREATE,
-                    },
-            .t =
-                    {
-                            .tcm_family = AF_UNSPEC,
-                            .tcm_ifindex = ifIndex,
-                            .tcm_handle = TC_H_UNSPEC,
-                            .tcm_parent = TC_H_MAKE(TC_H_CLSACT,
-                                                    ingress ? TC_H_MIN_INGRESS : TC_H_MIN_EGRESS),
-                            .tcm_info = static_cast<__u32>((PRIO_CLAT << 16) | htons(proto)),
-                    },
-            .kind =
-                    {
-                            .attr =
-                                    {
-                                            .nla_len = sizeof(req.kind),
-                                            .nla_type = TCA_KIND,
-                                    },
-                            .str = BPF,
-                    },
-            .options =
-                    {
-                            .attr =
-                                    {
-                                            .nla_len = sizeof(req.options),
-                                            .nla_type = NLA_F_NESTED | TCA_OPTIONS,
-                                    },
-                            .fd =
-                                    {
-                                            .attr =
-                                                    {
-                                                            .nla_len = sizeof(req.options.fd),
-                                                            .nla_type = TCA_BPF_FD,
-                                                    },
-                                            .u32 = static_cast<__u32>(bpfFd),
-                                    },
-                            .name =
-                                    {
-                                            .attr =
-                                                    {
-                                                            .nla_len = sizeof(req.options.name),
-                                                            .nla_type = TCA_BPF_NAME,
-                                                    },
-                                            // Visible via 'tc filter show', but
-                                            // is overwritten by strncpy below
-                                            .str = "placeholder",
-                                    },
-                            .flags =
-                                    {
-                                            .attr =
-                                                    {
-                                                            .nla_len = sizeof(req.options.flags),
-                                                            .nla_type = TCA_BPF_FLAGS,
-                                                    },
-                                            .u32 = TCA_BPF_FLAG_ACT_DIRECT,
-                                    },
-                    },
-    };
-#undef BPF
-
-    strncpy(req.options.name.str, name, sizeof(req.options.name.str));
-
-    return sendAndProcessNetlinkResponse(&req, sizeof(req));
-}
-
-// tc filter del dev .. in/egress prio 4 protocol ..
-int tcFilterDelDev(int ifIndex, bool ingress, uint16_t proto) {
-    const struct {
-        nlmsghdr n;
-        tcmsg t;
-    } req = {
-            .n =
-                    {
-                            .nlmsg_len = sizeof(req),
-                            .nlmsg_type = RTM_DELTFILTER,
-                            .nlmsg_flags = NETLINK_REQUEST_FLAGS,
-                    },
-            .t =
-                    {
-                            .tcm_family = AF_UNSPEC,
-                            .tcm_ifindex = ifIndex,
-                            .tcm_handle = TC_H_UNSPEC,
-                            .tcm_parent = TC_H_MAKE(TC_H_CLSACT,
-                                                    ingress ? TC_H_MIN_INGRESS : TC_H_MIN_EGRESS),
-                            .tcm_info = static_cast<__u32>((PRIO_CLAT << 16) | htons(proto)),
-                    },
-    };
-
-    return sendAndProcessNetlinkResponse(&req, sizeof(req));
-}
-
-}  // namespace net
-}  // namespace android
diff --git a/server/OffloadUtils.h b/server/OffloadUtils.h
deleted file mode 100644
index 684ffb3..0000000
--- a/server/OffloadUtils.h
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <android-base/result.h>
-#include <errno.h>
-#include <linux/if_ether.h>
-#include <linux/if_link.h>
-#include <linux/rtnetlink.h>
-
-#include <string>
-
-#include "bpf/BpfUtils.h"
-#include "netdbpf/bpf_shared.h"
-
-namespace android {
-namespace net {
-
-// For better code clarity - do not change values - used for booleans like
-// with_ethernet_header or isEthernet.
-constexpr bool RAWIP = false;
-constexpr bool ETHER = true;
-
-// For better code clarity when used for 'bool ingress' parameter.
-constexpr bool EGRESS = false;
-constexpr bool INGRESS = true;
-
-// this returns an ARPHRD_* constant or a -errno
-int hardwareAddressType(const std::string& interface);
-
-// return MTU or -errno
-int deviceMTU(const std::string& interface);
-
-base::Result<bool> isEthernet(const std::string& interface);
-
-inline int getClatEgress4MapFd(void) {
-    const int fd = bpf::mapRetrieveRW(CLAT_EGRESS4_MAP_PATH);
-    return (fd == -1) ? -errno : fd;
-}
-
-inline int getClatEgress4ProgFd(bool with_ethernet_header) {
-    const int fd = bpf::retrieveProgram(with_ethernet_header ? CLAT_EGRESS4_PROG_ETHER_PATH
-                                                             : CLAT_EGRESS4_PROG_RAWIP_PATH);
-    return (fd == -1) ? -errno : fd;
-}
-
-inline int getClatIngress6MapFd(void) {
-    const int fd = bpf::mapRetrieveRW(CLAT_INGRESS6_MAP_PATH);
-    return (fd == -1) ? -errno : fd;
-}
-
-inline int getClatIngress6ProgFd(bool with_ethernet_header) {
-    const int fd = bpf::retrieveProgram(with_ethernet_header ? CLAT_INGRESS6_PROG_ETHER_PATH
-                                                             : CLAT_INGRESS6_PROG_RAWIP_PATH);
-    return (fd == -1) ? -errno : fd;
-}
-
-int doTcQdiscClsact(int ifIndex, uint16_t nlMsgType, uint16_t nlMsgFlags);
-
-inline int tcQdiscAddDevClsact(int ifIndex) {
-    return doTcQdiscClsact(ifIndex, RTM_NEWQDISC, NLM_F_EXCL | NLM_F_CREATE);
-}
-
-inline int tcQdiscReplaceDevClsact(int ifIndex) {
-    return doTcQdiscClsact(ifIndex, RTM_NEWQDISC, NLM_F_CREATE | NLM_F_REPLACE);
-}
-
-inline int tcQdiscDelDevClsact(int ifIndex) {
-    return doTcQdiscClsact(ifIndex, RTM_DELQDISC, 0);
-}
-
-// tc filter add dev .. in/egress prio 4 protocol ipv6/ip bpf object-pinned /sys/fs/bpf/...
-// direct-action
-int tcFilterAddDevBpf(int ifIndex, bool ingress, uint16_t proto, int bpfFd, bool ethernet);
-
-// tc filter add dev .. ingress prio 4 protocol ipv6 bpf object-pinned /sys/fs/bpf/... direct-action
-inline int tcFilterAddDevIngressClatIpv6(int ifIndex, int bpfFd, bool ethernet) {
-    return tcFilterAddDevBpf(ifIndex, INGRESS, ETH_P_IPV6, bpfFd, ethernet);
-}
-
-// tc filter add dev .. egress prio 4 protocol ip bpf object-pinned /sys/fs/bpf/... direct-action
-inline int tcFilterAddDevEgressClatIpv4(int ifIndex, int bpfFd, bool ethernet) {
-    return tcFilterAddDevBpf(ifIndex, EGRESS, ETH_P_IP, bpfFd, ethernet);
-}
-
-// tc filter del dev .. in/egress prio .. protocol ..
-int tcFilterDelDev(int ifIndex, bool ingress, uint16_t proto);
-
-// tc filter del dev .. ingress prio 4 protocol ipv6
-inline int tcFilterDelDevIngressClatIpv6(int ifIndex) {
-    return tcFilterDelDev(ifIndex, INGRESS, ETH_P_IPV6);
-}
-
-// tc filter del dev .. egress prio 4 protocol ip
-inline int tcFilterDelDevEgressClatIpv4(int ifIndex) {
-    return tcFilterDelDev(ifIndex, EGRESS, ETH_P_IP);
-}
-
-}  // namespace net
-}  // namespace android
diff --git a/server/OffloadUtilsTest.cpp b/server/OffloadUtilsTest.cpp
deleted file mode 100644
index 16c108b..0000000
--- a/server/OffloadUtilsTest.cpp
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * OffloadUtilsTest.cpp - unit tests for OffloadUtils.cpp
- */
-
-#include <gtest/gtest.h>
-
-#include "OffloadUtils.h"
-
-#include <linux/if_arp.h>
-#include <stdlib.h>
-#include <sys/wait.h>
-
-#include "bpf/BpfUtils.h"
-#include "netdbpf/bpf_shared.h"
-
-namespace android {
-namespace net {
-
-class OffloadUtilsTest : public ::testing::Test {
-  public:
-    void SetUp() {}
-};
-
-TEST_F(OffloadUtilsTest, HardwareAddressTypeOfNonExistingIf) {
-    ASSERT_EQ(-ENODEV, hardwareAddressType("not_existing_if"));
-}
-
-TEST_F(OffloadUtilsTest, HardwareAddressTypeOfLoopback) {
-    ASSERT_EQ(ARPHRD_LOOPBACK, hardwareAddressType("lo"));
-}
-
-// If wireless 'wlan0' interface exists it should be Ethernet.
-TEST_F(OffloadUtilsTest, HardwareAddressTypeOfWireless) {
-    int type = hardwareAddressType("wlan0");
-    if (type == -ENODEV) return;
-
-    ASSERT_EQ(ARPHRD_ETHER, type);
-}
-
-// If cellular 'rmnet_data0' interface exists it should
-// *probably* not be Ethernet and instead be RawIp.
-TEST_F(OffloadUtilsTest, HardwareAddressTypeOfCellular) {
-    int type = hardwareAddressType("rmnet_data0");
-    if (type == -ENODEV) return;
-
-    ASSERT_NE(ARPHRD_ETHER, type);
-
-    // ARPHRD_RAWIP is 530 on some pre-4.14 Qualcomm devices.
-    if (type == 530) return;
-
-    ASSERT_EQ(ARPHRD_RAWIP, type);
-}
-
-TEST_F(OffloadUtilsTest, IsEthernetOfNonExistingIf) {
-    auto res = isEthernet("not_existing_if");
-    ASSERT_FALSE(res.ok());
-    ASSERT_EQ(ENODEV, res.error().code());
-}
-
-TEST_F(OffloadUtilsTest, IsEthernetOfLoopback) {
-    auto res = isEthernet("lo");
-    ASSERT_FALSE(res.ok());
-    ASSERT_EQ(EAFNOSUPPORT, res.error().code());
-}
-
-// If wireless 'wlan0' interface exists it should be Ethernet.
-// See also HardwareAddressTypeOfWireless.
-TEST_F(OffloadUtilsTest, IsEthernetOfWireless) {
-    auto res = isEthernet("wlan0");
-    if (!res.ok() && res.error().code() == ENODEV) return;
-
-    ASSERT_RESULT_OK(res);
-    ASSERT_TRUE(res.value());
-}
-
-// If cellular 'rmnet_data0' interface exists it should
-// *probably* not be Ethernet and instead be RawIp.
-// See also HardwareAddressTypeOfCellular.
-TEST_F(OffloadUtilsTest, IsEthernetOfCellular) {
-    auto res = isEthernet("rmnet_data0");
-    if (!res.ok() && res.error().code() == ENODEV) return;
-
-    ASSERT_RESULT_OK(res);
-    ASSERT_FALSE(res.value());
-}
-
-TEST_F(OffloadUtilsTest, DeviceMTUOfNonExistingIf) {
-    ASSERT_EQ(-ENODEV, deviceMTU("not_existing_if"));
-}
-
-TEST_F(OffloadUtilsTest, DeviceMTUofLoopback) {
-    ASSERT_EQ(65536, deviceMTU("lo"));
-}
-
-TEST_F(OffloadUtilsTest, GetClatEgress4MapFd) {
-    int fd = getClatEgress4MapFd();
-    ASSERT_GE(fd, 3);  // 0,1,2 - stdin/out/err, thus fd >= 3
-    EXPECT_EQ(FD_CLOEXEC, fcntl(fd, F_GETFD));
-    close(fd);
-}
-
-TEST_F(OffloadUtilsTest, GetClatEgress4RawIpProgFd) {
-    int fd = getClatEgress4ProgFd(RAWIP);
-    ASSERT_GE(fd, 3);
-    EXPECT_EQ(FD_CLOEXEC, fcntl(fd, F_GETFD));
-    close(fd);
-}
-
-TEST_F(OffloadUtilsTest, GetClatEgress4EtherProgFd) {
-    int fd = getClatEgress4ProgFd(ETHER);
-    ASSERT_GE(fd, 3);
-    EXPECT_EQ(FD_CLOEXEC, fcntl(fd, F_GETFD));
-    close(fd);
-}
-
-TEST_F(OffloadUtilsTest, GetClatIngress6MapFd) {
-    int fd = getClatIngress6MapFd();
-    ASSERT_GE(fd, 3);  // 0,1,2 - stdin/out/err, thus fd >= 3
-    EXPECT_EQ(FD_CLOEXEC, fcntl(fd, F_GETFD));
-    close(fd);
-}
-
-TEST_F(OffloadUtilsTest, GetClatIngress6RawIpProgFd) {
-    int fd = getClatIngress6ProgFd(RAWIP);
-    ASSERT_GE(fd, 3);
-    EXPECT_EQ(FD_CLOEXEC, fcntl(fd, F_GETFD));
-    close(fd);
-}
-
-TEST_F(OffloadUtilsTest, GetClatIngress6EtherProgFd) {
-    int fd = getClatIngress6ProgFd(ETHER);
-    ASSERT_GE(fd, 3);
-    EXPECT_EQ(FD_CLOEXEC, fcntl(fd, F_GETFD));
-    close(fd);
-}
-
-// See Linux kernel source in include/net/flow.h
-#define LOOPBACK_IFINDEX 1
-
-TEST_F(OffloadUtilsTest, AttachReplaceDetachClsactLo) {
-    // This attaches and detaches a configuration-less and thus no-op clsact
-    // qdisc to loopback interface (and it takes fractions of a second)
-    EXPECT_EQ(0, tcQdiscAddDevClsact(LOOPBACK_IFINDEX));
-    EXPECT_EQ(0, tcQdiscReplaceDevClsact(LOOPBACK_IFINDEX));
-    EXPECT_EQ(0, tcQdiscDelDevClsact(LOOPBACK_IFINDEX));
-    EXPECT_EQ(-EINVAL, tcQdiscDelDevClsact(LOOPBACK_IFINDEX));
-}
-
-static void checkAttachDetachBpfFilterClsactLo(const bool ingress, const bool ethernet) {
-    // Older kernels return EINVAL instead of ENOENT due to lacking proper error propagation...
-    const int errNOENT = android::bpf::isAtLeastKernelVersion(4, 19, 0) ? ENOENT : EINVAL;
-
-    int clatBpfFd = ingress ? getClatIngress6ProgFd(ethernet) : getClatEgress4ProgFd(ethernet);
-    ASSERT_GE(clatBpfFd, 3);
-
-    // This attaches and detaches a clsact plus ebpf program to loopback
-    // interface, but it should not affect traffic by virtue of us not
-    // actually populating the ebpf control map.
-    // Furthermore: it only takes fractions of a second.
-    EXPECT_EQ(-EINVAL, tcFilterDelDevIngressClatIpv6(LOOPBACK_IFINDEX));
-    EXPECT_EQ(-EINVAL, tcFilterDelDevEgressClatIpv4(LOOPBACK_IFINDEX));
-    EXPECT_EQ(0, tcQdiscAddDevClsact(LOOPBACK_IFINDEX));
-    EXPECT_EQ(-errNOENT, tcFilterDelDevIngressClatIpv6(LOOPBACK_IFINDEX));
-    EXPECT_EQ(-errNOENT, tcFilterDelDevEgressClatIpv4(LOOPBACK_IFINDEX));
-    if (ingress) {
-        EXPECT_EQ(0, tcFilterAddDevIngressClatIpv6(LOOPBACK_IFINDEX, clatBpfFd, ethernet));
-        EXPECT_EQ(0, tcFilterDelDevIngressClatIpv6(LOOPBACK_IFINDEX));
-    } else {
-        EXPECT_EQ(0, tcFilterAddDevEgressClatIpv4(LOOPBACK_IFINDEX, clatBpfFd, ethernet));
-        EXPECT_EQ(0, tcFilterDelDevEgressClatIpv4(LOOPBACK_IFINDEX));
-    }
-    EXPECT_EQ(-errNOENT, tcFilterDelDevIngressClatIpv6(LOOPBACK_IFINDEX));
-    EXPECT_EQ(-errNOENT, tcFilterDelDevEgressClatIpv4(LOOPBACK_IFINDEX));
-    EXPECT_EQ(0, tcQdiscDelDevClsact(LOOPBACK_IFINDEX));
-    EXPECT_EQ(-EINVAL, tcFilterDelDevIngressClatIpv6(LOOPBACK_IFINDEX));
-    EXPECT_EQ(-EINVAL, tcFilterDelDevEgressClatIpv4(LOOPBACK_IFINDEX));
-
-    close(clatBpfFd);
-}
-
-TEST_F(OffloadUtilsTest, CheckAttachBpfFilterRawIpClsactEgressLo) {
-    checkAttachDetachBpfFilterClsactLo(EGRESS, RAWIP);
-}
-
-TEST_F(OffloadUtilsTest, CheckAttachBpfFilterEthernetClsactEgressLo) {
-    checkAttachDetachBpfFilterClsactLo(EGRESS, ETHER);
-}
-
-TEST_F(OffloadUtilsTest, CheckAttachBpfFilterRawIpClsactIngressLo) {
-    checkAttachDetachBpfFilterClsactLo(INGRESS, RAWIP);
-}
-
-TEST_F(OffloadUtilsTest, CheckAttachBpfFilterEthernetClsactIngressLo) {
-    checkAttachDetachBpfFilterClsactLo(INGRESS, ETHER);
-}
-
-}  // namespace net
-}  // namespace android
diff --git a/server/PhysicalNetwork.cpp b/server/PhysicalNetwork.cpp
index 7b9a19a..bb3f653 100644
--- a/server/PhysicalNetwork.cpp
+++ b/server/PhysicalNetwork.cpp
@@ -84,14 +84,20 @@
 }
 
 void PhysicalNetwork::invalidateRouteCache(const std::string& interface) {
+    // This method invalidates all socket destination cache entries in the kernel by creating and
+    // removing a low-priority route.
+    // This number is an arbitrary number that need to be higher than any other route created either
+    // by netd or by an IPv6 RouterAdvertisement.
+    int priority = 100000;
+
     for (const auto& dst : { "0.0.0.0/0", "::/0" }) {
         // If any of these operations fail, there's no point in logging because RouteController will
         // have already logged a message. There's also no point returning an error since there's
         // nothing we can do.
         (void)RouteController::addRoute(interface.c_str(), dst, "throw", RouteController::INTERFACE,
-                                        0 /* mtu */);
-        (void) RouteController::removeRoute(interface.c_str(), dst, "throw",
-                                         RouteController::INTERFACE);
+                                        0 /* mtu */, priority);
+        (void)RouteController::removeRoute(interface.c_str(), dst, "throw",
+                                           RouteController::INTERFACE, priority);
     }
 }
 
@@ -158,7 +164,7 @@
     return 0;
 }
 
-int PhysicalNetwork::addUsers(const UidRanges& uidRanges, uint32_t subPriority) {
+int PhysicalNetwork::addUsers(const UidRanges& uidRanges, int32_t subPriority) {
     if (!isValidSubPriority(subPriority) || !canAddUidRanges(uidRanges, subPriority)) {
         return -EINVAL;
     }
@@ -175,7 +181,7 @@
     return 0;
 }
 
-int PhysicalNetwork::removeUsers(const UidRanges& uidRanges, uint32_t subPriority) {
+int PhysicalNetwork::removeUsers(const UidRanges& uidRanges, int32_t subPriority) {
     if (!isValidSubPriority(subPriority)) return -EINVAL;
 
     for (const std::string& interface : mInterfaces) {
@@ -230,9 +236,11 @@
     return 0;
 }
 
-bool PhysicalNetwork::isValidSubPriority(uint32_t priority) {
-    return priority >= UidRanges::DEFAULT_SUB_PRIORITY &&
-           priority <= UidRanges::LOWEST_SUB_PRIORITY;
+bool PhysicalNetwork::isValidSubPriority(int32_t priority) {
+    // SUB_PRIORITY_NO_DEFAULT is a special value, see UidRanges.h.
+    return (priority >= UidRanges::SUB_PRIORITY_HIGHEST &&
+            priority <= UidRanges::SUB_PRIORITY_LOWEST) ||
+           priority == UidRanges::SUB_PRIORITY_NO_DEFAULT;
 }
 
 }  // namespace android::net
diff --git a/server/PhysicalNetwork.h b/server/PhysicalNetwork.h
index d9461b2..f114cca 100644
--- a/server/PhysicalNetwork.h
+++ b/server/PhysicalNetwork.h
@@ -42,8 +42,8 @@
 
     [[nodiscard]] int addAsDefault();
     [[nodiscard]] int removeAsDefault();
-    [[nodiscard]] int addUsers(const UidRanges& uidRanges, uint32_t subPriority) override;
-    [[nodiscard]] int removeUsers(const UidRanges& uidRanges, uint32_t subPriority) override;
+    [[nodiscard]] int addUsers(const UidRanges& uidRanges, int32_t subPriority) override;
+    [[nodiscard]] int removeUsers(const UidRanges& uidRanges, int32_t subPriority) override;
     bool isPhysical() override { return true; }
     bool canAddUsers() override { return true; }
 
@@ -53,7 +53,7 @@
     [[nodiscard]] int removeInterface(const std::string& interface) override;
     int destroySocketsLackingPermission(Permission permission);
     void invalidateRouteCache(const std::string& interface);
-    bool isValidSubPriority(uint32_t priority) override;
+    bool isValidSubPriority(int32_t priority) override;
 
     Delegate* const mDelegate;
     Permission mPermission;
diff --git a/server/RouteController.cpp b/server/RouteController.cpp
index ba305e6..d63dbd2 100644
--- a/server/RouteController.cpp
+++ b/server/RouteController.cpp
@@ -31,7 +31,7 @@
 #include "Fwmark.h"
 #include "NetdConstants.h"
 #include "NetlinkCommands.h"
-#include "OffloadUtils.h"
+#include "TcUtils.h"
 
 #include <android-base/file.h>
 #include <android-base/stringprintf.h>
@@ -43,12 +43,11 @@
 using android::base::StartsWith;
 using android::base::StringPrintf;
 using android::base::WriteStringToFile;
-using android::net::UidRangeParcel;
 
 namespace android::net {
 
 auto RouteController::iptablesRestoreCommandFunction = execIptablesRestoreCommand;
-
+auto RouteController::ifNameToIndexFunction = if_nametoindex;
 // BEGIN CONSTANTS --------------------------------------------------------------------------------
 
 const uint32_t ROUTE_TABLE_LOCAL_NETWORK  = 97;
@@ -62,10 +61,6 @@
 const char* const ROUTE_TABLE_NAME_LOCAL = "local";
 const char* const ROUTE_TABLE_NAME_MAIN  = "main";
 
-// None of our regular routes specify priority, which causes them to have the default priority.
-// For default throw routes, we use a fixed priority of 100000.
-uint32_t PRIO_THROW = 100000;
-
 const char* const RouteController::LOCAL_MANGLE_INPUT = "routectrl_mangle_INPUT";
 
 const uint8_t AF_FAMILIES[] = {AF_INET, AF_INET6};
@@ -80,7 +75,6 @@
 const bool ACTION_DEL = false;
 const bool MODIFY_NON_UID_BASED_RULES = true;
 
-const char* const RT_TABLES_PATH = "/data/misc/net/rt_tables";
 const mode_t RT_TABLES_MODE = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;  // mode 0644, rw-r--r--
 
 // Avoids "non-constant-expression cannot be narrowed from type 'unsigned int' to 'unsigned short'"
@@ -131,8 +125,16 @@
 
 static void maybeModifyQdiscClsact(const char* interface, bool add);
 
+static uint32_t getRouteTableIndexFromGlobalRouteTableIndex(uint32_t index, bool local) {
+    // The local table is
+    // "global table - ROUTE_TABLE_OFFSET_FROM_INDEX + ROUTE_TABLE_OFFSET_FROM_INDEX_FOR_LOCAL"
+    const uint32_t localTableOffset = RouteController::ROUTE_TABLE_OFFSET_FROM_INDEX_FOR_LOCAL -
+                                      RouteController::ROUTE_TABLE_OFFSET_FROM_INDEX;
+    return local ? index + localTableOffset : index;
+}
+
 // Caller must hold sInterfaceToTableLock.
-uint32_t RouteController::getRouteTableForInterfaceLocked(const char* interface) {
+uint32_t RouteController::getRouteTableForInterfaceLocked(const char* interface, bool local) {
     // If we already know the routing table for this interface name, use it.
     // This ensures we can remove rules and routes for an interface that has been removed,
     // or has been removed and re-added with a different interface index.
@@ -142,19 +144,22 @@
     // if the same interface disconnects and then reconnects with a different interface ID
     // when the reconnect happens the interface will not be in the map, and the code will
     // determine the new routing table from the interface ID, below.
+    //
+    // sInterfaceToTable stores the *global* routing table for the interface, and the local table is
+    // "global table - ROUTE_TABLE_OFFSET_FROM_INDEX + ROUTE_TABLE_OFFSET_FROM_INDEX_FOR_LOCAL"
     auto iter = sInterfaceToTable.find(interface);
     if (iter != sInterfaceToTable.end()) {
-        return iter->second;
+        return getRouteTableIndexFromGlobalRouteTableIndex(iter->second, local);
     }
 
-    uint32_t index = if_nametoindex(interface);
+    uint32_t index = RouteController::ifNameToIndexFunction(interface);
     if (index == 0) {
         ALOGE("cannot find interface %s: %s", interface, strerror(errno));
         return RT_TABLE_UNSPEC;
     }
     index += RouteController::ROUTE_TABLE_OFFSET_FROM_INDEX;
     sInterfaceToTable[interface] = index;
-    return index;
+    return getRouteTableIndexFromGlobalRouteTableIndex(index, local);
 }
 
 uint32_t RouteController::getIfIndex(const char* interface) {
@@ -179,9 +184,9 @@
     return ifindex - ROUTE_TABLE_OFFSET_FROM_INDEX;
 }
 
-uint32_t RouteController::getRouteTableForInterface(const char* interface) {
+uint32_t RouteController::getRouteTableForInterface(const char* interface, bool local) {
     std::lock_guard lock(sInterfaceToTableLock);
-    return getRouteTableForInterfaceLocked(interface);
+    return getRouteTableForInterfaceLocked(interface, local);
 }
 
 void addTableName(uint32_t table, const std::string& name, std::string* contents) {
@@ -205,8 +210,13 @@
     addTableName(ROUTE_TABLE_LEGACY_SYSTEM,  ROUTE_TABLE_NAME_LEGACY_SYSTEM,  &contents);
 
     std::lock_guard lock(sInterfaceToTableLock);
-    for (const auto& entry : sInterfaceToTable) {
-        addTableName(entry.second, entry.first, &contents);
+    for (const auto& [ifName, ifIndex] : sInterfaceToTable) {
+        addTableName(ifIndex, ifName, &contents);
+        // Add table for the local route of the network. It's expected to be used for excluding the
+        // local traffic in the VPN network.
+        // Start from ROUTE_TABLE_OFFSET_FROM_INDEX_FOR_LOCAL plus with the interface table index.
+        uint32_t offset = ROUTE_TABLE_OFFSET_FROM_INDEX_FOR_LOCAL - ROUTE_TABLE_OFFSET_FROM_INDEX;
+        addTableName(offset + ifIndex, ifName + INTERFACE_LOCAL_SUFFIX, &contents);
     }
 
     if (!WriteStringToFile(contents, RT_TABLES_PATH, RT_TABLES_MODE, AID_SYSTEM, AID_WIFI)) {
@@ -243,10 +253,15 @@
 //   range (inclusive). Otherwise, the rule matches packets from all UIDs.
 //
 // Returns 0 on success or negative errno on failure.
-[[nodiscard]] static int modifyIpRule(uint16_t action, uint32_t priority, uint8_t ruleType,
+[[nodiscard]] static int modifyIpRule(uint16_t action, int32_t priority, uint8_t ruleType,
                                       uint32_t table, uint32_t fwmark, uint32_t mask,
                                       const char* iif, const char* oif, uid_t uidStart,
                                       uid_t uidEnd) {
+    if (priority < 0) {
+        ALOGE("invalid IP-rule priority %d", priority);
+        return -ERANGE;
+    }
+
     // Ensure that if you set a bit in the fwmark, it's not being ignored by the mask.
     if (fwmark & ~mask) {
         ALOGE("mask 0x%x does not select all the bits set in fwmark 0x%x", mask, fwmark);
@@ -330,14 +345,14 @@
     return 0;
 }
 
-[[nodiscard]] static int modifyIpRule(uint16_t action, uint32_t priority, uint32_t table,
+[[nodiscard]] static int modifyIpRule(uint16_t action, int32_t priority, uint32_t table,
                                       uint32_t fwmark, uint32_t mask, const char* iif,
                                       const char* oif, uid_t uidStart, uid_t uidEnd) {
     return modifyIpRule(action, priority, FR_ACT_TO_TBL, table, fwmark, mask, iif, oif, uidStart,
                         uidEnd);
 }
 
-[[nodiscard]] static int modifyIpRule(uint16_t action, uint32_t priority, uint32_t table,
+[[nodiscard]] static int modifyIpRule(uint16_t action, int32_t priority, uint32_t table,
                                       uint32_t fwmark, uint32_t mask) {
     return modifyIpRule(action, priority, table, fwmark, mask, IIF_NONE, OIF_NONE, INVALID_UID,
                         INVALID_UID);
@@ -346,7 +361,7 @@
 // Adds or deletes an IPv4 or IPv6 route.
 // Returns 0 on success or negative errno on failure.
 int modifyIpRoute(uint16_t action, uint16_t flags, uint32_t table, const char* interface,
-                  const char* destination, const char* nexthop, uint32_t mtu) {
+                  const char* destination, const char* nexthop, uint32_t mtu, uint32_t priority) {
     // At least the destination must be non-null.
     if (!destination) {
         ALOGE("null destination");
@@ -387,7 +402,8 @@
     } else {
         // If an interface was specified, find the ifindex.
         if (interface != OIF_NONE) {
-            ifindex = if_nametoindex(interface);
+            ifindex = RouteController::ifNameToIndexFunction(interface);
+
             if (!ifindex) {
                 ALOGE("cannot find interface %s", interface);
                 return -ENODEV;
@@ -401,8 +417,6 @@
         }
     }
 
-    bool isDefaultThrowRoute = (type == RTN_THROW && prefixLength == 0);
-
     // Assemble a rtmsg and put it in an array of iovec structures.
     rtmsg route = {
             .rtm_family = family,
@@ -416,21 +430,21 @@
     rtattr rtaGateway = { U16_RTA_LENGTH(rawLength), RTA_GATEWAY };
 
     iovec iov[] = {
-        { nullptr,         0 },
-        { &route,          sizeof(route) },
-        { &RTATTR_TABLE,   sizeof(RTATTR_TABLE) },
-        { &table,          sizeof(table) },
-        { &rtaDst,         sizeof(rtaDst) },
-        { rawAddress,      static_cast<size_t>(rawLength) },
-        { &RTATTR_OIF,     interface != OIF_NONE ? sizeof(RTATTR_OIF) : 0 },
-        { &ifindex,        interface != OIF_NONE ? sizeof(ifindex) : 0 },
-        { &rtaGateway,     nexthop ? sizeof(rtaGateway) : 0 },
-        { rawNexthop,      nexthop ? static_cast<size_t>(rawLength) : 0 },
-        { &RTATTR_METRICS, mtu != 0 ? sizeof(RTATTR_METRICS) : 0 },
-        { &RTATTRX_MTU,    mtu != 0 ? sizeof(RTATTRX_MTU) : 0 },
-        { &mtu,            mtu != 0 ? sizeof(mtu) : 0 },
-        { &RTATTR_PRIO,    isDefaultThrowRoute ? sizeof(RTATTR_PRIO) : 0 },
-        { &PRIO_THROW,     isDefaultThrowRoute ? sizeof(PRIO_THROW) : 0 },
+            {nullptr, 0},
+            {&route, sizeof(route)},
+            {&RTATTR_TABLE, sizeof(RTATTR_TABLE)},
+            {&table, sizeof(table)},
+            {&rtaDst, sizeof(rtaDst)},
+            {rawAddress, static_cast<size_t>(rawLength)},
+            {&RTATTR_OIF, interface != OIF_NONE ? sizeof(RTATTR_OIF) : 0},
+            {&ifindex, interface != OIF_NONE ? sizeof(ifindex) : 0},
+            {&rtaGateway, nexthop ? sizeof(rtaGateway) : 0},
+            {rawNexthop, nexthop ? static_cast<size_t>(rawLength) : 0},
+            {&RTATTR_METRICS, mtu != 0 ? sizeof(RTATTR_METRICS) : 0},
+            {&RTATTRX_MTU, mtu != 0 ? sizeof(RTATTRX_MTU) : 0},
+            {&mtu, mtu != 0 ? sizeof(mtu) : 0},
+            {&RTATTR_PRIO, priority != 0 ? sizeof(RTATTR_PRIO) : 0},
+            {&priority, priority != 0 ? sizeof(priority) : 0},
     };
 
     // Allow creating multiple link-local routes in the same table, so we can make IPv6
@@ -492,19 +506,21 @@
 // have, if they are subject to this VPN, their traffic has to go through it. Allows the traffic to
 // bypass the VPN if the protectedFromVpn bit is set.
 [[nodiscard]] static int modifyVpnUidRangeRule(uint32_t table, uid_t uidStart, uid_t uidEnd,
-                                               uint32_t subPriority, bool secure, bool add) {
+                                               int32_t subPriority, bool secure, bool add,
+                                               bool excludeLocalRoutes) {
     Fwmark fwmark;
     Fwmark mask;
 
     fwmark.protectedFromVpn = false;
     mask.protectedFromVpn = true;
 
-    uint32_t priority;
+    int32_t priority;
 
     if (secure) {
         priority = RULE_PRIORITY_SECURE_VPN;
     } else {
-        priority = RULE_PRIORITY_BYPASSABLE_VPN;
+        priority = excludeLocalRoutes ? RULE_PRIORITY_BYPASSABLE_VPN_LOCAL_EXCLUSION
+                                      : RULE_PRIORITY_BYPASSABLE_VPN_NO_LOCAL_EXCLUSION;
 
         fwmark.explicitlySelected = false;
         mask.explicitlySelected = true;
@@ -520,7 +536,7 @@
 // This is needed for DnsProxyListener to correctly resolve a request for a user who is in the
 // target set, but where the DnsProxyListener itself is not.
 [[nodiscard]] static int modifyVpnSystemPermissionRule(unsigned netId, uint32_t table, bool secure,
-                                                       bool add) {
+                                                       bool add, bool excludeLocalRoutes) {
     Fwmark fwmark;
     Fwmark mask;
 
@@ -530,7 +546,14 @@
     fwmark.permission = PERMISSION_SYSTEM;
     mask.permission = PERMISSION_SYSTEM;
 
-    uint32_t priority = secure ? RULE_PRIORITY_SECURE_VPN : RULE_PRIORITY_BYPASSABLE_VPN;
+    uint32_t priority;
+
+    if (secure) {
+        priority = RULE_PRIORITY_SECURE_VPN;
+    } else {
+        priority = excludeLocalRoutes ? RULE_PRIORITY_BYPASSABLE_VPN_LOCAL_EXCLUSION
+                                      : RULE_PRIORITY_BYPASSABLE_VPN_NO_LOCAL_EXCLUSION;
+    }
 
     return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE, priority, table, fwmark.intValue,
                         mask.intValue);
@@ -545,7 +568,7 @@
 // modifyNetworkPermission().
 [[nodiscard]] static int modifyExplicitNetworkRule(unsigned netId, uint32_t table,
                                                    Permission permission, uid_t uidStart,
-                                                   uid_t uidEnd, uint32_t subPriority, bool add) {
+                                                   uid_t uidEnd, int32_t subPriority, bool add) {
     Fwmark fwmark;
     Fwmark mask;
 
@@ -569,7 +592,7 @@
 // the outgoing interface (typically for link-local communications).
 [[nodiscard]] static int modifyOutputInterfaceRules(const char* interface, uint32_t table,
                                                     Permission permission, uid_t uidStart,
-                                                    uid_t uidEnd, uint32_t subPriority, bool add) {
+                                                    uid_t uidEnd, int32_t subPriority, bool add) {
     Fwmark fwmark;
     Fwmark mask;
 
@@ -615,6 +638,26 @@
                         INVALID_UID);
 }
 
+int RouteController::modifyVpnLocalExclusionRule(bool add, const char* physicalInterface) {
+    uint32_t table = getRouteTableForInterface(physicalInterface, true /* local */);
+    if (table == RT_TABLE_UNSPEC) {
+        return -ESRCH;
+    }
+
+    Fwmark fwmark;
+    Fwmark mask;
+
+    fwmark.explicitlySelected = false;
+    mask.explicitlySelected = true;
+
+    fwmark.permission = PERMISSION_NONE;
+    mask.permission = PERMISSION_NONE;
+
+    return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE, RULE_PRIORITY_LOCAL_ROUTES, table,
+                        fwmark.intValue, mask.intValue, IIF_LOOPBACK, OIF_NONE, INVALID_UID,
+                        INVALID_UID);
+}
+
 // A rule to enable split tunnel VPNs.
 //
 // If a packet with a VPN's netId doesn't find a route in the VPN's routing table, it's allowed to
@@ -622,7 +665,7 @@
 int RouteController::modifyVpnFallthroughRule(uint16_t action, unsigned vpnNetId,
                                               const char* physicalInterface,
                                               Permission permission) {
-    uint32_t table = getRouteTableForInterface(physicalInterface);
+    uint32_t table = getRouteTableForInterface(physicalInterface, false /* local */);
     if (table == RT_TABLE_UNSPEC) {
         return -ESRCH;
     }
@@ -670,7 +713,7 @@
 [[nodiscard]] static int addLocalNetworkRules(unsigned localNetId) {
     if (int ret = modifyExplicitNetworkRule(localNetId, ROUTE_TABLE_LOCAL_NETWORK, PERMISSION_NONE,
                                             INVALID_UID, INVALID_UID,
-                                            UidRanges::DEFAULT_SUB_PRIORITY, ACTION_ADD)) {
+                                            UidRanges::SUB_PRIORITY_HIGHEST, ACTION_ADD)) {
         return ret;
     }
 
@@ -687,7 +730,7 @@
 /* static */
 int RouteController::configureDummyNetwork() {
     const char *interface = DummyNetwork::INTERFACE_NAME;
-    uint32_t table = getRouteTableForInterface(interface);
+    uint32_t table = getRouteTableForInterface(interface, false /* local */);
     if (table == RT_TABLE_UNSPEC) {
         // getRouteTableForInterface has already logged an error.
         return -ESRCH;
@@ -702,19 +745,19 @@
     }
 
     if ((ret = modifyOutputInterfaceRules(interface, table, PERMISSION_NONE, INVALID_UID,
-                                          INVALID_UID, UidRanges::DEFAULT_SUB_PRIORITY,
+                                          INVALID_UID, UidRanges::SUB_PRIORITY_HIGHEST,
                                           ACTION_ADD))) {
         ALOGE("Can't create oif rules for %s: %s", interface, strerror(-ret));
         return ret;
     }
 
     if ((ret = modifyIpRoute(RTM_NEWROUTE, NETLINK_ROUTE_CREATE_FLAGS, table, interface,
-                             "0.0.0.0/0", nullptr, 0 /* mtu */))) {
+                             "0.0.0.0/0", nullptr, 0 /* mtu */, 0 /* priority */))) {
         return ret;
     }
 
     if ((ret = modifyIpRoute(RTM_NEWROUTE, NETLINK_ROUTE_CREATE_FLAGS, table, interface, "::/0",
-                             nullptr, 0 /* mtu */))) {
+                             nullptr, 0 /* mtu */, 0 /* priority */))) {
         return ret;
     }
 
@@ -736,12 +779,12 @@
     }
     maybeModifyQdiscClsact(interface, add);
     return modifyOutputInterfaceRules(interface, ROUTE_TABLE_LOCAL_NETWORK, PERMISSION_NONE,
-                                      INVALID_UID, INVALID_UID, UidRanges::DEFAULT_SUB_PRIORITY,
+                                      INVALID_UID, INVALID_UID, UidRanges::SUB_PRIORITY_HIGHEST,
                                       add);
 }
 
 [[nodiscard]] static int modifyUidNetworkRule(unsigned netId, uint32_t table, uid_t uidStart,
-                                              uid_t uidEnd, uint32_t subPriority, bool add,
+                                              uid_t uidEnd, int32_t subPriority, bool add,
                                               bool explicitSelect) {
     if ((uidStart == INVALID_UID) || (uidEnd == INVALID_UID)) {
         ALOGE("modifyUidNetworkRule, invalid UIDs (%u, %u)", uidStart, uidEnd);
@@ -769,7 +812,7 @@
 }
 
 [[nodiscard]] static int modifyUidDefaultNetworkRule(uint32_t table, uid_t uidStart, uid_t uidEnd,
-                                                     uint32_t subPriority, bool add) {
+                                                     int32_t subPriority, bool add) {
     if ((uidStart == INVALID_UID) || (uidEnd == INVALID_UID)) {
         ALOGE("modifyUidDefaultNetworkRule, invalid UIDs (%u, %u)", uidStart, uidEnd);
         return -EUSERS;
@@ -794,7 +837,7 @@
 int RouteController::modifyPhysicalNetwork(unsigned netId, const char* interface,
                                            const UidRangeMap& uidRangeMap, Permission permission,
                                            bool add, bool modifyNonUidBasedRules) {
-    uint32_t table = getRouteTableForInterface(interface);
+    uint32_t table = getRouteTableForInterface(interface, false /* local */);
     if (table == RT_TABLE_UNSPEC) {
         return -ESRCH;
     }
@@ -809,9 +852,13 @@
                                                add, IMPLICIT)) {
                 return ret;
             }
-            if (int ret = modifyUidDefaultNetworkRule(table, range.start, range.stop, subPriority,
-                                                      add)) {
-                return ret;
+            // SUB_PRIORITY_NO_DEFAULT is "special" and does not require a
+            // default network rule, see UidRanges.h.
+            if (subPriority != UidRanges::SUB_PRIORITY_NO_DEFAULT) {
+                if (int ret = modifyUidDefaultNetworkRule(table, range.start, range.stop,
+                                                          subPriority, add)) {
+                    return ret;
+                }
             }
         }
     }
@@ -825,11 +872,11 @@
         return ret;
     }
     if (int ret = modifyExplicitNetworkRule(netId, table, permission, INVALID_UID, INVALID_UID,
-                                            UidRanges::DEFAULT_SUB_PRIORITY, add)) {
+                                            UidRanges::SUB_PRIORITY_HIGHEST, add)) {
         return ret;
     }
     if (int ret = modifyOutputInterfaceRules(interface, table, permission, INVALID_UID, INVALID_UID,
-                                             UidRanges::DEFAULT_SUB_PRIORITY, add)) {
+                                             UidRanges::SUB_PRIORITY_HIGHEST, add)) {
         return ret;
     }
 
@@ -860,7 +907,7 @@
 }
 
 [[nodiscard]] static int modifyUidUnreachableRule(unsigned netId, uid_t uidStart, uid_t uidEnd,
-                                                  uint32_t subPriority, bool add,
+                                                  int32_t subPriority, bool add,
                                                   bool explicitSelect) {
     if ((uidStart == INVALID_UID) || (uidEnd == INVALID_UID)) {
         ALOGE("modifyUidUnreachableRule, invalid UIDs (%u, %u)", uidStart, uidEnd);
@@ -888,7 +935,7 @@
 }
 
 [[nodiscard]] static int modifyUidDefaultUnreachableRule(uid_t uidStart, uid_t uidEnd,
-                                                         uint32_t subPriority, bool add) {
+                                                         int32_t subPriority, bool add) {
     if ((uidStart == INVALID_UID) || (uidEnd == INVALID_UID)) {
         ALOGE("modifyUidDefaultUnreachableRule, invalid UIDs (%u, %u)", uidStart, uidEnd);
         return -EUSERS;
@@ -951,8 +998,8 @@
 
 int RouteController::modifyVirtualNetwork(unsigned netId, const char* interface,
                                           const UidRangeMap& uidRangeMap, bool secure, bool add,
-                                          bool modifyNonUidBasedRules) {
-    uint32_t table = getRouteTableForInterface(interface);
+                                          bool modifyNonUidBasedRules, bool excludeLocalRoutes) {
+    uint32_t table = getRouteTableForInterface(interface, false /* false */);
     if (table == RT_TABLE_UNSPEC) {
         return -ESRCH;
     }
@@ -960,7 +1007,7 @@
     for (const auto& [subPriority, uidRanges] : uidRangeMap) {
         for (const UidRangeParcel& range : uidRanges.getRanges()) {
             if (int ret = modifyVpnUidRangeRule(table, range.start, range.stop, subPriority, secure,
-                                                add)) {
+                                                add, excludeLocalRoutes)) {
                 return ret;
             }
             if (int ret = modifyExplicitNetworkRule(netId, table, PERMISSION_NONE, range.start,
@@ -981,11 +1028,12 @@
         if (int ret = modifyVpnOutputToLocalRule(interface, add)) {
             return ret;
         }
-        if (int ret = modifyVpnSystemPermissionRule(netId, table, secure, add)) {
+        if (int ret =
+                    modifyVpnSystemPermissionRule(netId, table, secure, add, excludeLocalRoutes)) {
             return ret;
         }
         return modifyExplicitNetworkRule(netId, table, PERMISSION_NONE, UID_ROOT, UID_ROOT,
-                                         UidRanges::DEFAULT_SUB_PRIORITY, add);
+                                         UidRanges::SUB_PRIORITY_HIGHEST, add);
     }
 
     return 0;
@@ -993,7 +1041,7 @@
 
 int RouteController::modifyDefaultNetwork(uint16_t action, const char* interface,
                                           Permission permission) {
-    uint32_t table = getRouteTableForInterface(interface);
+    uint32_t table = getRouteTableForInterface(interface, false /* local */);
     if (table == RT_TABLE_UNSPEC) {
         return -ESRCH;
     }
@@ -1013,7 +1061,7 @@
 
 int RouteController::modifyTetheredNetwork(uint16_t action, const char* inputInterface,
                                            const char* outputInterface) {
-    uint32_t table = getRouteTableForInterface(outputInterface);
+    uint32_t table = getRouteTableForInterface(outputInterface, false /* local */);
     if (table == RT_TABLE_UNSPEC) {
         return -ESRCH;
     }
@@ -1026,11 +1074,11 @@
 // Returns 0 on success or negative errno on failure.
 int RouteController::modifyRoute(uint16_t action, uint16_t flags, const char* interface,
                                  const char* destination, const char* nexthop, TableType tableType,
-                                 int mtu) {
+                                 int mtu, int priority) {
     uint32_t table;
     switch (tableType) {
         case RouteController::INTERFACE: {
-            table = getRouteTableForInterface(interface);
+            table = getRouteTableForInterface(interface, false /* local */);
             if (table == RT_TABLE_UNSPEC) {
                 return -ESRCH;
             }
@@ -1050,7 +1098,7 @@
         }
     }
 
-    int ret = modifyIpRoute(action, flags, table, interface, destination, nexthop, mtu);
+    int ret = modifyIpRoute(action, flags, table, interface, destination, nexthop, mtu, priority);
     // Trying to add a route that already exists shouldn't cause an error.
     if (ret && !(action == RTM_NEWROUTE && ret == -EEXIST)) {
         return ret;
@@ -1068,7 +1116,7 @@
     if (StartsWith(interface, "v4-") && add) return;
 
     // The interface may have already gone away in the delete case.
-    uint32_t ifindex = if_nametoindex(interface);
+    uint32_t ifindex = RouteController::ifNameToIndexFunction(interface);
     if (!ifindex) {
         ALOGE("cannot find interface %s", interface);
         return;
@@ -1127,11 +1175,22 @@
     return rtNetlinkFlush(RTM_GETROUTE, RTM_DELROUTE, "routes", shouldDelete);
 }
 
-// Returns 0 on success or negative errno on failure.
 int RouteController::flushRoutes(const char* interface) {
+    // Try to flush both local and global routing tables.
+    //
+    // Flush local first because flush global routing tables may erase the sInterfaceToTable map.
+    // Then the fake <iface>_local interface will be unable to find the index because the local
+    // interface depends physical interface to find the correct index.
+    int ret = flushRoutes(interface, true);
+    ret |= flushRoutes(interface, false);
+    return ret;
+}
+
+// Returns 0 on success or negative errno on failure.
+int RouteController::flushRoutes(const char* interface, bool local) {
     std::lock_guard lock(sInterfaceToTableLock);
 
-    uint32_t table = getRouteTableForInterfaceLocked(interface);
+    uint32_t table = getRouteTableForInterfaceLocked(interface, local);
     if (table == RT_TABLE_UNSPEC) {
         return -ESRCH;
     }
@@ -1140,7 +1199,8 @@
 
     // If we failed to flush routes, the caller may elect to keep this interface around, so keep
     // track of its name.
-    if (ret == 0) {
+    // Skip erasing local fake interface since it does not exist in sInterfaceToTable.
+    if (ret == 0 && !local) {
         sInterfaceToTable.erase(interface);
     }
 
@@ -1192,6 +1252,7 @@
                                         MODIFY_NON_UID_BASED_RULES)) {
         return ret;
     }
+
     maybeModifyQdiscClsact(interface, ACTION_ADD);
     updateTableNamesFile();
     return 0;
@@ -1204,21 +1265,25 @@
                                         MODIFY_NON_UID_BASED_RULES)) {
         return ret;
     }
+
     if (int ret = flushRoutes(interface)) {
         return ret;
     }
+
     if (int ret = clearTetheringRules(interface)) {
         return ret;
     }
+
     maybeModifyQdiscClsact(interface, ACTION_DEL);
     updateTableNamesFile();
     return 0;
 }
 
 int RouteController::addInterfaceToVirtualNetwork(unsigned netId, const char* interface,
-                                                  bool secure, const UidRangeMap& uidRangeMap) {
+                                                  bool secure, const UidRangeMap& uidRangeMap,
+                                                  bool excludeLocalRoutes) {
     if (int ret = modifyVirtualNetwork(netId, interface, uidRangeMap, secure, ACTION_ADD,
-                                       MODIFY_NON_UID_BASED_RULES)) {
+                                       MODIFY_NON_UID_BASED_RULES, excludeLocalRoutes)) {
         return ret;
     }
     updateTableNamesFile();
@@ -1226,10 +1291,10 @@
 }
 
 int RouteController::removeInterfaceFromVirtualNetwork(unsigned netId, const char* interface,
-                                                       bool secure,
-                                                       const UidRangeMap& uidRangeMap) {
+                                                       bool secure, const UidRangeMap& uidRangeMap,
+                                                       bool excludeLocalRoutes) {
     if (int ret = modifyVirtualNetwork(netId, interface, uidRangeMap, secure, ACTION_DEL,
-                                       MODIFY_NON_UID_BASED_RULES)) {
+                                       MODIFY_NON_UID_BASED_RULES, excludeLocalRoutes)) {
         return ret;
     }
     if (int ret = flushRoutes(interface)) {
@@ -1263,15 +1328,17 @@
 }
 
 int RouteController::addUsersToVirtualNetwork(unsigned netId, const char* interface, bool secure,
-                                              const UidRangeMap& uidRangeMap) {
+                                              const UidRangeMap& uidRangeMap,
+                                              bool excludeLocalRoutes) {
     return modifyVirtualNetwork(netId, interface, uidRangeMap, secure, ACTION_ADD,
-                                !MODIFY_NON_UID_BASED_RULES);
+                                !MODIFY_NON_UID_BASED_RULES, excludeLocalRoutes);
 }
 
 int RouteController::removeUsersFromVirtualNetwork(unsigned netId, const char* interface,
-                                                   bool secure, const UidRangeMap& uidRangeMap) {
+                                                   bool secure, const UidRangeMap& uidRangeMap,
+                                                   bool excludeLocalRoutes) {
     return modifyVirtualNetwork(netId, interface, uidRangeMap, secure, ACTION_DEL,
-                                !MODIFY_NON_UID_BASED_RULES);
+                                !MODIFY_NON_UID_BASED_RULES, excludeLocalRoutes);
 }
 
 int RouteController::addInterfaceToDefaultNetwork(const char* interface, Permission permission) {
@@ -1284,21 +1351,21 @@
 }
 
 int RouteController::addRoute(const char* interface, const char* destination, const char* nexthop,
-                              TableType tableType, int mtu) {
+                              TableType tableType, int mtu, int priority) {
     return modifyRoute(RTM_NEWROUTE, NETLINK_ROUTE_CREATE_FLAGS, interface, destination, nexthop,
-                       tableType, mtu);
+                       tableType, mtu, priority);
 }
 
 int RouteController::removeRoute(const char* interface, const char* destination,
-                                 const char* nexthop, TableType tableType) {
+                                 const char* nexthop, TableType tableType, int priority) {
     return modifyRoute(RTM_DELROUTE, NETLINK_REQUEST_FLAGS, interface, destination, nexthop,
-                       tableType, 0);
+                       tableType, 0 /* mtu */, priority);
 }
 
 int RouteController::updateRoute(const char* interface, const char* destination,
                                  const char* nexthop, TableType tableType, int mtu) {
     return modifyRoute(RTM_NEWROUTE, NETLINK_ROUTE_REPLACE_FLAGS, interface, destination, nexthop,
-                       tableType, mtu);
+                       tableType, mtu, 0 /* priority */);
 }
 
 int RouteController::enableTethering(const char* inputInterface, const char* outputInterface) {
@@ -1311,13 +1378,21 @@
 
 int RouteController::addVirtualNetworkFallthrough(unsigned vpnNetId, const char* physicalInterface,
                                                   Permission permission) {
-    return modifyVpnFallthroughRule(RTM_NEWRULE, vpnNetId, physicalInterface, permission);
+    if (int ret = modifyVpnFallthroughRule(RTM_NEWRULE, vpnNetId, physicalInterface, permission)) {
+        return ret;
+    }
+
+    return modifyVpnLocalExclusionRule(true /* add */, physicalInterface);
 }
 
 int RouteController::removeVirtualNetworkFallthrough(unsigned vpnNetId,
                                                      const char* physicalInterface,
                                                      Permission permission) {
-    return modifyVpnFallthroughRule(RTM_DELRULE, vpnNetId, physicalInterface, permission);
+    if (int ret = modifyVpnFallthroughRule(RTM_DELRULE, vpnNetId, physicalInterface, permission)) {
+        return ret;
+    }
+
+    return modifyVpnLocalExclusionRule(false /* add */, physicalInterface);
 }
 
 int RouteController::addUsersToPhysicalNetwork(unsigned netId, const char* interface,
diff --git a/server/RouteController.h b/server/RouteController.h
index 38d2d62..9b04cfd 100644
--- a/server/RouteController.h
+++ b/server/RouteController.h
@@ -16,8 +16,9 @@
 
 #pragma once
 
-#include "NetdConstants.h"  // IptablesTarget
-#include "Network.h"        // UidRangeMap
+#include "InterfaceController.h"  // getParameter
+#include "NetdConstants.h"        // IptablesTarget
+#include "Network.h"              // UidRangeMap
 #include "Permission.h"
 
 #include <android-base/thread_annotations.h>
@@ -30,11 +31,11 @@
 namespace android::net {
 
 // clang-format off
-const uint32_t RULE_PRIORITY_VPN_OVERRIDE_SYSTEM     = 10000;
-const uint32_t RULE_PRIORITY_VPN_OVERRIDE_OIF        = 11000;
-const uint32_t RULE_PRIORITY_VPN_OUTPUT_TO_LOCAL     = 12000;
-const uint32_t RULE_PRIORITY_SECURE_VPN              = 13000;
-const uint32_t RULE_PRIORITY_PROHIBIT_NON_VPN        = 14000;
+constexpr int32_t RULE_PRIORITY_VPN_OVERRIDE_SYSTEM               = 10000;
+constexpr int32_t RULE_PRIORITY_VPN_OVERRIDE_OIF                  = 11000;
+constexpr int32_t RULE_PRIORITY_VPN_OUTPUT_TO_LOCAL               = 12000;
+constexpr int32_t RULE_PRIORITY_SECURE_VPN                        = 13000;
+constexpr int32_t RULE_PRIORITY_PROHIBIT_NON_VPN                  = 14000;
 // Rules used when applications explicitly select a network that they have permission to use only
 // because they are in the list of UID ranges for that network.
 //
@@ -42,21 +43,23 @@
 // not have the necessary permission bits in the fwmark. We cannot just give any socket on any of
 // these networks the permission bits, because if the UID that created the socket loses access to
 // the network, then the socket must not match any rule that selects that network.
-const uint32_t RULE_PRIORITY_UID_EXPLICIT_NETWORK    = 15000;
-const uint32_t RULE_PRIORITY_EXPLICIT_NETWORK        = 16000;
-const uint32_t RULE_PRIORITY_OUTPUT_INTERFACE        = 17000;
-const uint32_t RULE_PRIORITY_LEGACY_SYSTEM           = 18000;
-const uint32_t RULE_PRIORITY_LEGACY_NETWORK          = 19000;
-const uint32_t RULE_PRIORITY_LOCAL_NETWORK           = 20000;
-const uint32_t RULE_PRIORITY_TETHERING               = 21000;
+constexpr int32_t RULE_PRIORITY_UID_EXPLICIT_NETWORK              = 15000;
+constexpr int32_t RULE_PRIORITY_EXPLICIT_NETWORK                  = 16000;
+constexpr int32_t RULE_PRIORITY_OUTPUT_INTERFACE                  = 17000;
+constexpr int32_t RULE_PRIORITY_LEGACY_SYSTEM                     = 18000;
+constexpr int32_t RULE_PRIORITY_LEGACY_NETWORK                    = 19000;
+constexpr int32_t RULE_PRIORITY_LOCAL_NETWORK                     = 20000;
+constexpr int32_t RULE_PRIORITY_TETHERING                         = 21000;
 // Implicit rules for sockets that connected on a given network because the network was the default
 // network for the UID.
-const uint32_t RULE_PRIORITY_UID_IMPLICIT_NETWORK    = 22000;
-const uint32_t RULE_PRIORITY_IMPLICIT_NETWORK        = 23000;
-const uint32_t RULE_PRIORITY_BYPASSABLE_VPN          = 24000;
-// reserved for RULE_PRIORITY_UID_VPN_FALLTHROUGH    = 25000;
-const uint32_t RULE_PRIORITY_VPN_FALLTHROUGH         = 26000;
-const uint32_t RULE_PRIORITY_UID_DEFAULT_NETWORK     = 27000;
+constexpr int32_t RULE_PRIORITY_UID_IMPLICIT_NETWORK              = 22000;
+constexpr int32_t RULE_PRIORITY_IMPLICIT_NETWORK                  = 23000;
+constexpr int32_t RULE_PRIORITY_BYPASSABLE_VPN_NO_LOCAL_EXCLUSION = 24000;
+// Rules used for excluding local route in the VPN network.
+constexpr int32_t RULE_PRIORITY_LOCAL_ROUTES                      = 25000;
+constexpr int32_t RULE_PRIORITY_BYPASSABLE_VPN_LOCAL_EXCLUSION    = 26000;
+constexpr int32_t RULE_PRIORITY_VPN_FALLTHROUGH                   = 27000;
+constexpr int32_t RULE_PRIORITY_UID_DEFAULT_NETWORK               = 28000;
 // Rule used when framework wants to disable default network from specified applications. There will
 // be a small interval the same uid range exists in both UID_DEFAULT_UNREACHABLE and
 // UID_DEFAULT_NETWORK when framework is switching user preferences.
@@ -71,9 +74,9 @@
 // The priority is lower than UID_DEFAULT_NETWORK. Otherwise, the app will be told by
 // ConnectivityService that it has a network in step 1 of the second case. But if it tries to use
 // the network, it will not work. That will potentially cause a user-visible error.
-const uint32_t RULE_PRIORITY_UID_DEFAULT_UNREACHABLE = 28000;
-const uint32_t RULE_PRIORITY_DEFAULT_NETWORK         = 29000;
-const uint32_t RULE_PRIORITY_UNREACHABLE             = 32000;
+constexpr int32_t RULE_PRIORITY_UID_DEFAULT_UNREACHABLE           = 29000;
+constexpr int32_t RULE_PRIORITY_DEFAULT_NETWORK                   = 30000;
+constexpr int32_t RULE_PRIORITY_UNREACHABLE                       = 32000;
 // clang-format on
 
 class UidRanges;
@@ -89,7 +92,11 @@
     };
 
     static const int ROUTE_TABLE_OFFSET_FROM_INDEX = 1000;
+    // Offset for the table of virtual local network created from the physical interface.
+    static const int ROUTE_TABLE_OFFSET_FROM_INDEX_FOR_LOCAL = 1000000000;
 
+    static constexpr const char* INTERFACE_LOCAL_SUFFIX = "_local";
+    static constexpr const char* RT_TABLES_PATH = "/data/misc/net/rt_tables";
     static const char* const LOCAL_MANGLE_INPUT;
 
     [[nodiscard]] static int Init(unsigned localNetId);
@@ -116,20 +123,24 @@
 
     [[nodiscard]] static int addInterfaceToVirtualNetwork(unsigned netId, const char* interface,
                                                           bool secure,
-                                                          const UidRangeMap& uidRangeMap);
+                                                          const UidRangeMap& uidRangeMap,
+                                                          bool excludeLocalRoutes);
     [[nodiscard]] static int removeInterfaceFromVirtualNetwork(unsigned netId,
                                                                const char* interface, bool secure,
-                                                               const UidRangeMap& uidRangeMap);
+                                                               const UidRangeMap& uidRangeMap,
+                                                               bool excludeLocalRoutes);
 
     [[nodiscard]] static int modifyPhysicalNetworkPermission(unsigned netId, const char* interface,
                                                              Permission oldPermission,
                                                              Permission newPermission);
 
     [[nodiscard]] static int addUsersToVirtualNetwork(unsigned netId, const char* interface,
-                                                      bool secure, const UidRangeMap& uidRangeMap);
+                                                      bool secure, const UidRangeMap& uidRangeMap,
+                                                      bool excludeLocalRoutes);
     [[nodiscard]] static int removeUsersFromVirtualNetwork(unsigned netId, const char* interface,
                                                            bool secure,
-                                                           const UidRangeMap& uidRangeMap);
+                                                           const UidRangeMap& uidRangeMap,
+                                                           bool excludeLocalRoutes);
 
     [[nodiscard]] static int addUsersToRejectNonSecureNetworkRule(const UidRanges& uidRanges);
     [[nodiscard]] static int removeUsersFromRejectNonSecureNetworkRule(const UidRanges& uidRanges);
@@ -142,9 +153,10 @@
     // |nexthop| can be NULL (to indicate a directly-connected route), "unreachable" (to indicate a
     // route that's blocked), "throw" (to indicate the lack of a match), or a regular IP address.
     [[nodiscard]] static int addRoute(const char* interface, const char* destination,
-                                      const char* nexthop, TableType tableType, int mtu);
+                                      const char* nexthop, TableType tableType, int mtu,
+                                      int priority);
     [[nodiscard]] static int removeRoute(const char* interface, const char* destination,
-                                         const char* nexthop, TableType tableType);
+                                         const char* nexthop, TableType tableType, int priority);
     [[nodiscard]] static int updateRoute(const char* interface, const char* destination,
                                          const char* nexthop, TableType tableType, int mtu);
 
@@ -175,8 +187,9 @@
     // For testing.
     static int (*iptablesRestoreCommandFunction)(IptablesTarget, const std::string&,
                                                  const std::string&, std::string *);
+    static uint32_t (*ifNameToIndexFunction)(const char*);
 
-private:
+  private:
     friend class RouteControllerTest;
 
     static std::mutex sInterfaceToTableLock;
@@ -184,10 +197,13 @@
 
     static int configureDummyNetwork();
     [[nodiscard]] static int flushRoutes(const char* interface) EXCLUDES(sInterfaceToTableLock);
+    [[nodiscard]] static int flushRoutes(const char* interface, bool local)
+            EXCLUDES(sInterfaceToTableLock);
     [[nodiscard]] static int flushRoutes(uint32_t table);
-    static uint32_t getRouteTableForInterfaceLocked(const char* interface)
+    static uint32_t getRouteTableForInterfaceLocked(const char* interface, bool local)
             REQUIRES(sInterfaceToTableLock);
-    static uint32_t getRouteTableForInterface(const char *interface) EXCLUDES(sInterfaceToTableLock);
+    static uint32_t getRouteTableForInterface(const char* interface, bool local)
+            EXCLUDES(sInterfaceToTableLock);
     static int modifyDefaultNetwork(uint16_t action, const char* interface, Permission permission);
     static int modifyPhysicalNetwork(unsigned netId, const char* interface,
                                      const UidRangeMap& uidRangeMap, Permission permission,
@@ -195,15 +211,16 @@
     static int modifyUnreachableNetwork(unsigned netId, const UidRangeMap& uidRangeMap, bool add);
     static int modifyRoute(uint16_t action, uint16_t flags, const char* interface,
                            const char* destination, const char* nexthop, TableType tableType,
-                           int mtu);
+                           int mtu, int priority);
     static int modifyTetheredNetwork(uint16_t action, const char* inputInterface,
                                      const char* outputInterface);
     static int modifyVpnFallthroughRule(uint16_t action, unsigned vpnNetId,
                                         const char* physicalInterface, Permission permission);
     static int modifyVirtualNetwork(unsigned netId, const char* interface,
                                     const UidRangeMap& uidRangeMap, bool secure, bool add,
-                                    bool modifyNonUidBasedRules);
+                                    bool modifyNonUidBasedRules, bool excludeLocalRoutes);
     static void updateTableNamesFile() EXCLUDES(sInterfaceToTableLock);
+    static int modifyVpnLocalExclusionRule(bool add, const char* physicalInterface);
 };
 
 // Public because they are called by by RouteControllerTest.cpp.
@@ -211,7 +228,7 @@
 // functions public.
 [[nodiscard]] int modifyIpRoute(uint16_t action, uint16_t flags, uint32_t table,
                                 const char* interface, const char* destination, const char* nexthop,
-                                uint32_t mtu);
+                                uint32_t mtu, uint32_t priority);
 uint32_t getRulePriority(const nlmsghdr *nlh);
 [[nodiscard]] int modifyIncomingPacketMark(unsigned netId, const char* interface,
                                            Permission permission, bool add);
diff --git a/server/RouteControllerTest.cpp b/server/RouteControllerTest.cpp
index e85a83c..8bdc879 100644
--- a/server/RouteControllerTest.cpp
+++ b/server/RouteControllerTest.cpp
@@ -17,6 +17,7 @@
  */
 
 #include <gtest/gtest.h>
+#include <fstream>
 
 #include "Fwmark.h"
 #include "IptablesBaseTest.h"
@@ -27,6 +28,13 @@
 
 using android::base::StringPrintf;
 
+static const char* TEST_IFACE1 = "netdtest1";
+static const char* TEST_IFACE2 = "netdtest2";
+static const uint32_t TEST_IFACE1_INDEX = 901;
+static const uint32_t TEST_IFACE2_INDEX = 902;
+// See Linux kernel source in include/net/flow.h
+#define LOOPBACK_IFINDEX 1
+
 namespace android {
 namespace net {
 
@@ -34,11 +42,20 @@
 public:
     RouteControllerTest() {
         RouteController::iptablesRestoreCommandFunction = fakeExecIptablesRestoreCommand;
+        RouteController::ifNameToIndexFunction = fakeIfaceNameToIndexFunction;
     }
 
     int flushRoutes(uint32_t a) {
         return RouteController::flushRoutes(a);
     }
+
+    uint32_t static fakeIfaceNameToIndexFunction(const char* iface) {
+        // "lo" is the same as the real one
+        if (!strcmp(iface, "lo")) return LOOPBACK_IFINDEX;
+        if (!strcmp(iface, TEST_IFACE1)) return TEST_IFACE1_INDEX;
+        if (!strcmp(iface, TEST_IFACE2)) return TEST_IFACE2_INDEX;
+        return 0;
+    }
 };
 
 TEST_F(RouteControllerTest, TestGetRulePriority) {
@@ -80,23 +97,20 @@
                   "Test table2 number too large");
 
     EXPECT_EQ(0, modifyIpRoute(RTM_NEWROUTE, NETLINK_ROUTE_CREATE_FLAGS, table1, "lo",
-              "192.0.2.2/32", nullptr, 0 /* mtu */));
+                               "192.0.2.2/32", nullptr, 0 /* mtu */, 0 /* priority */));
     EXPECT_EQ(0, modifyIpRoute(RTM_NEWROUTE, NETLINK_ROUTE_CREATE_FLAGS, table1, "lo",
-              "192.0.2.3/32", nullptr, 0 /* mtu */));
+                               "192.0.2.3/32", nullptr, 0 /* mtu */, 0 /* priority */));
     EXPECT_EQ(0, modifyIpRoute(RTM_NEWROUTE, NETLINK_ROUTE_CREATE_FLAGS, table2, "lo",
-              "192.0.2.4/32", nullptr, 0 /* mtu */));
+                               "192.0.2.4/32", nullptr, 0 /* mtu */, 0 /* priority */));
 
     EXPECT_EQ(0, flushRoutes(table1));
 
-    EXPECT_EQ(-ESRCH,
-              modifyIpRoute(RTM_DELROUTE, NETLINK_ROUTE_CREATE_FLAGS, table1, "lo", "192.0.2.2/32",
-                            nullptr, 0 /* mtu */));
-    EXPECT_EQ(-ESRCH,
-              modifyIpRoute(RTM_DELROUTE, NETLINK_ROUTE_CREATE_FLAGS, table1, "lo", "192.0.2.3/32",
-                            nullptr, 0 /* mtu */));
-    EXPECT_EQ(0,
-              modifyIpRoute(RTM_DELROUTE, NETLINK_ROUTE_CREATE_FLAGS, table2, "lo", "192.0.2.4/32",
-                            nullptr, 0 /* mtu */));
+    EXPECT_EQ(-ESRCH, modifyIpRoute(RTM_DELROUTE, NETLINK_ROUTE_CREATE_FLAGS, table1, "lo",
+                                    "192.0.2.2/32", nullptr, 0 /* mtu */, 0 /* priority */));
+    EXPECT_EQ(-ESRCH, modifyIpRoute(RTM_DELROUTE, NETLINK_ROUTE_CREATE_FLAGS, table1, "lo",
+                                    "192.0.2.3/32", nullptr, 0 /* mtu */, 0 /* priority */));
+    EXPECT_EQ(0, modifyIpRoute(RTM_DELROUTE, NETLINK_ROUTE_CREATE_FLAGS, table2, "lo",
+                               "192.0.2.4/32", nullptr, 0 /* mtu */, 0 /* priority */));
 }
 
 TEST_F(RouteControllerTest, TestModifyIncomingPacketMark) {
@@ -118,5 +132,46 @@
       mask)});
 }
 
+bool hasLocalInterfaceInRouteTable(const char* iface) {
+    // Calculate the table index from interface index
+    std::string index = std::to_string(RouteController::ROUTE_TABLE_OFFSET_FROM_INDEX_FOR_LOCAL +
+                                       RouteController::ifNameToIndexFunction(iface));
+    std::string localIface =
+            index + " " + std::string(iface) + std::string(RouteController::INTERFACE_LOCAL_SUFFIX);
+    std::string line;
+
+    std::ifstream input(RouteController::RT_TABLES_PATH);
+    while (std::getline(input, line)) {
+        if (line.find(localIface) != std::string::npos) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+TEST_F(RouteControllerTest, TestCreateVirtualLocalInterfaceTable) {
+    static constexpr int TEST_NETID = 65500;
+    std::map<int32_t, UidRanges> uidRangeMap;
+    EXPECT_EQ(0, RouteController::addInterfaceToVirtualNetwork(TEST_NETID, TEST_IFACE1, false,
+                                                               uidRangeMap, false));
+    // Expect to create <iface>_local in the routing table
+    EXPECT_TRUE(hasLocalInterfaceInRouteTable(TEST_IFACE1));
+    // Add another interface, <TEST_IFACE2>_local should also be created
+    EXPECT_EQ(0, RouteController::addInterfaceToVirtualNetwork(TEST_NETID, TEST_IFACE2, false,
+                                                               uidRangeMap, false));
+    EXPECT_TRUE(hasLocalInterfaceInRouteTable(TEST_IFACE2));
+    // Remove TEST_IFACE1
+    EXPECT_EQ(0, RouteController::removeInterfaceFromVirtualNetwork(TEST_NETID, TEST_IFACE1, false,
+                                                                    uidRangeMap, false));
+    // Interface remove should also remove the virtual local interface for routing table
+    EXPECT_FALSE(hasLocalInterfaceInRouteTable(TEST_IFACE1));
+    // <TEST_IFACE2> should still in the routing table
+    EXPECT_TRUE(hasLocalInterfaceInRouteTable(TEST_IFACE2));
+    EXPECT_EQ(0, RouteController::removeInterfaceFromVirtualNetwork(TEST_NETID, TEST_IFACE2, false,
+                                                                    uidRangeMap, false));
+    EXPECT_FALSE(hasLocalInterfaceInRouteTable(TEST_IFACE2));
+}
+
 }  // namespace net
 }  // namespace android
diff --git a/server/SockDiag.cpp b/server/SockDiag.cpp
index b3d9150..49ca8d7 100644
--- a/server/SockDiag.cpp
+++ b/server/SockDiag.cpp
@@ -133,7 +133,10 @@
     }
     request.nlh.nlmsg_len = len;
 
-    if (writev(mSock, iov, iovcnt) != (ssize_t) len) {
+    ssize_t writevRet = writev(mSock, iov, iovcnt);
+    // Don't let pointers to the stack escape.
+    iov[0] = {nullptr, 0};
+    if (writevRet != (ssize_t)len) {
         return -errno;
     }
 
@@ -315,11 +318,12 @@
         return ret;
     }
 
-    auto destroyAll = [ifindex](uint8_t, const inet_diag_msg* msg) {
+    // Destroy all sockets on the address, except link-local sockets where ifindex doesn't match.
+    auto shouldDestroy = [ifindex](uint8_t, const inet_diag_msg* msg) {
         return ifindex == 0 || ifindex == (int)msg->id.idiag_if;
     };
 
-    return readDiagMsg(proto, destroyAll);
+    return readDiagMsg(proto, shouldDestroy);
 }
 
 int SockDiag::destroySockets(const char* addrstr, int ifindex) {
diff --git a/server/TcUtils.h b/server/TcUtils.h
new file mode 100644
index 0000000..d205c04
--- /dev/null
+++ b/server/TcUtils.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/result.h>
+#include <errno.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/rtnetlink.h>
+#include <tcutils/tcutils.h>
+
+#include <string>
+
+#include "bpf/BpfUtils.h"
+#include "bpf_shared.h"
+
+namespace android {
+namespace net {
+
+// For better code clarity - do not change values - used for booleans like
+// with_ethernet_header or isEthernet.
+constexpr bool RAWIP = false;
+constexpr bool ETHER = true;
+
+// For better code clarity when used for 'bool ingress' parameter.
+constexpr bool EGRESS = false;
+constexpr bool INGRESS = true;
+
+// The priority of clat hook - must be after tethering.
+constexpr uint16_t PRIO_CLAT = 4;
+
+inline base::Result<bool> isEthernet(const std::string& interface) {
+    bool result = false;
+    if (int error = ::android::isEthernet(interface.c_str(), result)) {
+        errno = error;
+        return ErrnoErrorf("isEthernet failed for interface {}", interface);
+    }
+    return result;
+}
+
+inline int getClatEgress4MapFd(void) {
+    const int fd = bpf::mapRetrieveRW(CLAT_EGRESS4_MAP_PATH);
+    return (fd == -1) ? -errno : fd;
+}
+
+inline int getClatIngress6MapFd(void) {
+    const int fd = bpf::mapRetrieveRW(CLAT_INGRESS6_MAP_PATH);
+    return (fd == -1) ? -errno : fd;
+}
+
+inline int tcQdiscAddDevClsact(int ifIndex) {
+    return doTcQdiscClsact(ifIndex, RTM_NEWQDISC, NLM_F_EXCL | NLM_F_CREATE);
+}
+
+inline int tcQdiscReplaceDevClsact(int ifIndex) {
+    return doTcQdiscClsact(ifIndex, RTM_NEWQDISC, NLM_F_CREATE | NLM_F_REPLACE);
+}
+
+inline int tcQdiscDelDevClsact(int ifIndex) {
+    return doTcQdiscClsact(ifIndex, RTM_DELQDISC, 0);
+}
+
+// tc filter add dev .. ingress prio 4 protocol ipv6 bpf object-pinned /sys/fs/bpf/... direct-action
+inline int tcFilterAddDevIngressClatIpv6(int ifIndex, const std::string& bpfProgPath) {
+    return tcAddBpfFilter(ifIndex, INGRESS, PRIO_CLAT, ETH_P_IPV6, bpfProgPath.c_str());
+}
+
+// tc filter add dev .. egress prio 4 protocol ip bpf object-pinned /sys/fs/bpf/... direct-action
+inline int tcFilterAddDevEgressClatIpv4(int ifIndex, const std::string& bpfProgPath) {
+    return tcAddBpfFilter(ifIndex, EGRESS, PRIO_CLAT, ETH_P_IP, bpfProgPath.c_str());
+}
+
+// tc filter del dev .. ingress prio 4 protocol ipv6
+inline int tcFilterDelDevIngressClatIpv6(int ifIndex) {
+    return tcDeleteFilter(ifIndex, INGRESS, PRIO_CLAT, ETH_P_IPV6);
+}
+
+// tc filter del dev .. egress prio 4 protocol ip
+inline int tcFilterDelDevEgressClatIpv4(int ifIndex) {
+    return tcDeleteFilter(ifIndex, EGRESS, PRIO_CLAT, ETH_P_IP);
+}
+
+}  // namespace net
+}  // namespace android
diff --git a/server/TetherController.cpp b/server/TetherController.cpp
index 325fc41..7919357 100644
--- a/server/TetherController.cpp
+++ b/server/TetherController.cpp
@@ -51,8 +51,8 @@
 #include "InterfaceController.h"
 #include "NetdConstants.h"
 #include "NetworkController.h"
-#include "OffloadUtils.h"
 #include "Permission.h"
+#include "TcUtils.h"
 #include "TetherController.h"
 
 #include "android/net/TetherOffloadRuleParcel.h"
@@ -350,8 +350,7 @@
 
     ALOGD("Stopping tethering services");
 
-    kill(mDaemonPid, SIGTERM);
-    waitpid(mDaemonPid, nullptr, 0);
+    ::stopProcess(mDaemonPid, "tethering(dnsmasq)");
     mDaemonPid = 0;
     close(mDaemonFd);
     mDaemonFd = -1;
@@ -879,7 +878,7 @@
          * which is what TetherController sets up.
          * The 1st matches rx, and sets up the pair for the tx side.
          */
-        if (!stats.intIface[0]) {
+        if (stats.intIface.empty()) {
             ALOGV("0Filter RX iface_in=%s iface_out=%s rx_bytes=%" PRId64 " rx_packets=%" PRId64
                   " ", iface0.c_str(), iface1.c_str(), bytes, packets);
             stats.intIface = iface0;
diff --git a/server/TetherController.h b/server/TetherController.h
index 585686a..b4472bd 100644
--- a/server/TetherController.h
+++ b/server/TetherController.h
@@ -28,7 +28,7 @@
 #include "NetdConstants.h"
 #include "android-base/result.h"
 #include "bpf/BpfMap.h"
-#include "netdbpf/bpf_shared.h"
+#include "bpf_shared.h"
 
 #include "android/net/TetherOffloadRuleParcel.h"
 
diff --git a/server/TetherControllerTest.cpp b/server/TetherControllerTest.cpp
index e700f60..0c72bb4 100644
--- a/server/TetherControllerTest.cpp
+++ b/server/TetherControllerTest.cpp
@@ -33,7 +33,7 @@
 #include <netdutils/StatusOr.h>
 
 #include "IptablesBaseTest.h"
-#include "OffloadUtils.h"
+#include "TcUtils.h"
 #include "TetherController.h"
 
 using android::base::Join;
diff --git a/server/TrafficController.cpp b/server/TrafficController.cpp
deleted file mode 100644
index 1f678cb..0000000
--- a/server/TrafficController.cpp
+++ /dev/null
@@ -1,1038 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "TrafficController"
-#include <inttypes.h>
-#include <linux/bpf.h>
-#include <linux/if_ether.h>
-#include <linux/in.h>
-#include <linux/inet_diag.h>
-#include <linux/netlink.h>
-#include <linux/sock_diag.h>
-#include <linux/unistd.h>
-#include <net/if.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/utsname.h>
-#include <sys/wait.h>
-#include <mutex>
-#include <unordered_set>
-#include <vector>
-
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-#include <android-base/unique_fd.h>
-#include <netdutils/StatusOr.h>
-
-#include <netdutils/Misc.h>
-#include <netdutils/Syscalls.h>
-#include <processgroup/processgroup.h>
-#include "TrafficController.h"
-#include "bpf/BpfMap.h"
-
-#include "FirewallController.h"
-#include "InterfaceController.h"
-#include "NetlinkListener.h"
-#include "netdutils/DumpWriter.h"
-#include "qtaguid/qtaguid.h"
-
-namespace android {
-namespace net {
-
-using base::StringPrintf;
-using base::unique_fd;
-using bpf::getSocketCookie;
-using bpf::NONEXISTENT_COOKIE;
-using bpf::OVERFLOW_COUNTERSET;
-using bpf::retrieveProgram;
-using bpf::synchronizeKernelRCU;
-using netdutils::DumpWriter;
-using netdutils::extract;
-using netdutils::ScopedIndent;
-using netdutils::Slice;
-using netdutils::sSyscalls;
-using netdutils::Status;
-using netdutils::statusFromErrno;
-using netdutils::StatusOr;
-using netdutils::status::ok;
-
-constexpr int kSockDiagMsgType = SOCK_DIAG_BY_FAMILY;
-constexpr int kSockDiagDoneMsgType = NLMSG_DONE;
-constexpr int PER_UID_STATS_ENTRIES_LIMIT = 500;
-// At most 90% of the stats map may be used by tagged traffic entries. This ensures
-// that 10% of the map is always available to count untagged traffic, one entry per UID.
-// Otherwise, apps would be able to avoid data usage accounting entirely by filling up the
-// map with tagged traffic entries.
-constexpr int TOTAL_UID_STATS_ENTRIES_LIMIT = STATS_MAP_SIZE * 0.9;
-
-static_assert(BPF_PERMISSION_INTERNET == INetd::PERMISSION_INTERNET,
-              "Mismatch between BPF and AIDL permissions: PERMISSION_INTERNET");
-static_assert(BPF_PERMISSION_UPDATE_DEVICE_STATS == INetd::PERMISSION_UPDATE_DEVICE_STATS,
-              "Mismatch between BPF and AIDL permissions: PERMISSION_UPDATE_DEVICE_STATS");
-static_assert(STATS_MAP_SIZE - TOTAL_UID_STATS_ENTRIES_LIMIT > 100,
-              "The limit for stats map is to high, stats data may be lost due to overflow");
-
-#define FLAG_MSG_TRANS(result, flag, value) \
-    do {                                    \
-        if ((value) & (flag)) {             \
-            (result).append(" " #flag);     \
-            (value) &= ~(flag);             \
-        }                                   \
-    } while (0)
-
-const std::string uidMatchTypeToString(uint8_t match) {
-    std::string matchType;
-    FLAG_MSG_TRANS(matchType, HAPPY_BOX_MATCH, match);
-    FLAG_MSG_TRANS(matchType, PENALTY_BOX_MATCH, match);
-    FLAG_MSG_TRANS(matchType, DOZABLE_MATCH, match);
-    FLAG_MSG_TRANS(matchType, STANDBY_MATCH, match);
-    FLAG_MSG_TRANS(matchType, POWERSAVE_MATCH, match);
-    FLAG_MSG_TRANS(matchType, RESTRICTED_MATCH, match);
-    FLAG_MSG_TRANS(matchType, IIF_MATCH, match);
-    if (match) {
-        return StringPrintf("Unknown match: %u", match);
-    }
-    return matchType;
-}
-
-bool TrafficController::hasUpdateDeviceStatsPermission(uid_t uid) {
-    // This implementation is the same logic as method ActivityManager#checkComponentPermission.
-    // It implies that the calling uid can never be the same as PER_USER_RANGE.
-    uint32_t appId = uid % PER_USER_RANGE;
-    return ((appId == AID_ROOT) || (appId == AID_SYSTEM) ||
-            mPrivilegedUser.find(appId) != mPrivilegedUser.end());
-}
-
-const std::string UidPermissionTypeToString(int permission) {
-    if (permission == INetd::PERMISSION_NONE) {
-        return "PERMISSION_NONE";
-    }
-    if (permission == INetd::PERMISSION_UNINSTALLED) {
-        // This should never appear in the map, complain loudly if it does.
-        return "PERMISSION_UNINSTALLED error!";
-    }
-    std::string permissionType;
-    FLAG_MSG_TRANS(permissionType, BPF_PERMISSION_INTERNET, permission);
-    FLAG_MSG_TRANS(permissionType, BPF_PERMISSION_UPDATE_DEVICE_STATS, permission);
-    if (permission) {
-        return StringPrintf("Unknown permission: %u", permission);
-    }
-    return permissionType;
-}
-
-StatusOr<std::unique_ptr<NetlinkListenerInterface>> TrafficController::makeSkDestroyListener() {
-    const auto& sys = sSyscalls.get();
-    ASSIGN_OR_RETURN(auto event, sys.eventfd(0, EFD_CLOEXEC));
-    const int domain = AF_NETLINK;
-    const int type = SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK;
-    const int protocol = NETLINK_INET_DIAG;
-    ASSIGN_OR_RETURN(auto sock, sys.socket(domain, type, protocol));
-
-    // TODO: if too many sockets are closed too quickly, we can overflow the socket buffer, and
-    // some entries in mCookieTagMap will not be freed. In order to fix this we would need to
-    // periodically dump all sockets and remove the tag entries for sockets that have been closed.
-    // For now, set a large-enough buffer that we can close hundreds of sockets without getting
-    // ENOBUFS and leaking mCookieTagMap entries.
-    int rcvbuf = 512 * 1024;
-    auto ret = sys.setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf));
-    if (!ret.ok()) {
-        ALOGW("Failed to set SkDestroyListener buffer size to %d: %s", rcvbuf, ret.msg().c_str());
-    }
-
-    sockaddr_nl addr = {
-        .nl_family = AF_NETLINK,
-        .nl_groups = 1 << (SKNLGRP_INET_TCP_DESTROY - 1) | 1 << (SKNLGRP_INET_UDP_DESTROY - 1) |
-                     1 << (SKNLGRP_INET6_TCP_DESTROY - 1) | 1 << (SKNLGRP_INET6_UDP_DESTROY - 1)};
-    RETURN_IF_NOT_OK(sys.bind(sock, addr));
-
-    const sockaddr_nl kernel = {.nl_family = AF_NETLINK};
-    RETURN_IF_NOT_OK(sys.connect(sock, kernel));
-
-    std::unique_ptr<NetlinkListenerInterface> listener =
-            std::make_unique<NetlinkListener>(std::move(event), std::move(sock), "SkDestroyListen");
-
-    return listener;
-}
-
-TrafficController::TrafficController()
-    : mPerUidStatsEntriesLimit(PER_UID_STATS_ENTRIES_LIMIT),
-      mTotalUidStatsEntriesLimit(TOTAL_UID_STATS_ENTRIES_LIMIT) {}
-
-TrafficController::TrafficController(uint32_t perUidLimit, uint32_t totalLimit)
-    : mPerUidStatsEntriesLimit(perUidLimit), mTotalUidStatsEntriesLimit(totalLimit) {}
-
-Status TrafficController::initMaps() {
-    std::lock_guard guard(mMutex);
-
-    RETURN_IF_NOT_OK(mCookieTagMap.init(COOKIE_TAG_MAP_PATH));
-    RETURN_IF_NOT_OK(mUidCounterSetMap.init(UID_COUNTERSET_MAP_PATH));
-    RETURN_IF_NOT_OK(mAppUidStatsMap.init(APP_UID_STATS_MAP_PATH));
-    RETURN_IF_NOT_OK(mStatsMapA.init(STATS_MAP_A_PATH));
-    RETURN_IF_NOT_OK(mStatsMapB.init(STATS_MAP_B_PATH));
-    RETURN_IF_NOT_OK(mIfaceIndexNameMap.init(IFACE_INDEX_NAME_MAP_PATH));
-    RETURN_IF_NOT_OK(mIfaceStatsMap.init(IFACE_STATS_MAP_PATH));
-
-    RETURN_IF_NOT_OK(mConfigurationMap.init(CONFIGURATION_MAP_PATH));
-    RETURN_IF_NOT_OK(
-            mConfigurationMap.writeValue(UID_RULES_CONFIGURATION_KEY, DEFAULT_CONFIG, BPF_ANY));
-    RETURN_IF_NOT_OK(mConfigurationMap.writeValue(CURRENT_STATS_MAP_CONFIGURATION_KEY, SELECT_MAP_A,
-                                                  BPF_ANY));
-
-    RETURN_IF_NOT_OK(mUidOwnerMap.init(UID_OWNER_MAP_PATH));
-    RETURN_IF_NOT_OK(mUidOwnerMap.clear());
-    RETURN_IF_NOT_OK(mUidPermissionMap.init(UID_PERMISSION_MAP_PATH));
-
-    return netdutils::status::ok;
-}
-
-static Status attachProgramToCgroup(const char* programPath, const unique_fd& cgroupFd,
-                                    bpf_attach_type type) {
-    unique_fd cgroupProg(retrieveProgram(programPath));
-    if (cgroupProg == -1) {
-        int ret = errno;
-        ALOGE("Failed to get program from %s: %s", programPath, strerror(ret));
-        return statusFromErrno(ret, "cgroup program get failed");
-    }
-    if (android::bpf::attachProgram(type, cgroupProg, cgroupFd)) {
-        int ret = errno;
-        ALOGE("Program from %s attach failed: %s", programPath, strerror(ret));
-        return statusFromErrno(ret, "program attach failed");
-    }
-    return netdutils::status::ok;
-}
-
-static Status initPrograms() {
-    std::string cg2_path;
-
-    if (!CgroupGetControllerPath(CGROUPV2_CONTROLLER_NAME, &cg2_path)) {
-         int ret = errno;
-         ALOGE("Failed to find cgroup v2 root");
-         return statusFromErrno(ret, "Failed to find cgroup v2 root");
-    }
-
-    unique_fd cg_fd(open(cg2_path.c_str(), O_DIRECTORY | O_RDONLY | O_CLOEXEC));
-    if (cg_fd == -1) {
-        int ret = errno;
-        ALOGE("Failed to open the cgroup directory: %s", strerror(ret));
-        return statusFromErrno(ret, "Open the cgroup directory failed");
-    }
-    RETURN_IF_NOT_OK(attachProgramToCgroup(BPF_EGRESS_PROG_PATH, cg_fd, BPF_CGROUP_INET_EGRESS));
-    RETURN_IF_NOT_OK(attachProgramToCgroup(BPF_INGRESS_PROG_PATH, cg_fd, BPF_CGROUP_INET_INGRESS));
-
-    // For the devices that support cgroup socket filter, the socket filter
-    // should be loaded successfully by bpfloader. So we attach the filter to
-    // cgroup if the program is pinned properly.
-    // TODO: delete the if statement once all devices should support cgroup
-    // socket filter (ie. the minimum kernel version required is 4.14).
-    if (!access(CGROUP_SOCKET_PROG_PATH, F_OK)) {
-        RETURN_IF_NOT_OK(
-                attachProgramToCgroup(CGROUP_SOCKET_PROG_PATH, cg_fd, BPF_CGROUP_INET_SOCK_CREATE));
-    }
-    return netdutils::status::ok;
-}
-
-Status TrafficController::start() {
-    /* When netd restarts from a crash without total system reboot, the program
-     * is still attached to the cgroup, detach it so the program can be freed
-     * and we can load and attach new program into the target cgroup.
-     *
-     * TODO: Scrape existing socket when run-time restart and clean up the map
-     * if the socket no longer exist
-     */
-
-    RETURN_IF_NOT_OK(initMaps());
-
-    RETURN_IF_NOT_OK(initPrograms());
-
-    // Fetch the list of currently-existing interfaces. At this point NetlinkHandler is
-    // already running, so it will call addInterface() when any new interface appears.
-    std::map<std::string, uint32_t> ifacePairs;
-    ASSIGN_OR_RETURN(ifacePairs, InterfaceController::getIfaceList());
-    for (const auto& ifacePair:ifacePairs) {
-        addInterface(ifacePair.first.c_str(), ifacePair.second);
-    }
-
-    auto result = makeSkDestroyListener();
-    if (!isOk(result)) {
-        ALOGE("Unable to create SkDestroyListener: %s", toString(result).c_str());
-    } else {
-        mSkDestroyListener = std::move(result.value());
-    }
-    // Rx handler extracts nfgenmsg looks up and invokes registered dispatch function.
-    const auto rxHandler = [this](const nlmsghdr&, const Slice msg) {
-        std::lock_guard guard(mMutex);
-        inet_diag_msg diagmsg = {};
-        if (extract(msg, diagmsg) < sizeof(inet_diag_msg)) {
-            ALOGE("Unrecognized netlink message: %s", toString(msg).c_str());
-            return;
-        }
-        uint64_t sock_cookie = static_cast<uint64_t>(diagmsg.id.idiag_cookie[0]) |
-                               (static_cast<uint64_t>(diagmsg.id.idiag_cookie[1]) << 32);
-
-        Status s = mCookieTagMap.deleteValue(sock_cookie);
-        if (!isOk(s) && s.code() != ENOENT) {
-            ALOGE("Failed to delete cookie %" PRIx64 ": %s", sock_cookie, toString(s).c_str());
-            return;
-        }
-    };
-    expectOk(mSkDestroyListener->subscribe(kSockDiagMsgType, rxHandler));
-
-    // In case multiple netlink message comes in as a stream, we need to handle the rxDone message
-    // properly.
-    const auto rxDoneHandler = [](const nlmsghdr&, const Slice msg) {
-        // Ignore NLMSG_DONE  messages
-        inet_diag_msg diagmsg = {};
-        extract(msg, diagmsg);
-    };
-    expectOk(mSkDestroyListener->subscribe(kSockDiagDoneMsgType, rxDoneHandler));
-
-    return netdutils::status::ok;
-}
-
-int TrafficController::tagSocket(int sockFd, uint32_t tag, uid_t uid, uid_t callingUid) {
-    std::lock_guard guard(mMutex);
-    if (uid != callingUid && !hasUpdateDeviceStatsPermission(callingUid)) {
-        return -EPERM;
-    }
-
-    uint64_t sock_cookie = getSocketCookie(sockFd);
-    if (sock_cookie == NONEXISTENT_COOKIE) return -errno;
-    UidTagValue newKey = {.uid = (uint32_t)uid, .tag = tag};
-
-    uint32_t totalEntryCount = 0;
-    uint32_t perUidEntryCount = 0;
-    // Now we go through the stats map and count how many entries are associated
-    // with target uid. If the uid entry hit the limit for each uid, we block
-    // the request to prevent the map from overflow. It is safe here to iterate
-    // over the map since when mMutex is hold, system server cannot toggle
-    // the live stats map and clean it. So nobody can delete entries from the map.
-    const auto countUidStatsEntries = [uid, &totalEntryCount, &perUidEntryCount](
-                                              const StatsKey& key,
-                                              const BpfMap<StatsKey, StatsValue>&) {
-        if (key.uid == uid) {
-            perUidEntryCount++;
-        }
-        totalEntryCount++;
-        return base::Result<void>();
-    };
-    auto configuration = mConfigurationMap.readValue(CURRENT_STATS_MAP_CONFIGURATION_KEY);
-    if (!configuration.ok()) {
-        ALOGE("Failed to get current configuration: %s, fd: %d",
-              strerror(configuration.error().code()), mConfigurationMap.getMap().get());
-        return -configuration.error().code();
-    }
-    if (configuration.value() != SELECT_MAP_A && configuration.value() != SELECT_MAP_B) {
-        ALOGE("unknown configuration value: %d", configuration.value());
-        return -EINVAL;
-    }
-
-    BpfMap<StatsKey, StatsValue>& currentMap =
-            (configuration.value() == SELECT_MAP_A) ? mStatsMapA : mStatsMapB;
-    base::Result<void> res = currentMap.iterate(countUidStatsEntries);
-    if (!res.ok()) {
-        ALOGE("Failed to count the stats entry in map %d: %s", currentMap.getMap().get(),
-              strerror(res.error().code()));
-        return -res.error().code();
-    }
-
-    if (totalEntryCount > mTotalUidStatsEntriesLimit ||
-        perUidEntryCount > mPerUidStatsEntriesLimit) {
-        ALOGE("Too many stats entries in the map, total count: %u, uid(%u) count: %u, blocking tag"
-              " request to prevent map overflow",
-              totalEntryCount, uid, perUidEntryCount);
-        return -EMFILE;
-    }
-    // Update the tag information of a socket to the cookieUidMap. Use BPF_ANY
-    // flag so it will insert a new entry to the map if that value doesn't exist
-    // yet. And update the tag if there is already a tag stored. Since the eBPF
-    // program in kernel only read this map, and is protected by rcu read lock. It
-    // should be fine to cocurrently update the map while eBPF program is running.
-    res = mCookieTagMap.writeValue(sock_cookie, newKey, BPF_ANY);
-    if (!res.ok()) {
-        ALOGE("Failed to tag the socket: %s, fd: %d", strerror(res.error().code()),
-              mCookieTagMap.getMap().get());
-        return -res.error().code();
-    }
-    return 0;
-}
-
-int TrafficController::untagSocket(int sockFd) {
-    std::lock_guard guard(mMutex);
-    uint64_t sock_cookie = getSocketCookie(sockFd);
-
-    if (sock_cookie == NONEXISTENT_COOKIE) return -errno;
-    base::Result<void> res = mCookieTagMap.deleteValue(sock_cookie);
-    if (!res.ok()) {
-        ALOGE("Failed to untag socket: %s\n", strerror(res.error().code()));
-        return -res.error().code();
-    }
-    return 0;
-}
-
-int TrafficController::setCounterSet(int counterSetNum, uid_t uid, uid_t callingUid) {
-    if (counterSetNum < 0 || counterSetNum >= OVERFLOW_COUNTERSET) return -EINVAL;
-
-    std::lock_guard guard(mMutex);
-    if (!hasUpdateDeviceStatsPermission(callingUid)) return -EPERM;
-
-    // The default counter set for all uid is 0, so deleting the current counterset for that uid
-    // will automatically set it to 0.
-    if (counterSetNum == 0) {
-        Status res = mUidCounterSetMap.deleteValue(uid);
-        if (isOk(res) || (!isOk(res) && res.code() == ENOENT)) {
-            return 0;
-        } else {
-            ALOGE("Failed to delete the counterSet: %s\n", strerror(res.code()));
-            return -res.code();
-        }
-    }
-    uint8_t tmpCounterSetNum = (uint8_t)counterSetNum;
-    Status res = mUidCounterSetMap.writeValue(uid, tmpCounterSetNum, BPF_ANY);
-    if (!isOk(res)) {
-        ALOGE("Failed to set the counterSet: %s, fd: %d", strerror(res.code()),
-              mUidCounterSetMap.getMap().get());
-        return -res.code();
-    }
-    return 0;
-}
-
-// This method only get called by system_server when an app get uinstalled, it
-// is called inside removeUidsLocked() while holding mStatsLock. So it is safe
-// to iterate and modify the stats maps.
-int TrafficController::deleteTagData(uint32_t tag, uid_t uid, uid_t callingUid) {
-    std::lock_guard guard(mMutex);
-    if (!hasUpdateDeviceStatsPermission(callingUid)) return -EPERM;
-
-    // First we go through the cookieTagMap to delete the target uid tag combination. Or delete all
-    // the tags related to the uid if the tag is 0.
-    const auto deleteMatchedCookieEntries = [uid, tag](const uint64_t& key,
-                                                       const UidTagValue& value,
-                                                       BpfMap<uint64_t, UidTagValue>& map) {
-        if (value.uid == uid && (value.tag == tag || tag == 0)) {
-            auto res = map.deleteValue(key);
-            if (res.ok() || (res.error().code() == ENOENT)) {
-                return base::Result<void>();
-            }
-            ALOGE("Failed to delete data(cookie = %" PRIu64 "): %s\n", key,
-                  strerror(res.error().code()));
-        }
-        // Move forward to next cookie in the map.
-        return base::Result<void>();
-    };
-    mCookieTagMap.iterateWithValue(deleteMatchedCookieEntries);
-    // Now we go through the Tag stats map and delete the data entry with correct uid and tag
-    // combination. Or all tag stats under that uid if the target tag is 0.
-    const auto deleteMatchedUidTagEntries = [uid, tag](const StatsKey& key,
-                                                       BpfMap<StatsKey, StatsValue>& map) {
-        if (key.uid == uid && (key.tag == tag || tag == 0)) {
-            auto res = map.deleteValue(key);
-            if (res.ok() || (res.error().code() == ENOENT)) {
-                //Entry is deleted, use the current key to get a new nextKey;
-                return base::Result<void>();
-            }
-            ALOGE("Failed to delete data(uid=%u, tag=%u): %s\n", key.uid, key.tag,
-                  strerror(res.error().code()));
-        }
-        return base::Result<void>();
-    };
-    mStatsMapB.iterate(deleteMatchedUidTagEntries);
-    mStatsMapA.iterate(deleteMatchedUidTagEntries);
-    // If the tag is not zero, we already deleted all the data entry required. If tag is 0, we also
-    // need to delete the stats stored in uidStatsMap and counterSet map.
-    if (tag != 0) return 0;
-
-    auto res = mUidCounterSetMap.deleteValue(uid);
-    if (!res.ok() && res.error().code() != ENOENT) {
-        ALOGE("Failed to delete counterSet data(uid=%u, tag=%u): %s\n", uid, tag,
-              strerror(res.error().code()));
-    }
-
-    auto deleteAppUidStatsEntry = [uid](const uint32_t& key,
-                                        BpfMap<uint32_t, StatsValue>& map) -> base::Result<void> {
-        if (key == uid) {
-            auto res = map.deleteValue(key);
-            if (res.ok() || (res.error().code() == ENOENT)) {
-                return {};
-            }
-            ALOGE("Failed to delete data(uid=%u): %s", key, strerror(res.error().code()));
-        }
-        return {};
-    };
-    mAppUidStatsMap.iterate(deleteAppUidStatsEntry);
-    return 0;
-}
-
-int TrafficController::addInterface(const char* name, uint32_t ifaceIndex) {
-    IfaceValue iface;
-    if (ifaceIndex == 0) {
-        ALOGE("Unknown interface %s(%d)", name, ifaceIndex);
-        return -1;
-    }
-
-    strlcpy(iface.name, name, sizeof(IfaceValue));
-    Status res = mIfaceIndexNameMap.writeValue(ifaceIndex, iface, BPF_ANY);
-    if (!isOk(res)) {
-        ALOGE("Failed to add iface %s(%d): %s", name, ifaceIndex, strerror(res.code()));
-        return -res.code();
-    }
-    return 0;
-}
-
-Status TrafficController::updateOwnerMapEntry(UidOwnerMatchType match, uid_t uid, FirewallRule rule,
-                                              FirewallType type) {
-    std::lock_guard guard(mMutex);
-    if ((rule == ALLOW && type == ALLOWLIST) || (rule == DENY && type == DENYLIST)) {
-        RETURN_IF_NOT_OK(addRule(uid, match));
-    } else if ((rule == ALLOW && type == DENYLIST) || (rule == DENY && type == ALLOWLIST)) {
-        RETURN_IF_NOT_OK(removeRule(uid, match));
-    } else {
-        //Cannot happen.
-        return statusFromErrno(EINVAL, "");
-    }
-    return netdutils::status::ok;
-}
-
-Status TrafficController::removeRule(uint32_t uid, UidOwnerMatchType match) {
-    auto oldMatch = mUidOwnerMap.readValue(uid);
-    if (oldMatch.ok()) {
-        UidOwnerValue newMatch = {
-                .iif = (match == IIF_MATCH) ? 0 : oldMatch.value().iif,
-                .rule = static_cast<uint8_t>(oldMatch.value().rule & ~match),
-        };
-        if (newMatch.rule == 0) {
-            RETURN_IF_NOT_OK(mUidOwnerMap.deleteValue(uid));
-        } else {
-            RETURN_IF_NOT_OK(mUidOwnerMap.writeValue(uid, newMatch, BPF_ANY));
-        }
-    } else {
-        return statusFromErrno(ENOENT, StringPrintf("uid: %u does not exist in map", uid));
-    }
-    return netdutils::status::ok;
-}
-
-Status TrafficController::addRule(uint32_t uid, UidOwnerMatchType match, uint32_t iif) {
-    // iif should be non-zero if and only if match == MATCH_IIF
-    if (match == IIF_MATCH && iif == 0) {
-        return statusFromErrno(EINVAL, "Interface match must have nonzero interface index");
-    } else if (match != IIF_MATCH && iif != 0) {
-        return statusFromErrno(EINVAL, "Non-interface match must have zero interface index");
-    }
-    auto oldMatch = mUidOwnerMap.readValue(uid);
-    if (oldMatch.ok()) {
-        UidOwnerValue newMatch = {
-                .iif = iif ? iif : oldMatch.value().iif,
-                .rule = static_cast<uint8_t>(oldMatch.value().rule | match),
-        };
-        RETURN_IF_NOT_OK(mUidOwnerMap.writeValue(uid, newMatch, BPF_ANY));
-    } else {
-        UidOwnerValue newMatch = {
-                .iif = iif,
-                .rule = static_cast<uint8_t>(match),
-        };
-        RETURN_IF_NOT_OK(mUidOwnerMap.writeValue(uid, newMatch, BPF_ANY));
-    }
-    return netdutils::status::ok;
-}
-
-Status TrafficController::updateUidOwnerMap(const std::vector<uint32_t>& appUids,
-                                            UidOwnerMatchType matchType,
-                                            BandwidthController::IptOp op) {
-    std::lock_guard guard(mMutex);
-    for (uint32_t uid : appUids) {
-        if (op == BandwidthController::IptOpDelete) {
-            RETURN_IF_NOT_OK(removeRule(uid, matchType));
-        } else if (op == BandwidthController::IptOpInsert) {
-            RETURN_IF_NOT_OK(addRule(uid, matchType));
-        } else {
-            // Cannot happen.
-            return statusFromErrno(EINVAL, StringPrintf("invalid IptOp: %d, %d", op, matchType));
-        }
-    }
-    return netdutils::status::ok;
-}
-
-int TrafficController::changeUidOwnerRule(ChildChain chain, uid_t uid, FirewallRule rule,
-                                          FirewallType type) {
-    Status res;
-    switch (chain) {
-        case DOZABLE:
-            res = updateOwnerMapEntry(DOZABLE_MATCH, uid, rule, type);
-            break;
-        case STANDBY:
-            res = updateOwnerMapEntry(STANDBY_MATCH, uid, rule, type);
-            break;
-        case POWERSAVE:
-            res = updateOwnerMapEntry(POWERSAVE_MATCH, uid, rule, type);
-            break;
-        case RESTRICTED:
-            res = updateOwnerMapEntry(RESTRICTED_MATCH, uid, rule, type);
-            break;
-        case NONE:
-        default:
-            return -EINVAL;
-    }
-    if (!isOk(res)) {
-        ALOGE("change uid(%u) rule of %d failed: %s, rule: %d, type: %d", uid, chain,
-              res.msg().c_str(), rule, type);
-        return -res.code();
-    }
-    return 0;
-}
-
-Status TrafficController::replaceRulesInMap(const UidOwnerMatchType match,
-                                            const std::vector<int32_t>& uids) {
-    std::lock_guard guard(mMutex);
-    std::set<int32_t> uidSet(uids.begin(), uids.end());
-    std::vector<uint32_t> uidsToDelete;
-    auto getUidsToDelete = [&uidsToDelete, &uidSet](const uint32_t& key,
-                                                    const BpfMap<uint32_t, UidOwnerValue>&) {
-        if (uidSet.find((int32_t) key) == uidSet.end()) {
-            uidsToDelete.push_back(key);
-        }
-        return base::Result<void>();
-    };
-    RETURN_IF_NOT_OK(mUidOwnerMap.iterate(getUidsToDelete));
-
-    for(auto uid : uidsToDelete) {
-        RETURN_IF_NOT_OK(removeRule(uid, match));
-    }
-
-    for (auto uid : uids) {
-        RETURN_IF_NOT_OK(addRule(uid, match));
-    }
-    return netdutils::status::ok;
-}
-
-Status TrafficController::addUidInterfaceRules(const int iif,
-                                               const std::vector<int32_t>& uidsToAdd) {
-    if (!iif) {
-        return statusFromErrno(EINVAL, "Interface rule must specify interface");
-    }
-    std::lock_guard guard(mMutex);
-
-    for (auto uid : uidsToAdd) {
-        netdutils::Status result = addRule(uid, IIF_MATCH, iif);
-        if (!isOk(result)) {
-            ALOGW("addRule failed(%d): uid=%d iif=%d", result.code(), uid, iif);
-        }
-    }
-    return netdutils::status::ok;
-}
-
-Status TrafficController::removeUidInterfaceRules(const std::vector<int32_t>& uidsToDelete) {
-    std::lock_guard guard(mMutex);
-
-    for (auto uid : uidsToDelete) {
-        netdutils::Status result = removeRule(uid, IIF_MATCH);
-        if (!isOk(result)) {
-            ALOGW("removeRule failed(%d): uid=%d", result.code(), uid);
-        }
-    }
-    return netdutils::status::ok;
-}
-
-int TrafficController::replaceUidOwnerMap(const std::string& name, bool isAllowlist __unused,
-                                          const std::vector<int32_t>& uids) {
-    // FirewallRule rule = isAllowlist ? ALLOW : DENY;
-    // FirewallType type = isAllowlist ? ALLOWLIST : DENYLIST;
-    Status res;
-    if (!name.compare(FirewallController::LOCAL_DOZABLE)) {
-        res = replaceRulesInMap(DOZABLE_MATCH, uids);
-    } else if (!name.compare(FirewallController::LOCAL_STANDBY)) {
-        res = replaceRulesInMap(STANDBY_MATCH, uids);
-    } else if (!name.compare(FirewallController::LOCAL_POWERSAVE)) {
-        res = replaceRulesInMap(POWERSAVE_MATCH, uids);
-    } else if (!name.compare(FirewallController::LOCAL_RESTRICTED)) {
-        res = replaceRulesInMap(RESTRICTED_MATCH, uids);
-    } else {
-        ALOGE("unknown chain name: %s", name.c_str());
-        return -EINVAL;
-    }
-    if (!isOk(res)) {
-        ALOGE("Failed to clean up chain: %s: %s", name.c_str(), res.msg().c_str());
-        return -res.code();
-    }
-    return 0;
-}
-
-int TrafficController::toggleUidOwnerMap(ChildChain chain, bool enable) {
-    std::lock_guard guard(mMutex);
-    uint32_t key = UID_RULES_CONFIGURATION_KEY;
-    auto oldConfiguration = mConfigurationMap.readValue(key);
-    if (!oldConfiguration.ok()) {
-        ALOGE("Cannot read the old configuration from map: %s",
-              oldConfiguration.error().message().c_str());
-        return -oldConfiguration.error().code();
-    }
-    Status res;
-    BpfConfig newConfiguration;
-    uint8_t match;
-    switch (chain) {
-        case DOZABLE:
-            match = DOZABLE_MATCH;
-            break;
-        case STANDBY:
-            match = STANDBY_MATCH;
-            break;
-        case POWERSAVE:
-            match = POWERSAVE_MATCH;
-            break;
-        case RESTRICTED:
-            match = RESTRICTED_MATCH;
-            break;
-        default:
-            return -EINVAL;
-    }
-    newConfiguration =
-            enable ? (oldConfiguration.value() | match) : (oldConfiguration.value() & (~match));
-    res = mConfigurationMap.writeValue(key, newConfiguration, BPF_EXIST);
-    if (!isOk(res)) {
-        ALOGE("Failed to toggleUidOwnerMap(%d): %s", chain, res.msg().c_str());
-    }
-    return -res.code();
-}
-
-Status TrafficController::swapActiveStatsMap() {
-    std::lock_guard guard(mMutex);
-
-    uint32_t key = CURRENT_STATS_MAP_CONFIGURATION_KEY;
-    auto oldConfiguration = mConfigurationMap.readValue(key);
-    if (!oldConfiguration.ok()) {
-        ALOGE("Cannot read the old configuration from map: %s",
-              oldConfiguration.error().message().c_str());
-        return Status(oldConfiguration.error().code(), oldConfiguration.error().message());
-    }
-
-    // Write to the configuration map to inform the kernel eBPF program to switch
-    // from using one map to the other. Use flag BPF_EXIST here since the map should
-    // be already populated in initMaps.
-    uint8_t newConfigure = (oldConfiguration.value() == SELECT_MAP_A) ? SELECT_MAP_B : SELECT_MAP_A;
-    auto res = mConfigurationMap.writeValue(CURRENT_STATS_MAP_CONFIGURATION_KEY, newConfigure,
-                                            BPF_EXIST);
-    if (!res.ok()) {
-        ALOGE("Failed to toggle the stats map: %s", strerror(res.error().code()));
-        return res;
-    }
-    // After changing the config, we need to make sure all the current running
-    // eBPF programs are finished and all the CPUs are aware of this config change
-    // before we modify the old map. So we do a special hack here to wait for
-    // the kernel to do a synchronize_rcu(). Once the kernel called
-    // synchronize_rcu(), the config we just updated will be available to all cores
-    // and the next eBPF programs triggered inside the kernel will use the new
-    // map configuration. So once this function returns we can safely modify the
-    // old stats map without concerning about race between the kernel and
-    // userspace.
-    int ret = synchronizeKernelRCU();
-    if (ret) {
-        ALOGE("map swap synchronize_rcu() ended with failure: %s", strerror(-ret));
-        return statusFromErrno(-ret, "map swap synchronize_rcu() failed");
-    }
-    return netdutils::status::ok;
-}
-
-void TrafficController::setPermissionForUids(int permission, const std::vector<uid_t>& uids) {
-    std::lock_guard guard(mMutex);
-    if (permission == INetd::PERMISSION_UNINSTALLED) {
-        for (uid_t uid : uids) {
-            // Clean up all permission information for the related uid if all the
-            // packages related to it are uninstalled.
-            mPrivilegedUser.erase(uid);
-            Status ret = mUidPermissionMap.deleteValue(uid);
-            if (!isOk(ret) && ret.code() != ENOENT) {
-                ALOGE("Failed to clean up the permission for %u: %s", uid, strerror(ret.code()));
-            }
-        }
-        return;
-    }
-
-    bool privileged = (permission & INetd::PERMISSION_UPDATE_DEVICE_STATS);
-
-    for (uid_t uid : uids) {
-        if (privileged) {
-            mPrivilegedUser.insert(uid);
-        } else {
-            mPrivilegedUser.erase(uid);
-        }
-
-        // The map stores all the permissions that the UID has, except if the only permission
-        // the UID has is the INTERNET permission, then the UID should not appear in the map.
-        if (permission != INetd::PERMISSION_INTERNET) {
-            Status ret = mUidPermissionMap.writeValue(uid, permission, BPF_ANY);
-            if (!isOk(ret)) {
-                ALOGE("Failed to set permission: %s of uid(%u) to permission map: %s",
-                      UidPermissionTypeToString(permission).c_str(), uid, strerror(ret.code()));
-            }
-        } else {
-            Status ret = mUidPermissionMap.deleteValue(uid);
-            if (!isOk(ret) && ret.code() != ENOENT) {
-                ALOGE("Failed to remove uid %u from permission map: %s", uid, strerror(ret.code()));
-            }
-        }
-    }
-}
-
-std::string getProgramStatus(const char *path) {
-    int ret = access(path, R_OK);
-    if (ret == 0) {
-        return StringPrintf("OK");
-    }
-    if (ret != 0 && errno == ENOENT) {
-        return StringPrintf("program is missing at: %s", path);
-    }
-    return StringPrintf("check Program %s error: %s", path, strerror(errno));
-}
-
-std::string getMapStatus(const base::unique_fd& map_fd, const char* path) {
-    if (map_fd.get() < 0) {
-        return StringPrintf("map fd lost");
-    }
-    if (access(path, F_OK) != 0) {
-        return StringPrintf("map not pinned to location: %s", path);
-    }
-    return StringPrintf("OK");
-}
-
-// NOLINTNEXTLINE(google-runtime-references): grandfathered pass by non-const reference
-void dumpBpfMap(const std::string& mapName, DumpWriter& dw, const std::string& header) {
-    dw.blankline();
-    dw.println("%s:", mapName.c_str());
-    if (!header.empty()) {
-        dw.println(header);
-    }
-}
-
-const String16 TrafficController::DUMP_KEYWORD = String16("trafficcontroller");
-
-void TrafficController::dump(DumpWriter& dw, bool verbose) {
-    std::lock_guard guard(mMutex);
-    ScopedIndent indentTop(dw);
-    dw.println("TrafficController");
-
-    ScopedIndent indentPreBpfModule(dw);
-
-    dw.blankline();
-    dw.println("mCookieTagMap status: %s",
-               getMapStatus(mCookieTagMap.getMap(), COOKIE_TAG_MAP_PATH).c_str());
-    dw.println("mUidCounterSetMap status: %s",
-               getMapStatus(mUidCounterSetMap.getMap(), UID_COUNTERSET_MAP_PATH).c_str());
-    dw.println("mAppUidStatsMap status: %s",
-               getMapStatus(mAppUidStatsMap.getMap(), APP_UID_STATS_MAP_PATH).c_str());
-    dw.println("mStatsMapA status: %s",
-               getMapStatus(mStatsMapA.getMap(), STATS_MAP_A_PATH).c_str());
-    dw.println("mStatsMapB status: %s",
-               getMapStatus(mStatsMapB.getMap(), STATS_MAP_B_PATH).c_str());
-    dw.println("mIfaceIndexNameMap status: %s",
-               getMapStatus(mIfaceIndexNameMap.getMap(), IFACE_INDEX_NAME_MAP_PATH).c_str());
-    dw.println("mIfaceStatsMap status: %s",
-               getMapStatus(mIfaceStatsMap.getMap(), IFACE_STATS_MAP_PATH).c_str());
-    dw.println("mConfigurationMap status: %s",
-               getMapStatus(mConfigurationMap.getMap(), CONFIGURATION_MAP_PATH).c_str());
-    dw.println("mUidOwnerMap status: %s",
-               getMapStatus(mUidOwnerMap.getMap(), UID_OWNER_MAP_PATH).c_str());
-
-    dw.blankline();
-    dw.println("Cgroup ingress program status: %s",
-               getProgramStatus(BPF_INGRESS_PROG_PATH).c_str());
-    dw.println("Cgroup egress program status: %s", getProgramStatus(BPF_EGRESS_PROG_PATH).c_str());
-    dw.println("xt_bpf ingress program status: %s",
-               getProgramStatus(XT_BPF_INGRESS_PROG_PATH).c_str());
-    dw.println("xt_bpf egress program status: %s",
-               getProgramStatus(XT_BPF_EGRESS_PROG_PATH).c_str());
-    dw.println("xt_bpf bandwidth allowlist program status: %s",
-               getProgramStatus(XT_BPF_ALLOWLIST_PROG_PATH).c_str());
-    dw.println("xt_bpf bandwidth denylist program status: %s",
-               getProgramStatus(XT_BPF_DENYLIST_PROG_PATH).c_str());
-
-    if (!verbose) {
-        return;
-    }
-
-    dw.blankline();
-    dw.println("BPF map content:");
-
-    ScopedIndent indentForMapContent(dw);
-
-    // Print CookieTagMap content.
-    dumpBpfMap("mCookieTagMap", dw, "");
-    const auto printCookieTagInfo = [&dw](const uint64_t& key, const UidTagValue& value,
-                                          const BpfMap<uint64_t, UidTagValue>&) {
-        dw.println("cookie=%" PRIu64 " tag=0x%x uid=%u", key, value.tag, value.uid);
-        return base::Result<void>();
-    };
-    base::Result<void> res = mCookieTagMap.iterateWithValue(printCookieTagInfo);
-    if (!res.ok()) {
-        dw.println("mCookieTagMap print end with error: %s", res.error().message().c_str());
-    }
-
-    // Print UidCounterSetMap Content
-    dumpBpfMap("mUidCounterSetMap", dw, "");
-    const auto printUidInfo = [&dw](const uint32_t& key, const uint8_t& value,
-                                    const BpfMap<uint32_t, uint8_t>&) {
-        dw.println("%u %u", key, value);
-        return base::Result<void>();
-    };
-    res = mUidCounterSetMap.iterateWithValue(printUidInfo);
-    if (!res.ok()) {
-        dw.println("mUidCounterSetMap print end with error: %s", res.error().message().c_str());
-    }
-
-    // Print AppUidStatsMap content
-    std::string appUidStatsHeader = StringPrintf("uid rxBytes rxPackets txBytes txPackets");
-    dumpBpfMap("mAppUidStatsMap:", dw, appUidStatsHeader);
-    auto printAppUidStatsInfo = [&dw](const uint32_t& key, const StatsValue& value,
-                                      const BpfMap<uint32_t, StatsValue>&) {
-        dw.println("%u %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64, key, value.rxBytes,
-                   value.rxPackets, value.txBytes, value.txPackets);
-        return base::Result<void>();
-    };
-    res = mAppUidStatsMap.iterateWithValue(printAppUidStatsInfo);
-    if (!res.ok()) {
-        dw.println("mAppUidStatsMap print end with error: %s", res.error().message().c_str());
-    }
-
-    // Print uidStatsMap content
-    std::string statsHeader = StringPrintf("ifaceIndex ifaceName tag_hex uid_int cnt_set rxBytes"
-                                           " rxPackets txBytes txPackets");
-    dumpBpfMap("mStatsMapA", dw, statsHeader);
-    const auto printStatsInfo = [&dw, this](const StatsKey& key, const StatsValue& value,
-                                            const BpfMap<StatsKey, StatsValue>&) {
-        uint32_t ifIndex = key.ifaceIndex;
-        auto ifname = mIfaceIndexNameMap.readValue(ifIndex);
-        if (!ifname.ok()) {
-            ifname = IfaceValue{"unknown"};
-        }
-        dw.println("%u %s 0x%x %u %u %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64, ifIndex,
-                   ifname.value().name, key.tag, key.uid, key.counterSet, value.rxBytes,
-                   value.rxPackets, value.txBytes, value.txPackets);
-        return base::Result<void>();
-    };
-    res = mStatsMapA.iterateWithValue(printStatsInfo);
-    if (!res.ok()) {
-        dw.println("mStatsMapA print end with error: %s", res.error().message().c_str());
-    }
-
-    // Print TagStatsMap content.
-    dumpBpfMap("mStatsMapB", dw, statsHeader);
-    res = mStatsMapB.iterateWithValue(printStatsInfo);
-    if (!res.ok()) {
-        dw.println("mStatsMapB print end with error: %s", res.error().message().c_str());
-    }
-
-    // Print ifaceIndexToNameMap content.
-    dumpBpfMap("mIfaceIndexNameMap", dw, "");
-    const auto printIfaceNameInfo = [&dw](const uint32_t& key, const IfaceValue& value,
-                                          const BpfMap<uint32_t, IfaceValue>&) {
-        const char* ifname = value.name;
-        dw.println("ifaceIndex=%u ifaceName=%s", key, ifname);
-        return base::Result<void>();
-    };
-    res = mIfaceIndexNameMap.iterateWithValue(printIfaceNameInfo);
-    if (!res.ok()) {
-        dw.println("mIfaceIndexNameMap print end with error: %s", res.error().message().c_str());
-    }
-
-    // Print ifaceStatsMap content
-    std::string ifaceStatsHeader = StringPrintf("ifaceIndex ifaceName rxBytes rxPackets txBytes"
-                                                " txPackets");
-    dumpBpfMap("mIfaceStatsMap:", dw, ifaceStatsHeader);
-    const auto printIfaceStatsInfo = [&dw, this](const uint32_t& key, const StatsValue& value,
-                                                 const BpfMap<uint32_t, StatsValue>&) {
-        auto ifname = mIfaceIndexNameMap.readValue(key);
-        if (!ifname.ok()) {
-            ifname = IfaceValue{"unknown"};
-        }
-        dw.println("%u %s %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64, key, ifname.value().name,
-                   value.rxBytes, value.rxPackets, value.txBytes, value.txPackets);
-        return base::Result<void>();
-    };
-    res = mIfaceStatsMap.iterateWithValue(printIfaceStatsInfo);
-    if (!res.ok()) {
-        dw.println("mIfaceStatsMap print end with error: %s", res.error().message().c_str());
-    }
-
-    dw.blankline();
-
-    uint32_t key = UID_RULES_CONFIGURATION_KEY;
-    auto configuration = mConfigurationMap.readValue(key);
-    if (configuration.ok()) {
-        dw.println("current ownerMatch configuration: %d%s", configuration.value(),
-                   uidMatchTypeToString(configuration.value()).c_str());
-    } else {
-        dw.println("mConfigurationMap read ownerMatch configure failed with error: %s",
-                   configuration.error().message().c_str());
-    }
-
-    key = CURRENT_STATS_MAP_CONFIGURATION_KEY;
-    configuration = mConfigurationMap.readValue(key);
-    if (configuration.ok()) {
-        const char* statsMapDescription = "???";
-        switch (configuration.value()) {
-            case SELECT_MAP_A:
-                statsMapDescription = "SELECT_MAP_A";
-                break;
-            case SELECT_MAP_B:
-                statsMapDescription = "SELECT_MAP_B";
-                break;
-                // No default clause, so if we ever add a third map, this code will fail to build.
-        }
-        dw.println("current statsMap configuration: %d %s", configuration.value(),
-                   statsMapDescription);
-    } else {
-        dw.println("mConfigurationMap read stats map configure failed with error: %s",
-                   configuration.error().message().c_str());
-    }
-    dumpBpfMap("mUidOwnerMap", dw, "");
-    const auto printUidMatchInfo = [&dw, this](const uint32_t& key, const UidOwnerValue& value,
-                                               const BpfMap<uint32_t, UidOwnerValue>&) {
-        if (value.rule & IIF_MATCH) {
-            auto ifname = mIfaceIndexNameMap.readValue(value.iif);
-            if (ifname.ok()) {
-                dw.println("%u %s %s", key, uidMatchTypeToString(value.rule).c_str(),
-                           ifname.value().name);
-            } else {
-                dw.println("%u %s %u", key, uidMatchTypeToString(value.rule).c_str(), value.iif);
-            }
-        } else {
-            dw.println("%u %s", key, uidMatchTypeToString(value.rule).c_str());
-        }
-        return base::Result<void>();
-    };
-    res = mUidOwnerMap.iterateWithValue(printUidMatchInfo);
-    if (!res.ok()) {
-        dw.println("mUidOwnerMap print end with error: %s", res.error().message().c_str());
-    }
-    dumpBpfMap("mUidPermissionMap", dw, "");
-    const auto printUidPermissionInfo = [&dw](const uint32_t& key, const int& value,
-                                              const BpfMap<uint32_t, uint8_t>&) {
-        dw.println("%u %s", key, UidPermissionTypeToString(value).c_str());
-        return base::Result<void>();
-    };
-    res = mUidPermissionMap.iterateWithValue(printUidPermissionInfo);
-    if (!res.ok()) {
-        dw.println("mUidPermissionMap print end with error: %s", res.error().message().c_str());
-    }
-
-    dumpBpfMap("mPrivilegedUser", dw, "");
-    for (uid_t uid : mPrivilegedUser) {
-        dw.println("%u ALLOW_UPDATE_DEVICE_STATS", (uint32_t)uid);
-    }
-}
-
-}  // namespace net
-}  // namespace android
diff --git a/server/TrafficController.h b/server/TrafficController.h
deleted file mode 100644
index 2e79959..0000000
--- a/server/TrafficController.h
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NETD_SERVER_TRAFFIC_CONTROLLER_H
-#define NETD_SERVER_TRAFFIC_CONTROLLER_H
-
-#include <linux/bpf.h>
-
-#include "BandwidthController.h"
-#include "FirewallController.h"
-#include "NetlinkListener.h"
-#include "Network.h"
-#include "android-base/thread_annotations.h"
-#include "android-base/unique_fd.h"
-#include "bpf/BpfMap.h"
-#include "netdbpf/bpf_shared.h"
-#include "netdutils/DumpWriter.h"
-#include "netdutils/StatusOr.h"
-#include "utils/String16.h"
-
-using android::bpf::BpfMap;
-
-namespace android {
-namespace net {
-
-class TrafficController {
-  public:
-    TrafficController();
-    /*
-     * Initialize the whole controller
-     */
-    netdutils::Status start();
-    /*
-     * Tag the socket with the specified tag and uid. In the qtaguid module, the
-     * first tag request that grab the spinlock of rb_tree can update the tag
-     * information first and other request need to wait until it finish. All the
-     * tag request will be addressed in the order of they obtaining the spinlock.
-     * In the eBPF implementation, the kernel will try to update the eBPF map
-     * entry with the tag request. And the hashmap update process is protected by
-     * the spinlock initialized with the map. So the behavior of two modules
-     * should be the same. No additional lock needed.
-     */
-    int tagSocket(int sockFd, uint32_t tag, uid_t uid, uid_t callingUid) EXCLUDES(mMutex);
-
-    /*
-     * The untag process is similiar to tag socket and both old qtaguid module and
-     * new eBPF module have spinlock inside the kernel for concurrent update. No
-     * external lock is required.
-     */
-    int untagSocket(int sockFd);
-
-    /*
-     * Similiar as above, no external lock required.
-     */
-    int setCounterSet(int counterSetNum, uid_t uid, uid_t callingUid) EXCLUDES(mMutex);
-
-    /*
-     * When deleting a tag data, the qtaguid module will grab the spinlock of each
-     * related rb_tree one by one and delete the tag information, counterSet
-     * information, iface stats information and uid stats information one by one.
-     * The new eBPF implementation is done similiarly by removing the entry on
-     * each map one by one. And deleting processes are also protected by the
-     * spinlock of the map. So no additional lock is required.
-     */
-    int deleteTagData(uint32_t tag, uid_t uid, uid_t callingUid) EXCLUDES(mMutex);
-
-    /*
-     * Swap the stats map config from current active stats map to the idle one.
-     */
-    netdutils::Status swapActiveStatsMap() EXCLUDES(mMutex);
-
-    /*
-     * Add the interface name and index pair into the eBPF map.
-     */
-    int addInterface(const char* name, uint32_t ifaceIndex);
-
-    int changeUidOwnerRule(ChildChain chain, const uid_t uid, FirewallRule rule, FirewallType type);
-
-    int removeUidOwnerRule(const uid_t uid);
-
-    int replaceUidOwnerMap(const std::string& name, bool isAllowlist,
-                           const std::vector<int32_t>& uids);
-
-    netdutils::Status updateOwnerMapEntry(UidOwnerMatchType match, uid_t uid, FirewallRule rule,
-                                          FirewallType type) EXCLUDES(mMutex);
-
-    void dump(netdutils::DumpWriter& dw, bool verbose) EXCLUDES(mMutex);
-
-    netdutils::Status replaceRulesInMap(UidOwnerMatchType match, const std::vector<int32_t>& uids)
-            EXCLUDES(mMutex);
-
-    netdutils::Status addUidInterfaceRules(const int ifIndex, const std::vector<int32_t>& uids)
-            EXCLUDES(mMutex);
-    netdutils::Status removeUidInterfaceRules(const std::vector<int32_t>& uids) EXCLUDES(mMutex);
-
-    netdutils::Status updateUidOwnerMap(const std::vector<uint32_t>& appStrUids,
-                                        UidOwnerMatchType matchType, BandwidthController::IptOp op)
-            EXCLUDES(mMutex);
-    static const String16 DUMP_KEYWORD;
-
-    int toggleUidOwnerMap(ChildChain chain, bool enable) EXCLUDES(mMutex);
-
-    static netdutils::StatusOr<std::unique_ptr<NetlinkListenerInterface>> makeSkDestroyListener();
-
-    void setPermissionForUids(int permission, const std::vector<uid_t>& uids) EXCLUDES(mMutex);
-
-  private:
-    /*
-     * mCookieTagMap: Store the corresponding tag and uid for a specific socket.
-     * DO NOT hold any locks when modifying this map, otherwise when the untag
-     * operation is waiting for a lock hold by other process and there are more
-     * sockets being closed than can fit in the socket buffer of the netlink socket
-     * that receives them, then the kernel will drop some of these sockets and we
-     * won't delete their tags.
-     * Map Key: uint64_t socket cookie
-     * Map Value: UidTagValue, contains a uint32 uid and a uint32 tag.
-     */
-    BpfMap<uint64_t, UidTagValue> mCookieTagMap GUARDED_BY(mMutex);
-
-    /*
-     * mUidCounterSetMap: Store the counterSet of a specific uid.
-     * Map Key: uint32 uid.
-     * Map Value: uint32 counterSet specifies if the traffic is a background
-     * or foreground traffic.
-     */
-    BpfMap<uint32_t, uint8_t> mUidCounterSetMap GUARDED_BY(mMutex);
-
-    /*
-     * mAppUidStatsMap: Store the total traffic stats for a uid regardless of
-     * tag, counterSet and iface. The stats is used by TrafficStats.getUidStats
-     * API to return persistent stats for a specific uid since device boot.
-     */
-    BpfMap<uint32_t, StatsValue> mAppUidStatsMap;
-
-    /*
-     * mStatsMapA/mStatsMapB: Store the traffic statistics for a specific
-     * combination of uid, tag, iface and counterSet. These two maps contain
-     * both tagged and untagged traffic.
-     * Map Key: StatsKey contains the uid, tag, counterSet and ifaceIndex
-     * information.
-     * Map Value: Stats, contains packet count and byte count of each
-     * transport protocol on egress and ingress direction.
-     */
-    BpfMap<StatsKey, StatsValue> mStatsMapA GUARDED_BY(mMutex);
-
-    BpfMap<StatsKey, StatsValue> mStatsMapB GUARDED_BY(mMutex);
-
-    /*
-     * mIfaceIndexNameMap: Store the index name pair of each interface show up
-     * on the device since boot. The interface index is used by the eBPF program
-     * to correctly match the iface name when receiving a packet.
-     */
-    BpfMap<uint32_t, IfaceValue> mIfaceIndexNameMap;
-
-    /*
-     * mIfaceStataMap: Store per iface traffic stats gathered from xt_bpf
-     * filter.
-     */
-    BpfMap<uint32_t, StatsValue> mIfaceStatsMap;
-
-    /*
-     * mConfigurationMap: Store the current network policy about uid filtering
-     * and the current stats map in use. There are two configuration entries in
-     * the map right now:
-     * - Entry with UID_RULES_CONFIGURATION_KEY:
-     *    Store the configuration for the current uid rules. It indicates the device
-     *    is in doze/powersave/standby/restricted mode.
-     * - Entry with CURRENT_STATS_MAP_CONFIGURATION_KEY:
-     *    Stores the current live stats map that kernel program is writing to.
-     *    Userspace can do scraping and cleaning job on the other one depending on the
-     *    current configs.
-     */
-    BpfMap<uint32_t, uint8_t> mConfigurationMap GUARDED_BY(mMutex);
-
-    /*
-     * mUidOwnerMap: Store uids that are used for bandwidth control uid match.
-     */
-    BpfMap<uint32_t, UidOwnerValue> mUidOwnerMap GUARDED_BY(mMutex);
-
-    /*
-     * mUidOwnerMap: Store uids that are used for INTERNET permission check.
-     */
-    BpfMap<uint32_t, uint8_t> mUidPermissionMap GUARDED_BY(mMutex);
-
-    std::unique_ptr<NetlinkListenerInterface> mSkDestroyListener;
-
-    netdutils::Status removeRule(uint32_t uid, UidOwnerMatchType match) REQUIRES(mMutex);
-
-    netdutils::Status addRule(uint32_t uid, UidOwnerMatchType match, uint32_t iif = 0)
-            REQUIRES(mMutex);
-
-    // mMutex guards all accesses to mConfigurationMap, mUidOwnerMap, mUidPermissionMap,
-    // mStatsMapA, mStatsMapB and mPrivilegedUser. It is designed to solve the following
-    // problems:
-    // 1. Prevent concurrent access and modification to mConfigurationMap, mUidOwnerMap,
-    //    mUidPermissionMap, and mPrivilegedUser. These data members are controlled by netd but can
-    //    be modified from different threads. TrafficController provides several APIs directly
-    //    called by the binder RPC, and different binder threads can concurrently access these data
-    //    members mentioned above. Some of the data members such as mUidPermissionMap and
-    //    mPrivilegedUsers are also accessed from a different thread when tagging sockets or
-    //    setting the counterSet through FwmarkServer
-    // 2. Coordinate the deletion of uid stats in mStatsMapA and mStatsMapB. The system server
-    //    always call into netd to ask for a live stats map change before it pull and clean up the
-    //    stats from the inactive map. The mMutex will block netd from accessing the stats map when
-    //    the mConfigurationMap is updating the current stats map so netd will not accidentally
-    //    read the map that system_server is cleaning up.
-    std::mutex mMutex;
-
-    // The limit on the number of stats entries a uid can have in the per uid stats map.
-    // TrafficController will block that specific uid from tagging new sockets after the limit is
-    // reached.
-    const uint32_t mPerUidStatsEntriesLimit;
-
-    // The limit on the total number of stats entries in the per uid stats map. TrafficController
-    // will block all tagging requests after the limit is reached.
-    const uint32_t mTotalUidStatsEntriesLimit;
-
-    netdutils::Status loadAndAttachProgram(bpf_attach_type type, const char* path, const char* name,
-                                           base::unique_fd& cg_fd);
-
-    netdutils::Status initMaps() EXCLUDES(mMutex);
-
-    // Keep track of uids that have permission UPDATE_DEVICE_STATS so we don't
-    // need to call back to system server for permission check.
-    std::set<uid_t> mPrivilegedUser GUARDED_BY(mMutex);
-
-    UidOwnerMatchType jumpOpToMatch(BandwidthController::IptJumpOp jumpHandling);
-
-    bool hasUpdateDeviceStatsPermission(uid_t uid) REQUIRES(mMutex);
-
-    // For testing
-    TrafficController(uint32_t perUidLimit, uint32_t totalLimit);
-
-    // For testing
-    friend class TrafficControllerTest;
-};
-
-}  // namespace net
-}  // namespace android
-
-#endif  // NETD_SERVER_TRAFFIC_CONTROLLER_H
diff --git a/server/TrafficControllerTest.cpp b/server/TrafficControllerTest.cpp
deleted file mode 100644
index 159fb08..0000000
--- a/server/TrafficControllerTest.cpp
+++ /dev/null
@@ -1,880 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * TrafficControllerTest.cpp - unit tests for TrafficController.cpp
- */
-
-#include <cstdint>
-#include <string>
-#include <vector>
-
-#include <fcntl.h>
-#include <inttypes.h>
-#include <linux/inet_diag.h>
-#include <linux/sock_diag.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <gtest/gtest.h>
-
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-
-#include <netdutils/MockSyscalls.h>
-
-#include "FirewallController.h"
-#include "TrafficController.h"
-#include "bpf/BpfUtils.h"
-
-using namespace android::bpf;  // NOLINT(google-build-using-namespace): grandfathered
-
-namespace android {
-namespace net {
-
-using base::Result;
-using netdutils::isOk;
-
-constexpr int TEST_MAP_SIZE = 10;
-constexpr int TEST_COOKIE = 1;
-constexpr uid_t TEST_UID = 10086;
-constexpr uid_t TEST_UID2 = 54321;
-constexpr uid_t TEST_UID3 = 98765;
-constexpr uint32_t TEST_TAG = 42;
-constexpr uint32_t TEST_COUNTERSET = 1;
-constexpr uint32_t DEFAULT_COUNTERSET = 0;
-constexpr uint32_t TEST_PER_UID_STATS_ENTRIES_LIMIT = 3;
-constexpr uint32_t TEST_TOTAL_UID_STATS_ENTRIES_LIMIT = 7;
-
-#define ASSERT_VALID(x) ASSERT_TRUE((x).isValid())
-
-class TrafficControllerTest : public ::testing::Test {
-  protected:
-    TrafficControllerTest()
-        : mTc(TEST_PER_UID_STATS_ENTRIES_LIMIT, TEST_TOTAL_UID_STATS_ENTRIES_LIMIT) {}
-    TrafficController mTc;
-    BpfMap<uint64_t, UidTagValue> mFakeCookieTagMap;
-    BpfMap<uint32_t, uint8_t> mFakeUidCounterSetMap;
-    BpfMap<uint32_t, StatsValue> mFakeAppUidStatsMap;
-    BpfMap<StatsKey, StatsValue> mFakeStatsMapA;
-    BpfMap<uint32_t, uint8_t> mFakeConfigurationMap;
-    BpfMap<uint32_t, UidOwnerValue> mFakeUidOwnerMap;
-    BpfMap<uint32_t, uint8_t> mFakeUidPermissionMap;
-
-    void SetUp() {
-        std::lock_guard guard(mTc.mMutex);
-        ASSERT_EQ(0, setrlimitForTest());
-
-        mFakeCookieTagMap.reset(createMap(BPF_MAP_TYPE_HASH, sizeof(uint64_t), sizeof(UidTagValue),
-                                          TEST_MAP_SIZE, 0));
-        ASSERT_VALID(mFakeCookieTagMap);
-
-        mFakeUidCounterSetMap.reset(
-            createMap(BPF_MAP_TYPE_HASH, sizeof(uint32_t), sizeof(uint8_t), TEST_MAP_SIZE, 0));
-        ASSERT_VALID(mFakeUidCounterSetMap);
-
-        mFakeAppUidStatsMap.reset(createMap(BPF_MAP_TYPE_HASH, sizeof(uint32_t), sizeof(StatsValue),
-                                            TEST_MAP_SIZE, 0));
-        ASSERT_VALID(mFakeAppUidStatsMap);
-
-        mFakeStatsMapA.reset(createMap(BPF_MAP_TYPE_HASH, sizeof(StatsKey), sizeof(StatsValue),
-                                       TEST_MAP_SIZE, 0));
-        ASSERT_VALID(mFakeStatsMapA);
-
-        mFakeConfigurationMap.reset(
-                createMap(BPF_MAP_TYPE_HASH, sizeof(uint32_t), sizeof(uint8_t), 1, 0));
-        ASSERT_VALID(mFakeConfigurationMap);
-
-        mFakeUidOwnerMap.reset(createMap(BPF_MAP_TYPE_HASH, sizeof(uint32_t), sizeof(UidOwnerValue),
-                                         TEST_MAP_SIZE, 0));
-        ASSERT_VALID(mFakeUidOwnerMap);
-        mFakeUidPermissionMap.reset(
-                createMap(BPF_MAP_TYPE_HASH, sizeof(uint32_t), sizeof(uint8_t), TEST_MAP_SIZE, 0));
-        ASSERT_VALID(mFakeUidPermissionMap);
-
-        mTc.mCookieTagMap.reset(dupFd(mFakeCookieTagMap.getMap()));
-        ASSERT_VALID(mTc.mCookieTagMap);
-        mTc.mUidCounterSetMap.reset(dupFd(mFakeUidCounterSetMap.getMap()));
-        ASSERT_VALID(mTc.mUidCounterSetMap);
-        mTc.mAppUidStatsMap.reset(dupFd(mFakeAppUidStatsMap.getMap()));
-        ASSERT_VALID(mTc.mAppUidStatsMap);
-        mTc.mStatsMapA.reset(dupFd(mFakeStatsMapA.getMap()));
-        ASSERT_VALID(mTc.mStatsMapA);
-        mTc.mConfigurationMap.reset(dupFd(mFakeConfigurationMap.getMap()));
-        ASSERT_VALID(mTc.mConfigurationMap);
-
-        // Always write to stats map A by default.
-        ASSERT_RESULT_OK(mTc.mConfigurationMap.writeValue(CURRENT_STATS_MAP_CONFIGURATION_KEY,
-                                                          SELECT_MAP_A, BPF_ANY));
-        mTc.mUidOwnerMap.reset(dupFd(mFakeUidOwnerMap.getMap()));
-        ASSERT_VALID(mTc.mUidOwnerMap);
-        mTc.mUidPermissionMap.reset(dupFd(mFakeUidPermissionMap.getMap()));
-        ASSERT_VALID(mTc.mUidPermissionMap);
-        mTc.mPrivilegedUser.clear();
-    }
-
-    int dupFd(const android::base::unique_fd& mapFd) {
-        return fcntl(mapFd.get(), F_DUPFD_CLOEXEC, 0);
-    }
-
-    int setUpSocketAndTag(int protocol, uint64_t* cookie, uint32_t tag, uid_t uid,
-                          uid_t callingUid) {
-        int sock = socket(protocol, SOCK_STREAM | SOCK_CLOEXEC, 0);
-        EXPECT_LE(0, sock);
-        *cookie = getSocketCookie(sock);
-        EXPECT_NE(NONEXISTENT_COOKIE, *cookie);
-        EXPECT_EQ(0, mTc.tagSocket(sock, tag, uid, callingUid));
-        return sock;
-    }
-
-    void expectUidTag(uint64_t cookie, uid_t uid, uint32_t tag) {
-        Result<UidTagValue> tagResult = mFakeCookieTagMap.readValue(cookie);
-        ASSERT_RESULT_OK(tagResult);
-        EXPECT_EQ(uid, tagResult.value().uid);
-        EXPECT_EQ(tag, tagResult.value().tag);
-    }
-
-    void expectNoTag(uint64_t cookie) { EXPECT_FALSE(mFakeCookieTagMap.readValue(cookie).ok()); }
-
-    void populateFakeStats(uint64_t cookie, uint32_t uid, uint32_t tag, StatsKey* key) {
-        UidTagValue cookieMapkey = {.uid = (uint32_t)uid, .tag = tag};
-        EXPECT_RESULT_OK(mFakeCookieTagMap.writeValue(cookie, cookieMapkey, BPF_ANY));
-        *key = {.uid = uid, .tag = tag, .counterSet = TEST_COUNTERSET, .ifaceIndex = 1};
-        StatsValue statsMapValue = {.rxPackets = 1, .rxBytes = 100};
-        uint8_t counterSet = TEST_COUNTERSET;
-        EXPECT_RESULT_OK(mFakeUidCounterSetMap.writeValue(uid, counterSet, BPF_ANY));
-        EXPECT_RESULT_OK(mFakeStatsMapA.writeValue(*key, statsMapValue, BPF_ANY));
-        key->tag = 0;
-        EXPECT_RESULT_OK(mFakeStatsMapA.writeValue(*key, statsMapValue, BPF_ANY));
-        EXPECT_RESULT_OK(mFakeAppUidStatsMap.writeValue(uid, statsMapValue, BPF_ANY));
-        // put tag information back to statsKey
-        key->tag = tag;
-    }
-
-    void checkUidOwnerRuleForChain(ChildChain chain, UidOwnerMatchType match) {
-        uint32_t uid = TEST_UID;
-        EXPECT_EQ(0, mTc.changeUidOwnerRule(chain, uid, DENY, DENYLIST));
-        Result<UidOwnerValue> value = mFakeUidOwnerMap.readValue(uid);
-        EXPECT_RESULT_OK(value);
-        EXPECT_TRUE(value.value().rule & match);
-
-        uid = TEST_UID2;
-        EXPECT_EQ(0, mTc.changeUidOwnerRule(chain, uid, ALLOW, ALLOWLIST));
-        value = mFakeUidOwnerMap.readValue(uid);
-        EXPECT_RESULT_OK(value);
-        EXPECT_TRUE(value.value().rule & match);
-
-        EXPECT_EQ(0, mTc.changeUidOwnerRule(chain, uid, DENY, ALLOWLIST));
-        value = mFakeUidOwnerMap.readValue(uid);
-        EXPECT_FALSE(value.ok());
-        EXPECT_EQ(ENOENT, value.error().code());
-
-        uid = TEST_UID;
-        EXPECT_EQ(0, mTc.changeUidOwnerRule(chain, uid, ALLOW, DENYLIST));
-        value = mFakeUidOwnerMap.readValue(uid);
-        EXPECT_FALSE(value.ok());
-        EXPECT_EQ(ENOENT, value.error().code());
-
-        uid = TEST_UID3;
-        EXPECT_EQ(-ENOENT, mTc.changeUidOwnerRule(chain, uid, ALLOW, DENYLIST));
-        value = mFakeUidOwnerMap.readValue(uid);
-        EXPECT_FALSE(value.ok());
-        EXPECT_EQ(ENOENT, value.error().code());
-    }
-
-    void checkEachUidValue(const std::vector<int32_t>& uids, UidOwnerMatchType match) {
-        for (uint32_t uid : uids) {
-            Result<UidOwnerValue> value = mFakeUidOwnerMap.readValue(uid);
-            EXPECT_RESULT_OK(value);
-            EXPECT_TRUE(value.value().rule & match);
-        }
-        std::set<uint32_t> uidSet(uids.begin(), uids.end());
-        const auto checkNoOtherUid = [&uidSet](const int32_t& key,
-                                               const BpfMap<uint32_t, UidOwnerValue>&) {
-            EXPECT_NE(uidSet.end(), uidSet.find(key));
-            return Result<void>();
-        };
-        EXPECT_RESULT_OK(mFakeUidOwnerMap.iterate(checkNoOtherUid));
-    }
-
-    void checkUidMapReplace(const std::string& name, const std::vector<int32_t>& uids,
-                            UidOwnerMatchType match) {
-        bool isAllowlist = true;
-        EXPECT_EQ(0, mTc.replaceUidOwnerMap(name, isAllowlist, uids));
-        checkEachUidValue(uids, match);
-
-        isAllowlist = false;
-        EXPECT_EQ(0, mTc.replaceUidOwnerMap(name, isAllowlist, uids));
-        checkEachUidValue(uids, match);
-    }
-
-    void expectUidOwnerMapValues(const std::vector<uint32_t>& appUids, uint8_t expectedRule,
-                                 uint32_t expectedIif) {
-        for (uint32_t uid : appUids) {
-            Result<UidOwnerValue> value = mFakeUidOwnerMap.readValue(uid);
-            EXPECT_RESULT_OK(value);
-            EXPECT_EQ(expectedRule, value.value().rule)
-                    << "Expected rule for UID " << uid << " to be " << expectedRule << ", but was "
-                    << value.value().rule;
-            EXPECT_EQ(expectedIif, value.value().iif)
-                    << "Expected iif for UID " << uid << " to be " << expectedIif << ", but was "
-                    << value.value().iif;
-        }
-    }
-
-    template <class Key, class Value>
-    void expectMapEmpty(BpfMap<Key, Value>& map) {
-        auto isEmpty = map.isEmpty();
-        EXPECT_RESULT_OK(isEmpty);
-        EXPECT_TRUE(isEmpty.value());
-    }
-
-    void expectUidPermissionMapValues(const std::vector<uid_t>& appUids, uint8_t expectedValue) {
-        for (uid_t uid : appUids) {
-            Result<uint8_t> value = mFakeUidPermissionMap.readValue(uid);
-            EXPECT_RESULT_OK(value);
-            EXPECT_EQ(expectedValue, value.value())
-                    << "Expected value for UID " << uid << " to be " << expectedValue
-                    << ", but was " << value.value();
-        }
-    }
-
-    void expectPrivilegedUserSet(const std::vector<uid_t>& appUids) {
-        std::lock_guard guard(mTc.mMutex);
-        EXPECT_EQ(appUids.size(), mTc.mPrivilegedUser.size());
-        for (uid_t uid : appUids) {
-            EXPECT_NE(mTc.mPrivilegedUser.end(), mTc.mPrivilegedUser.find(uid));
-        }
-    }
-
-    void expectPrivilegedUserSetEmpty() {
-        std::lock_guard guard(mTc.mMutex);
-        EXPECT_TRUE(mTc.mPrivilegedUser.empty());
-    }
-
-    void addPrivilegedUid(uid_t uid) {
-        std::vector privilegedUid = {uid};
-        mTc.setPermissionForUids(INetd::PERMISSION_UPDATE_DEVICE_STATS, privilegedUid);
-    }
-
-    void removePrivilegedUid(uid_t uid) {
-        std::vector privilegedUid = {uid};
-        mTc.setPermissionForUids(INetd::PERMISSION_NONE, privilegedUid);
-    }
-
-    void expectFakeStatsUnchanged(uint64_t cookie, uint32_t tag, uint32_t uid,
-                                  StatsKey tagStatsMapKey) {
-        Result<UidTagValue> cookieMapResult = mFakeCookieTagMap.readValue(cookie);
-        EXPECT_RESULT_OK(cookieMapResult);
-        EXPECT_EQ(uid, cookieMapResult.value().uid);
-        EXPECT_EQ(tag, cookieMapResult.value().tag);
-        Result<uint8_t> counterSetResult = mFakeUidCounterSetMap.readValue(uid);
-        EXPECT_RESULT_OK(counterSetResult);
-        EXPECT_EQ(TEST_COUNTERSET, counterSetResult.value());
-        Result<StatsValue> statsMapResult = mFakeStatsMapA.readValue(tagStatsMapKey);
-        EXPECT_RESULT_OK(statsMapResult);
-        EXPECT_EQ((uint64_t)1, statsMapResult.value().rxPackets);
-        EXPECT_EQ((uint64_t)100, statsMapResult.value().rxBytes);
-        tagStatsMapKey.tag = 0;
-        statsMapResult = mFakeStatsMapA.readValue(tagStatsMapKey);
-        EXPECT_RESULT_OK(statsMapResult);
-        EXPECT_EQ((uint64_t)1, statsMapResult.value().rxPackets);
-        EXPECT_EQ((uint64_t)100, statsMapResult.value().rxBytes);
-        auto appStatsResult = mFakeAppUidStatsMap.readValue(uid);
-        EXPECT_RESULT_OK(appStatsResult);
-        EXPECT_EQ((uint64_t)1, appStatsResult.value().rxPackets);
-        EXPECT_EQ((uint64_t)100, appStatsResult.value().rxBytes);
-    }
-
-    void expectTagSocketReachLimit(uint32_t tag, uint32_t uid) {
-        int sock = socket(AF_INET6, SOCK_STREAM | SOCK_CLOEXEC, 0);
-        EXPECT_LE(0, sock);
-        if (sock < 0) return;
-        uint64_t sockCookie = getSocketCookie(sock);
-        EXPECT_NE(NONEXISTENT_COOKIE, sockCookie);
-        EXPECT_EQ(-EMFILE, mTc.tagSocket(sock, tag, uid, uid));
-        expectNoTag(sockCookie);
-
-        // Delete stats entries then tag socket success
-        EXPECT_EQ(0, mTc.deleteTagData(0, uid, 0));
-        EXPECT_EQ(0, mTc.tagSocket(sock, tag, uid, uid));
-        expectUidTag(sockCookie, uid, tag);
-    }
-};
-
-TEST_F(TrafficControllerTest, TestTagSocketV4) {
-    uint64_t sockCookie;
-    int v4socket = setUpSocketAndTag(AF_INET, &sockCookie, TEST_TAG, TEST_UID, TEST_UID);
-    expectUidTag(sockCookie, TEST_UID, TEST_TAG);
-    ASSERT_EQ(0, mTc.untagSocket(v4socket));
-    expectNoTag(sockCookie);
-    expectMapEmpty(mFakeCookieTagMap);
-}
-
-TEST_F(TrafficControllerTest, TestReTagSocket) {
-    uint64_t sockCookie;
-    int v4socket = setUpSocketAndTag(AF_INET, &sockCookie, TEST_TAG, TEST_UID, TEST_UID);
-    expectUidTag(sockCookie, TEST_UID, TEST_TAG);
-    ASSERT_EQ(0, mTc.tagSocket(v4socket, TEST_TAG + 1, TEST_UID + 1, TEST_UID + 1));
-    expectUidTag(sockCookie, TEST_UID + 1, TEST_TAG + 1);
-}
-
-TEST_F(TrafficControllerTest, TestTagTwoSockets) {
-    uint64_t sockCookie1;
-    uint64_t sockCookie2;
-    int v4socket1 = setUpSocketAndTag(AF_INET, &sockCookie1, TEST_TAG, TEST_UID, TEST_UID);
-    setUpSocketAndTag(AF_INET, &sockCookie2, TEST_TAG, TEST_UID, TEST_UID);
-    expectUidTag(sockCookie1, TEST_UID, TEST_TAG);
-    expectUidTag(sockCookie2, TEST_UID, TEST_TAG);
-    ASSERT_EQ(0, mTc.untagSocket(v4socket1));
-    expectNoTag(sockCookie1);
-    expectUidTag(sockCookie2, TEST_UID, TEST_TAG);
-    ASSERT_FALSE(mFakeCookieTagMap.getNextKey(sockCookie2).ok());
-}
-
-TEST_F(TrafficControllerTest, TestTagSocketV6) {
-    uint64_t sockCookie;
-    int v6socket = setUpSocketAndTag(AF_INET6, &sockCookie, TEST_TAG, TEST_UID, TEST_UID);
-    expectUidTag(sockCookie, TEST_UID, TEST_TAG);
-    ASSERT_EQ(0, mTc.untagSocket(v6socket));
-    expectNoTag(sockCookie);
-    expectMapEmpty(mFakeCookieTagMap);
-}
-
-TEST_F(TrafficControllerTest, TestTagInvalidSocket) {
-    int invalidSocket = -1;
-    ASSERT_GT(0, mTc.tagSocket(invalidSocket, TEST_TAG, TEST_UID, TEST_UID));
-    expectMapEmpty(mFakeCookieTagMap);
-}
-
-TEST_F(TrafficControllerTest, TestTagSocketWithoutPermission) {
-    int sock = socket(AF_INET6, SOCK_STREAM | SOCK_CLOEXEC, 0);
-    ASSERT_NE(-1, sock);
-    ASSERT_EQ(-EPERM, mTc.tagSocket(sock, TEST_TAG, TEST_UID, TEST_UID2));
-    expectMapEmpty(mFakeCookieTagMap);
-}
-
-TEST_F(TrafficControllerTest, TestTagSocketWithPermission) {
-    // Grant permission to calling uid.
-    std::vector<uid_t> callingUid = {TEST_UID2};
-    mTc.setPermissionForUids(INetd::PERMISSION_UPDATE_DEVICE_STATS, callingUid);
-
-    // Tag a socket to a different uid other then callingUid.
-    uint64_t sockCookie;
-    int v6socket = setUpSocketAndTag(AF_INET6, &sockCookie, TEST_TAG, TEST_UID, TEST_UID2);
-    expectUidTag(sockCookie, TEST_UID, TEST_TAG);
-    EXPECT_EQ(0, mTc.untagSocket(v6socket));
-    expectNoTag(sockCookie);
-    expectMapEmpty(mFakeCookieTagMap);
-
-    // Clean up the permission
-    mTc.setPermissionForUids(INetd::PERMISSION_NONE, callingUid);
-    expectPrivilegedUserSetEmpty();
-}
-
-TEST_F(TrafficControllerTest, TestUntagInvalidSocket) {
-    int invalidSocket = -1;
-    ASSERT_GT(0, mTc.untagSocket(invalidSocket));
-    int v4socket = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
-    ASSERT_GT(0, mTc.untagSocket(v4socket));
-    expectMapEmpty(mFakeCookieTagMap);
-}
-
-TEST_F(TrafficControllerTest, TestTagSocketReachLimitFail) {
-    uid_t uid = TEST_UID;
-    StatsKey tagStatsMapKey[4];
-    for (int i = 0; i < 3; i++) {
-        uint64_t cookie = TEST_COOKIE + i;
-        uint32_t tag = TEST_TAG + i;
-        populateFakeStats(cookie, uid, tag, &tagStatsMapKey[i]);
-    }
-    expectTagSocketReachLimit(TEST_TAG, TEST_UID);
-}
-
-TEST_F(TrafficControllerTest, TestTagSocketReachTotalLimitFail) {
-    StatsKey tagStatsMapKey[4];
-    for (int i = 0; i < 4; i++) {
-        uint64_t cookie = TEST_COOKIE + i;
-        uint32_t tag = TEST_TAG + i;
-        uid_t uid = TEST_UID + i;
-        populateFakeStats(cookie, uid, tag, &tagStatsMapKey[i]);
-    }
-    expectTagSocketReachLimit(TEST_TAG, TEST_UID);
-}
-
-TEST_F(TrafficControllerTest, TestSetCounterSet) {
-    uid_t callingUid = TEST_UID2;
-    addPrivilegedUid(callingUid);
-    ASSERT_EQ(0, mTc.setCounterSet(TEST_COUNTERSET, TEST_UID, callingUid));
-    uid_t uid = TEST_UID;
-    Result<uint8_t> counterSetResult = mFakeUidCounterSetMap.readValue(uid);
-    ASSERT_RESULT_OK(counterSetResult);
-    ASSERT_EQ(TEST_COUNTERSET, counterSetResult.value());
-    ASSERT_EQ(0, mTc.setCounterSet(DEFAULT_COUNTERSET, TEST_UID, callingUid));
-    ASSERT_FALSE(mFakeUidCounterSetMap.readValue(uid).ok());
-    expectMapEmpty(mFakeUidCounterSetMap);
-}
-
-TEST_F(TrafficControllerTest, TestSetCounterSetWithoutPermission) {
-    ASSERT_EQ(-EPERM, mTc.setCounterSet(TEST_COUNTERSET, TEST_UID, TEST_UID2));
-    uid_t uid = TEST_UID;
-    ASSERT_FALSE(mFakeUidCounterSetMap.readValue(uid).ok());
-    expectMapEmpty(mFakeUidCounterSetMap);
-}
-
-TEST_F(TrafficControllerTest, TestSetInvalidCounterSet) {
-    uid_t callingUid = TEST_UID2;
-    addPrivilegedUid(callingUid);
-    ASSERT_GT(0, mTc.setCounterSet(OVERFLOW_COUNTERSET, TEST_UID, callingUid));
-    uid_t uid = TEST_UID;
-    ASSERT_FALSE(mFakeUidCounterSetMap.readValue(uid).ok());
-    expectMapEmpty(mFakeUidCounterSetMap);
-}
-
-TEST_F(TrafficControllerTest, TestDeleteTagDataWithoutPermission) {
-    uint64_t cookie = 1;
-    uid_t uid = TEST_UID;
-    uint32_t tag = TEST_TAG;
-    StatsKey tagStatsMapKey;
-    populateFakeStats(cookie, uid, tag, &tagStatsMapKey);
-    ASSERT_EQ(-EPERM, mTc.deleteTagData(0, TEST_UID, TEST_UID2));
-
-    expectFakeStatsUnchanged(cookie, tag, uid, tagStatsMapKey);
-}
-
-TEST_F(TrafficControllerTest, TestDeleteTagData) {
-    uid_t callingUid = TEST_UID2;
-    addPrivilegedUid(callingUid);
-    uint64_t cookie = 1;
-    uid_t uid = TEST_UID;
-    uint32_t tag = TEST_TAG;
-    StatsKey tagStatsMapKey;
-    populateFakeStats(cookie, uid, tag, &tagStatsMapKey);
-    ASSERT_EQ(0, mTc.deleteTagData(TEST_TAG, TEST_UID, callingUid));
-    ASSERT_FALSE(mFakeCookieTagMap.readValue(cookie).ok());
-    Result<uint8_t> counterSetResult = mFakeUidCounterSetMap.readValue(uid);
-    ASSERT_RESULT_OK(counterSetResult);
-    ASSERT_EQ(TEST_COUNTERSET, counterSetResult.value());
-    ASSERT_FALSE(mFakeStatsMapA.readValue(tagStatsMapKey).ok());
-    tagStatsMapKey.tag = 0;
-    Result<StatsValue> statsMapResult = mFakeStatsMapA.readValue(tagStatsMapKey);
-    ASSERT_RESULT_OK(statsMapResult);
-    ASSERT_EQ((uint64_t)1, statsMapResult.value().rxPackets);
-    ASSERT_EQ((uint64_t)100, statsMapResult.value().rxBytes);
-    auto appStatsResult = mFakeAppUidStatsMap.readValue(TEST_UID);
-    ASSERT_RESULT_OK(appStatsResult);
-    ASSERT_EQ((uint64_t)1, appStatsResult.value().rxPackets);
-    ASSERT_EQ((uint64_t)100, appStatsResult.value().rxBytes);
-}
-
-TEST_F(TrafficControllerTest, TestDeleteAllUidData) {
-    uid_t callingUid = TEST_UID2;
-    addPrivilegedUid(callingUid);
-    uint64_t cookie = 1;
-    uid_t uid = TEST_UID;
-    uint32_t tag = TEST_TAG;
-    StatsKey tagStatsMapKey;
-    populateFakeStats(cookie, uid, tag, &tagStatsMapKey);
-    ASSERT_EQ(0, mTc.deleteTagData(0, TEST_UID, callingUid));
-    ASSERT_FALSE(mFakeCookieTagMap.readValue(cookie).ok());
-    ASSERT_FALSE(mFakeUidCounterSetMap.readValue(uid).ok());
-    ASSERT_FALSE(mFakeStatsMapA.readValue(tagStatsMapKey).ok());
-    tagStatsMapKey.tag = 0;
-    ASSERT_FALSE(mFakeStatsMapA.readValue(tagStatsMapKey).ok());
-    ASSERT_FALSE(mFakeAppUidStatsMap.readValue(TEST_UID).ok());
-}
-
-TEST_F(TrafficControllerTest, TestDeleteDataWithTwoTags) {
-    uid_t callingUid = TEST_UID2;
-    addPrivilegedUid(callingUid);
-    uint64_t cookie1 = 1;
-    uint64_t cookie2 = 2;
-    uid_t uid = TEST_UID;
-    uint32_t tag1 = TEST_TAG;
-    uint32_t tag2 = TEST_TAG + 1;
-    StatsKey tagStatsMapKey1;
-    StatsKey tagStatsMapKey2;
-    populateFakeStats(cookie1, uid, tag1, &tagStatsMapKey1);
-    populateFakeStats(cookie2, uid, tag2, &tagStatsMapKey2);
-    ASSERT_EQ(0, mTc.deleteTagData(TEST_TAG, TEST_UID, callingUid));
-    ASSERT_FALSE(mFakeCookieTagMap.readValue(cookie1).ok());
-    Result<UidTagValue> cookieMapResult = mFakeCookieTagMap.readValue(cookie2);
-    ASSERT_RESULT_OK(cookieMapResult);
-    ASSERT_EQ(TEST_UID, cookieMapResult.value().uid);
-    ASSERT_EQ(TEST_TAG + 1, cookieMapResult.value().tag);
-    Result<uint8_t> counterSetResult = mFakeUidCounterSetMap.readValue(uid);
-    ASSERT_RESULT_OK(counterSetResult);
-    ASSERT_EQ(TEST_COUNTERSET, counterSetResult.value());
-    ASSERT_FALSE(mFakeStatsMapA.readValue(tagStatsMapKey1).ok());
-    Result<StatsValue> statsMapResult = mFakeStatsMapA.readValue(tagStatsMapKey2);
-    ASSERT_RESULT_OK(statsMapResult);
-    ASSERT_EQ((uint64_t)1, statsMapResult.value().rxPackets);
-    ASSERT_EQ((uint64_t)100, statsMapResult.value().rxBytes);
-}
-
-TEST_F(TrafficControllerTest, TestDeleteDataWithTwoUids) {
-    uid_t callingUid = TEST_UID2;
-    addPrivilegedUid(callingUid);
-    uint64_t cookie1 = 1;
-    uint64_t cookie2 = 2;
-    uid_t uid1 = TEST_UID;
-    uid_t uid2 = TEST_UID + 1;
-    uint32_t tag = TEST_TAG;
-    StatsKey tagStatsMapKey1;
-    StatsKey tagStatsMapKey2;
-    populateFakeStats(cookie1, uid1, tag, &tagStatsMapKey1);
-    populateFakeStats(cookie2, uid2, tag, &tagStatsMapKey2);
-
-    // Delete the stats of one of the uid. Check if it is properly collected by
-    // removedStats.
-    ASSERT_EQ(0, mTc.deleteTagData(0, uid2, callingUid));
-    ASSERT_FALSE(mFakeCookieTagMap.readValue(cookie2).ok());
-    Result<uint8_t> counterSetResult = mFakeUidCounterSetMap.readValue(uid1);
-    ASSERT_RESULT_OK(counterSetResult);
-    ASSERT_EQ(TEST_COUNTERSET, counterSetResult.value());
-    ASSERT_FALSE(mFakeUidCounterSetMap.readValue(uid2).ok());
-    ASSERT_FALSE(mFakeStatsMapA.readValue(tagStatsMapKey2).ok());
-    tagStatsMapKey2.tag = 0;
-    ASSERT_FALSE(mFakeStatsMapA.readValue(tagStatsMapKey2).ok());
-    ASSERT_FALSE(mFakeAppUidStatsMap.readValue(uid2).ok());
-    tagStatsMapKey1.tag = 0;
-    Result<StatsValue> statsMapResult = mFakeStatsMapA.readValue(tagStatsMapKey1);
-    ASSERT_RESULT_OK(statsMapResult);
-    ASSERT_EQ((uint64_t)1, statsMapResult.value().rxPackets);
-    ASSERT_EQ((uint64_t)100, statsMapResult.value().rxBytes);
-    auto appStatsResult = mFakeAppUidStatsMap.readValue(uid1);
-    ASSERT_RESULT_OK(appStatsResult);
-    ASSERT_EQ((uint64_t)1, appStatsResult.value().rxPackets);
-    ASSERT_EQ((uint64_t)100, appStatsResult.value().rxBytes);
-
-    // Delete the stats of the other uid.
-    ASSERT_EQ(0, mTc.deleteTagData(0, uid1, callingUid));
-    ASSERT_FALSE(mFakeStatsMapA.readValue(tagStatsMapKey1).ok());
-    ASSERT_FALSE(mFakeAppUidStatsMap.readValue(uid1).ok());
-}
-
-TEST_F(TrafficControllerTest, TestUpdateOwnerMapEntry) {
-    uint32_t uid = TEST_UID;
-    ASSERT_TRUE(isOk(mTc.updateOwnerMapEntry(STANDBY_MATCH, uid, DENY, DENYLIST)));
-    Result<UidOwnerValue> value = mFakeUidOwnerMap.readValue(uid);
-    ASSERT_RESULT_OK(value);
-    ASSERT_TRUE(value.value().rule & STANDBY_MATCH);
-
-    ASSERT_TRUE(isOk(mTc.updateOwnerMapEntry(DOZABLE_MATCH, uid, ALLOW, ALLOWLIST)));
-    value = mFakeUidOwnerMap.readValue(uid);
-    ASSERT_RESULT_OK(value);
-    ASSERT_TRUE(value.value().rule & DOZABLE_MATCH);
-
-    ASSERT_TRUE(isOk(mTc.updateOwnerMapEntry(DOZABLE_MATCH, uid, DENY, ALLOWLIST)));
-    value = mFakeUidOwnerMap.readValue(uid);
-    ASSERT_RESULT_OK(value);
-    ASSERT_FALSE(value.value().rule & DOZABLE_MATCH);
-
-    ASSERT_TRUE(isOk(mTc.updateOwnerMapEntry(STANDBY_MATCH, uid, ALLOW, DENYLIST)));
-    ASSERT_FALSE(mFakeUidOwnerMap.readValue(uid).ok());
-
-    uid = TEST_UID2;
-    ASSERT_FALSE(isOk(mTc.updateOwnerMapEntry(STANDBY_MATCH, uid, ALLOW, DENYLIST)));
-    ASSERT_FALSE(mFakeUidOwnerMap.readValue(uid).ok());
-}
-
-TEST_F(TrafficControllerTest, TestChangeUidOwnerRule) {
-    checkUidOwnerRuleForChain(DOZABLE, DOZABLE_MATCH);
-    checkUidOwnerRuleForChain(STANDBY, STANDBY_MATCH);
-    checkUidOwnerRuleForChain(POWERSAVE, POWERSAVE_MATCH);
-    checkUidOwnerRuleForChain(RESTRICTED, RESTRICTED_MATCH);
-    ASSERT_EQ(-EINVAL, mTc.changeUidOwnerRule(NONE, TEST_UID, ALLOW, ALLOWLIST));
-    ASSERT_EQ(-EINVAL, mTc.changeUidOwnerRule(INVALID_CHAIN, TEST_UID, ALLOW, ALLOWLIST));
-}
-
-TEST_F(TrafficControllerTest, TestReplaceUidOwnerMap) {
-    std::vector<int32_t> uids = {TEST_UID, TEST_UID2, TEST_UID3};
-    checkUidMapReplace("fw_dozable", uids, DOZABLE_MATCH);
-    checkUidMapReplace("fw_standby", uids, STANDBY_MATCH);
-    checkUidMapReplace("fw_powersave", uids, POWERSAVE_MATCH);
-    checkUidMapReplace("fw_restricted", uids, RESTRICTED_MATCH);
-    ASSERT_EQ(-EINVAL, mTc.replaceUidOwnerMap("unknow", true, uids));
-}
-
-TEST_F(TrafficControllerTest, TestReplaceSameChain) {
-    std::vector<int32_t> uids = {TEST_UID, TEST_UID2, TEST_UID3};
-    checkUidMapReplace("fw_dozable", uids, DOZABLE_MATCH);
-    std::vector<int32_t> newUids = {TEST_UID2, TEST_UID3};
-    checkUidMapReplace("fw_dozable", newUids, DOZABLE_MATCH);
-}
-
-TEST_F(TrafficControllerTest, TestDenylistUidMatch) {
-    std::vector<uint32_t> appUids = {1000, 1001, 10012};
-    ASSERT_TRUE(isOk(
-            mTc.updateUidOwnerMap(appUids, PENALTY_BOX_MATCH, BandwidthController::IptOpInsert)));
-    expectUidOwnerMapValues(appUids, PENALTY_BOX_MATCH, 0);
-    ASSERT_TRUE(isOk(
-            mTc.updateUidOwnerMap(appUids, PENALTY_BOX_MATCH, BandwidthController::IptOpDelete)));
-    expectMapEmpty(mFakeUidOwnerMap);
-}
-
-TEST_F(TrafficControllerTest, TestAllowlistUidMatch) {
-    std::vector<uint32_t> appUids = {1000, 1001, 10012};
-    ASSERT_TRUE(isOk(
-            mTc.updateUidOwnerMap(appUids, HAPPY_BOX_MATCH, BandwidthController::IptOpInsert)));
-    expectUidOwnerMapValues(appUids, HAPPY_BOX_MATCH, 0);
-    ASSERT_TRUE(isOk(
-            mTc.updateUidOwnerMap(appUids, HAPPY_BOX_MATCH, BandwidthController::IptOpDelete)));
-    expectMapEmpty(mFakeUidOwnerMap);
-}
-
-TEST_F(TrafficControllerTest, TestReplaceMatchUid) {
-    std::vector<uint32_t> appUids = {1000, 1001, 10012};
-    // Add appUids to the denylist and expect that their values are all PENALTY_BOX_MATCH.
-    ASSERT_TRUE(isOk(
-            mTc.updateUidOwnerMap(appUids, PENALTY_BOX_MATCH, BandwidthController::IptOpInsert)));
-    expectUidOwnerMapValues(appUids, PENALTY_BOX_MATCH, 0);
-
-    // Add the same UIDs to the allowlist and expect that we get PENALTY_BOX_MATCH |
-    // HAPPY_BOX_MATCH.
-    ASSERT_TRUE(isOk(
-            mTc.updateUidOwnerMap(appUids, HAPPY_BOX_MATCH, BandwidthController::IptOpInsert)));
-    expectUidOwnerMapValues(appUids, HAPPY_BOX_MATCH | PENALTY_BOX_MATCH, 0);
-
-    // Remove the same UIDs from the allowlist and check the PENALTY_BOX_MATCH is still there.
-    ASSERT_TRUE(isOk(
-            mTc.updateUidOwnerMap(appUids, HAPPY_BOX_MATCH, BandwidthController::IptOpDelete)));
-    expectUidOwnerMapValues(appUids, PENALTY_BOX_MATCH, 0);
-
-    // Remove the same UIDs from the denylist and check the map is empty.
-    ASSERT_TRUE(isOk(
-            mTc.updateUidOwnerMap(appUids, PENALTY_BOX_MATCH, BandwidthController::IptOpDelete)));
-    ASSERT_FALSE(mFakeUidOwnerMap.getFirstKey().ok());
-}
-
-TEST_F(TrafficControllerTest, TestDeleteWrongMatchSilentlyFails) {
-    std::vector<uint32_t> appUids = {1000, 1001, 10012};
-    // If the uid does not exist in the map, trying to delete a rule about it will fail.
-    ASSERT_FALSE(isOk(
-            mTc.updateUidOwnerMap(appUids, HAPPY_BOX_MATCH, BandwidthController::IptOpDelete)));
-    expectMapEmpty(mFakeUidOwnerMap);
-
-    // Add denylist rules for appUids.
-    ASSERT_TRUE(isOk(
-            mTc.updateUidOwnerMap(appUids, HAPPY_BOX_MATCH, BandwidthController::IptOpInsert)));
-    expectUidOwnerMapValues(appUids, HAPPY_BOX_MATCH, 0);
-
-    // Delete (non-existent) denylist rules for appUids, and check that this silently does
-    // nothing if the uid is in the map but does not have denylist match. This is required because
-    // NetworkManagementService will try to remove a uid from denylist after adding it to the
-    // allowlist and if the remove fails it will not update the uid status.
-    ASSERT_TRUE(isOk(
-            mTc.updateUidOwnerMap(appUids, PENALTY_BOX_MATCH, BandwidthController::IptOpDelete)));
-    expectUidOwnerMapValues(appUids, HAPPY_BOX_MATCH, 0);
-}
-
-TEST_F(TrafficControllerTest, TestAddUidInterfaceFilteringRules) {
-    int iif0 = 15;
-    ASSERT_TRUE(isOk(mTc.addUidInterfaceRules(iif0, {1000, 1001})));
-    expectUidOwnerMapValues({1000, 1001}, IIF_MATCH, iif0);
-
-    // Add some non-overlapping new uids. They should coexist with existing rules
-    int iif1 = 16;
-    ASSERT_TRUE(isOk(mTc.addUidInterfaceRules(iif1, {2000, 2001})));
-    expectUidOwnerMapValues({1000, 1001}, IIF_MATCH, iif0);
-    expectUidOwnerMapValues({2000, 2001}, IIF_MATCH, iif1);
-
-    // Overwrite some existing uids
-    int iif2 = 17;
-    ASSERT_TRUE(isOk(mTc.addUidInterfaceRules(iif2, {1000, 2000})));
-    expectUidOwnerMapValues({1001}, IIF_MATCH, iif0);
-    expectUidOwnerMapValues({2001}, IIF_MATCH, iif1);
-    expectUidOwnerMapValues({1000, 2000}, IIF_MATCH, iif2);
-}
-
-TEST_F(TrafficControllerTest, TestRemoveUidInterfaceFilteringRules) {
-    int iif0 = 15;
-    int iif1 = 16;
-    ASSERT_TRUE(isOk(mTc.addUidInterfaceRules(iif0, {1000, 1001})));
-    ASSERT_TRUE(isOk(mTc.addUidInterfaceRules(iif1, {2000, 2001})));
-    expectUidOwnerMapValues({1000, 1001}, IIF_MATCH, iif0);
-    expectUidOwnerMapValues({2000, 2001}, IIF_MATCH, iif1);
-
-    // Rmove some uids
-    ASSERT_TRUE(isOk(mTc.removeUidInterfaceRules({1001, 2001})));
-    expectUidOwnerMapValues({1000}, IIF_MATCH, iif0);
-    expectUidOwnerMapValues({2000}, IIF_MATCH, iif1);
-    checkEachUidValue({1000, 2000}, IIF_MATCH);  // Make sure there are only two uids remaining
-
-    // Remove non-existent uids shouldn't fail
-    ASSERT_TRUE(isOk(mTc.removeUidInterfaceRules({2000, 3000})));
-    expectUidOwnerMapValues({1000}, IIF_MATCH, iif0);
-    checkEachUidValue({1000}, IIF_MATCH);  // Make sure there are only one uid remaining
-
-    // Remove everything
-    ASSERT_TRUE(isOk(mTc.removeUidInterfaceRules({1000})));
-    expectMapEmpty(mFakeUidOwnerMap);
-}
-
-TEST_F(TrafficControllerTest, TestUidInterfaceFilteringRulesCoexistWithExistingMatches) {
-    // Set up existing PENALTY_BOX_MATCH rules
-    ASSERT_TRUE(isOk(mTc.updateUidOwnerMap({1000, 1001, 10012}, PENALTY_BOX_MATCH,
-                                           BandwidthController::IptOpInsert)));
-    expectUidOwnerMapValues({1000, 1001, 10012}, PENALTY_BOX_MATCH, 0);
-
-    // Add some partially-overlapping uid owner rules and check result
-    int iif1 = 32;
-    ASSERT_TRUE(isOk(mTc.addUidInterfaceRules(iif1, {10012, 10013, 10014})));
-    expectUidOwnerMapValues({1000, 1001}, PENALTY_BOX_MATCH, 0);
-    expectUidOwnerMapValues({10012}, PENALTY_BOX_MATCH | IIF_MATCH, iif1);
-    expectUidOwnerMapValues({10013, 10014}, IIF_MATCH, iif1);
-
-    // Removing some PENALTY_BOX_MATCH rules should not change uid interface rule
-    ASSERT_TRUE(isOk(mTc.updateUidOwnerMap({1001, 10012}, PENALTY_BOX_MATCH,
-                                           BandwidthController::IptOpDelete)));
-    expectUidOwnerMapValues({1000}, PENALTY_BOX_MATCH, 0);
-    expectUidOwnerMapValues({10012, 10013, 10014}, IIF_MATCH, iif1);
-
-    // Remove all uid interface rules
-    ASSERT_TRUE(isOk(mTc.removeUidInterfaceRules({10012, 10013, 10014})));
-    expectUidOwnerMapValues({1000}, PENALTY_BOX_MATCH, 0);
-    // Make sure these are the only uids left
-    checkEachUidValue({1000}, PENALTY_BOX_MATCH);
-}
-
-TEST_F(TrafficControllerTest, TestUidInterfaceFilteringRulesCoexistWithNewMatches) {
-    int iif1 = 56;
-    // Set up existing uid interface rules
-    ASSERT_TRUE(isOk(mTc.addUidInterfaceRules(iif1, {10001, 10002})));
-    expectUidOwnerMapValues({10001, 10002}, IIF_MATCH, iif1);
-
-    // Add some partially-overlapping doze rules
-    EXPECT_EQ(0, mTc.replaceUidOwnerMap("fw_dozable", true, {10002, 10003}));
-    expectUidOwnerMapValues({10001}, IIF_MATCH, iif1);
-    expectUidOwnerMapValues({10002}, DOZABLE_MATCH | IIF_MATCH, iif1);
-    expectUidOwnerMapValues({10003}, DOZABLE_MATCH, 0);
-
-    // Introduce a third rule type (powersave) on various existing UIDs
-    EXPECT_EQ(0, mTc.replaceUidOwnerMap("fw_powersave", true, {10000, 10001, 10002, 10003}));
-    expectUidOwnerMapValues({10000}, POWERSAVE_MATCH, 0);
-    expectUidOwnerMapValues({10001}, POWERSAVE_MATCH | IIF_MATCH, iif1);
-    expectUidOwnerMapValues({10002}, POWERSAVE_MATCH | DOZABLE_MATCH | IIF_MATCH, iif1);
-    expectUidOwnerMapValues({10003}, POWERSAVE_MATCH | DOZABLE_MATCH, 0);
-
-    // Remove all doze rules
-    EXPECT_EQ(0, mTc.replaceUidOwnerMap("fw_dozable", true, {}));
-    expectUidOwnerMapValues({10000}, POWERSAVE_MATCH, 0);
-    expectUidOwnerMapValues({10001}, POWERSAVE_MATCH | IIF_MATCH, iif1);
-    expectUidOwnerMapValues({10002}, POWERSAVE_MATCH | IIF_MATCH, iif1);
-    expectUidOwnerMapValues({10003}, POWERSAVE_MATCH, 0);
-
-    // Remove all powersave rules, expect ownerMap to only have uid interface rules left
-    EXPECT_EQ(0, mTc.replaceUidOwnerMap("fw_powersave", true, {}));
-    expectUidOwnerMapValues({10001, 10002}, IIF_MATCH, iif1);
-    // Make sure these are the only uids left
-    checkEachUidValue({10001, 10002}, IIF_MATCH);
-}
-
-TEST_F(TrafficControllerTest, TestGrantInternetPermission) {
-    std::vector<uid_t> appUids = {TEST_UID, TEST_UID2, TEST_UID3};
-
-    mTc.setPermissionForUids(INetd::PERMISSION_INTERNET, appUids);
-    expectMapEmpty(mFakeUidPermissionMap);
-    expectPrivilegedUserSetEmpty();
-}
-
-TEST_F(TrafficControllerTest, TestRevokeInternetPermission) {
-    std::vector<uid_t> appUids = {TEST_UID, TEST_UID2, TEST_UID3};
-
-    mTc.setPermissionForUids(INetd::PERMISSION_NONE, appUids);
-    expectUidPermissionMapValues(appUids, INetd::PERMISSION_NONE);
-}
-
-TEST_F(TrafficControllerTest, TestPermissionUninstalled) {
-    std::vector<uid_t> appUids = {TEST_UID, TEST_UID2, TEST_UID3};
-
-    mTc.setPermissionForUids(INetd::PERMISSION_UPDATE_DEVICE_STATS, appUids);
-    expectUidPermissionMapValues(appUids, INetd::PERMISSION_UPDATE_DEVICE_STATS);
-    expectPrivilegedUserSet(appUids);
-
-    std::vector<uid_t> uidToRemove = {TEST_UID};
-    mTc.setPermissionForUids(INetd::PERMISSION_UNINSTALLED, uidToRemove);
-
-    std::vector<uid_t> uidRemain = {TEST_UID3, TEST_UID2};
-    expectUidPermissionMapValues(uidRemain, INetd::PERMISSION_UPDATE_DEVICE_STATS);
-    expectPrivilegedUserSet(uidRemain);
-
-    mTc.setPermissionForUids(INetd::PERMISSION_UNINSTALLED, uidRemain);
-    expectMapEmpty(mFakeUidPermissionMap);
-    expectPrivilegedUserSetEmpty();
-}
-
-TEST_F(TrafficControllerTest, TestGrantUpdateStatsPermission) {
-    std::vector<uid_t> appUids = {TEST_UID, TEST_UID2, TEST_UID3};
-
-    mTc.setPermissionForUids(INetd::PERMISSION_UPDATE_DEVICE_STATS, appUids);
-    expectUidPermissionMapValues(appUids, INetd::PERMISSION_UPDATE_DEVICE_STATS);
-    expectPrivilegedUserSet(appUids);
-
-    mTc.setPermissionForUids(INetd::PERMISSION_NONE, appUids);
-    expectPrivilegedUserSetEmpty();
-    expectUidPermissionMapValues(appUids, INetd::PERMISSION_NONE);
-}
-
-TEST_F(TrafficControllerTest, TestRevokeUpdateStatsPermission) {
-    std::vector<uid_t> appUids = {TEST_UID, TEST_UID2, TEST_UID3};
-
-    mTc.setPermissionForUids(INetd::PERMISSION_UPDATE_DEVICE_STATS, appUids);
-    expectPrivilegedUserSet(appUids);
-
-    std::vector<uid_t> uidToRemove = {TEST_UID};
-    mTc.setPermissionForUids(INetd::PERMISSION_NONE, uidToRemove);
-
-    std::vector<uid_t> uidRemain = {TEST_UID3, TEST_UID2};
-    expectPrivilegedUserSet(uidRemain);
-
-    mTc.setPermissionForUids(INetd::PERMISSION_NONE, uidRemain);
-    expectPrivilegedUserSetEmpty();
-}
-
-TEST_F(TrafficControllerTest, TestGrantWrongPermission) {
-    std::vector<uid_t> appUids = {TEST_UID, TEST_UID2, TEST_UID3};
-
-    mTc.setPermissionForUids(INetd::PERMISSION_NONE, appUids);
-    expectPrivilegedUserSetEmpty();
-    expectUidPermissionMapValues(appUids, INetd::PERMISSION_NONE);
-}
-
-TEST_F(TrafficControllerTest, TestGrantDuplicatePermissionSlientlyFail) {
-    std::vector<uid_t> appUids = {TEST_UID, TEST_UID2, TEST_UID3};
-
-    mTc.setPermissionForUids(INetd::PERMISSION_INTERNET, appUids);
-    expectMapEmpty(mFakeUidPermissionMap);
-
-    std::vector<uid_t> uidToAdd = {TEST_UID};
-    mTc.setPermissionForUids(INetd::PERMISSION_INTERNET, uidToAdd);
-
-    expectPrivilegedUserSetEmpty();
-
-    mTc.setPermissionForUids(INetd::PERMISSION_NONE, appUids);
-    expectUidPermissionMapValues(appUids, INetd::PERMISSION_NONE);
-
-    mTc.setPermissionForUids(INetd::PERMISSION_UPDATE_DEVICE_STATS, appUids);
-    expectPrivilegedUserSet(appUids);
-
-    mTc.setPermissionForUids(INetd::PERMISSION_UPDATE_DEVICE_STATS, uidToAdd);
-    expectPrivilegedUserSet(appUids);
-
-    mTc.setPermissionForUids(INetd::PERMISSION_NONE, appUids);
-    expectPrivilegedUserSetEmpty();
-}
-
-}  // namespace net
-}  // namespace android
diff --git a/server/UidRanges.cpp b/server/UidRanges.cpp
index 093a1e2..c90f30b 100644
--- a/server/UidRanges.cpp
+++ b/server/UidRanges.cpp
@@ -36,6 +36,12 @@
     return lhs.start != rhs.start ? (lhs.start < rhs.start) : (lhs.stop < rhs.stop);
 };
 
+// Check whether two uid ranges have overlapped uid. For any uid included in both ranges, it is
+// considered as overlap.
+bool isOverlapped(const UidRangeParcel& r1, const UidRangeParcel& r2) {
+    return (r1.stop >= r2.start) && (r1.start <= r2.stop);
+}
+
 UidRangeParcel makeUidRangeParcel(int start, int stop) {
     UidRangeParcel res;
     res.start = start;
@@ -127,10 +133,6 @@
     mRanges.erase(end, mRanges.end());
 }
 
-bool UidRanges::isOverlapped(const UidRangeParcel& r1, const UidRangeParcel& r2) const {
-    return (r1.stop >= r2.start) && (r1.start <= r2.stop);
-}
-
 bool UidRanges::overlapsSelf() const {
     // Compare each element one by one
     for (size_t i = 0; i < mRanges.size(); i++) {
@@ -143,12 +145,20 @@
     return false;
 }
 
+// std::binary_search cannot do partial match. For example, an uid range x-y not only overlaps with
+// x-y, but also w-x, y-z, w-z, ...etc. Therefore, we need a specialized binary search.
 bool UidRanges::overlaps(const UidRanges& other) const {
-    for (const auto& thisRange : mRanges) {
-        for (const auto& inputRange : other.getRanges()) {
-            if (isOverlapped(thisRange, inputRange)) {
-                return true;
-            }
+    for (const auto& target : other.getRanges()) {
+        int first = 0;
+        int end = mRanges.size() - 1;
+
+        while (first <= end) {
+            int middle = (first + end) / 2;
+            if (isOverlapped(mRanges[middle], target)) return true;
+            if (compUidRangeParcel(mRanges[middle], target))
+                first = middle + 1;
+            else
+                end = middle - 1;
         }
     }
     return false;
diff --git a/server/UidRanges.h b/server/UidRanges.h
index 99e7a99..9123eb1 100644
--- a/server/UidRanges.h
+++ b/server/UidRanges.h
@@ -28,8 +28,14 @@
 
 class UidRanges {
 public:
-    static constexpr int DEFAULT_SUB_PRIORITY = 0;
-    static constexpr int LOWEST_SUB_PRIORITY = 999;
+    static constexpr int SUB_PRIORITY_HIGHEST = 0;
+    static constexpr int SUB_PRIORITY_LOWEST = 998;
+    // "Special" value used for giving UIDs access to a network (by installing explicit and implicit
+    // network rules) without automatically making that network default. This rule works in
+    // conjunction with the other subpriorities, meaning that the network could still be configured
+    // as the app's default using one of the lower values (0-998).
+    // Note: SUB_PRIORITY_NO_DEFAULT *must* be SUB_PRIORITY_LOWEST + 1!
+    static constexpr int SUB_PRIORITY_NO_DEFAULT = 999;
 
     UidRanges() {}
     UidRanges(const std::vector<android::net::UidRangeParcel>& ranges);
@@ -50,9 +56,7 @@
     bool empty() const { return mRanges.empty(); }
 
   private:
-    // a utility to check if two UidRangeParcels have uid overlap.
-    bool isOverlapped(const UidRangeParcel& r1, const UidRangeParcel& r2) const;
-
+    // Keep it sorted. The overlaps() implements binary search, which requires a sorted data.
     std::vector<UidRangeParcel> mRanges;
 };
 
diff --git a/server/UnreachableNetwork.cpp b/server/UnreachableNetwork.cpp
index 2f801f0..6880225 100644
--- a/server/UnreachableNetwork.cpp
+++ b/server/UnreachableNetwork.cpp
@@ -26,7 +26,7 @@
 // The unreachable network is used to reject traffic. It is used for system purposes only.
 UnreachableNetwork::UnreachableNetwork(unsigned netId) : Network(netId) {}
 
-int UnreachableNetwork::addUsers(const UidRanges& uidRanges, uint32_t subPriority) {
+int UnreachableNetwork::addUsers(const UidRanges& uidRanges, int32_t subPriority) {
     if (!isValidSubPriority(subPriority) || !canAddUidRanges(uidRanges, subPriority)) {
         return -EINVAL;
     }
@@ -40,7 +40,7 @@
     return 0;
 }
 
-int UnreachableNetwork::removeUsers(const UidRanges& uidRanges, uint32_t subPriority) {
+int UnreachableNetwork::removeUsers(const UidRanges& uidRanges, int32_t subPriority) {
     if (!isValidSubPriority(subPriority)) return -EINVAL;
 
     int ret =
@@ -53,9 +53,9 @@
     return 0;
 }
 
-bool UnreachableNetwork::isValidSubPriority(uint32_t priority) {
-    return priority >= UidRanges::DEFAULT_SUB_PRIORITY &&
-           priority <= UidRanges::LOWEST_SUB_PRIORITY;
+bool UnreachableNetwork::isValidSubPriority(int32_t priority) {
+    return priority >= UidRanges::SUB_PRIORITY_HIGHEST &&
+           priority <= UidRanges::SUB_PRIORITY_LOWEST;
 }
 
 }  // namespace net
diff --git a/server/UnreachableNetwork.h b/server/UnreachableNetwork.h
index f1547d6..d2cefde 100644
--- a/server/UnreachableNetwork.h
+++ b/server/UnreachableNetwork.h
@@ -23,14 +23,14 @@
 class UnreachableNetwork : public Network {
   public:
     explicit UnreachableNetwork(unsigned netId);
-    [[nodiscard]] int addUsers(const UidRanges& uidRanges, uint32_t subPriority) override;
-    [[nodiscard]] int removeUsers(const UidRanges& uidRanges, uint32_t subPriority) override;
+    [[nodiscard]] int addUsers(const UidRanges& uidRanges, int32_t subPriority) override;
+    [[nodiscard]] int removeUsers(const UidRanges& uidRanges, int32_t subPriority) override;
     bool isUnreachable() override { return true; }
     bool canAddUsers() override { return true; }
 
   private:
     std::string getTypeString() const override { return "UNREACHABLE"; };
-    bool isValidSubPriority(uint32_t priority) override;
+    bool isValidSubPriority(int32_t priority) override;
 };
 
 }  // namespace android::net
\ No newline at end of file
diff --git a/server/VirtualNetwork.cpp b/server/VirtualNetwork.cpp
index 1906e20..495fd16 100644
--- a/server/VirtualNetwork.cpp
+++ b/server/VirtualNetwork.cpp
@@ -27,18 +27,20 @@
 namespace android {
 namespace net {
 
-VirtualNetwork::VirtualNetwork(unsigned netId, bool secure) : Network(netId, secure) {}
+VirtualNetwork::VirtualNetwork(unsigned netId, bool secure, bool excludeLocalRoutes)
+    : Network(netId, secure), mExcludeLocalRoutes(excludeLocalRoutes) {}
 
 VirtualNetwork::~VirtualNetwork() {}
 
-int VirtualNetwork::addUsers(const UidRanges& uidRanges, uint32_t subPriority) {
+int VirtualNetwork::addUsers(const UidRanges& uidRanges, int32_t subPriority) {
     if (!isValidSubPriority(subPriority) || !canAddUidRanges(uidRanges, subPriority)) {
         return -EINVAL;
     }
 
     for (const std::string& interface : mInterfaces) {
         int ret = RouteController::addUsersToVirtualNetwork(mNetId, interface.c_str(), mSecure,
-                                                            {{subPriority, uidRanges}});
+                                                            {{subPriority, uidRanges}},
+                                                            mExcludeLocalRoutes);
         if (ret) {
             ALOGE("failed to add users on interface %s of netId %u", interface.c_str(), mNetId);
             return ret;
@@ -48,12 +50,13 @@
     return 0;
 }
 
-int VirtualNetwork::removeUsers(const UidRanges& uidRanges, uint32_t subPriority) {
+int VirtualNetwork::removeUsers(const UidRanges& uidRanges, int32_t subPriority) {
     if (!isValidSubPriority(subPriority)) return -EINVAL;
 
     for (const std::string& interface : mInterfaces) {
         int ret = RouteController::removeUsersFromVirtualNetwork(mNetId, interface.c_str(), mSecure,
-                                                                 {{subPriority, uidRanges}});
+                                                                 {{subPriority, uidRanges}},
+                                                                 mExcludeLocalRoutes);
         if (ret) {
             ALOGE("failed to remove users on interface %s of netId %u", interface.c_str(), mNetId);
             return ret;
@@ -67,8 +70,8 @@
     if (hasInterface(interface)) {
         return 0;
     }
-    if (int ret = RouteController::addInterfaceToVirtualNetwork(mNetId, interface.c_str(), mSecure,
-                                                                mUidRangeMap)) {
+    if (int ret = RouteController::addInterfaceToVirtualNetwork(
+                mNetId, interface.c_str(), mSecure, mUidRangeMap, mExcludeLocalRoutes)) {
         ALOGE("failed to add interface %s to VPN netId %u", interface.c_str(), mNetId);
         return ret;
     }
@@ -80,8 +83,8 @@
     if (!hasInterface(interface)) {
         return 0;
     }
-    if (int ret = RouteController::removeInterfaceFromVirtualNetwork(mNetId, interface.c_str(),
-                                                                     mSecure, mUidRangeMap)) {
+    if (int ret = RouteController::removeInterfaceFromVirtualNetwork(
+                mNetId, interface.c_str(), mSecure, mUidRangeMap, mExcludeLocalRoutes)) {
         ALOGE("failed to remove interface %s from VPN netId %u", interface.c_str(), mNetId);
         return ret;
     }
@@ -89,9 +92,9 @@
     return 0;
 }
 
-bool VirtualNetwork::isValidSubPriority(uint32_t priority) {
+bool VirtualNetwork::isValidSubPriority(int32_t priority) {
     // Only supports default subsidiary permissions.
-    return priority == UidRanges::DEFAULT_SUB_PRIORITY;
+    return priority == UidRanges::SUB_PRIORITY_HIGHEST;
 }
 
 }  // namespace net
diff --git a/server/VirtualNetwork.h b/server/VirtualNetwork.h
index 20c9e2c..63bc589 100644
--- a/server/VirtualNetwork.h
+++ b/server/VirtualNetwork.h
@@ -28,21 +28,25 @@
 // Only a few privileged UIDs may skip the VPN and go directly to the underlying physical network.
 //
 // A non-secure VPN ("bypassable" VPN) also grabs all user traffic by default. But all apps are
-// permitted to skip it and pick any other network for their connections.
+// permitted to skip it and pick any other network for their connections. A bypassable VPN may
+// optionally exclude local routes, which means it will not grab traffic that is destined to IP
+// addresses considered to be on the local link.
 class VirtualNetwork : public Network {
 public:
-    VirtualNetwork(unsigned netId, bool secure);
-    virtual ~VirtualNetwork();
-    [[nodiscard]] int addUsers(const UidRanges& uidRanges, uint32_t subPriority) override;
-    [[nodiscard]] int removeUsers(const UidRanges& uidRanges, uint32_t subPriority) override;
-    bool isVirtual() override { return true; }
-    bool canAddUsers() override { return true; }
+  explicit VirtualNetwork(unsigned netId, bool secure, bool excludeLocalRoutes = false);
+  virtual ~VirtualNetwork();
+  [[nodiscard]] int addUsers(const UidRanges& uidRanges, int32_t subPriority) override;
+  [[nodiscard]] int removeUsers(const UidRanges& uidRanges, int32_t subPriority) override;
+  bool isVirtual() override { return true; }
+  bool canAddUsers() override { return true; }
 
-  private:
-    std::string getTypeString() const override { return "VIRTUAL"; };
-    [[nodiscard]] int addInterface(const std::string& interface) override;
-    [[nodiscard]] int removeInterface(const std::string& interface) override;
-    bool isValidSubPriority(uint32_t priority) override;
+private:
+  std::string getTypeString() const override { return "VIRTUAL"; };
+  [[nodiscard]] int addInterface(const std::string& interface) override;
+  [[nodiscard]] int removeInterface(const std::string& interface) override;
+  bool isValidSubPriority(int32_t priority) override;
+  // Whether the local traffic will be excluded from the VPN network.
+  [[maybe_unused]] const bool mExcludeLocalRoutes;
 };
 
 }  // namespace android::net
diff --git a/server/XfrmController.cpp b/server/XfrmController.cpp
index 24168a2..51710c8 100644
--- a/server/XfrmController.cpp
+++ b/server/XfrmController.cpp
@@ -66,10 +66,11 @@
 #include "netdutils/Fd.h"
 #include "netdutils/Slice.h"
 #include "netdutils/Syscalls.h"
+#include "netdutils/Utils.h"
 
-using android::net::INetd;
 using android::netdutils::DumpWriter;
 using android::netdutils::Fd;
+using android::netdutils::getIfaceNames;
 using android::netdutils::ScopedIndent;
 using android::netdutils::Slice;
 using android::netdutils::Status;
@@ -410,7 +411,7 @@
 }
 
 netdutils::Status XfrmController::flushInterfaces() {
-    const auto& ifaces = InterfaceController::getIfaceNames();
+    const auto& ifaces = getIfaceNames();
     RETURN_IF_NOT_OK(ifaces);
     const String8 ifPrefix8 = String8(INetd::IPSEC_INTERFACE_PREFIX().string());
 
diff --git a/server/aidl_api/netd_aidl_interface/1/.hash b/server/aidl_api/netd_aidl_interface/1/.hash
deleted file mode 100644
index d33e903..0000000
--- a/server/aidl_api/netd_aidl_interface/1/.hash
+++ /dev/null
@@ -1 +0,0 @@
-69c2ac134efbb31e9591d7e5c3640fb839e23bdb
diff --git a/server/aidl_api/netd_aidl_interface/1/android/net/INetd.aidl b/server/aidl_api/netd_aidl_interface/1/android/net/INetd.aidl
deleted file mode 100644
index 664c643..0000000
--- a/server/aidl_api/netd_aidl_interface/1/android/net/INetd.aidl
+++ /dev/null
@@ -1,132 +0,0 @@
-package android.net;
-interface INetd {
-  boolean isAlive();
-  boolean firewallReplaceUidChain(in @utf8InCpp String chainName, boolean isWhitelist, in int[] uids);
-  boolean bandwidthEnableDataSaver(boolean enable);
-  void networkCreatePhysical(int netId, int permission);
-  void networkCreateVpn(int netId, boolean secure);
-  void networkDestroy(int netId);
-  void networkAddInterface(int netId, in @utf8InCpp String iface);
-  void networkRemoveInterface(int netId, in @utf8InCpp String iface);
-  void networkAddUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges);
-  void networkRemoveUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges);
-  void networkRejectNonSecureVpn(boolean add, in android.net.UidRangeParcel[] uidRanges);
-  void socketDestroy(in android.net.UidRangeParcel[] uidRanges, in int[] exemptUids);
-  boolean tetherApplyDnsInterfaces();
-  android.net.TetherStatsParcel[] tetherGetStats();
-  void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength);
-  void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength);
-  @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter);
-  void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter, in @utf8InCpp String value);
-  void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid);
-  int ipSecAllocateSpi(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi);
-  void ipSecAddSecurityAssociation(int transformId, int mode, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int underlyingNetId, int spi, int markValue, int markMask, in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits, in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits, in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits, int encapType, int encapLocalPort, int encapRemotePort, int interfaceId);
-  void ipSecDeleteSecurityAssociation(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi, int markValue, int markMask, int interfaceId);
-  void ipSecApplyTransportModeTransform(in ParcelFileDescriptor socket, int transformId, int direction, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi);
-  void ipSecRemoveTransportModeTransform(in ParcelFileDescriptor socket);
-  void ipSecAddSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId);
-  void ipSecUpdateSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId);
-  void ipSecDeleteSecurityPolicy(int transformId, int selAddrFamily, int direction, int markValue, int markMask, int interfaceId);
-  void ipSecAddTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId);
-  void ipSecUpdateTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId);
-  void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName);
-  void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask);
-  void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask);
-  void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode);
-  void idletimerAddInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel);
-  void idletimerRemoveInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel);
-  void strictUidCleartextPenalty(int uid, int policyPenalty);
-  @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix);
-  void clatdStop(in @utf8InCpp String ifName);
-  boolean ipfwdEnabled();
-  @utf8InCpp String[] ipfwdGetRequesterList();
-  void ipfwdEnableForwarding(in @utf8InCpp String requester);
-  void ipfwdDisableForwarding(in @utf8InCpp String requester);
-  void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface);
-  void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface);
-  void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes);
-  void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName);
-  void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes);
-  void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName);
-  void bandwidthSetGlobalAlert(long bytes);
-  void bandwidthAddNaughtyApp(int uid);
-  void bandwidthRemoveNaughtyApp(int uid);
-  void bandwidthAddNiceApp(int uid);
-  void bandwidthRemoveNiceApp(int uid);
-  void tetherStart(in @utf8InCpp String[] dhcpRanges);
-  void tetherStop();
-  boolean tetherIsEnabled();
-  void tetherInterfaceAdd(in @utf8InCpp String ifName);
-  void tetherInterfaceRemove(in @utf8InCpp String ifName);
-  @utf8InCpp String[] tetherInterfaceList();
-  void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs);
-  @utf8InCpp String[] tetherDnsList();
-  void networkAddRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop);
-  void networkRemoveRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop);
-  void networkAddLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid);
-  void networkRemoveLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid);
-  int networkGetDefault();
-  void networkSetDefault(int netId);
-  void networkClearDefault();
-  void networkSetPermissionForNetwork(int netId, int permission);
-  void networkSetPermissionForUser(int permission, in int[] uids);
-  void networkClearPermissionForUser(in int[] uids);
-  void trafficSetNetPermForUids(int permission, in int[] uids);
-  void networkSetProtectAllow(int uid);
-  void networkSetProtectDeny(int uid);
-  boolean networkCanProtect(int uid);
-  void firewallSetFirewallType(int firewalltype);
-  void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule);
-  void firewallSetUidRule(int childChain, int uid, int firewallRule);
-  void firewallEnableChildChain(int childChain, boolean enable);
-  @utf8InCpp String[] interfaceGetList();
-  android.net.InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName);
-  void interfaceSetCfg(in android.net.InterfaceConfigurationParcel cfg);
-  void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable);
-  void interfaceClearAddrs(in @utf8InCpp String ifName);
-  void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable);
-  void interfaceSetMtu(in @utf8InCpp String ifName, int mtu);
-  void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface);
-  void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface);
-  void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues);
-  void registerUnsolicitedEventListener(android.net.INetdUnsolicitedEventListener listener);
-  const int IPV4 = 4;
-  const int IPV6 = 6;
-  const int CONF = 1;
-  const int NEIGH = 2;
-  const String IPSEC_INTERFACE_PREFIX = "ipsec";
-  const int IPV6_ADDR_GEN_MODE_EUI64 = 0;
-  const int IPV6_ADDR_GEN_MODE_NONE = 1;
-  const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2;
-  const int IPV6_ADDR_GEN_MODE_RANDOM = 3;
-  const int IPV6_ADDR_GEN_MODE_DEFAULT = 0;
-  const int PENALTY_POLICY_ACCEPT = 1;
-  const int PENALTY_POLICY_LOG = 2;
-  const int PENALTY_POLICY_REJECT = 3;
-  const int LOCAL_NET_ID = 99;
-  const String NEXTHOP_NONE = "";
-  const String NEXTHOP_UNREACHABLE = "unreachable";
-  const String NEXTHOP_THROW = "throw";
-  const int PERMISSION_NONE = 0;
-  const int PERMISSION_NETWORK = 1;
-  const int PERMISSION_SYSTEM = 2;
-  const int NO_PERMISSIONS = 0;
-  const int PERMISSION_INTERNET = 4;
-  const int PERMISSION_UPDATE_DEVICE_STATS = 8;
-  const int PERMISSION_UNINSTALLED = -1;
-  const int FIREWALL_WHITELIST = 0;
-  const int FIREWALL_BLACKLIST = 1;
-  const int FIREWALL_RULE_ALLOW = 1;
-  const int FIREWALL_RULE_DENY = 2;
-  const int FIREWALL_CHAIN_NONE = 0;
-  const int FIREWALL_CHAIN_DOZABLE = 1;
-  const int FIREWALL_CHAIN_STANDBY = 2;
-  const int FIREWALL_CHAIN_POWERSAVE = 3;
-  const String IF_STATE_UP = "up";
-  const String IF_STATE_DOWN = "down";
-  const String IF_FLAG_BROADCAST = "broadcast";
-  const String IF_FLAG_LOOPBACK = "loopback";
-  const String IF_FLAG_POINTOPOINT = "point-to-point";
-  const String IF_FLAG_RUNNING = "running";
-  const String IF_FLAG_MULTICAST = "multicast";
-}
diff --git a/server/aidl_api/netd_aidl_interface/1/android/net/INetdUnsolicitedEventListener.aidl b/server/aidl_api/netd_aidl_interface/1/android/net/INetdUnsolicitedEventListener.aidl
deleted file mode 100644
index 18631ff..0000000
--- a/server/aidl_api/netd_aidl_interface/1/android/net/INetdUnsolicitedEventListener.aidl
+++ /dev/null
@@ -1,14 +0,0 @@
-package android.net;
-interface INetdUnsolicitedEventListener {
-  oneway void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs, int uid);
-  oneway void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName);
-  oneway void onInterfaceDnsServerInfo(@utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers);
-  oneway void onInterfaceAddressUpdated(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope);
-  oneway void onInterfaceAddressRemoved(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope);
-  oneway void onInterfaceAdded(@utf8InCpp String ifName);
-  oneway void onInterfaceRemoved(@utf8InCpp String ifName);
-  oneway void onInterfaceChanged(@utf8InCpp String ifName, boolean up);
-  oneway void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up);
-  oneway void onRouteChanged(boolean updated, @utf8InCpp String route, @utf8InCpp String gateway, @utf8InCpp String ifName);
-  oneway void onStrictCleartextDetected(int uid, @utf8InCpp String hex);
-}
diff --git a/server/aidl_api/netd_aidl_interface/1/android/net/InterfaceConfigurationParcel.aidl b/server/aidl_api/netd_aidl_interface/1/android/net/InterfaceConfigurationParcel.aidl
deleted file mode 100644
index 93407dc..0000000
--- a/server/aidl_api/netd_aidl_interface/1/android/net/InterfaceConfigurationParcel.aidl
+++ /dev/null
@@ -1,8 +0,0 @@
-package android.net;
-parcelable InterfaceConfigurationParcel {
-  @utf8InCpp String ifName;
-  @utf8InCpp String hwAddr;
-  @utf8InCpp String ipv4Addr;
-  int prefixLength;
-  @utf8InCpp String[] flags;
-}
diff --git a/server/aidl_api/netd_aidl_interface/1/android/net/TetherStatsParcel.aidl b/server/aidl_api/netd_aidl_interface/1/android/net/TetherStatsParcel.aidl
deleted file mode 100644
index d1782bb..0000000
--- a/server/aidl_api/netd_aidl_interface/1/android/net/TetherStatsParcel.aidl
+++ /dev/null
@@ -1,8 +0,0 @@
-package android.net;
-parcelable TetherStatsParcel {
-  @utf8InCpp String iface;
-  long rxBytes;
-  long rxPackets;
-  long txBytes;
-  long txPackets;
-}
diff --git a/server/aidl_api/netd_aidl_interface/1/android/net/UidRangeParcel.aidl b/server/aidl_api/netd_aidl_interface/1/android/net/UidRangeParcel.aidl
deleted file mode 100644
index d3bc7ed..0000000
--- a/server/aidl_api/netd_aidl_interface/1/android/net/UidRangeParcel.aidl
+++ /dev/null
@@ -1,5 +0,0 @@
-package android.net;
-parcelable UidRangeParcel {
-  int start;
-  int stop;
-}
diff --git a/server/aidl_api/netd_aidl_interface/2/.hash b/server/aidl_api/netd_aidl_interface/2/.hash
deleted file mode 100644
index 5fc5b2d..0000000
--- a/server/aidl_api/netd_aidl_interface/2/.hash
+++ /dev/null
@@ -1 +0,0 @@
-e395d63302c47e7d2dac0d503045779029ff598b
diff --git a/server/aidl_api/netd_aidl_interface/2/android/net/INetd.aidl b/server/aidl_api/netd_aidl_interface/2/android/net/INetd.aidl
deleted file mode 100644
index 0e2d5f4..0000000
--- a/server/aidl_api/netd_aidl_interface/2/android/net/INetd.aidl
+++ /dev/null
@@ -1,153 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a frozen 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;
-interface INetd {
-  boolean isAlive();
-  boolean firewallReplaceUidChain(in @utf8InCpp String chainName, boolean isWhitelist, in int[] uids);
-  boolean bandwidthEnableDataSaver(boolean enable);
-  void networkCreatePhysical(int netId, int permission);
-  void networkCreateVpn(int netId, boolean secure);
-  void networkDestroy(int netId);
-  void networkAddInterface(int netId, in @utf8InCpp String iface);
-  void networkRemoveInterface(int netId, in @utf8InCpp String iface);
-  void networkAddUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges);
-  void networkRemoveUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges);
-  void networkRejectNonSecureVpn(boolean add, in android.net.UidRangeParcel[] uidRanges);
-  void socketDestroy(in android.net.UidRangeParcel[] uidRanges, in int[] exemptUids);
-  boolean tetherApplyDnsInterfaces();
-  android.net.TetherStatsParcel[] tetherGetStats();
-  void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength);
-  void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength);
-  @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter);
-  void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter, in @utf8InCpp String value);
-  void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid);
-  int ipSecAllocateSpi(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi);
-  void ipSecAddSecurityAssociation(int transformId, int mode, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int underlyingNetId, int spi, int markValue, int markMask, in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits, in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits, in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits, int encapType, int encapLocalPort, int encapRemotePort, int interfaceId);
-  void ipSecDeleteSecurityAssociation(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi, int markValue, int markMask, int interfaceId);
-  void ipSecApplyTransportModeTransform(in ParcelFileDescriptor socket, int transformId, int direction, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi);
-  void ipSecRemoveTransportModeTransform(in ParcelFileDescriptor socket);
-  void ipSecAddSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId);
-  void ipSecUpdateSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId);
-  void ipSecDeleteSecurityPolicy(int transformId, int selAddrFamily, int direction, int markValue, int markMask, int interfaceId);
-  void ipSecAddTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId);
-  void ipSecUpdateTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId);
-  void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName);
-  void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask);
-  void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask);
-  void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode);
-  void idletimerAddInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel);
-  void idletimerRemoveInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel);
-  void strictUidCleartextPenalty(int uid, int policyPenalty);
-  @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix);
-  void clatdStop(in @utf8InCpp String ifName);
-  boolean ipfwdEnabled();
-  @utf8InCpp String[] ipfwdGetRequesterList();
-  void ipfwdEnableForwarding(in @utf8InCpp String requester);
-  void ipfwdDisableForwarding(in @utf8InCpp String requester);
-  void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface);
-  void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface);
-  void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes);
-  void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName);
-  void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes);
-  void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName);
-  void bandwidthSetGlobalAlert(long bytes);
-  void bandwidthAddNaughtyApp(int uid);
-  void bandwidthRemoveNaughtyApp(int uid);
-  void bandwidthAddNiceApp(int uid);
-  void bandwidthRemoveNiceApp(int uid);
-  void tetherStart(in @utf8InCpp String[] dhcpRanges);
-  void tetherStop();
-  boolean tetherIsEnabled();
-  void tetherInterfaceAdd(in @utf8InCpp String ifName);
-  void tetherInterfaceRemove(in @utf8InCpp String ifName);
-  @utf8InCpp String[] tetherInterfaceList();
-  void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs);
-  @utf8InCpp String[] tetherDnsList();
-  void networkAddRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop);
-  void networkRemoveRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop);
-  void networkAddLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid);
-  void networkRemoveLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid);
-  int networkGetDefault();
-  void networkSetDefault(int netId);
-  void networkClearDefault();
-  void networkSetPermissionForNetwork(int netId, int permission);
-  void networkSetPermissionForUser(int permission, in int[] uids);
-  void networkClearPermissionForUser(in int[] uids);
-  void trafficSetNetPermForUids(int permission, in int[] uids);
-  void networkSetProtectAllow(int uid);
-  void networkSetProtectDeny(int uid);
-  boolean networkCanProtect(int uid);
-  void firewallSetFirewallType(int firewalltype);
-  void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule);
-  void firewallSetUidRule(int childChain, int uid, int firewallRule);
-  void firewallEnableChildChain(int childChain, boolean enable);
-  @utf8InCpp String[] interfaceGetList();
-  android.net.InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName);
-  void interfaceSetCfg(in android.net.InterfaceConfigurationParcel cfg);
-  void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable);
-  void interfaceClearAddrs(in @utf8InCpp String ifName);
-  void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable);
-  void interfaceSetMtu(in @utf8InCpp String ifName, int mtu);
-  void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface);
-  void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface);
-  void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues);
-  void registerUnsolicitedEventListener(android.net.INetdUnsolicitedEventListener listener);
-  void firewallAddUidInterfaceRules(in @utf8InCpp String ifName, in int[] uids);
-  void firewallRemoveUidInterfaceRules(in int[] uids);
-  void trafficSwapActiveStatsMap();
-  IBinder getOemNetd();
-  const int IPV4 = 4;
-  const int IPV6 = 6;
-  const int CONF = 1;
-  const int NEIGH = 2;
-  const String IPSEC_INTERFACE_PREFIX = "ipsec";
-  const int IPV6_ADDR_GEN_MODE_EUI64 = 0;
-  const int IPV6_ADDR_GEN_MODE_NONE = 1;
-  const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2;
-  const int IPV6_ADDR_GEN_MODE_RANDOM = 3;
-  const int IPV6_ADDR_GEN_MODE_DEFAULT = 0;
-  const int PENALTY_POLICY_ACCEPT = 1;
-  const int PENALTY_POLICY_LOG = 2;
-  const int PENALTY_POLICY_REJECT = 3;
-  const int LOCAL_NET_ID = 99;
-  const String NEXTHOP_NONE = "";
-  const String NEXTHOP_UNREACHABLE = "unreachable";
-  const String NEXTHOP_THROW = "throw";
-  const int PERMISSION_NONE = 0;
-  const int PERMISSION_NETWORK = 1;
-  const int PERMISSION_SYSTEM = 2;
-  const int NO_PERMISSIONS = 0;
-  const int PERMISSION_INTERNET = 4;
-  const int PERMISSION_UPDATE_DEVICE_STATS = 8;
-  const int PERMISSION_UNINSTALLED = -1;
-  const int FIREWALL_WHITELIST = 0;
-  const int FIREWALL_BLACKLIST = 1;
-  const int FIREWALL_RULE_ALLOW = 1;
-  const int FIREWALL_RULE_DENY = 2;
-  const int FIREWALL_CHAIN_NONE = 0;
-  const int FIREWALL_CHAIN_DOZABLE = 1;
-  const int FIREWALL_CHAIN_STANDBY = 2;
-  const int FIREWALL_CHAIN_POWERSAVE = 3;
-  const String IF_STATE_UP = "up";
-  const String IF_STATE_DOWN = "down";
-  const String IF_FLAG_BROADCAST = "broadcast";
-  const String IF_FLAG_LOOPBACK = "loopback";
-  const String IF_FLAG_POINTOPOINT = "point-to-point";
-  const String IF_FLAG_RUNNING = "running";
-  const String IF_FLAG_MULTICAST = "multicast";
-}
diff --git a/server/aidl_api/netd_aidl_interface/2/android/net/INetdUnsolicitedEventListener.aidl b/server/aidl_api/netd_aidl_interface/2/android/net/INetdUnsolicitedEventListener.aidl
deleted file mode 100644
index 621f1cf..0000000
--- a/server/aidl_api/netd_aidl_interface/2/android/net/INetdUnsolicitedEventListener.aidl
+++ /dev/null
@@ -1,31 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a frozen 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;
-interface INetdUnsolicitedEventListener {
-  oneway void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs, int uid);
-  oneway void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName);
-  oneway void onInterfaceDnsServerInfo(@utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers);
-  oneway void onInterfaceAddressUpdated(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope);
-  oneway void onInterfaceAddressRemoved(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope);
-  oneway void onInterfaceAdded(@utf8InCpp String ifName);
-  oneway void onInterfaceRemoved(@utf8InCpp String ifName);
-  oneway void onInterfaceChanged(@utf8InCpp String ifName, boolean up);
-  oneway void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up);
-  oneway void onRouteChanged(boolean updated, @utf8InCpp String route, @utf8InCpp String gateway, @utf8InCpp String ifName);
-  oneway void onStrictCleartextDetected(int uid, @utf8InCpp String hex);
-}
diff --git a/server/aidl_api/netd_aidl_interface/2/android/net/InterfaceConfigurationParcel.aidl b/server/aidl_api/netd_aidl_interface/2/android/net/InterfaceConfigurationParcel.aidl
deleted file mode 100644
index 18de61f..0000000
--- a/server/aidl_api/netd_aidl_interface/2/android/net/InterfaceConfigurationParcel.aidl
+++ /dev/null
@@ -1,25 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a frozen 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;
-parcelable InterfaceConfigurationParcel {
-  @utf8InCpp String ifName;
-  @utf8InCpp String hwAddr;
-  @utf8InCpp String ipv4Addr;
-  int prefixLength;
-  @utf8InCpp String[] flags;
-}
diff --git a/server/aidl_api/netd_aidl_interface/2/android/net/TetherStatsParcel.aidl b/server/aidl_api/netd_aidl_interface/2/android/net/TetherStatsParcel.aidl
deleted file mode 100644
index c0ba676..0000000
--- a/server/aidl_api/netd_aidl_interface/2/android/net/TetherStatsParcel.aidl
+++ /dev/null
@@ -1,25 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a frozen 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;
-parcelable TetherStatsParcel {
-  @utf8InCpp String iface;
-  long rxBytes;
-  long rxPackets;
-  long txBytes;
-  long txPackets;
-}
diff --git a/server/aidl_api/netd_aidl_interface/2/android/net/UidRangeParcel.aidl b/server/aidl_api/netd_aidl_interface/2/android/net/UidRangeParcel.aidl
deleted file mode 100644
index c2c35db..0000000
--- a/server/aidl_api/netd_aidl_interface/2/android/net/UidRangeParcel.aidl
+++ /dev/null
@@ -1,22 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a frozen 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;
-parcelable UidRangeParcel {
-  int start;
-  int stop;
-}
diff --git a/server/aidl_api/netd_aidl_interface/3/.hash b/server/aidl_api/netd_aidl_interface/3/.hash
deleted file mode 100644
index 59cf708..0000000
--- a/server/aidl_api/netd_aidl_interface/3/.hash
+++ /dev/null
@@ -1 +0,0 @@
-e17c1f9b2068b539b22e3a4a447edea3c80aee4b
diff --git a/server/aidl_api/netd_aidl_interface/3/android/net/INetd.aidl b/server/aidl_api/netd_aidl_interface/3/android/net/INetd.aidl
deleted file mode 100644
index 135b738..0000000
--- a/server/aidl_api/netd_aidl_interface/3/android/net/INetd.aidl
+++ /dev/null
@@ -1,161 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// 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 INetd {
-  boolean isAlive();
-  boolean firewallReplaceUidChain(in @utf8InCpp String chainName, boolean isWhitelist, in int[] uids);
-  boolean bandwidthEnableDataSaver(boolean enable);
-  void networkCreatePhysical(int netId, int permission);
-  void networkCreateVpn(int netId, boolean secure);
-  void networkDestroy(int netId);
-  void networkAddInterface(int netId, in @utf8InCpp String iface);
-  void networkRemoveInterface(int netId, in @utf8InCpp String iface);
-  void networkAddUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges);
-  void networkRemoveUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges);
-  void networkRejectNonSecureVpn(boolean add, in android.net.UidRangeParcel[] uidRanges);
-  void socketDestroy(in android.net.UidRangeParcel[] uidRanges, in int[] exemptUids);
-  boolean tetherApplyDnsInterfaces();
-  android.net.TetherStatsParcel[] tetherGetStats();
-  void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength);
-  void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength);
-  @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter);
-  void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter, in @utf8InCpp String value);
-  void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid);
-  int ipSecAllocateSpi(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi);
-  void ipSecAddSecurityAssociation(int transformId, int mode, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int underlyingNetId, int spi, int markValue, int markMask, in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits, in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits, in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits, int encapType, int encapLocalPort, int encapRemotePort, int interfaceId);
-  void ipSecDeleteSecurityAssociation(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi, int markValue, int markMask, int interfaceId);
-  void ipSecApplyTransportModeTransform(in ParcelFileDescriptor socket, int transformId, int direction, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi);
-  void ipSecRemoveTransportModeTransform(in ParcelFileDescriptor socket);
-  void ipSecAddSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId);
-  void ipSecUpdateSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId);
-  void ipSecDeleteSecurityPolicy(int transformId, int selAddrFamily, int direction, int markValue, int markMask, int interfaceId);
-  void ipSecAddTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId);
-  void ipSecUpdateTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId);
-  void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName);
-  void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask);
-  void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask);
-  void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode);
-  void idletimerAddInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel);
-  void idletimerRemoveInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel);
-  void strictUidCleartextPenalty(int uid, int policyPenalty);
-  @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix);
-  void clatdStop(in @utf8InCpp String ifName);
-  boolean ipfwdEnabled();
-  @utf8InCpp String[] ipfwdGetRequesterList();
-  void ipfwdEnableForwarding(in @utf8InCpp String requester);
-  void ipfwdDisableForwarding(in @utf8InCpp String requester);
-  void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface);
-  void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface);
-  void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes);
-  void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName);
-  void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes);
-  void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName);
-  void bandwidthSetGlobalAlert(long bytes);
-  void bandwidthAddNaughtyApp(int uid);
-  void bandwidthRemoveNaughtyApp(int uid);
-  void bandwidthAddNiceApp(int uid);
-  void bandwidthRemoveNiceApp(int uid);
-  void tetherStart(in @utf8InCpp String[] dhcpRanges);
-  void tetherStop();
-  boolean tetherIsEnabled();
-  void tetherInterfaceAdd(in @utf8InCpp String ifName);
-  void tetherInterfaceRemove(in @utf8InCpp String ifName);
-  @utf8InCpp String[] tetherInterfaceList();
-  void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs);
-  @utf8InCpp String[] tetherDnsList();
-  void networkAddRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop);
-  void networkRemoveRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop);
-  void networkAddLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid);
-  void networkRemoveLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid);
-  int networkGetDefault();
-  void networkSetDefault(int netId);
-  void networkClearDefault();
-  void networkSetPermissionForNetwork(int netId, int permission);
-  void networkSetPermissionForUser(int permission, in int[] uids);
-  void networkClearPermissionForUser(in int[] uids);
-  void trafficSetNetPermForUids(int permission, in int[] uids);
-  void networkSetProtectAllow(int uid);
-  void networkSetProtectDeny(int uid);
-  boolean networkCanProtect(int uid);
-  void firewallSetFirewallType(int firewalltype);
-  void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule);
-  void firewallSetUidRule(int childChain, int uid, int firewallRule);
-  void firewallEnableChildChain(int childChain, boolean enable);
-  @utf8InCpp String[] interfaceGetList();
-  android.net.InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName);
-  void interfaceSetCfg(in android.net.InterfaceConfigurationParcel cfg);
-  void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable);
-  void interfaceClearAddrs(in @utf8InCpp String ifName);
-  void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable);
-  void interfaceSetMtu(in @utf8InCpp String ifName, int mtu);
-  void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface);
-  void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface);
-  void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues);
-  void registerUnsolicitedEventListener(android.net.INetdUnsolicitedEventListener listener);
-  void firewallAddUidInterfaceRules(in @utf8InCpp String ifName, in int[] uids);
-  void firewallRemoveUidInterfaceRules(in int[] uids);
-  void trafficSwapActiveStatsMap();
-  IBinder getOemNetd();
-  void tetherStartWithConfiguration(in android.net.TetherConfigParcel config);
-  android.net.MarkMaskParcel getFwmarkForNetwork(int netId);
-  void networkAddRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo);
-  void networkUpdateRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo);
-  void networkRemoveRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo);
-  void tetherOffloadRuleAdd(in android.net.TetherOffloadRuleParcel rule);
-  void tetherOffloadRuleRemove(in android.net.TetherOffloadRuleParcel rule);
-  const int IPV4 = 4;
-  const int IPV6 = 6;
-  const int CONF = 1;
-  const int NEIGH = 2;
-  const String IPSEC_INTERFACE_PREFIX = "ipsec";
-  const int IPV6_ADDR_GEN_MODE_EUI64 = 0;
-  const int IPV6_ADDR_GEN_MODE_NONE = 1;
-  const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2;
-  const int IPV6_ADDR_GEN_MODE_RANDOM = 3;
-  const int IPV6_ADDR_GEN_MODE_DEFAULT = 0;
-  const int PENALTY_POLICY_ACCEPT = 1;
-  const int PENALTY_POLICY_LOG = 2;
-  const int PENALTY_POLICY_REJECT = 3;
-  const int LOCAL_NET_ID = 99;
-  const String NEXTHOP_NONE = "";
-  const String NEXTHOP_UNREACHABLE = "unreachable";
-  const String NEXTHOP_THROW = "throw";
-  const int PERMISSION_NONE = 0;
-  const int PERMISSION_NETWORK = 1;
-  const int PERMISSION_SYSTEM = 2;
-  const int NO_PERMISSIONS = 0;
-  const int PERMISSION_INTERNET = 4;
-  const int PERMISSION_UPDATE_DEVICE_STATS = 8;
-  const int PERMISSION_UNINSTALLED = -1;
-  const int FIREWALL_WHITELIST = 0;
-  const int FIREWALL_BLACKLIST = 1;
-  const int FIREWALL_RULE_ALLOW = 1;
-  const int FIREWALL_RULE_DENY = 2;
-  const int FIREWALL_CHAIN_NONE = 0;
-  const int FIREWALL_CHAIN_DOZABLE = 1;
-  const int FIREWALL_CHAIN_STANDBY = 2;
-  const int FIREWALL_CHAIN_POWERSAVE = 3;
-  const String IF_STATE_UP = "up";
-  const String IF_STATE_DOWN = "down";
-  const String IF_FLAG_BROADCAST = "broadcast";
-  const String IF_FLAG_LOOPBACK = "loopback";
-  const String IF_FLAG_POINTOPOINT = "point-to-point";
-  const String IF_FLAG_RUNNING = "running";
-  const String IF_FLAG_MULTICAST = "multicast";
-}
diff --git a/server/aidl_api/netd_aidl_interface/3/android/net/INetdUnsolicitedEventListener.aidl b/server/aidl_api/netd_aidl_interface/3/android/net/INetdUnsolicitedEventListener.aidl
deleted file mode 100644
index 4459363..0000000
--- a/server/aidl_api/netd_aidl_interface/3/android/net/INetdUnsolicitedEventListener.aidl
+++ /dev/null
@@ -1,32 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// 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 INetdUnsolicitedEventListener {
-  oneway void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs, int uid);
-  oneway void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName);
-  oneway void onInterfaceDnsServerInfo(@utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers);
-  oneway void onInterfaceAddressUpdated(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope);
-  oneway void onInterfaceAddressRemoved(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope);
-  oneway void onInterfaceAdded(@utf8InCpp String ifName);
-  oneway void onInterfaceRemoved(@utf8InCpp String ifName);
-  oneway void onInterfaceChanged(@utf8InCpp String ifName, boolean up);
-  oneway void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up);
-  oneway void onRouteChanged(boolean updated, @utf8InCpp String route, @utf8InCpp String gateway, @utf8InCpp String ifName);
-  oneway void onStrictCleartextDetected(int uid, @utf8InCpp String hex);
-}
diff --git a/server/aidl_api/netd_aidl_interface/3/android/net/InterfaceConfigurationParcel.aidl b/server/aidl_api/netd_aidl_interface/3/android/net/InterfaceConfigurationParcel.aidl
deleted file mode 100644
index 01e0f95..0000000
--- a/server/aidl_api/netd_aidl_interface/3/android/net/InterfaceConfigurationParcel.aidl
+++ /dev/null
@@ -1,26 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// 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 InterfaceConfigurationParcel {
-  @utf8InCpp String ifName;
-  @utf8InCpp String hwAddr;
-  @utf8InCpp String ipv4Addr;
-  int prefixLength;
-  @utf8InCpp String[] flags;
-}
diff --git a/server/aidl_api/netd_aidl_interface/3/android/net/MarkMaskParcel.aidl b/server/aidl_api/netd_aidl_interface/3/android/net/MarkMaskParcel.aidl
deleted file mode 100644
index 62be838..0000000
--- a/server/aidl_api/netd_aidl_interface/3/android/net/MarkMaskParcel.aidl
+++ /dev/null
@@ -1,23 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// 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 MarkMaskParcel {
-  int mark;
-  int mask;
-}
diff --git a/server/aidl_api/netd_aidl_interface/3/android/net/RouteInfoParcel.aidl b/server/aidl_api/netd_aidl_interface/3/android/net/RouteInfoParcel.aidl
deleted file mode 100644
index 5e0ee62..0000000
--- a/server/aidl_api/netd_aidl_interface/3/android/net/RouteInfoParcel.aidl
+++ /dev/null
@@ -1,24 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// 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;
-parcelable RouteInfoParcel {
-  @utf8InCpp String destination;
-  @utf8InCpp String ifName;
-  @utf8InCpp String nextHop;
-  int mtu;
-}
diff --git a/server/aidl_api/netd_aidl_interface/3/android/net/TetherConfigParcel.aidl b/server/aidl_api/netd_aidl_interface/3/android/net/TetherConfigParcel.aidl
deleted file mode 100644
index b136454..0000000
--- a/server/aidl_api/netd_aidl_interface/3/android/net/TetherConfigParcel.aidl
+++ /dev/null
@@ -1,23 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// 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 TetherConfigParcel {
-  boolean usingLegacyDnsProxy;
-  @utf8InCpp String[] dhcpRanges;
-}
diff --git a/server/aidl_api/netd_aidl_interface/3/android/net/TetherOffloadRuleParcel.aidl b/server/aidl_api/netd_aidl_interface/3/android/net/TetherOffloadRuleParcel.aidl
deleted file mode 100644
index 3abf0f8..0000000
--- a/server/aidl_api/netd_aidl_interface/3/android/net/TetherOffloadRuleParcel.aidl
+++ /dev/null
@@ -1,27 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// 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 TetherOffloadRuleParcel {
-  int inputInterfaceIndex;
-  int outputInterfaceIndex;
-  byte[] destination;
-  int prefixLength;
-  byte[] srcL2Address;
-  byte[] dstL2Address;
-}
diff --git a/server/aidl_api/netd_aidl_interface/3/android/net/TetherStatsParcel.aidl b/server/aidl_api/netd_aidl_interface/3/android/net/TetherStatsParcel.aidl
deleted file mode 100644
index 71ffb9b..0000000
--- a/server/aidl_api/netd_aidl_interface/3/android/net/TetherStatsParcel.aidl
+++ /dev/null
@@ -1,26 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// 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 TetherStatsParcel {
-  @utf8InCpp String iface;
-  long rxBytes;
-  long rxPackets;
-  long txBytes;
-  long txPackets;
-}
diff --git a/server/aidl_api/netd_aidl_interface/3/android/net/UidRangeParcel.aidl b/server/aidl_api/netd_aidl_interface/3/android/net/UidRangeParcel.aidl
deleted file mode 100644
index 84ff457..0000000
--- a/server/aidl_api/netd_aidl_interface/3/android/net/UidRangeParcel.aidl
+++ /dev/null
@@ -1,23 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// 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 UidRangeParcel {
-  int start;
-  int stop;
-}
diff --git a/server/aidl_api/netd_aidl_interface/4/.hash b/server/aidl_api/netd_aidl_interface/4/.hash
deleted file mode 100644
index 0c3f810..0000000
--- a/server/aidl_api/netd_aidl_interface/4/.hash
+++ /dev/null
@@ -1 +0,0 @@
-63adaa5098e4d8621e90c5a84f7cb93505c79311
diff --git a/server/aidl_api/netd_aidl_interface/4/android/net/INetd.aidl b/server/aidl_api/netd_aidl_interface/4/android/net/INetd.aidl
deleted file mode 100644
index 47e2931..0000000
--- a/server/aidl_api/netd_aidl_interface/4/android/net/INetd.aidl
+++ /dev/null
@@ -1,164 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// 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 INetd {
-  boolean isAlive();
-  boolean firewallReplaceUidChain(in @utf8InCpp String chainName, boolean isWhitelist, in int[] uids);
-  boolean bandwidthEnableDataSaver(boolean enable);
-  void networkCreatePhysical(int netId, int permission);
-  void networkCreateVpn(int netId, boolean secure);
-  void networkDestroy(int netId);
-  void networkAddInterface(int netId, in @utf8InCpp String iface);
-  void networkRemoveInterface(int netId, in @utf8InCpp String iface);
-  void networkAddUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges);
-  void networkRemoveUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges);
-  void networkRejectNonSecureVpn(boolean add, in android.net.UidRangeParcel[] uidRanges);
-  void socketDestroy(in android.net.UidRangeParcel[] uidRanges, in int[] exemptUids);
-  boolean tetherApplyDnsInterfaces();
-  android.net.TetherStatsParcel[] tetherGetStats();
-  void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength);
-  void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength);
-  @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter);
-  void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter, in @utf8InCpp String value);
-  void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid);
-  int ipSecAllocateSpi(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi);
-  void ipSecAddSecurityAssociation(int transformId, int mode, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int underlyingNetId, int spi, int markValue, int markMask, in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits, in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits, in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits, int encapType, int encapLocalPort, int encapRemotePort, int interfaceId);
-  void ipSecDeleteSecurityAssociation(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi, int markValue, int markMask, int interfaceId);
-  void ipSecApplyTransportModeTransform(in ParcelFileDescriptor socket, int transformId, int direction, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi);
-  void ipSecRemoveTransportModeTransform(in ParcelFileDescriptor socket);
-  void ipSecAddSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId);
-  void ipSecUpdateSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId);
-  void ipSecDeleteSecurityPolicy(int transformId, int selAddrFamily, int direction, int markValue, int markMask, int interfaceId);
-  void ipSecAddTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId);
-  void ipSecUpdateTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId);
-  void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName);
-  void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask);
-  void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask);
-  void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode);
-  void idletimerAddInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel);
-  void idletimerRemoveInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel);
-  void strictUidCleartextPenalty(int uid, int policyPenalty);
-  @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix);
-  void clatdStop(in @utf8InCpp String ifName);
-  boolean ipfwdEnabled();
-  @utf8InCpp String[] ipfwdGetRequesterList();
-  void ipfwdEnableForwarding(in @utf8InCpp String requester);
-  void ipfwdDisableForwarding(in @utf8InCpp String requester);
-  void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface);
-  void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface);
-  void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes);
-  void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName);
-  void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes);
-  void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName);
-  void bandwidthSetGlobalAlert(long bytes);
-  void bandwidthAddNaughtyApp(int uid);
-  void bandwidthRemoveNaughtyApp(int uid);
-  void bandwidthAddNiceApp(int uid);
-  void bandwidthRemoveNiceApp(int uid);
-  void tetherStart(in @utf8InCpp String[] dhcpRanges);
-  void tetherStop();
-  boolean tetherIsEnabled();
-  void tetherInterfaceAdd(in @utf8InCpp String ifName);
-  void tetherInterfaceRemove(in @utf8InCpp String ifName);
-  @utf8InCpp String[] tetherInterfaceList();
-  void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs);
-  @utf8InCpp String[] tetherDnsList();
-  void networkAddRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop);
-  void networkRemoveRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop);
-  void networkAddLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid);
-  void networkRemoveLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid);
-  int networkGetDefault();
-  void networkSetDefault(int netId);
-  void networkClearDefault();
-  void networkSetPermissionForNetwork(int netId, int permission);
-  void networkSetPermissionForUser(int permission, in int[] uids);
-  void networkClearPermissionForUser(in int[] uids);
-  void trafficSetNetPermForUids(int permission, in int[] uids);
-  void networkSetProtectAllow(int uid);
-  void networkSetProtectDeny(int uid);
-  boolean networkCanProtect(int uid);
-  void firewallSetFirewallType(int firewalltype);
-  void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule);
-  void firewallSetUidRule(int childChain, int uid, int firewallRule);
-  void firewallEnableChildChain(int childChain, boolean enable);
-  @utf8InCpp String[] interfaceGetList();
-  android.net.InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName);
-  void interfaceSetCfg(in android.net.InterfaceConfigurationParcel cfg);
-  void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable);
-  void interfaceClearAddrs(in @utf8InCpp String ifName);
-  void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable);
-  void interfaceSetMtu(in @utf8InCpp String ifName, int mtu);
-  void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface);
-  void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface);
-  void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues);
-  void registerUnsolicitedEventListener(android.net.INetdUnsolicitedEventListener listener);
-  void firewallAddUidInterfaceRules(in @utf8InCpp String ifName, in int[] uids);
-  void firewallRemoveUidInterfaceRules(in int[] uids);
-  void trafficSwapActiveStatsMap();
-  IBinder getOemNetd();
-  void tetherStartWithConfiguration(in android.net.TetherConfigParcel config);
-  android.net.MarkMaskParcel getFwmarkForNetwork(int netId);
-  void networkAddRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo);
-  void networkUpdateRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo);
-  void networkRemoveRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo);
-  void tetherOffloadRuleAdd(in android.net.TetherOffloadRuleParcel rule);
-  void tetherOffloadRuleRemove(in android.net.TetherOffloadRuleParcel rule);
-  android.net.TetherStatsParcel[] tetherOffloadGetStats();
-  void tetherOffloadSetInterfaceQuota(int ifIndex, long quotaBytes);
-  android.net.TetherStatsParcel tetherOffloadGetAndClearStats(int ifIndex);
-  const int IPV4 = 4;
-  const int IPV6 = 6;
-  const int CONF = 1;
-  const int NEIGH = 2;
-  const String IPSEC_INTERFACE_PREFIX = "ipsec";
-  const int IPV6_ADDR_GEN_MODE_EUI64 = 0;
-  const int IPV6_ADDR_GEN_MODE_NONE = 1;
-  const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2;
-  const int IPV6_ADDR_GEN_MODE_RANDOM = 3;
-  const int IPV6_ADDR_GEN_MODE_DEFAULT = 0;
-  const int PENALTY_POLICY_ACCEPT = 1;
-  const int PENALTY_POLICY_LOG = 2;
-  const int PENALTY_POLICY_REJECT = 3;
-  const int LOCAL_NET_ID = 99;
-  const String NEXTHOP_NONE = "";
-  const String NEXTHOP_UNREACHABLE = "unreachable";
-  const String NEXTHOP_THROW = "throw";
-  const int PERMISSION_NONE = 0;
-  const int PERMISSION_NETWORK = 1;
-  const int PERMISSION_SYSTEM = 2;
-  const int NO_PERMISSIONS = 0;
-  const int PERMISSION_INTERNET = 4;
-  const int PERMISSION_UPDATE_DEVICE_STATS = 8;
-  const int PERMISSION_UNINSTALLED = -1;
-  const int FIREWALL_WHITELIST = 0;
-  const int FIREWALL_BLACKLIST = 1;
-  const int FIREWALL_RULE_ALLOW = 1;
-  const int FIREWALL_RULE_DENY = 2;
-  const int FIREWALL_CHAIN_NONE = 0;
-  const int FIREWALL_CHAIN_DOZABLE = 1;
-  const int FIREWALL_CHAIN_STANDBY = 2;
-  const int FIREWALL_CHAIN_POWERSAVE = 3;
-  const String IF_STATE_UP = "up";
-  const String IF_STATE_DOWN = "down";
-  const String IF_FLAG_BROADCAST = "broadcast";
-  const String IF_FLAG_LOOPBACK = "loopback";
-  const String IF_FLAG_POINTOPOINT = "point-to-point";
-  const String IF_FLAG_RUNNING = "running";
-  const String IF_FLAG_MULTICAST = "multicast";
-}
diff --git a/server/aidl_api/netd_aidl_interface/4/android/net/INetdUnsolicitedEventListener.aidl b/server/aidl_api/netd_aidl_interface/4/android/net/INetdUnsolicitedEventListener.aidl
deleted file mode 100644
index 4459363..0000000
--- a/server/aidl_api/netd_aidl_interface/4/android/net/INetdUnsolicitedEventListener.aidl
+++ /dev/null
@@ -1,32 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// 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 INetdUnsolicitedEventListener {
-  oneway void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs, int uid);
-  oneway void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName);
-  oneway void onInterfaceDnsServerInfo(@utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers);
-  oneway void onInterfaceAddressUpdated(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope);
-  oneway void onInterfaceAddressRemoved(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope);
-  oneway void onInterfaceAdded(@utf8InCpp String ifName);
-  oneway void onInterfaceRemoved(@utf8InCpp String ifName);
-  oneway void onInterfaceChanged(@utf8InCpp String ifName, boolean up);
-  oneway void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up);
-  oneway void onRouteChanged(boolean updated, @utf8InCpp String route, @utf8InCpp String gateway, @utf8InCpp String ifName);
-  oneway void onStrictCleartextDetected(int uid, @utf8InCpp String hex);
-}
diff --git a/server/aidl_api/netd_aidl_interface/4/android/net/InterfaceConfigurationParcel.aidl b/server/aidl_api/netd_aidl_interface/4/android/net/InterfaceConfigurationParcel.aidl
deleted file mode 100644
index 01e0f95..0000000
--- a/server/aidl_api/netd_aidl_interface/4/android/net/InterfaceConfigurationParcel.aidl
+++ /dev/null
@@ -1,26 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// 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 InterfaceConfigurationParcel {
-  @utf8InCpp String ifName;
-  @utf8InCpp String hwAddr;
-  @utf8InCpp String ipv4Addr;
-  int prefixLength;
-  @utf8InCpp String[] flags;
-}
diff --git a/server/aidl_api/netd_aidl_interface/4/android/net/MarkMaskParcel.aidl b/server/aidl_api/netd_aidl_interface/4/android/net/MarkMaskParcel.aidl
deleted file mode 100644
index 62be838..0000000
--- a/server/aidl_api/netd_aidl_interface/4/android/net/MarkMaskParcel.aidl
+++ /dev/null
@@ -1,23 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// 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 MarkMaskParcel {
-  int mark;
-  int mask;
-}
diff --git a/server/aidl_api/netd_aidl_interface/4/android/net/RouteInfoParcel.aidl b/server/aidl_api/netd_aidl_interface/4/android/net/RouteInfoParcel.aidl
deleted file mode 100644
index 5e0ee62..0000000
--- a/server/aidl_api/netd_aidl_interface/4/android/net/RouteInfoParcel.aidl
+++ /dev/null
@@ -1,24 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// 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;
-parcelable RouteInfoParcel {
-  @utf8InCpp String destination;
-  @utf8InCpp String ifName;
-  @utf8InCpp String nextHop;
-  int mtu;
-}
diff --git a/server/aidl_api/netd_aidl_interface/4/android/net/TetherConfigParcel.aidl b/server/aidl_api/netd_aidl_interface/4/android/net/TetherConfigParcel.aidl
deleted file mode 100644
index b136454..0000000
--- a/server/aidl_api/netd_aidl_interface/4/android/net/TetherConfigParcel.aidl
+++ /dev/null
@@ -1,23 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// 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 TetherConfigParcel {
-  boolean usingLegacyDnsProxy;
-  @utf8InCpp String[] dhcpRanges;
-}
diff --git a/server/aidl_api/netd_aidl_interface/4/android/net/TetherOffloadRuleParcel.aidl b/server/aidl_api/netd_aidl_interface/4/android/net/TetherOffloadRuleParcel.aidl
deleted file mode 100644
index c9d8458..0000000
--- a/server/aidl_api/netd_aidl_interface/4/android/net/TetherOffloadRuleParcel.aidl
+++ /dev/null
@@ -1,28 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// 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 TetherOffloadRuleParcel {
-  int inputInterfaceIndex;
-  int outputInterfaceIndex;
-  byte[] destination;
-  int prefixLength;
-  byte[] srcL2Address;
-  byte[] dstL2Address;
-  int pmtu = 1500;
-}
diff --git a/server/aidl_api/netd_aidl_interface/4/android/net/TetherStatsParcel.aidl b/server/aidl_api/netd_aidl_interface/4/android/net/TetherStatsParcel.aidl
deleted file mode 100644
index 0b0960e..0000000
--- a/server/aidl_api/netd_aidl_interface/4/android/net/TetherStatsParcel.aidl
+++ /dev/null
@@ -1,27 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// 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 TetherStatsParcel {
-  @utf8InCpp String iface;
-  long rxBytes;
-  long rxPackets;
-  long txBytes;
-  long txPackets;
-  int ifIndex = 0;
-}
diff --git a/server/aidl_api/netd_aidl_interface/4/android/net/UidRangeParcel.aidl b/server/aidl_api/netd_aidl_interface/4/android/net/UidRangeParcel.aidl
deleted file mode 100644
index 84ff457..0000000
--- a/server/aidl_api/netd_aidl_interface/4/android/net/UidRangeParcel.aidl
+++ /dev/null
@@ -1,23 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// 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 UidRangeParcel {
-  int start;
-  int stop;
-}
diff --git a/server/aidl_api/netd_aidl_interface/5/.hash b/server/aidl_api/netd_aidl_interface/5/.hash
deleted file mode 100644
index a6ced45..0000000
--- a/server/aidl_api/netd_aidl_interface/5/.hash
+++ /dev/null
@@ -1 +0,0 @@
-d97c56dd789cee9eeb5cdcec43a99df0a01873a5
diff --git a/server/aidl_api/netd_aidl_interface/5/android/net/INetd.aidl b/server/aidl_api/netd_aidl_interface/5/android/net/INetd.aidl
deleted file mode 100644
index b30748a..0000000
--- a/server/aidl_api/netd_aidl_interface/5/android/net/INetd.aidl
+++ /dev/null
@@ -1,167 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// 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 INetd {
-  boolean isAlive();
-  boolean firewallReplaceUidChain(in @utf8InCpp String chainName, boolean isAllowlist, in int[] uids);
-  boolean bandwidthEnableDataSaver(boolean enable);
-  void networkCreatePhysical(int netId, int permission);
-  void networkCreateVpn(int netId, boolean secure);
-  void networkDestroy(int netId);
-  void networkAddInterface(int netId, in @utf8InCpp String iface);
-  void networkRemoveInterface(int netId, in @utf8InCpp String iface);
-  void networkAddUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges);
-  void networkRemoveUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges);
-  void networkRejectNonSecureVpn(boolean add, in android.net.UidRangeParcel[] uidRanges);
-  void socketDestroy(in android.net.UidRangeParcel[] uidRanges, in int[] exemptUids);
-  boolean tetherApplyDnsInterfaces();
-  android.net.TetherStatsParcel[] tetherGetStats();
-  void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength);
-  void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength);
-  @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter);
-  void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter, in @utf8InCpp String value);
-  void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid);
-  int ipSecAllocateSpi(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi);
-  void ipSecAddSecurityAssociation(int transformId, int mode, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int underlyingNetId, int spi, int markValue, int markMask, in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits, in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits, in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits, int encapType, int encapLocalPort, int encapRemotePort, int interfaceId);
-  void ipSecDeleteSecurityAssociation(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi, int markValue, int markMask, int interfaceId);
-  void ipSecApplyTransportModeTransform(in ParcelFileDescriptor socket, int transformId, int direction, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi);
-  void ipSecRemoveTransportModeTransform(in ParcelFileDescriptor socket);
-  void ipSecAddSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId);
-  void ipSecUpdateSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId);
-  void ipSecDeleteSecurityPolicy(int transformId, int selAddrFamily, int direction, int markValue, int markMask, int interfaceId);
-  void ipSecAddTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId);
-  void ipSecUpdateTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId);
-  void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName);
-  void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask);
-  void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask);
-  void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode);
-  void idletimerAddInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel);
-  void idletimerRemoveInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel);
-  void strictUidCleartextPenalty(int uid, int policyPenalty);
-  @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix);
-  void clatdStop(in @utf8InCpp String ifName);
-  boolean ipfwdEnabled();
-  @utf8InCpp String[] ipfwdGetRequesterList();
-  void ipfwdEnableForwarding(in @utf8InCpp String requester);
-  void ipfwdDisableForwarding(in @utf8InCpp String requester);
-  void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface);
-  void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface);
-  void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes);
-  void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName);
-  void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes);
-  void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName);
-  void bandwidthSetGlobalAlert(long bytes);
-  void bandwidthAddNaughtyApp(int uid);
-  void bandwidthRemoveNaughtyApp(int uid);
-  void bandwidthAddNiceApp(int uid);
-  void bandwidthRemoveNiceApp(int uid);
-  void tetherStart(in @utf8InCpp String[] dhcpRanges);
-  void tetherStop();
-  boolean tetherIsEnabled();
-  void tetherInterfaceAdd(in @utf8InCpp String ifName);
-  void tetherInterfaceRemove(in @utf8InCpp String ifName);
-  @utf8InCpp String[] tetherInterfaceList();
-  void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs);
-  @utf8InCpp String[] tetherDnsList();
-  void networkAddRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop);
-  void networkRemoveRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop);
-  void networkAddLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid);
-  void networkRemoveLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid);
-  int networkGetDefault();
-  void networkSetDefault(int netId);
-  void networkClearDefault();
-  void networkSetPermissionForNetwork(int netId, int permission);
-  void networkSetPermissionForUser(int permission, in int[] uids);
-  void networkClearPermissionForUser(in int[] uids);
-  void trafficSetNetPermForUids(int permission, in int[] uids);
-  void networkSetProtectAllow(int uid);
-  void networkSetProtectDeny(int uid);
-  boolean networkCanProtect(int uid);
-  void firewallSetFirewallType(int firewalltype);
-  void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule);
-  void firewallSetUidRule(int childChain, int uid, int firewallRule);
-  void firewallEnableChildChain(int childChain, boolean enable);
-  @utf8InCpp String[] interfaceGetList();
-  android.net.InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName);
-  void interfaceSetCfg(in android.net.InterfaceConfigurationParcel cfg);
-  void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable);
-  void interfaceClearAddrs(in @utf8InCpp String ifName);
-  void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable);
-  void interfaceSetMtu(in @utf8InCpp String ifName, int mtu);
-  void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface);
-  void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface);
-  void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues);
-  void registerUnsolicitedEventListener(android.net.INetdUnsolicitedEventListener listener);
-  void firewallAddUidInterfaceRules(in @utf8InCpp String ifName, in int[] uids);
-  void firewallRemoveUidInterfaceRules(in int[] uids);
-  void trafficSwapActiveStatsMap();
-  IBinder getOemNetd();
-  void tetherStartWithConfiguration(in android.net.TetherConfigParcel config);
-  android.net.MarkMaskParcel getFwmarkForNetwork(int netId);
-  void networkAddRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo);
-  void networkUpdateRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo);
-  void networkRemoveRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo);
-  void tetherOffloadRuleAdd(in android.net.TetherOffloadRuleParcel rule);
-  void tetherOffloadRuleRemove(in android.net.TetherOffloadRuleParcel rule);
-  android.net.TetherStatsParcel[] tetherOffloadGetStats();
-  void tetherOffloadSetInterfaceQuota(int ifIndex, long quotaBytes);
-  android.net.TetherStatsParcel tetherOffloadGetAndClearStats(int ifIndex);
-  const int IPV4 = 4;
-  const int IPV6 = 6;
-  const int CONF = 1;
-  const int NEIGH = 2;
-  const String IPSEC_INTERFACE_PREFIX = "ipsec";
-  const int IPV6_ADDR_GEN_MODE_EUI64 = 0;
-  const int IPV6_ADDR_GEN_MODE_NONE = 1;
-  const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2;
-  const int IPV6_ADDR_GEN_MODE_RANDOM = 3;
-  const int IPV6_ADDR_GEN_MODE_DEFAULT = 0;
-  const int PENALTY_POLICY_ACCEPT = 1;
-  const int PENALTY_POLICY_LOG = 2;
-  const int PENALTY_POLICY_REJECT = 3;
-  const int LOCAL_NET_ID = 99;
-  const String NEXTHOP_NONE = "";
-  const String NEXTHOP_UNREACHABLE = "unreachable";
-  const String NEXTHOP_THROW = "throw";
-  const int PERMISSION_NONE = 0;
-  const int PERMISSION_NETWORK = 1;
-  const int PERMISSION_SYSTEM = 2;
-  const int NO_PERMISSIONS = 0;
-  const int PERMISSION_INTERNET = 4;
-  const int PERMISSION_UPDATE_DEVICE_STATS = 8;
-  const int PERMISSION_UNINSTALLED = -1;
-  const @JavaPassthrough(annotation="@Deprecated") int FIREWALL_WHITELIST = 0;
-  const int FIREWALL_ALLOWLIST = 0;
-  const @JavaPassthrough(annotation="@Deprecated") int FIREWALL_BLACKLIST = 1;
-  const int FIREWALL_DENYLIST = 1;
-  const int FIREWALL_RULE_ALLOW = 1;
-  const int FIREWALL_RULE_DENY = 2;
-  const int FIREWALL_CHAIN_NONE = 0;
-  const int FIREWALL_CHAIN_DOZABLE = 1;
-  const int FIREWALL_CHAIN_STANDBY = 2;
-  const int FIREWALL_CHAIN_POWERSAVE = 3;
-  const int FIREWALL_CHAIN_RESTRICTED = 4;
-  const String IF_STATE_UP = "up";
-  const String IF_STATE_DOWN = "down";
-  const String IF_FLAG_BROADCAST = "broadcast";
-  const String IF_FLAG_LOOPBACK = "loopback";
-  const String IF_FLAG_POINTOPOINT = "point-to-point";
-  const String IF_FLAG_RUNNING = "running";
-  const String IF_FLAG_MULTICAST = "multicast";
-}
diff --git a/server/aidl_api/netd_aidl_interface/5/android/net/INetdUnsolicitedEventListener.aidl b/server/aidl_api/netd_aidl_interface/5/android/net/INetdUnsolicitedEventListener.aidl
deleted file mode 100644
index 4459363..0000000
--- a/server/aidl_api/netd_aidl_interface/5/android/net/INetdUnsolicitedEventListener.aidl
+++ /dev/null
@@ -1,32 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// 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 INetdUnsolicitedEventListener {
-  oneway void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs, int uid);
-  oneway void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName);
-  oneway void onInterfaceDnsServerInfo(@utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers);
-  oneway void onInterfaceAddressUpdated(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope);
-  oneway void onInterfaceAddressRemoved(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope);
-  oneway void onInterfaceAdded(@utf8InCpp String ifName);
-  oneway void onInterfaceRemoved(@utf8InCpp String ifName);
-  oneway void onInterfaceChanged(@utf8InCpp String ifName, boolean up);
-  oneway void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up);
-  oneway void onRouteChanged(boolean updated, @utf8InCpp String route, @utf8InCpp String gateway, @utf8InCpp String ifName);
-  oneway void onStrictCleartextDetected(int uid, @utf8InCpp String hex);
-}
diff --git a/server/aidl_api/netd_aidl_interface/5/android/net/InterfaceConfigurationParcel.aidl b/server/aidl_api/netd_aidl_interface/5/android/net/InterfaceConfigurationParcel.aidl
deleted file mode 100644
index 01e0f95..0000000
--- a/server/aidl_api/netd_aidl_interface/5/android/net/InterfaceConfigurationParcel.aidl
+++ /dev/null
@@ -1,26 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// 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 InterfaceConfigurationParcel {
-  @utf8InCpp String ifName;
-  @utf8InCpp String hwAddr;
-  @utf8InCpp String ipv4Addr;
-  int prefixLength;
-  @utf8InCpp String[] flags;
-}
diff --git a/server/aidl_api/netd_aidl_interface/5/android/net/MarkMaskParcel.aidl b/server/aidl_api/netd_aidl_interface/5/android/net/MarkMaskParcel.aidl
deleted file mode 100644
index 62be838..0000000
--- a/server/aidl_api/netd_aidl_interface/5/android/net/MarkMaskParcel.aidl
+++ /dev/null
@@ -1,23 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// 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 MarkMaskParcel {
-  int mark;
-  int mask;
-}
diff --git a/server/aidl_api/netd_aidl_interface/5/android/net/RouteInfoParcel.aidl b/server/aidl_api/netd_aidl_interface/5/android/net/RouteInfoParcel.aidl
deleted file mode 100644
index 5e0ee62..0000000
--- a/server/aidl_api/netd_aidl_interface/5/android/net/RouteInfoParcel.aidl
+++ /dev/null
@@ -1,24 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// 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;
-parcelable RouteInfoParcel {
-  @utf8InCpp String destination;
-  @utf8InCpp String ifName;
-  @utf8InCpp String nextHop;
-  int mtu;
-}
diff --git a/server/aidl_api/netd_aidl_interface/5/android/net/TetherConfigParcel.aidl b/server/aidl_api/netd_aidl_interface/5/android/net/TetherConfigParcel.aidl
deleted file mode 100644
index b136454..0000000
--- a/server/aidl_api/netd_aidl_interface/5/android/net/TetherConfigParcel.aidl
+++ /dev/null
@@ -1,23 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// 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 TetherConfigParcel {
-  boolean usingLegacyDnsProxy;
-  @utf8InCpp String[] dhcpRanges;
-}
diff --git a/server/aidl_api/netd_aidl_interface/5/android/net/TetherOffloadRuleParcel.aidl b/server/aidl_api/netd_aidl_interface/5/android/net/TetherOffloadRuleParcel.aidl
deleted file mode 100644
index c9d8458..0000000
--- a/server/aidl_api/netd_aidl_interface/5/android/net/TetherOffloadRuleParcel.aidl
+++ /dev/null
@@ -1,28 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// 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 TetherOffloadRuleParcel {
-  int inputInterfaceIndex;
-  int outputInterfaceIndex;
-  byte[] destination;
-  int prefixLength;
-  byte[] srcL2Address;
-  byte[] dstL2Address;
-  int pmtu = 1500;
-}
diff --git a/server/aidl_api/netd_aidl_interface/5/android/net/TetherStatsParcel.aidl b/server/aidl_api/netd_aidl_interface/5/android/net/TetherStatsParcel.aidl
deleted file mode 100644
index 0b0960e..0000000
--- a/server/aidl_api/netd_aidl_interface/5/android/net/TetherStatsParcel.aidl
+++ /dev/null
@@ -1,27 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// 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 TetherStatsParcel {
-  @utf8InCpp String iface;
-  long rxBytes;
-  long rxPackets;
-  long txBytes;
-  long txPackets;
-  int ifIndex = 0;
-}
diff --git a/server/aidl_api/netd_aidl_interface/5/android/net/UidRangeParcel.aidl b/server/aidl_api/netd_aidl_interface/5/android/net/UidRangeParcel.aidl
deleted file mode 100644
index debc6be..0000000
--- a/server/aidl_api/netd_aidl_interface/5/android/net/UidRangeParcel.aidl
+++ /dev/null
@@ -1,24 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// 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 */
-@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable
-parcelable UidRangeParcel {
-  int start;
-  int stop;
-}
diff --git a/server/aidl_api/netd_aidl_interface/6/.hash b/server/aidl_api/netd_aidl_interface/6/.hash
deleted file mode 100644
index f5acf5d..0000000
--- a/server/aidl_api/netd_aidl_interface/6/.hash
+++ /dev/null
@@ -1 +0,0 @@
-b08451d9673b09cba84f1fd8740e1fdac64ff7be
diff --git a/server/aidl_api/netd_aidl_interface/6/android/net/INetd.aidl b/server/aidl_api/netd_aidl_interface/6/android/net/INetd.aidl
deleted file mode 100644
index a7952f2..0000000
--- a/server/aidl_api/netd_aidl_interface/6/android/net/INetd.aidl
+++ /dev/null
@@ -1,198 +0,0 @@
-/**
- * Copyright (c) 2016, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file 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 INetd {
-  boolean isAlive();
-  boolean firewallReplaceUidChain(in @utf8InCpp String chainName, boolean isAllowlist, in int[] uids);
-  boolean bandwidthEnableDataSaver(boolean enable);
-  /**
-   * @deprecated use networkCreate() instead.
-   */
-  void networkCreatePhysical(int netId, int permission);
-  /**
-   * @deprecated use networkCreate() instead.
-   */
-  void networkCreateVpn(int netId, boolean secure);
-  void networkDestroy(int netId);
-  void networkAddInterface(int netId, in @utf8InCpp String iface);
-  void networkRemoveInterface(int netId, in @utf8InCpp String iface);
-  void networkAddUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges);
-  void networkRemoveUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges);
-  void networkRejectNonSecureVpn(boolean add, in android.net.UidRangeParcel[] uidRanges);
-  void socketDestroy(in android.net.UidRangeParcel[] uidRanges, in int[] exemptUids);
-  boolean tetherApplyDnsInterfaces();
-  android.net.TetherStatsParcel[] tetherGetStats();
-  void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength);
-  void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength);
-  @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter);
-  void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter, in @utf8InCpp String value);
-  void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid);
-  int ipSecAllocateSpi(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi);
-  void ipSecAddSecurityAssociation(int transformId, int mode, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int underlyingNetId, int spi, int markValue, int markMask, in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits, in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits, in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits, int encapType, int encapLocalPort, int encapRemotePort, int interfaceId);
-  void ipSecDeleteSecurityAssociation(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi, int markValue, int markMask, int interfaceId);
-  void ipSecApplyTransportModeTransform(in ParcelFileDescriptor socket, int transformId, int direction, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi);
-  void ipSecRemoveTransportModeTransform(in ParcelFileDescriptor socket);
-  void ipSecAddSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId);
-  void ipSecUpdateSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId);
-  void ipSecDeleteSecurityPolicy(int transformId, int selAddrFamily, int direction, int markValue, int markMask, int interfaceId);
-  void ipSecAddTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId);
-  void ipSecUpdateTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId);
-  void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName);
-  void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask);
-  void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask);
-  void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode);
-  void idletimerAddInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel);
-  void idletimerRemoveInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel);
-  void strictUidCleartextPenalty(int uid, int policyPenalty);
-  @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix);
-  void clatdStop(in @utf8InCpp String ifName);
-  boolean ipfwdEnabled();
-  @utf8InCpp String[] ipfwdGetRequesterList();
-  void ipfwdEnableForwarding(in @utf8InCpp String requester);
-  void ipfwdDisableForwarding(in @utf8InCpp String requester);
-  void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface);
-  void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface);
-  void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes);
-  void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName);
-  void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes);
-  void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName);
-  void bandwidthSetGlobalAlert(long bytes);
-  void bandwidthAddNaughtyApp(int uid);
-  void bandwidthRemoveNaughtyApp(int uid);
-  void bandwidthAddNiceApp(int uid);
-  void bandwidthRemoveNiceApp(int uid);
-  void tetherStart(in @utf8InCpp String[] dhcpRanges);
-  void tetherStop();
-  boolean tetherIsEnabled();
-  void tetherInterfaceAdd(in @utf8InCpp String ifName);
-  void tetherInterfaceRemove(in @utf8InCpp String ifName);
-  @utf8InCpp String[] tetherInterfaceList();
-  void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs);
-  @utf8InCpp String[] tetherDnsList();
-  void networkAddRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop);
-  void networkRemoveRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop);
-  void networkAddLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid);
-  void networkRemoveLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid);
-  int networkGetDefault();
-  void networkSetDefault(int netId);
-  void networkClearDefault();
-  void networkSetPermissionForNetwork(int netId, int permission);
-  void networkSetPermissionForUser(int permission, in int[] uids);
-  void networkClearPermissionForUser(in int[] uids);
-  void trafficSetNetPermForUids(int permission, in int[] uids);
-  void networkSetProtectAllow(int uid);
-  void networkSetProtectDeny(int uid);
-  boolean networkCanProtect(int uid);
-  void firewallSetFirewallType(int firewalltype);
-  void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule);
-  void firewallSetUidRule(int childChain, int uid, int firewallRule);
-  void firewallEnableChildChain(int childChain, boolean enable);
-  @utf8InCpp String[] interfaceGetList();
-  android.net.InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName);
-  void interfaceSetCfg(in android.net.InterfaceConfigurationParcel cfg);
-  void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable);
-  void interfaceClearAddrs(in @utf8InCpp String ifName);
-  void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable);
-  void interfaceSetMtu(in @utf8InCpp String ifName, int mtu);
-  void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface);
-  void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface);
-  void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues);
-  void registerUnsolicitedEventListener(android.net.INetdUnsolicitedEventListener listener);
-  void firewallAddUidInterfaceRules(in @utf8InCpp String ifName, in int[] uids);
-  void firewallRemoveUidInterfaceRules(in int[] uids);
-  void trafficSwapActiveStatsMap();
-  IBinder getOemNetd();
-  void tetherStartWithConfiguration(in android.net.TetherConfigParcel config);
-  android.net.MarkMaskParcel getFwmarkForNetwork(int netId);
-  void networkAddRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo);
-  void networkUpdateRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo);
-  void networkRemoveRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo);
-  void tetherOffloadRuleAdd(in android.net.TetherOffloadRuleParcel rule);
-  void tetherOffloadRuleRemove(in android.net.TetherOffloadRuleParcel rule);
-  android.net.TetherStatsParcel[] tetherOffloadGetStats();
-  void tetherOffloadSetInterfaceQuota(int ifIndex, long quotaBytes);
-  android.net.TetherStatsParcel tetherOffloadGetAndClearStats(int ifIndex);
-  void networkCreate(in android.net.NativeNetworkConfig config);
-  const int IPV4 = 4;
-  const int IPV6 = 6;
-  const int CONF = 1;
-  const int NEIGH = 2;
-  const String IPSEC_INTERFACE_PREFIX = "ipsec";
-  const int IPV6_ADDR_GEN_MODE_EUI64 = 0;
-  const int IPV6_ADDR_GEN_MODE_NONE = 1;
-  const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2;
-  const int IPV6_ADDR_GEN_MODE_RANDOM = 3;
-  const int IPV6_ADDR_GEN_MODE_DEFAULT = 0;
-  const int PENALTY_POLICY_ACCEPT = 1;
-  const int PENALTY_POLICY_LOG = 2;
-  const int PENALTY_POLICY_REJECT = 3;
-  const int LOCAL_NET_ID = 99;
-  const int DUMMY_NET_ID = 51;
-  const int UNREACHABLE_NET_ID = 52;
-  const String NEXTHOP_NONE = "";
-  const String NEXTHOP_UNREACHABLE = "unreachable";
-  const String NEXTHOP_THROW = "throw";
-  const int PERMISSION_NONE = 0;
-  const int PERMISSION_NETWORK = 1;
-  const int PERMISSION_SYSTEM = 2;
-  const int NO_PERMISSIONS = 0;
-  const int PERMISSION_INTERNET = 4;
-  const int PERMISSION_UPDATE_DEVICE_STATS = 8;
-  const int PERMISSION_UNINSTALLED = -1;
-  /**
-   * @deprecated use FIREWALL_ALLOWLIST.
-   */
-  const int FIREWALL_WHITELIST = 0;
-  const int FIREWALL_ALLOWLIST = 0;
-  /**
-   * @deprecated use FIREWALL_DENYLIST.
-   */
-  const int FIREWALL_BLACKLIST = 1;
-  const int FIREWALL_DENYLIST = 1;
-  const int FIREWALL_RULE_ALLOW = 1;
-  const int FIREWALL_RULE_DENY = 2;
-  const int FIREWALL_CHAIN_NONE = 0;
-  const int FIREWALL_CHAIN_DOZABLE = 1;
-  const int FIREWALL_CHAIN_STANDBY = 2;
-  const int FIREWALL_CHAIN_POWERSAVE = 3;
-  const int FIREWALL_CHAIN_RESTRICTED = 4;
-  const String IF_STATE_UP = "up";
-  const String IF_STATE_DOWN = "down";
-  const String IF_FLAG_BROADCAST = "broadcast";
-  const String IF_FLAG_LOOPBACK = "loopback";
-  const String IF_FLAG_POINTOPOINT = "point-to-point";
-  const String IF_FLAG_RUNNING = "running";
-  const String IF_FLAG_MULTICAST = "multicast";
-}
diff --git a/server/aidl_api/netd_aidl_interface/6/android/net/INetdUnsolicitedEventListener.aidl b/server/aidl_api/netd_aidl_interface/6/android/net/INetdUnsolicitedEventListener.aidl
deleted file mode 100644
index 31775df..0000000
--- a/server/aidl_api/netd_aidl_interface/6/android/net/INetdUnsolicitedEventListener.aidl
+++ /dev/null
@@ -1,48 +0,0 @@
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file 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 INetdUnsolicitedEventListener {
-  oneway void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs, int uid);
-  oneway void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName);
-  oneway void onInterfaceDnsServerInfo(@utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers);
-  oneway void onInterfaceAddressUpdated(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope);
-  oneway void onInterfaceAddressRemoved(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope);
-  oneway void onInterfaceAdded(@utf8InCpp String ifName);
-  oneway void onInterfaceRemoved(@utf8InCpp String ifName);
-  oneway void onInterfaceChanged(@utf8InCpp String ifName, boolean up);
-  oneway void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up);
-  oneway void onRouteChanged(boolean updated, @utf8InCpp String route, @utf8InCpp String gateway, @utf8InCpp String ifName);
-  oneway void onStrictCleartextDetected(int uid, @utf8InCpp String hex);
-}
diff --git a/server/aidl_api/netd_aidl_interface/6/android/net/InterfaceConfigurationParcel.aidl b/server/aidl_api/netd_aidl_interface/6/android/net/InterfaceConfigurationParcel.aidl
deleted file mode 100644
index 1869d8d..0000000
--- a/server/aidl_api/netd_aidl_interface/6/android/net/InterfaceConfigurationParcel.aidl
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file 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 InterfaceConfigurationParcel {
-  @utf8InCpp String ifName;
-  @utf8InCpp String hwAddr;
-  @utf8InCpp String ipv4Addr;
-  int prefixLength;
-  @utf8InCpp String[] flags;
-}
diff --git a/server/aidl_api/netd_aidl_interface/6/android/net/MarkMaskParcel.aidl b/server/aidl_api/netd_aidl_interface/6/android/net/MarkMaskParcel.aidl
deleted file mode 100644
index 8ea20d1..0000000
--- a/server/aidl_api/netd_aidl_interface/6/android/net/MarkMaskParcel.aidl
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file 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 MarkMaskParcel {
-  int mark;
-  int mask;
-}
diff --git a/server/aidl_api/netd_aidl_interface/6/android/net/NativeNetworkConfig.aidl b/server/aidl_api/netd_aidl_interface/6/android/net/NativeNetworkConfig.aidl
deleted file mode 100644
index 76562b2..0000000
--- a/server/aidl_api/netd_aidl_interface/6/android/net/NativeNetworkConfig.aidl
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file 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 */
-@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable
-parcelable NativeNetworkConfig {
-  int netId;
-  android.net.NativeNetworkType networkType = android.net.NativeNetworkType.PHYSICAL;
-  int permission;
-  boolean secure;
-  android.net.NativeVpnType vpnType = android.net.NativeVpnType.PLATFORM;
-}
diff --git a/server/aidl_api/netd_aidl_interface/6/android/net/NativeNetworkType.aidl b/server/aidl_api/netd_aidl_interface/6/android/net/NativeNetworkType.aidl
deleted file mode 100644
index 06c8979..0000000
--- a/server/aidl_api/netd_aidl_interface/6/android/net/NativeNetworkType.aidl
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file 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;
-@Backing(type="int")
-enum NativeNetworkType {
-  PHYSICAL = 0,
-  VIRTUAL = 1,
-}
diff --git a/server/aidl_api/netd_aidl_interface/6/android/net/NativeVpnType.aidl b/server/aidl_api/netd_aidl_interface/6/android/net/NativeVpnType.aidl
deleted file mode 100644
index 8a8be83..0000000
--- a/server/aidl_api/netd_aidl_interface/6/android/net/NativeVpnType.aidl
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file 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;
-@Backing(type="int")
-enum NativeVpnType {
-  SERVICE = 1,
-  PLATFORM = 2,
-  LEGACY = 3,
-  OEM = 4,
-}
diff --git a/server/aidl_api/netd_aidl_interface/6/android/net/RouteInfoParcel.aidl b/server/aidl_api/netd_aidl_interface/6/android/net/RouteInfoParcel.aidl
deleted file mode 100644
index 5ef95e6..0000000
--- a/server/aidl_api/netd_aidl_interface/6/android/net/RouteInfoParcel.aidl
+++ /dev/null
@@ -1,40 +0,0 @@
-/**
- * Copyright (c) 2020, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file 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;
-parcelable RouteInfoParcel {
-  @utf8InCpp String destination;
-  @utf8InCpp String ifName;
-  @utf8InCpp String nextHop;
-  int mtu;
-}
diff --git a/server/aidl_api/netd_aidl_interface/6/android/net/TetherConfigParcel.aidl b/server/aidl_api/netd_aidl_interface/6/android/net/TetherConfigParcel.aidl
deleted file mode 100644
index 7b39c22..0000000
--- a/server/aidl_api/netd_aidl_interface/6/android/net/TetherConfigParcel.aidl
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file 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 TetherConfigParcel {
-  boolean usingLegacyDnsProxy;
-  @utf8InCpp String[] dhcpRanges;
-}
diff --git a/server/aidl_api/netd_aidl_interface/6/android/net/TetherOffloadRuleParcel.aidl b/server/aidl_api/netd_aidl_interface/6/android/net/TetherOffloadRuleParcel.aidl
deleted file mode 100644
index 983e986..0000000
--- a/server/aidl_api/netd_aidl_interface/6/android/net/TetherOffloadRuleParcel.aidl
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file 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 TetherOffloadRuleParcel {
-  int inputInterfaceIndex;
-  int outputInterfaceIndex;
-  byte[] destination;
-  int prefixLength;
-  byte[] srcL2Address;
-  byte[] dstL2Address;
-  int pmtu = 1500;
-}
diff --git a/server/aidl_api/netd_aidl_interface/6/android/net/TetherStatsParcel.aidl b/server/aidl_api/netd_aidl_interface/6/android/net/TetherStatsParcel.aidl
deleted file mode 100644
index 5f1b722..0000000
--- a/server/aidl_api/netd_aidl_interface/6/android/net/TetherStatsParcel.aidl
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file 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 TetherStatsParcel {
-  @utf8InCpp String iface;
-  long rxBytes;
-  long rxPackets;
-  long txBytes;
-  long txPackets;
-  int ifIndex = 0;
-}
diff --git a/server/aidl_api/netd_aidl_interface/6/android/net/UidRangeParcel.aidl b/server/aidl_api/netd_aidl_interface/6/android/net/UidRangeParcel.aidl
deleted file mode 100644
index 72e987a..0000000
--- a/server/aidl_api/netd_aidl_interface/6/android/net/UidRangeParcel.aidl
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file 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 */
-@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable
-parcelable UidRangeParcel {
-  int start;
-  int stop;
-}
diff --git a/server/aidl_api/netd_aidl_interface/7/.hash b/server/aidl_api/netd_aidl_interface/7/.hash
deleted file mode 100644
index cad59df..0000000
--- a/server/aidl_api/netd_aidl_interface/7/.hash
+++ /dev/null
@@ -1 +0,0 @@
-850353de5d19a0dd718f8fd20791f0532e6a34c7
diff --git a/server/aidl_api/netd_aidl_interface/7/android/net/INetd.aidl b/server/aidl_api/netd_aidl_interface/7/android/net/INetd.aidl
deleted file mode 100644
index ec03d86..0000000
--- a/server/aidl_api/netd_aidl_interface/7/android/net/INetd.aidl
+++ /dev/null
@@ -1,200 +0,0 @@
-/**
- * Copyright (c) 2016, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file 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 INetd {
-  boolean isAlive();
-  boolean firewallReplaceUidChain(in @utf8InCpp String chainName, boolean isAllowlist, in int[] uids);
-  boolean bandwidthEnableDataSaver(boolean enable);
-  /**
-   * @deprecated use networkCreate() instead.
-   */
-  void networkCreatePhysical(int netId, int permission);
-  /**
-   * @deprecated use networkCreate() instead.
-   */
-  void networkCreateVpn(int netId, boolean secure);
-  void networkDestroy(int netId);
-  void networkAddInterface(int netId, in @utf8InCpp String iface);
-  void networkRemoveInterface(int netId, in @utf8InCpp String iface);
-  void networkAddUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges);
-  void networkRemoveUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges);
-  void networkRejectNonSecureVpn(boolean add, in android.net.UidRangeParcel[] uidRanges);
-  void socketDestroy(in android.net.UidRangeParcel[] uidRanges, in int[] exemptUids);
-  boolean tetherApplyDnsInterfaces();
-  android.net.TetherStatsParcel[] tetherGetStats();
-  void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength);
-  void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength);
-  @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter);
-  void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter, in @utf8InCpp String value);
-  void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid);
-  int ipSecAllocateSpi(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi);
-  void ipSecAddSecurityAssociation(int transformId, int mode, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int underlyingNetId, int spi, int markValue, int markMask, in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits, in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits, in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits, int encapType, int encapLocalPort, int encapRemotePort, int interfaceId);
-  void ipSecDeleteSecurityAssociation(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi, int markValue, int markMask, int interfaceId);
-  void ipSecApplyTransportModeTransform(in ParcelFileDescriptor socket, int transformId, int direction, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi);
-  void ipSecRemoveTransportModeTransform(in ParcelFileDescriptor socket);
-  void ipSecAddSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId);
-  void ipSecUpdateSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId);
-  void ipSecDeleteSecurityPolicy(int transformId, int selAddrFamily, int direction, int markValue, int markMask, int interfaceId);
-  void ipSecAddTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId);
-  void ipSecUpdateTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId);
-  void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName);
-  void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask);
-  void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask);
-  void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode);
-  void idletimerAddInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel);
-  void idletimerRemoveInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel);
-  void strictUidCleartextPenalty(int uid, int policyPenalty);
-  @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix);
-  void clatdStop(in @utf8InCpp String ifName);
-  boolean ipfwdEnabled();
-  @utf8InCpp String[] ipfwdGetRequesterList();
-  void ipfwdEnableForwarding(in @utf8InCpp String requester);
-  void ipfwdDisableForwarding(in @utf8InCpp String requester);
-  void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface);
-  void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface);
-  void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes);
-  void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName);
-  void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes);
-  void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName);
-  void bandwidthSetGlobalAlert(long bytes);
-  void bandwidthAddNaughtyApp(int uid);
-  void bandwidthRemoveNaughtyApp(int uid);
-  void bandwidthAddNiceApp(int uid);
-  void bandwidthRemoveNiceApp(int uid);
-  void tetherStart(in @utf8InCpp String[] dhcpRanges);
-  void tetherStop();
-  boolean tetherIsEnabled();
-  void tetherInterfaceAdd(in @utf8InCpp String ifName);
-  void tetherInterfaceRemove(in @utf8InCpp String ifName);
-  @utf8InCpp String[] tetherInterfaceList();
-  void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs);
-  @utf8InCpp String[] tetherDnsList();
-  void networkAddRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop);
-  void networkRemoveRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop);
-  void networkAddLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid);
-  void networkRemoveLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid);
-  int networkGetDefault();
-  void networkSetDefault(int netId);
-  void networkClearDefault();
-  void networkSetPermissionForNetwork(int netId, int permission);
-  void networkSetPermissionForUser(int permission, in int[] uids);
-  void networkClearPermissionForUser(in int[] uids);
-  void trafficSetNetPermForUids(int permission, in int[] uids);
-  void networkSetProtectAllow(int uid);
-  void networkSetProtectDeny(int uid);
-  boolean networkCanProtect(int uid);
-  void firewallSetFirewallType(int firewalltype);
-  void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule);
-  void firewallSetUidRule(int childChain, int uid, int firewallRule);
-  void firewallEnableChildChain(int childChain, boolean enable);
-  @utf8InCpp String[] interfaceGetList();
-  android.net.InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName);
-  void interfaceSetCfg(in android.net.InterfaceConfigurationParcel cfg);
-  void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable);
-  void interfaceClearAddrs(in @utf8InCpp String ifName);
-  void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable);
-  void interfaceSetMtu(in @utf8InCpp String ifName, int mtu);
-  void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface);
-  void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface);
-  void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues);
-  void registerUnsolicitedEventListener(android.net.INetdUnsolicitedEventListener listener);
-  void firewallAddUidInterfaceRules(in @utf8InCpp String ifName, in int[] uids);
-  void firewallRemoveUidInterfaceRules(in int[] uids);
-  void trafficSwapActiveStatsMap();
-  IBinder getOemNetd();
-  void tetherStartWithConfiguration(in android.net.TetherConfigParcel config);
-  android.net.MarkMaskParcel getFwmarkForNetwork(int netId);
-  void networkAddRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo);
-  void networkUpdateRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo);
-  void networkRemoveRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo);
-  void tetherOffloadRuleAdd(in android.net.TetherOffloadRuleParcel rule);
-  void tetherOffloadRuleRemove(in android.net.TetherOffloadRuleParcel rule);
-  android.net.TetherStatsParcel[] tetherOffloadGetStats();
-  void tetherOffloadSetInterfaceQuota(int ifIndex, long quotaBytes);
-  android.net.TetherStatsParcel tetherOffloadGetAndClearStats(int ifIndex);
-  void networkCreate(in android.net.NativeNetworkConfig config);
-  void networkAddUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig);
-  void networkRemoveUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig);
-  const int IPV4 = 4;
-  const int IPV6 = 6;
-  const int CONF = 1;
-  const int NEIGH = 2;
-  const String IPSEC_INTERFACE_PREFIX = "ipsec";
-  const int IPV6_ADDR_GEN_MODE_EUI64 = 0;
-  const int IPV6_ADDR_GEN_MODE_NONE = 1;
-  const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2;
-  const int IPV6_ADDR_GEN_MODE_RANDOM = 3;
-  const int IPV6_ADDR_GEN_MODE_DEFAULT = 0;
-  const int PENALTY_POLICY_ACCEPT = 1;
-  const int PENALTY_POLICY_LOG = 2;
-  const int PENALTY_POLICY_REJECT = 3;
-  const int LOCAL_NET_ID = 99;
-  const int DUMMY_NET_ID = 51;
-  const int UNREACHABLE_NET_ID = 52;
-  const String NEXTHOP_NONE = "";
-  const String NEXTHOP_UNREACHABLE = "unreachable";
-  const String NEXTHOP_THROW = "throw";
-  const int PERMISSION_NONE = 0;
-  const int PERMISSION_NETWORK = 1;
-  const int PERMISSION_SYSTEM = 2;
-  const int NO_PERMISSIONS = 0;
-  const int PERMISSION_INTERNET = 4;
-  const int PERMISSION_UPDATE_DEVICE_STATS = 8;
-  const int PERMISSION_UNINSTALLED = -1;
-  /**
-   * @deprecated use FIREWALL_ALLOWLIST.
-   */
-  const int FIREWALL_WHITELIST = 0;
-  const int FIREWALL_ALLOWLIST = 0;
-  /**
-   * @deprecated use FIREWALL_DENYLIST.
-   */
-  const int FIREWALL_BLACKLIST = 1;
-  const int FIREWALL_DENYLIST = 1;
-  const int FIREWALL_RULE_ALLOW = 1;
-  const int FIREWALL_RULE_DENY = 2;
-  const int FIREWALL_CHAIN_NONE = 0;
-  const int FIREWALL_CHAIN_DOZABLE = 1;
-  const int FIREWALL_CHAIN_STANDBY = 2;
-  const int FIREWALL_CHAIN_POWERSAVE = 3;
-  const int FIREWALL_CHAIN_RESTRICTED = 4;
-  const String IF_STATE_UP = "up";
-  const String IF_STATE_DOWN = "down";
-  const String IF_FLAG_BROADCAST = "broadcast";
-  const String IF_FLAG_LOOPBACK = "loopback";
-  const String IF_FLAG_POINTOPOINT = "point-to-point";
-  const String IF_FLAG_RUNNING = "running";
-  const String IF_FLAG_MULTICAST = "multicast";
-}
diff --git a/server/aidl_api/netd_aidl_interface/7/android/net/INetdUnsolicitedEventListener.aidl b/server/aidl_api/netd_aidl_interface/7/android/net/INetdUnsolicitedEventListener.aidl
deleted file mode 100644
index 31775df..0000000
--- a/server/aidl_api/netd_aidl_interface/7/android/net/INetdUnsolicitedEventListener.aidl
+++ /dev/null
@@ -1,48 +0,0 @@
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file 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 INetdUnsolicitedEventListener {
-  oneway void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs, int uid);
-  oneway void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName);
-  oneway void onInterfaceDnsServerInfo(@utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers);
-  oneway void onInterfaceAddressUpdated(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope);
-  oneway void onInterfaceAddressRemoved(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope);
-  oneway void onInterfaceAdded(@utf8InCpp String ifName);
-  oneway void onInterfaceRemoved(@utf8InCpp String ifName);
-  oneway void onInterfaceChanged(@utf8InCpp String ifName, boolean up);
-  oneway void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up);
-  oneway void onRouteChanged(boolean updated, @utf8InCpp String route, @utf8InCpp String gateway, @utf8InCpp String ifName);
-  oneway void onStrictCleartextDetected(int uid, @utf8InCpp String hex);
-}
diff --git a/server/aidl_api/netd_aidl_interface/7/android/net/InterfaceConfigurationParcel.aidl b/server/aidl_api/netd_aidl_interface/7/android/net/InterfaceConfigurationParcel.aidl
deleted file mode 100644
index 1869d8d..0000000
--- a/server/aidl_api/netd_aidl_interface/7/android/net/InterfaceConfigurationParcel.aidl
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file 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 InterfaceConfigurationParcel {
-  @utf8InCpp String ifName;
-  @utf8InCpp String hwAddr;
-  @utf8InCpp String ipv4Addr;
-  int prefixLength;
-  @utf8InCpp String[] flags;
-}
diff --git a/server/aidl_api/netd_aidl_interface/7/android/net/MarkMaskParcel.aidl b/server/aidl_api/netd_aidl_interface/7/android/net/MarkMaskParcel.aidl
deleted file mode 100644
index 8ea20d1..0000000
--- a/server/aidl_api/netd_aidl_interface/7/android/net/MarkMaskParcel.aidl
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file 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 MarkMaskParcel {
-  int mark;
-  int mask;
-}
diff --git a/server/aidl_api/netd_aidl_interface/7/android/net/NativeNetworkConfig.aidl b/server/aidl_api/netd_aidl_interface/7/android/net/NativeNetworkConfig.aidl
deleted file mode 100644
index 76562b2..0000000
--- a/server/aidl_api/netd_aidl_interface/7/android/net/NativeNetworkConfig.aidl
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file 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 */
-@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable
-parcelable NativeNetworkConfig {
-  int netId;
-  android.net.NativeNetworkType networkType = android.net.NativeNetworkType.PHYSICAL;
-  int permission;
-  boolean secure;
-  android.net.NativeVpnType vpnType = android.net.NativeVpnType.PLATFORM;
-}
diff --git a/server/aidl_api/netd_aidl_interface/7/android/net/NativeNetworkType.aidl b/server/aidl_api/netd_aidl_interface/7/android/net/NativeNetworkType.aidl
deleted file mode 100644
index 06c8979..0000000
--- a/server/aidl_api/netd_aidl_interface/7/android/net/NativeNetworkType.aidl
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file 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;
-@Backing(type="int")
-enum NativeNetworkType {
-  PHYSICAL = 0,
-  VIRTUAL = 1,
-}
diff --git a/server/aidl_api/netd_aidl_interface/7/android/net/NativeVpnType.aidl b/server/aidl_api/netd_aidl_interface/7/android/net/NativeVpnType.aidl
deleted file mode 100644
index 8a8be83..0000000
--- a/server/aidl_api/netd_aidl_interface/7/android/net/NativeVpnType.aidl
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file 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;
-@Backing(type="int")
-enum NativeVpnType {
-  SERVICE = 1,
-  PLATFORM = 2,
-  LEGACY = 3,
-  OEM = 4,
-}
diff --git a/server/aidl_api/netd_aidl_interface/7/android/net/RouteInfoParcel.aidl b/server/aidl_api/netd_aidl_interface/7/android/net/RouteInfoParcel.aidl
deleted file mode 100644
index 5ef95e6..0000000
--- a/server/aidl_api/netd_aidl_interface/7/android/net/RouteInfoParcel.aidl
+++ /dev/null
@@ -1,40 +0,0 @@
-/**
- * Copyright (c) 2020, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file 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;
-parcelable RouteInfoParcel {
-  @utf8InCpp String destination;
-  @utf8InCpp String ifName;
-  @utf8InCpp String nextHop;
-  int mtu;
-}
diff --git a/server/aidl_api/netd_aidl_interface/7/android/net/TetherConfigParcel.aidl b/server/aidl_api/netd_aidl_interface/7/android/net/TetherConfigParcel.aidl
deleted file mode 100644
index 7b39c22..0000000
--- a/server/aidl_api/netd_aidl_interface/7/android/net/TetherConfigParcel.aidl
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file 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 TetherConfigParcel {
-  boolean usingLegacyDnsProxy;
-  @utf8InCpp String[] dhcpRanges;
-}
diff --git a/server/aidl_api/netd_aidl_interface/7/android/net/TetherOffloadRuleParcel.aidl b/server/aidl_api/netd_aidl_interface/7/android/net/TetherOffloadRuleParcel.aidl
deleted file mode 100644
index 983e986..0000000
--- a/server/aidl_api/netd_aidl_interface/7/android/net/TetherOffloadRuleParcel.aidl
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file 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 TetherOffloadRuleParcel {
-  int inputInterfaceIndex;
-  int outputInterfaceIndex;
-  byte[] destination;
-  int prefixLength;
-  byte[] srcL2Address;
-  byte[] dstL2Address;
-  int pmtu = 1500;
-}
diff --git a/server/aidl_api/netd_aidl_interface/7/android/net/TetherStatsParcel.aidl b/server/aidl_api/netd_aidl_interface/7/android/net/TetherStatsParcel.aidl
deleted file mode 100644
index 5f1b722..0000000
--- a/server/aidl_api/netd_aidl_interface/7/android/net/TetherStatsParcel.aidl
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file 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 TetherStatsParcel {
-  @utf8InCpp String iface;
-  long rxBytes;
-  long rxPackets;
-  long txBytes;
-  long txPackets;
-  int ifIndex = 0;
-}
diff --git a/server/aidl_api/netd_aidl_interface/7/android/net/UidRangeParcel.aidl b/server/aidl_api/netd_aidl_interface/7/android/net/UidRangeParcel.aidl
deleted file mode 100644
index 72e987a..0000000
--- a/server/aidl_api/netd_aidl_interface/7/android/net/UidRangeParcel.aidl
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file 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 */
-@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable
-parcelable UidRangeParcel {
-  int start;
-  int stop;
-}
diff --git a/server/aidl_api/netd_aidl_interface/7/android/net/netd/aidl/NativeUidRangeConfig.aidl b/server/aidl_api/netd_aidl_interface/7/android/net/netd/aidl/NativeUidRangeConfig.aidl
deleted file mode 100644
index 9bb679f..0000000
--- a/server/aidl_api/netd_aidl_interface/7/android/net/netd/aidl/NativeUidRangeConfig.aidl
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file 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.netd.aidl;
-/* @hide */
-@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable
-parcelable NativeUidRangeConfig {
-  int netId;
-  android.net.UidRangeParcel[] uidRanges;
-  int subPriority;
-}
diff --git a/server/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl b/server/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl
deleted file mode 100644
index ec03d86..0000000
--- a/server/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl
+++ /dev/null
@@ -1,200 +0,0 @@
-/**
- * Copyright (c) 2016, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file 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 INetd {
-  boolean isAlive();
-  boolean firewallReplaceUidChain(in @utf8InCpp String chainName, boolean isAllowlist, in int[] uids);
-  boolean bandwidthEnableDataSaver(boolean enable);
-  /**
-   * @deprecated use networkCreate() instead.
-   */
-  void networkCreatePhysical(int netId, int permission);
-  /**
-   * @deprecated use networkCreate() instead.
-   */
-  void networkCreateVpn(int netId, boolean secure);
-  void networkDestroy(int netId);
-  void networkAddInterface(int netId, in @utf8InCpp String iface);
-  void networkRemoveInterface(int netId, in @utf8InCpp String iface);
-  void networkAddUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges);
-  void networkRemoveUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges);
-  void networkRejectNonSecureVpn(boolean add, in android.net.UidRangeParcel[] uidRanges);
-  void socketDestroy(in android.net.UidRangeParcel[] uidRanges, in int[] exemptUids);
-  boolean tetherApplyDnsInterfaces();
-  android.net.TetherStatsParcel[] tetherGetStats();
-  void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength);
-  void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength);
-  @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter);
-  void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter, in @utf8InCpp String value);
-  void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid);
-  int ipSecAllocateSpi(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi);
-  void ipSecAddSecurityAssociation(int transformId, int mode, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int underlyingNetId, int spi, int markValue, int markMask, in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits, in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits, in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits, int encapType, int encapLocalPort, int encapRemotePort, int interfaceId);
-  void ipSecDeleteSecurityAssociation(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi, int markValue, int markMask, int interfaceId);
-  void ipSecApplyTransportModeTransform(in ParcelFileDescriptor socket, int transformId, int direction, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi);
-  void ipSecRemoveTransportModeTransform(in ParcelFileDescriptor socket);
-  void ipSecAddSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId);
-  void ipSecUpdateSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId);
-  void ipSecDeleteSecurityPolicy(int transformId, int selAddrFamily, int direction, int markValue, int markMask, int interfaceId);
-  void ipSecAddTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId);
-  void ipSecUpdateTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId);
-  void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName);
-  void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask);
-  void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask);
-  void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode);
-  void idletimerAddInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel);
-  void idletimerRemoveInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel);
-  void strictUidCleartextPenalty(int uid, int policyPenalty);
-  @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix);
-  void clatdStop(in @utf8InCpp String ifName);
-  boolean ipfwdEnabled();
-  @utf8InCpp String[] ipfwdGetRequesterList();
-  void ipfwdEnableForwarding(in @utf8InCpp String requester);
-  void ipfwdDisableForwarding(in @utf8InCpp String requester);
-  void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface);
-  void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface);
-  void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes);
-  void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName);
-  void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes);
-  void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName);
-  void bandwidthSetGlobalAlert(long bytes);
-  void bandwidthAddNaughtyApp(int uid);
-  void bandwidthRemoveNaughtyApp(int uid);
-  void bandwidthAddNiceApp(int uid);
-  void bandwidthRemoveNiceApp(int uid);
-  void tetherStart(in @utf8InCpp String[] dhcpRanges);
-  void tetherStop();
-  boolean tetherIsEnabled();
-  void tetherInterfaceAdd(in @utf8InCpp String ifName);
-  void tetherInterfaceRemove(in @utf8InCpp String ifName);
-  @utf8InCpp String[] tetherInterfaceList();
-  void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs);
-  @utf8InCpp String[] tetherDnsList();
-  void networkAddRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop);
-  void networkRemoveRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop);
-  void networkAddLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid);
-  void networkRemoveLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid);
-  int networkGetDefault();
-  void networkSetDefault(int netId);
-  void networkClearDefault();
-  void networkSetPermissionForNetwork(int netId, int permission);
-  void networkSetPermissionForUser(int permission, in int[] uids);
-  void networkClearPermissionForUser(in int[] uids);
-  void trafficSetNetPermForUids(int permission, in int[] uids);
-  void networkSetProtectAllow(int uid);
-  void networkSetProtectDeny(int uid);
-  boolean networkCanProtect(int uid);
-  void firewallSetFirewallType(int firewalltype);
-  void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule);
-  void firewallSetUidRule(int childChain, int uid, int firewallRule);
-  void firewallEnableChildChain(int childChain, boolean enable);
-  @utf8InCpp String[] interfaceGetList();
-  android.net.InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName);
-  void interfaceSetCfg(in android.net.InterfaceConfigurationParcel cfg);
-  void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable);
-  void interfaceClearAddrs(in @utf8InCpp String ifName);
-  void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable);
-  void interfaceSetMtu(in @utf8InCpp String ifName, int mtu);
-  void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface);
-  void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface);
-  void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues);
-  void registerUnsolicitedEventListener(android.net.INetdUnsolicitedEventListener listener);
-  void firewallAddUidInterfaceRules(in @utf8InCpp String ifName, in int[] uids);
-  void firewallRemoveUidInterfaceRules(in int[] uids);
-  void trafficSwapActiveStatsMap();
-  IBinder getOemNetd();
-  void tetherStartWithConfiguration(in android.net.TetherConfigParcel config);
-  android.net.MarkMaskParcel getFwmarkForNetwork(int netId);
-  void networkAddRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo);
-  void networkUpdateRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo);
-  void networkRemoveRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo);
-  void tetherOffloadRuleAdd(in android.net.TetherOffloadRuleParcel rule);
-  void tetherOffloadRuleRemove(in android.net.TetherOffloadRuleParcel rule);
-  android.net.TetherStatsParcel[] tetherOffloadGetStats();
-  void tetherOffloadSetInterfaceQuota(int ifIndex, long quotaBytes);
-  android.net.TetherStatsParcel tetherOffloadGetAndClearStats(int ifIndex);
-  void networkCreate(in android.net.NativeNetworkConfig config);
-  void networkAddUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig);
-  void networkRemoveUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig);
-  const int IPV4 = 4;
-  const int IPV6 = 6;
-  const int CONF = 1;
-  const int NEIGH = 2;
-  const String IPSEC_INTERFACE_PREFIX = "ipsec";
-  const int IPV6_ADDR_GEN_MODE_EUI64 = 0;
-  const int IPV6_ADDR_GEN_MODE_NONE = 1;
-  const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2;
-  const int IPV6_ADDR_GEN_MODE_RANDOM = 3;
-  const int IPV6_ADDR_GEN_MODE_DEFAULT = 0;
-  const int PENALTY_POLICY_ACCEPT = 1;
-  const int PENALTY_POLICY_LOG = 2;
-  const int PENALTY_POLICY_REJECT = 3;
-  const int LOCAL_NET_ID = 99;
-  const int DUMMY_NET_ID = 51;
-  const int UNREACHABLE_NET_ID = 52;
-  const String NEXTHOP_NONE = "";
-  const String NEXTHOP_UNREACHABLE = "unreachable";
-  const String NEXTHOP_THROW = "throw";
-  const int PERMISSION_NONE = 0;
-  const int PERMISSION_NETWORK = 1;
-  const int PERMISSION_SYSTEM = 2;
-  const int NO_PERMISSIONS = 0;
-  const int PERMISSION_INTERNET = 4;
-  const int PERMISSION_UPDATE_DEVICE_STATS = 8;
-  const int PERMISSION_UNINSTALLED = -1;
-  /**
-   * @deprecated use FIREWALL_ALLOWLIST.
-   */
-  const int FIREWALL_WHITELIST = 0;
-  const int FIREWALL_ALLOWLIST = 0;
-  /**
-   * @deprecated use FIREWALL_DENYLIST.
-   */
-  const int FIREWALL_BLACKLIST = 1;
-  const int FIREWALL_DENYLIST = 1;
-  const int FIREWALL_RULE_ALLOW = 1;
-  const int FIREWALL_RULE_DENY = 2;
-  const int FIREWALL_CHAIN_NONE = 0;
-  const int FIREWALL_CHAIN_DOZABLE = 1;
-  const int FIREWALL_CHAIN_STANDBY = 2;
-  const int FIREWALL_CHAIN_POWERSAVE = 3;
-  const int FIREWALL_CHAIN_RESTRICTED = 4;
-  const String IF_STATE_UP = "up";
-  const String IF_STATE_DOWN = "down";
-  const String IF_FLAG_BROADCAST = "broadcast";
-  const String IF_FLAG_LOOPBACK = "loopback";
-  const String IF_FLAG_POINTOPOINT = "point-to-point";
-  const String IF_FLAG_RUNNING = "running";
-  const String IF_FLAG_MULTICAST = "multicast";
-}
diff --git a/server/aidl_api/netd_aidl_interface/current/android/net/INetdUnsolicitedEventListener.aidl b/server/aidl_api/netd_aidl_interface/current/android/net/INetdUnsolicitedEventListener.aidl
deleted file mode 100644
index 31775df..0000000
--- a/server/aidl_api/netd_aidl_interface/current/android/net/INetdUnsolicitedEventListener.aidl
+++ /dev/null
@@ -1,48 +0,0 @@
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file 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 INetdUnsolicitedEventListener {
-  oneway void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs, int uid);
-  oneway void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName);
-  oneway void onInterfaceDnsServerInfo(@utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers);
-  oneway void onInterfaceAddressUpdated(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope);
-  oneway void onInterfaceAddressRemoved(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope);
-  oneway void onInterfaceAdded(@utf8InCpp String ifName);
-  oneway void onInterfaceRemoved(@utf8InCpp String ifName);
-  oneway void onInterfaceChanged(@utf8InCpp String ifName, boolean up);
-  oneway void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up);
-  oneway void onRouteChanged(boolean updated, @utf8InCpp String route, @utf8InCpp String gateway, @utf8InCpp String ifName);
-  oneway void onStrictCleartextDetected(int uid, @utf8InCpp String hex);
-}
diff --git a/server/aidl_api/netd_aidl_interface/current/android/net/InterfaceConfigurationParcel.aidl b/server/aidl_api/netd_aidl_interface/current/android/net/InterfaceConfigurationParcel.aidl
deleted file mode 100644
index 1869d8d..0000000
--- a/server/aidl_api/netd_aidl_interface/current/android/net/InterfaceConfigurationParcel.aidl
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file 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 InterfaceConfigurationParcel {
-  @utf8InCpp String ifName;
-  @utf8InCpp String hwAddr;
-  @utf8InCpp String ipv4Addr;
-  int prefixLength;
-  @utf8InCpp String[] flags;
-}
diff --git a/server/aidl_api/netd_aidl_interface/current/android/net/MarkMaskParcel.aidl b/server/aidl_api/netd_aidl_interface/current/android/net/MarkMaskParcel.aidl
deleted file mode 100644
index 8ea20d1..0000000
--- a/server/aidl_api/netd_aidl_interface/current/android/net/MarkMaskParcel.aidl
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file 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 MarkMaskParcel {
-  int mark;
-  int mask;
-}
diff --git a/server/aidl_api/netd_aidl_interface/current/android/net/NativeNetworkConfig.aidl b/server/aidl_api/netd_aidl_interface/current/android/net/NativeNetworkConfig.aidl
deleted file mode 100644
index 76562b2..0000000
--- a/server/aidl_api/netd_aidl_interface/current/android/net/NativeNetworkConfig.aidl
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file 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 */
-@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable
-parcelable NativeNetworkConfig {
-  int netId;
-  android.net.NativeNetworkType networkType = android.net.NativeNetworkType.PHYSICAL;
-  int permission;
-  boolean secure;
-  android.net.NativeVpnType vpnType = android.net.NativeVpnType.PLATFORM;
-}
diff --git a/server/aidl_api/netd_aidl_interface/current/android/net/NativeNetworkType.aidl b/server/aidl_api/netd_aidl_interface/current/android/net/NativeNetworkType.aidl
deleted file mode 100644
index 06c8979..0000000
--- a/server/aidl_api/netd_aidl_interface/current/android/net/NativeNetworkType.aidl
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file 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;
-@Backing(type="int")
-enum NativeNetworkType {
-  PHYSICAL = 0,
-  VIRTUAL = 1,
-}
diff --git a/server/aidl_api/netd_aidl_interface/current/android/net/NativeVpnType.aidl b/server/aidl_api/netd_aidl_interface/current/android/net/NativeVpnType.aidl
deleted file mode 100644
index 8a8be83..0000000
--- a/server/aidl_api/netd_aidl_interface/current/android/net/NativeVpnType.aidl
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file 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;
-@Backing(type="int")
-enum NativeVpnType {
-  SERVICE = 1,
-  PLATFORM = 2,
-  LEGACY = 3,
-  OEM = 4,
-}
diff --git a/server/aidl_api/netd_aidl_interface/current/android/net/RouteInfoParcel.aidl b/server/aidl_api/netd_aidl_interface/current/android/net/RouteInfoParcel.aidl
deleted file mode 100644
index 5ef95e6..0000000
--- a/server/aidl_api/netd_aidl_interface/current/android/net/RouteInfoParcel.aidl
+++ /dev/null
@@ -1,40 +0,0 @@
-/**
- * Copyright (c) 2020, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file 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;
-parcelable RouteInfoParcel {
-  @utf8InCpp String destination;
-  @utf8InCpp String ifName;
-  @utf8InCpp String nextHop;
-  int mtu;
-}
diff --git a/server/aidl_api/netd_aidl_interface/current/android/net/TetherConfigParcel.aidl b/server/aidl_api/netd_aidl_interface/current/android/net/TetherConfigParcel.aidl
deleted file mode 100644
index 7b39c22..0000000
--- a/server/aidl_api/netd_aidl_interface/current/android/net/TetherConfigParcel.aidl
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file 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 TetherConfigParcel {
-  boolean usingLegacyDnsProxy;
-  @utf8InCpp String[] dhcpRanges;
-}
diff --git a/server/aidl_api/netd_aidl_interface/current/android/net/TetherOffloadRuleParcel.aidl b/server/aidl_api/netd_aidl_interface/current/android/net/TetherOffloadRuleParcel.aidl
deleted file mode 100644
index 983e986..0000000
--- a/server/aidl_api/netd_aidl_interface/current/android/net/TetherOffloadRuleParcel.aidl
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file 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 TetherOffloadRuleParcel {
-  int inputInterfaceIndex;
-  int outputInterfaceIndex;
-  byte[] destination;
-  int prefixLength;
-  byte[] srcL2Address;
-  byte[] dstL2Address;
-  int pmtu = 1500;
-}
diff --git a/server/aidl_api/netd_aidl_interface/current/android/net/TetherStatsParcel.aidl b/server/aidl_api/netd_aidl_interface/current/android/net/TetherStatsParcel.aidl
deleted file mode 100644
index 5f1b722..0000000
--- a/server/aidl_api/netd_aidl_interface/current/android/net/TetherStatsParcel.aidl
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file 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 TetherStatsParcel {
-  @utf8InCpp String iface;
-  long rxBytes;
-  long rxPackets;
-  long txBytes;
-  long txPackets;
-  int ifIndex = 0;
-}
diff --git a/server/aidl_api/netd_aidl_interface/current/android/net/UidRangeParcel.aidl b/server/aidl_api/netd_aidl_interface/current/android/net/UidRangeParcel.aidl
deleted file mode 100644
index 72e987a..0000000
--- a/server/aidl_api/netd_aidl_interface/current/android/net/UidRangeParcel.aidl
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file 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 */
-@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable
-parcelable UidRangeParcel {
-  int start;
-  int stop;
-}
diff --git a/server/aidl_api/netd_aidl_interface/current/android/net/netd/aidl/NativeUidRangeConfig.aidl b/server/aidl_api/netd_aidl_interface/current/android/net/netd/aidl/NativeUidRangeConfig.aidl
deleted file mode 100644
index 9bb679f..0000000
--- a/server/aidl_api/netd_aidl_interface/current/android/net/netd/aidl/NativeUidRangeConfig.aidl
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file 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.netd.aidl;
-/* @hide */
-@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable
-parcelable NativeUidRangeConfig {
-  int netId;
-  android.net.UidRangeParcel[] uidRanges;
-  int subPriority;
-}
diff --git a/server/aidl_api/netd_event_listener_interface/1/.hash b/server/aidl_api/netd_event_listener_interface/1/.hash
deleted file mode 100644
index f39f730..0000000
--- a/server/aidl_api/netd_event_listener_interface/1/.hash
+++ /dev/null
@@ -1 +0,0 @@
-8e27594d285ca7c567d87e8cf74766c27647e02b
diff --git a/server/aidl_api/netd_event_listener_interface/1/android/net/metrics/INetdEventListener.aidl b/server/aidl_api/netd_event_listener_interface/1/android/net/metrics/INetdEventListener.aidl
deleted file mode 100644
index 9898a67..0000000
--- a/server/aidl_api/netd_event_listener_interface/1/android/net/metrics/INetdEventListener.aidl
+++ /dev/null
@@ -1,34 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a frozen 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.metrics;
-interface INetdEventListener {
-  oneway void onDnsEvent(int netId, int eventType, int returnCode, int latencyMs, @utf8InCpp String hostname, in @utf8InCpp String[] ipAddresses, int ipAddressesCount, int uid);
-  oneway void onPrivateDnsValidationEvent(int netId, String ipAddress, String hostname, boolean validated);
-  oneway void onConnectEvent(int netId, int error, int latencyMs, String ipAddr, int port, int uid);
-  oneway void onWakeupEvent(String prefix, int uid, int ethertype, int ipNextHeader, in byte[] dstHw, String srcIp, String dstIp, int srcPort, int dstPort, long timestampNs);
-  oneway void onTcpSocketStatsEvent(in int[] networkIds, in int[] sentPackets, in int[] lostPackets, in int[] rttUs, in int[] sentAckDiffMs);
-  oneway void onNat64PrefixEvent(int netId, boolean added, @utf8InCpp String prefixString, int prefixLength);
-  const int EVENT_GETADDRINFO = 1;
-  const int EVENT_GETHOSTBYNAME = 2;
-  const int EVENT_GETHOSTBYADDR = 3;
-  const int EVENT_RES_NSEND = 4;
-  const int REPORTING_LEVEL_NONE = 0;
-  const int REPORTING_LEVEL_METRICS = 1;
-  const int REPORTING_LEVEL_FULL = 2;
-  const int DNS_REPORTED_IP_ADDRESSES_LIMIT = 10;
-}
diff --git a/server/aidl_api/netd_event_listener_interface/current/android/net/metrics/INetdEventListener.aidl b/server/aidl_api/netd_event_listener_interface/current/android/net/metrics/INetdEventListener.aidl
deleted file mode 100644
index d71c3f2..0000000
--- a/server/aidl_api/netd_event_listener_interface/current/android/net/metrics/INetdEventListener.aidl
+++ /dev/null
@@ -1,35 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// 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.metrics;
-/* @hide */
-interface INetdEventListener {
-  oneway void onDnsEvent(int netId, int eventType, int returnCode, int latencyMs, @utf8InCpp String hostname, in @utf8InCpp String[] ipAddresses, int ipAddressesCount, int uid);
-  oneway void onPrivateDnsValidationEvent(int netId, String ipAddress, String hostname, boolean validated);
-  oneway void onConnectEvent(int netId, int error, int latencyMs, String ipAddr, int port, int uid);
-  oneway void onWakeupEvent(String prefix, int uid, int ethertype, int ipNextHeader, in byte[] dstHw, String srcIp, String dstIp, int srcPort, int dstPort, long timestampNs);
-  oneway void onTcpSocketStatsEvent(in int[] networkIds, in int[] sentPackets, in int[] lostPackets, in int[] rttUs, in int[] sentAckDiffMs);
-  oneway void onNat64PrefixEvent(int netId, boolean added, @utf8InCpp String prefixString, int prefixLength);
-  const int EVENT_GETADDRINFO = 1;
-  const int EVENT_GETHOSTBYNAME = 2;
-  const int EVENT_GETHOSTBYADDR = 3;
-  const int EVENT_RES_NSEND = 4;
-  const int REPORTING_LEVEL_NONE = 0;
-  const int REPORTING_LEVEL_METRICS = 1;
-  const int REPORTING_LEVEL_FULL = 2;
-  const int DNS_REPORTED_IP_ADDRESSES_LIMIT = 10;
-}
diff --git a/server/binder/android/net/INetd.aidl b/server/binder/android/net/INetd.aidl
deleted file mode 100644
index d6398c1..0000000
--- a/server/binder/android/net/INetd.aidl
+++ /dev/null
@@ -1,1380 +0,0 @@
-/**
- * Copyright (c) 2016, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.net.INetdUnsolicitedEventListener;
-import android.net.InterfaceConfigurationParcel;
-import android.net.MarkMaskParcel;
-import android.net.NativeNetworkConfig;
-import android.net.RouteInfoParcel;
-import android.net.TetherConfigParcel;
-import android.net.TetherOffloadRuleParcel;
-import android.net.TetherStatsParcel;
-import android.net.UidRangeParcel;
-import android.net.netd.aidl.NativeUidRangeConfig;
-
-/** {@hide} */
-interface INetd {
-    /**
-     * Returns true if the service is responding.
-     */
-    boolean isAlive();
-
-    /**
-     * Replaces the contents of the specified UID-based firewall chain.
-     *
-     * The chain may be an allowlist chain or a denylist chain. A denylist chain contains DROP
-     * rules for the specified UIDs and a RETURN rule at the end. An allowlist chain contains RETURN
-     * rules for the system UID range (0 to {@code UID_APP} - 1), RETURN rules for for the specified
-     * UIDs, and a DROP rule at the end. The chain will be created if it does not exist.
-     *
-     * @param chainName The name of the chain to replace.
-     * @param isAllowlist Whether this is an allowlist or denylist chain.
-     * @param uids The list of UIDs to allow/deny.
-     * @return true if the chain was successfully replaced, false otherwise.
-     */
-    boolean firewallReplaceUidChain(in @utf8InCpp String chainName,
-                                    boolean isAllowlist,
-                                    in int[] uids);
-
-    /**
-     * Enables or disables data saver mode on costly network interfaces.
-     *
-     * - When disabled, all packets to/from apps in the penalty box chain are rejected on costly
-     *   interfaces. Traffic to/from other apps or on other network interfaces is allowed.
-     * - When enabled, only apps that are in the happy box chain and not in the penalty box chain
-     *   are allowed network connectivity on costly interfaces. All other packets on these
-     *   interfaces are rejected. The happy box chain always contains all system UIDs; to disallow
-     *   traffic from system UIDs, place them in the penalty box chain.
-     *
-     * By default, data saver mode is disabled. This command has no effect but might still return an
-     * error) if {@code enable} is the same as the current value.
-     *
-     * @param enable whether to enable or disable data saver mode.
-     * @return true if the if the operation was successful, false otherwise.
-     */
-    boolean bandwidthEnableDataSaver(boolean enable);
-
-    /**
-     * Creates a physical network (i.e., one containing physical interfaces.
-     * @deprecated use networkCreate() instead.
-     *
-     * @param netId the networkId to create.
-     * @param permission the permission necessary to use the network. Must be one of
-     *         PERMISSION_NONE/PERMISSION_NETWORK/PERMISSION_SYSTEM.
-     *
-     * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
-     *         unix errno.
-     */
-    void networkCreatePhysical(int netId, int permission);
-
-    /**
-     * Creates a VPN network.
-     * @deprecated use networkCreate() instead.
-     *
-     * @param netId the network to create.
-     * @param secure whether unprivileged apps are allowed to bypass the VPN.
-     *
-     * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
-     *         unix errno.
-     */
-    void networkCreateVpn(int netId, boolean secure);
-
-    /**
-     * Destroys a network. Any interfaces added to the network are removed, and the network ceases
-     * to be the default network.
-     *
-     * @param netId the network to destroy.
-     *
-     * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
-     *         unix errno.
-     */
-    void networkDestroy(int netId);
-
-    /**
-     * Adds an interface to a network. The interface must not be assigned to any network, including
-     * the specified network.
-     *
-     * @param netId the network to add the interface to.
-     * @param interface the name of the interface to add.
-     *
-     * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
-     *         unix errno.
-     */
-    void networkAddInterface(int netId, in @utf8InCpp String iface);
-
-    /**
-     * Adds an interface to a network. The interface must be assigned to the specified network.
-     *
-     * @param netId the network to remove the interface from.
-     * @param interface the name of the interface to remove.
-     *
-     * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
-     *         unix errno.
-     */
-    void networkRemoveInterface(int netId, in @utf8InCpp String iface);
-
-    /**
-     * Adds the specified UID ranges to the specified network. The network can be physical or
-     * virtual. Traffic from the UID ranges will be routed to the network by default.
-     *
-     * @param netId the network ID of the network to add the ranges to.
-     * @param uidRanges a set of non-overlapping ranges of UIDs to add. These exact ranges
-     *        must not overlap with existing ranges assigned to this network.
-     *
-     * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
-     *         unix errno.
-     */
-    void networkAddUidRanges(int netId, in UidRangeParcel[] uidRanges);
-
-    /**
-     * Remove the specified UID ranges from the specified network. The network can be physical or
-     * virtual. Traffic from the UID ranges will no longer be routed to the network by default.
-     *
-     * @param netId the network ID of the network to remove the ranges from.
-     * @param uidRanges a set of non-overlapping ranges of UIDs to remove. These exact ranges
-     *        must already be assigned to this network.
-     *
-     * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
-     *         unix errno.
-     */
-    void networkRemoveUidRanges(int netId, in UidRangeParcel[] uidRanges);
-
-    /**
-     * Adds or removes one rule for each supplied UID range to prohibit all network activity outside
-     * of secure VPN.
-     *
-     * When a UID is covered by one of these rules, traffic sent through any socket that is not
-     * protected or explicitly overriden by the system will be rejected. The kernel will respond
-     * with an ICMP prohibit message.
-     *
-     * Initially, there are no such rules. Any rules that are added will only last until the next
-     * restart of netd or the device.
-     *
-     * @param add {@code true} if the specified UID ranges should be denied access to any network
-     *        which is not secure VPN by adding rules, {@code false} to remove existing rules.
-     * @param uidRanges a set of non-overlapping, contiguous ranges of UIDs to which to apply or
-     *        remove this restriction.
-     *        <p> Added rules should not overlap with existing rules. Likewise, removed rules should
-     *        each correspond to an existing rule.
-     *
-     * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
-     *         unix errno.
-     */
-    void networkRejectNonSecureVpn(boolean add, in UidRangeParcel[] uidRanges);
-
-    /**
-     * Administratively closes sockets belonging to the specified UIDs.
-     */
-    void socketDestroy(in UidRangeParcel[] uidRanges, in int[] exemptUids);
-
-    /**
-     * Instruct the tethering DNS server to reevaluated serving interfaces.
-     * This is needed to for the DNS server to observe changes in the set
-     * of potential listening IP addresses. (Listening on wildcard addresses
-     * can turn the device into an open resolver; b/7530468)
-     *
-     * TODO: Return something richer than just a boolean.
-     */
-    boolean tetherApplyDnsInterfaces();
-
-    /**
-     * Return tethering statistics.
-     *
-     * @return an array of TetherStatsParcel, where each entry contains the upstream interface
-     *         name and its tethering statistics since netd startup.
-     *         There will only ever be one entry for a given interface.
-     * @throws ServiceSpecificException in case of failure, with an error code indicating the
-     *         cause of the failure.
-     */
-    TetherStatsParcel[] tetherGetStats();
-
-    /**
-     * Add/Remove and IP address from an interface.
-     *
-     * @param ifName the interface name
-     * @param addrString the IP address to add/remove as a string literal
-     * @param prefixLength the prefix length associated with this IP address
-     *
-     * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
-     *         unix errno.
-     */
-    void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString,
-            int prefixLength);
-    void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString,
-            int prefixLength);
-
-    /**
-     * Set and get /proc/sys/net interface configuration parameters.
-     *
-     * @param ipversion One of IPV4/IPV6 integers, indicating the desired IP version directory.
-     * @param which One of CONF/NEIGH integers, indicating the desired parameter category directory.
-     * @param ifname The interface name portion of the path; may also be "all" or "default".
-     * @param parameter The parameter name portion of the path.
-     * @param value The value string to be written into the assembled path.
-     *
-     * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
-     *         unix errno.
-     */
-
-    const int IPV4  = 4;
-    const int IPV6  = 6;
-    const int CONF  = 1;
-    const int NEIGH = 2;
-    @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname,
-            in @utf8InCpp String parameter);
-    void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname,
-            in @utf8InCpp String parameter, in @utf8InCpp String value);
-
-   /**
-    * Sets owner of socket ParcelFileDescriptor to the new UID, checking to ensure that the caller's
-    * uid is that of the old owner's, and that this is a UDP-encap socket
-    *
-    * @param ParcelFileDescriptor socket Socket file descriptor
-    * @param int newUid UID of the new socket fd owner
-    */
-    void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid);
-
-   /**
-    * Reserve an SPI from the kernel
-    *
-    * @param transformId a unique identifier for allocated resources
-    * @param sourceAddress InetAddress as string for the sending endpoint
-    * @param destinationAddress InetAddress as string for the receiving endpoint
-    * @param spi a requested 32-bit unique ID or 0 to request random allocation
-    * @return the SPI that was allocated or 0 if failed
-    */
-    int ipSecAllocateSpi(
-            int transformId,
-            in @utf8InCpp String sourceAddress,
-            in @utf8InCpp String destinationAddress,
-            int spi);
-
-   /**
-    * Create an IpSec Security Association describing how ip(v6) traffic will be encrypted
-    * or decrypted.
-    *
-    * @param transformId a unique identifier for allocated resources
-    * @param mode either Transport or Tunnel mode
-    * @param sourceAddress InetAddress as string for the sending endpoint
-    * @param destinationAddress InetAddress as string for the receiving endpoint
-    * @param underlyingNetId the netId of the network to which the SA is applied. Only accepted for
-    *        tunnel mode SAs.
-    * @param spi a 32-bit unique ID allocated to the user
-    * @param markValue a 32-bit unique ID chosen by the user
-    * @param markMask a 32-bit mask chosen by the user
-    * @param authAlgo a string identifying the authentication algorithm to be used
-    * @param authKey a byte array containing the authentication key
-    * @param authTruncBits the truncation length of the MAC produced by the authentication algorithm
-    * @param cryptAlgo a string identifying the encryption algorithm to be used
-    * @param cryptKey a byte arrray containing the encryption key
-    * @param cryptTruncBits unused parameter
-    * @param aeadAlgo a string identifying the authenticated encryption algorithm to be used
-    * @param aeadKey a byte arrray containing the key to be used in authenticated encryption
-    * @param aeadIcvBits the truncation length of the ICV produced by the authentication algorithm
-    *        (similar to authTruncBits in function)
-    * @param encapType encapsulation type used (if any) for the udp encap socket
-    * @param encapLocalPort the port number on the host to be used in encap packets
-    * @param encapRemotePort the port number of the remote to be used for encap packets
-    * @param interfaceId the identifier for the IPsec tunnel interface.
-    *        Only accepted for tunnel mode SAs.
-    */
-    void ipSecAddSecurityAssociation(
-            int transformId,
-            int mode,
-            in @utf8InCpp String sourceAddress,
-            in @utf8InCpp String destinationAddress,
-            int underlyingNetId,
-            int spi,
-            int markValue,
-            int markMask,
-            in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits,
-            in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits,
-            in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits,
-            int encapType,
-            int encapLocalPort,
-            int encapRemotePort,
-            int interfaceId);
-
-   /**
-    * Delete a previously created security association identified by the provided parameters
-    *
-    * @param transformId a unique identifier for allocated resources
-    * @param sourceAddress InetAddress as string for the sending endpoint
-    * @param destinationAddress InetAddress as string for the receiving endpoint
-    * @param spi a requested 32-bit unique ID allocated to the user
-    * @param markValue a 32-bit unique ID chosen by the user
-    * @param markMask a 32-bit mask chosen by the user
-    * @param interfaceId the identifier for the IPsec tunnel interface.
-    */
-    void ipSecDeleteSecurityAssociation(
-            int transformId,
-            in @utf8InCpp String sourceAddress,
-            in @utf8InCpp String destinationAddress,
-            int spi,
-            int markValue,
-            int markMask,
-            int interfaceId);
-
-   /**
-    * Apply a previously created SA to a specified socket, starting IPsec on that socket
-    *
-    * @param socket a user-provided socket that will have IPsec applied
-    * @param transformId a unique identifier for allocated resources
-    * @param direction DIRECTION_IN or DIRECTION_OUT
-    * @param sourceAddress InetAddress as string for the sending endpoint
-    * @param destinationAddress InetAddress as string for the receiving endpoint
-    * @param spi a 32-bit unique ID allocated to the user (socket owner)
-    */
-    void ipSecApplyTransportModeTransform(
-            in ParcelFileDescriptor socket,
-            int transformId,
-            int direction,
-            in @utf8InCpp String sourceAddress,
-            in @utf8InCpp String destinationAddress,
-            int spi);
-
-   /**
-    * Remove an IPsec SA from a given socket. This will allow unencrypted traffic to flow
-    * on that socket if a transform had been previously applied.
-    *
-    * @param socket a user-provided socket from which to remove any IPsec configuration
-    */
-    void ipSecRemoveTransportModeTransform(
-            in ParcelFileDescriptor socket);
-
-   /**
-    * Adds an IPsec global policy.
-    *
-    * @param transformId a unique identifier for allocated resources
-    * @param selAddrFamily the address family identifier for the selector
-    * @param direction DIRECTION_IN or DIRECTION_OUT
-    * @param tmplSrcAddress InetAddress as string for the sending endpoint
-    * @param tmplDstAddress InetAddress as string for the receiving endpoint
-    * @param spi a 32-bit unique ID allocated to the user
-    * @param markValue a 32-bit unique ID chosen by the user
-    * @param markMask a 32-bit mask chosen by the user
-    * @param interfaceId the identifier for the IPsec tunnel interface.
-    */
-    void ipSecAddSecurityPolicy(
-            int transformId,
-            int selAddrFamily,
-            int direction,
-            in @utf8InCpp String tmplSrcAddress,
-            in @utf8InCpp String tmplDstAddress,
-            int spi,
-            int markValue,
-            int markMask,
-            int interfaceId);
-
-   /**
-    * Updates an IPsec global policy.
-    *
-    * @param transformId a unique identifier for allocated resources
-    * @param selAddrFamily the address family identifier for the selector
-    * @param direction DIRECTION_IN or DIRECTION_OUT
-    * @param tmplSrcAddress InetAddress as string for the sending endpoint
-    * @param tmplDstAddress InetAddress as string for the receiving endpoint
-    * @param spi a 32-bit unique ID allocated to the user
-    * @param markValue a 32-bit unique ID chosen by the user
-    * @param markMask a 32-bit mask chosen by the user
-    * @param interfaceId the identifier for the IPsec tunnel interface.
-    */
-    void ipSecUpdateSecurityPolicy(
-            int transformId,
-            int selAddrFamily,
-            int direction,
-            in @utf8InCpp String tmplSrcAddress,
-            in @utf8InCpp String tmplDstAddress,
-            int spi,
-            int markValue,
-            int markMask,
-            int interfaceId);
-
-   /**
-    * Deletes an IPsec global policy.
-    *
-    * Deletion of global policies does not do any matching based on the templates, thus
-    * template source/destination addresses are not needed (as opposed to add/update).
-    *
-    * @param transformId a unique identifier for allocated resources
-    * @param selAddrFamily the address family identifier for the selector
-    * @param direction DIRECTION_IN or DIRECTION_OUT
-    * @param markValue a 32-bit unique ID chosen by the user
-    * @param markMask a 32-bit mask chosen by the user
-    * @param interfaceId the identifier for the IPsec tunnel interface.
-    */
-    void ipSecDeleteSecurityPolicy(
-            int transformId,
-            int selAddrFamily,
-            int direction,
-            int markValue,
-            int markMask,
-            int interfaceId);
-
-    // This could not be declared as @uft8InCpp; thus, when used in native code it must be
-    // converted from a UTF-16 string to an ASCII string.
-    const String IPSEC_INTERFACE_PREFIX = "ipsec";
-
-   /**
-    * Add a IPsec Tunnel Interface.
-    *
-    * @param devName a unique identifier that represents the name of the device
-    * @param localAddress InetAddress as string for the local endpoint
-    * @param remoteAddress InetAddress as string for the remote endpoint
-    * @param iKey, to match Policies and SAs for input packets.
-    * @param oKey, to match Policies and SAs for output packets.
-    * @param interfaceId the identifier for the IPsec tunnel interface.
-    */
-    void ipSecAddTunnelInterface(
-            in @utf8InCpp String deviceName,
-            in @utf8InCpp String localAddress,
-            in @utf8InCpp String remoteAddress,
-            int iKey,
-            int oKey,
-            int interfaceId);
-
-   /**
-    * Update a IPsec Tunnel Interface.
-    *
-    * @param devName a unique identifier that represents the name of the device
-    * @param localAddress InetAddress as string for the local endpoint
-    * @param remoteAddress InetAddress as string for the remote endpoint
-    * @param iKey, to match Policies and SAs for input packets.
-    * @param oKey, to match Policies and SAs for output packets.
-    * @param interfaceId the identifier for the IPsec tunnel interface.
-    */
-    void ipSecUpdateTunnelInterface(
-            in @utf8InCpp String deviceName,
-            in @utf8InCpp String localAddress,
-            in @utf8InCpp String remoteAddress,
-            int iKey,
-            int oKey,
-            int interfaceId);
-
-   /**
-    * Removes a IPsec Tunnel Interface.
-    *
-    * @param devName a unique identifier that represents the name of the device
-    */
-    void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName);
-
-   /**
-    * Request notification of wakeup packets arriving on an interface. Notifications will be
-    * delivered to INetdEventListener.onWakeupEvent().
-    *
-    * @param ifName the interface
-    * @param prefix arbitrary string used to identify wakeup sources in onWakeupEvent
-    */
-    void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask);
-
-   /**
-    * Stop notification of wakeup packets arriving on an interface.
-    *
-    * @param ifName the interface
-    * @param prefix arbitrary string used to identify wakeup sources in onWakeupEvent
-    */
-    void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask);
-
-    const int IPV6_ADDR_GEN_MODE_EUI64 = 0;
-    const int IPV6_ADDR_GEN_MODE_NONE = 1;
-    const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2;
-    const int IPV6_ADDR_GEN_MODE_RANDOM = 3;
-
-    const int IPV6_ADDR_GEN_MODE_DEFAULT = 0;
-   /**
-    * Set IPv6 address generation mode. IPv6 should be disabled before changing mode.
-    *
-    * @param mode SLAAC address generation mechanism to use
-    */
-    void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode);
-
-   /**
-    * Add idletimer for specific interface
-    *
-    * @param ifName Name of target interface
-    * @param timeout The time in seconds that will trigger idletimer
-    * @param classLabel The unique identifier for this idletimer
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void idletimerAddInterface(
-            in @utf8InCpp String ifName,
-            int timeout,
-            in @utf8InCpp String classLabel);
-
-   /**
-    * Remove idletimer for specific interface
-    *
-    * @param ifName Name of target interface
-    * @param timeout The time in seconds that will trigger idletimer
-    * @param classLabel The unique identifier for this idletimer
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void idletimerRemoveInterface(
-            in @utf8InCpp String ifName,
-            int timeout,
-            in @utf8InCpp String classLabel);
-
-    const int PENALTY_POLICY_ACCEPT = 1;
-    const int PENALTY_POLICY_LOG = 2;
-    const int PENALTY_POLICY_REJECT = 3;
-
-   /**
-    * Offers to detect sockets sending data not wrapped inside a layer of SSL/TLS encryption.
-    *
-    * @param uid Uid of the app
-    * @param policyPenalty The penalty policy of the app
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void strictUidCleartextPenalty(int uid, int policyPenalty);
-
-   /**
-    * Start clatd
-    *
-    * @param ifName interface name to start clatd
-    * @param nat64Prefix the NAT64 prefix, e.g., "2001:db8:64::/96".
-    * @return a string, the IPv6 address that will be used for 464xlat.
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix);
-
-   /**
-    * Stop clatd
-    *
-    * @param ifName interface name to stop clatd
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void clatdStop(in @utf8InCpp String ifName);
-
-   /**
-    * Get status of IP forwarding
-    *
-    * @return true if IP forwarding is enabled, false otherwise.
-    */
-    boolean ipfwdEnabled();
-
-   /**
-    * Get requester list of IP forwarding
-    *
-    * @return An array of strings containing requester list of IP forwarding
-    */
-    @utf8InCpp String[] ipfwdGetRequesterList();
-
-   /**
-    * Enable IP forwarding for specific requester
-    *
-    * @param requester requester name to enable IP forwarding. It is a unique name which will be
-    *                  stored in Netd to make sure if any requester needs IP forwarding.
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void ipfwdEnableForwarding(in @utf8InCpp String requester);
-
-   /**
-    * Disable IP forwarding for specific requester
-    *
-    * @param requester requester name to disable IP forwarding. This name should match the
-    *                  names which are set by ipfwdEnableForwarding.
-    *                  IP forwarding would be disabled if it is the last requester.
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void ipfwdDisableForwarding(in @utf8InCpp String requester);
-
-   /**
-    * Add forwarding ip rule
-    *
-    * @param fromIface interface name to add forwarding ip rule
-    * @param toIface interface name to add forwarding ip rule
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface);
-
-   /**
-    * Remove forwarding ip rule
-    *
-    * @param fromIface interface name to remove forwarding ip rule
-    * @param toIface interface name to remove forwarding ip rule
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface);
-
-   /**
-    * Set quota for interface
-    *
-    * @param ifName Name of target interface
-    * @param bytes Quota value in bytes
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes);
-
-   /**
-    * Remove quota for interface
-    *
-    * @param ifName Name of target interface
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName);
-
-   /**
-    * Set alert for interface
-    *
-    * @param ifName Name of target interface
-    * @param bytes Alert value in bytes
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes);
-
-   /**
-    * Remove alert for interface
-    *
-    * @param ifName Name of target interface
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName);
-
-   /**
-    * Set global alert
-    *
-    * @param bytes Alert value in bytes
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void bandwidthSetGlobalAlert(long bytes);
-
-   /**
-    * Add naughty app bandwidth rule for specific app
-    *
-    * @param uid uid of target app
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void bandwidthAddNaughtyApp(int uid);
-
-   /**
-    * Remove naughty app bandwidth rule for specific app
-    *
-    * @param uid uid of target app
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void bandwidthRemoveNaughtyApp(int uid);
-
-   /**
-    * Add nice app bandwidth rule for specific app
-    *
-    * @param uid uid of target app
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void bandwidthAddNiceApp(int uid);
-
-   /**
-    * Remove nice app bandwidth rule for specific app
-    *
-    * @param uid uid of target app
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void bandwidthRemoveNiceApp(int uid);
-
-   /**
-    * Start tethering
-    *
-    * @param dhcpRanges dhcp ranges to set.
-    *                   dhcpRanges might contain many addresss {addr1, addr2, aadr3, addr4...}
-    *                   Netd splits them into ranges: addr1-addr2, addr3-addr4, etc.
-    *                   An odd number of addrs will fail.
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void tetherStart(in @utf8InCpp String[] dhcpRanges);
-
-   /**
-    * Stop tethering
-    *
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void tetherStop();
-
-   /**
-    * Get status of tethering
-    *
-    * @return true if tethering is enabled, false otherwise.
-    */
-    boolean tetherIsEnabled();
-
-   /**
-    * Setup interface for tethering
-    *
-    * @param ifName interface name to add
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void tetherInterfaceAdd(in @utf8InCpp String ifName);
-
-   /**
-    * Reset interface for tethering
-    *
-    * @param ifName interface name to remove
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void tetherInterfaceRemove(in @utf8InCpp String ifName);
-
-   /**
-    * Get the interface list which is stored in netd
-    * The list contains the interfaces managed by tetherInterfaceAdd/tetherInterfaceRemove
-    *
-    * @return An array of strings containing interface list result
-    */
-    @utf8InCpp String[] tetherInterfaceList();
-
-   /**
-    * Set DNS forwarder server
-    *
-    * @param netId the upstream network to forward DNS queries to
-    * @param dnsAddrs DNS server address to set
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs);
-
-   /**
-    * Return the DNS list set by tetherDnsSet
-    *
-    * @return An array of strings containing the list of DNS servers
-    */
-    @utf8InCpp String[] tetherDnsList();
-
-    const int LOCAL_NET_ID = 99;
-
-    /**
-     * Constant net ID for the "dummy" network.
-     *
-     * The dummy network is used to blackhole or reject traffic. Any attempt to use it will
-     * either drop the packets or fail with ENETUNREACH.
-     */
-    const int DUMMY_NET_ID = 51;
-
-    /**
-     * Constant net ID for the "unreachable" network.
-     *
-     * The unreachable network is used to reject traffic. Any attempt to use it will fail
-     * with ENETUNREACH.
-     */
-    const int UNREACHABLE_NET_ID = 52;
-
-    // Route does not specify a next hop
-    const String NEXTHOP_NONE = "";
-    // Route next hop is unreachable
-    const String NEXTHOP_UNREACHABLE = "unreachable";
-    // Route next hop is throw
-    const String NEXTHOP_THROW = "throw";
-
-   /**
-    * Add a route for specific network
-    *
-    * @param netId the network to add the route to
-    * @param ifName the name of interface of the route.
-    *               This interface should be assigned to the netID.
-    * @param destination the destination of the route
-    * @param nextHop The route's next hop address,
-    *                or it could be either NEXTHOP_NONE, NEXTHOP_UNREACHABLE, NEXTHOP_THROW.
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void networkAddRoute(
-            int netId,
-            in @utf8InCpp String ifName,
-            in @utf8InCpp String destination,
-            in @utf8InCpp String nextHop);
-
-   /**
-    * Remove a route for specific network
-    *
-    * @param netId the network to remove the route from
-    * @param ifName the name of interface of the route.
-    *               This interface should be assigned to the netID.
-    * @param destination the destination of the route
-    * @param nextHop The route's next hop address,
-    *                or it could be either NEXTHOP_NONE, NEXTHOP_UNREACHABLE, NEXTHOP_THROW.
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void networkRemoveRoute(
-            int netId,
-            in @utf8InCpp String ifName,
-            in @utf8InCpp String destination,
-            in @utf8InCpp String nextHop);
-
-   /**
-    * Add a route to legacy routing table for specific network
-    *
-    * @param netId the network to add the route to
-    * @param ifName the name of interface of the route.
-    *               This interface should be assigned to the netID.
-    * @param destination the destination of the route
-    * @param nextHop The route's next hop address,
-    *                or it could be either NEXTHOP_NONE, NEXTHOP_UNREACHABLE, NEXTHOP_THROW.
-    * @param uid uid of the user
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void networkAddLegacyRoute(
-            int netId,
-            in @utf8InCpp String ifName,
-            in @utf8InCpp String destination,
-            in @utf8InCpp String nextHop,
-            int uid);
-
-   /**
-    * Remove a route from legacy routing table for specific network
-    *
-    * @param netId the network to remove the route from
-    * @param ifName the name of interface of the route.
-    *               This interface should be assigned to the netID.
-    * @param destination the destination of the route
-    * @param nextHop The route's next hop address,
-    *                or it could be either NEXTHOP_NONE, NEXTHOP_UNREACHABLE, NEXTHOP_THROW.
-    * @param uid uid of the user
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void networkRemoveLegacyRoute(
-            int netId,
-            in @utf8InCpp String ifName,
-            in @utf8InCpp String destination,
-            in @utf8InCpp String nextHop,
-            int uid);
-
-   /**
-    * Get default network
-    *
-    * @return netId of default network
-    */
-    int networkGetDefault();
-
-   /**
-    * Set network as default network
-    *
-    * @param netId the network to set as the default
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void networkSetDefault(int netId);
-
-   /**
-    * Clear default network
-    *
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void networkClearDefault();
-
-   /**
-    * PERMISSION_NONE is used for regular networks and apps. TODO: use PERMISSION_INTERNET
-    * for this instead, and use PERMISSION_NONE to indicate no network permissions at all.
-    */
-    const int PERMISSION_NONE = 0;
-
-   /**
-    * PERMISSION_NETWORK represents the CHANGE_NETWORK_STATE permission.
-    */
-    const int PERMISSION_NETWORK = 1;
-
-   /**
-    * PERMISSION_SYSTEM represents the ability to use restricted networks. This is mostly
-    * equivalent to the CONNECTIVITY_USE_RESTRICTED_NETWORKS permission.
-    */
-    const int PERMISSION_SYSTEM = 2;
-
-   /**
-    * NO_PERMISSIONS indicates that this app is installed and doesn't have either
-    * PERMISSION_INTERNET or PERMISSION_UPDATE_DEVICE_STATS.
-    * TODO: use PERMISSION_NONE to represent this case
-    */
-    const int NO_PERMISSIONS = 0;
-
-   /**
-    * PERMISSION_INTERNET indicates that the app can create AF_INET and AF_INET6 sockets
-    */
-    const int PERMISSION_INTERNET = 4;
-
-   /**
-    * PERMISSION_UPDATE_DEVICE_STATS is used for system UIDs and privileged apps
-    * that have the UPDATE_DEVICE_STATS permission
-    */
-    const int PERMISSION_UPDATE_DEVICE_STATS = 8;
-
-   /**
-    * PERMISSION_UNINSTALLED is used when an app is uninstalled from the device. All internet
-    * related permissions need to be cleaned
-    */
-    const int PERMISSION_UNINSTALLED = -1;
-
-
-   /**
-    * Sets the permission required to access a specific network.
-    *
-    * @param netId the network to set
-    * @param permission network permission to use
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void networkSetPermissionForNetwork(int netId, int permission);
-
-   /**
-    * Assigns network access permissions to the specified users.
-    *
-    * @param permission network permission to use
-    * @param uids uid of users to set permission
-    */
-    void networkSetPermissionForUser(int permission, in int[] uids);
-
-   /**
-    * Clears network access permissions for the specified users.
-    *
-    * @param uids uid of users to clear permission
-    */
-    void networkClearPermissionForUser(in int[] uids);
-
-   /**
-    * Assigns android.permission.INTERNET and/or android.permission.UPDATE_DEVICE_STATS to the uids
-    * specified. Or remove all permissions from the uids.
-    *
-    * @param permission The permission to grant, it could be either PERMISSION_INTERNET and/or
-    *                   PERMISSION_UPDATE_DEVICE_STATS. If the permission is NO_PERMISSIONS, then
-    *                   revoke all permissions for the uids.
-    * @param uids uid of users to grant permission
-    */
-    void trafficSetNetPermForUids(int permission, in int[] uids);
-
-   /**
-    * Gives the specified user permission to protect sockets from VPNs.
-    * Typically used by VPN apps themselves, to ensure that the sockets
-    * they use to communicate with the VPN server aren't routed through
-    * the VPN network.
-    *
-    * @param uid uid of user to set
-    */
-    void networkSetProtectAllow(int uid);
-
-   /**
-    * Removes the permission to protect sockets from VPN.
-    *
-    * @param uid uid of user to set
-    */
-    void networkSetProtectDeny(int uid);
-
-   /**
-    * Get the status of network protect for user
-    *
-    * @param uids uid of user
-    * @return true if the user can protect sockets from VPN, false otherwise.
-    */
-    boolean networkCanProtect(int uid);
-
-    /** Only allows packets from specific UID/Interface.
-        @deprecated use FIREWALL_ALLOWLIST. */
-    const int FIREWALL_WHITELIST = 0;
-
-    /** Only allows packets from specific UID/Interface. */
-    const int FIREWALL_ALLOWLIST = 0;
-
-    /** Blocks packets from specific UID/Interface.
-        @deprecated use FIREWALL_DENYLIST. */
-    const int FIREWALL_BLACKLIST = 1;
-
-    /** Blocks packets from specific UID/Interface. */
-    const int FIREWALL_DENYLIST = 1;
-
-   /**
-    * Set type of firewall
-    * Type allowlist only allows packets from specific UID/Interface
-    * Type denylist blocks packets from specific UID/Interface
-    *
-    * @param firewalltype type of firewall, either FIREWALL_ALLOWLIST or FIREWALL_DENYLIST
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void firewallSetFirewallType(int firewalltype);
-
-    // Specify allow Rule which allows packets
-    const int FIREWALL_RULE_ALLOW = 1;
-    // Specify deny Rule which drops packets
-    const int FIREWALL_RULE_DENY = 2;
-
-    // No specific chain is chosen, use general firewall chain(fw_input, fw_output)
-    const int FIREWALL_CHAIN_NONE = 0;
-    // Specify DOZABLE chain(fw_dozable) which is used in dozable mode
-    const int FIREWALL_CHAIN_DOZABLE = 1;
-    // Specify STANDBY chain(fw_standby) which is used in standby mode
-    const int FIREWALL_CHAIN_STANDBY = 2;
-    // Specify POWERSAVE chain(fw_powersave) which is used in power save mode
-    const int FIREWALL_CHAIN_POWERSAVE = 3;
-    // Specify RESTRICTED chain(fw_restricted) which is used in restricted
-    // networking mode
-    const int FIREWALL_CHAIN_RESTRICTED = 4;
-
-   /**
-    * Set firewall rule for interface
-    *
-    * @param ifName the interface to allow/deny
-    * @param firewallRule either FIREWALL_RULE_ALLOW or FIREWALL_RULE_DENY
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule);
-
-   /**
-    * Set firewall rule for uid
-    *
-    * @param childChain target chain
-    * @param uid uid to allow/deny
-    * @param firewallRule either FIREWALL_RULE_ALLOW or FIREWALL_RULE_DENY
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void firewallSetUidRule(int childChain, int uid, int firewallRule);
-
-   /**
-    * Enable/Disable target firewall child chain
-    *
-    * @param childChain target chain to enable
-    * @param enable whether to enable or disable child chain.
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void firewallEnableChildChain(int childChain, boolean enable);
-
-   /**
-    * Get interface list
-    *
-    * @return An array of strings containing all the interfaces on the system.
-    * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
-    *         unix errno.
-    */
-    @utf8InCpp String[] interfaceGetList();
-
-    // Must be kept in sync with constant in InterfaceConfiguration.java
-    const String IF_STATE_UP = "up";
-    const String IF_STATE_DOWN = "down";
-
-    const String IF_FLAG_BROADCAST = "broadcast";
-    const String IF_FLAG_LOOPBACK = "loopback";
-    const String IF_FLAG_POINTOPOINT = "point-to-point";
-    const String IF_FLAG_RUNNING = "running";
-    const String IF_FLAG_MULTICAST = "multicast";
-
-   /**
-    * Get interface configuration
-    *
-    * @param ifName interface name
-    * @return An InterfaceConfigurationParcel for the specified interface.
-    * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
-    *         unix errno.
-    */
-    InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName);
-
-   /**
-    * Set interface configuration
-    *
-    * @param cfg Interface configuration to set
-    * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
-    *         unix errno.
-    */
-    void interfaceSetCfg(in InterfaceConfigurationParcel cfg);
-
-   /**
-    * Set interface IPv6 privacy extensions
-    *
-    * @param ifName interface name
-    * @param enable whether to enable or disable this setting.
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable);
-
-   /**
-    * Clear all IP addresses on the given interface
-    *
-    * @param ifName interface name
-    * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
-    *         POSIX errno.
-    */
-    void interfaceClearAddrs(in @utf8InCpp String ifName);
-
-   /**
-    * Enable or disable IPv6 on the given interface
-    *
-    * @param ifName interface name
-    * @param enable whether to enable or disable this setting.
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable);
-
-   /**
-    * Set interface MTU
-    *
-    * @param ifName interface name
-    * @param mtu MTU value
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void interfaceSetMtu(in @utf8InCpp String ifName, int mtu);
-
-   /**
-    * Add forwarding rule/stats on given interface.
-    *
-    * @param intIface downstream interface
-    * @param extIface upstream interface
-    */
-    void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface);
-
-   /**
-    * Remove forwarding rule/stats on given interface.
-    *
-    * @param intIface downstream interface
-    * @param extIface upstream interface
-    */
-    void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface);
-
-   /**
-    * Set the values of tcp_{rmem,wmem}.
-    *
-    * @param rmemValues the target values of tcp_rmem, each value is separated by spaces
-    * @param wmemValues the target values of tcp_wmem, each value is separated by spaces
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues);
-
-   /**
-    * Register unsolicited event listener
-    * Netd supports multiple unsolicited event listeners.
-    *
-    * @param listener unsolicited event listener to register
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void registerUnsolicitedEventListener(INetdUnsolicitedEventListener listener);
-
-    /**
-     * Add ingress interface filtering rules to a list of UIDs
-     *
-     * For a given uid, once a filtering rule is added, the kernel will only allow packets from the
-     * allowed interface and loopback to be sent to the list of UIDs.
-     *
-     * Calling this method on one or more UIDs with an existing filtering rule but a different
-     * interface name will result in the filtering rule being updated to allow the new interface
-     * instead. Otherwise calling this method will not affect existing rules set on other UIDs.
-     *
-     * @param ifName the name of the interface on which the filtering rules will allow packets to
-              be received.
-     * @param uids an array of UIDs which the filtering rules will be set
-     * @throws ServiceSpecificException in case of failure, with an error code indicating the
-     *         cause of the failure.
-     */
-    void firewallAddUidInterfaceRules(in @utf8InCpp String ifName, in int[] uids);
-
-    /**
-     * Remove ingress interface filtering rules from a list of UIDs
-     *
-     * Clear the ingress interface filtering rules from the list of UIDs which were previously set
-     * by firewallAddUidInterfaceRules(). Ignore any uid which does not have filtering rule.
-     *
-     * @param uids an array of UIDs from which the filtering rules will be removed
-     * @throws ServiceSpecificException in case of failure, with an error code indicating the
-     *         cause of the failure.
-     */
-    void firewallRemoveUidInterfaceRules(in int[] uids);
-
-   /**
-    * Request netd to change the current active network stats map.
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void trafficSwapActiveStatsMap();
-
-   /**
-    * Retrieves OEM netd listener interface
-    *
-    * @return a IBinder object, it could be casted to oem specific interface.
-    */
-    IBinder getOemNetd();
-
-   /**
-    * Start tethering with given configuration
-    *
-    * @param config config to start tethering.
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void tetherStartWithConfiguration(in TetherConfigParcel config);
-
-
-    /**
-     * Get the fwmark and its net id mask for the given network id.
-     *
-     * @param netId the network to get the fwmark and mask for.
-     * @return A MarkMaskParcel of the given network id.
-     */
-    MarkMaskParcel getFwmarkForNetwork(int netId);
-
-    /**
-    * Add a route for specific network
-    *
-    * @param netId the network to add the route to
-    * @param routeInfo parcelable with route information
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void networkAddRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo);
-
-    /**
-    * Update a route for specific network
-    *
-    * @param routeInfo parcelable with route information
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void networkUpdateRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo);
-
-    /**
-    * Remove a route for specific network
-    *
-    * @param routeInfo parcelable with route information
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void networkRemoveRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo);
-
-    /**
-     * Adds a tethering offload rule, or updates it if it already exists.
-     *
-     * Currently, only downstream /128 IPv6 entries are supported. An existing rule will be updated
-     * if the input interface and destination prefix match. Otherwise, a new rule will be created.
-     *
-     * @param rule The rule to add or update.
-     * @throws ServiceSpecificException in case of failure, with an error code indicating the
-     *                                  cause of the failure.
-     */
-    void tetherOffloadRuleAdd(in TetherOffloadRuleParcel rule);
-
-    /**
-     * Deletes a tethering offload rule.
-     *
-     * Currently, only downstream /128 IPv6 entries are supported. An existing rule will be deleted
-     * if the destination IP address and the source interface match. It is not an error if there is
-     * no matching rule to delete.
-     *
-     * @param rule The rule to delete.
-     * @throws ServiceSpecificException in case of failure, with an error code indicating the
-     *                                  cause of the failure.
-     */
-    void tetherOffloadRuleRemove(in TetherOffloadRuleParcel rule);
-
-    /**
-     * Return BPF tethering offload statistics.
-     *
-     * @return an array of TetherStatsParcel's, where each entry contains the upstream interface
-     *         index and its tethering statistics since tethering was first started.
-     *         There will only ever be one entry for a given interface index.
-     * @throws ServiceSpecificException in case of failure, with an error code indicating the
-     *         cause of the failure.
-     */
-    TetherStatsParcel[] tetherOffloadGetStats();
-
-   /**
-    * Set a per-interface quota for tethering offload.
-    *
-    * @param ifIndex Index of upstream interface
-    * @param quotaBytes The quota defined as the number of bytes, starting from zero and counting
-     *       from *now*. A value of QUOTA_UNLIMITED (-1) indicates there is no limit.
-    * @throws ServiceSpecificException in case of failure, with an error code indicating the
-    *         cause of the failure.
-    */
-    void tetherOffloadSetInterfaceQuota(int ifIndex, long quotaBytes);
-
-    /**
-     * Return BPF tethering offload statistics and clear the stats for a given upstream.
-     *
-     * Must only be called once all offload rules have already been deleted for the given upstream
-     * interface. The existing stats will be fetched and returned. The stats and the limit for the
-     * given upstream interface will be deleted as well.
-     *
-     * The stats and limit for a given upstream interface must be initialized (using
-     * tetherOffloadSetInterfaceQuota) before any offload will occur on that interface.
-     *
-     * @param ifIndex Index of upstream interface.
-     * @return TetherStatsParcel, which contains the given upstream interface index and its
-     *         tethering statistics since tethering was first started on that upstream interface.
-     * @throws ServiceSpecificException in case of failure, with an error code indicating the
-     *                                  cause of the failure.
-     */
-     TetherStatsParcel tetherOffloadGetAndClearStats(int ifIndex);
-
-    /**
-     * Creates a network.
-     *
-     * @param config the configuration of network.
-     * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
-     *         unix errno.
-     */
-    void networkCreate(in NativeNetworkConfig config);
-
-    /**
-     * Adds the specified UID ranges to the specified network. The network can be physical or
-     * virtual. Traffic from the UID ranges will be routed to the network by default. The possible
-     * value of subsidiary priority for physical and unreachable networks is 0-999. 0 is the highest
-     * priority. 0 is also the default value. Virtual network supports only the default value.
-     *
-     * @param NativeUidRangeConfig a parcel contains netId, UID ranges, subsidiary priority, etc.
-     *
-     * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
-     *         unix errno.
-     */
-    void networkAddUidRangesParcel(in NativeUidRangeConfig uidRangesConfig);
-
-    /**
-     * Removes the specified UID ranges from the specified network. The network can be physical or
-     * virtual. Traffic from the UID ranges will no longer be routed to the network by default. The
-     * possible value of subsidiary priority for physical and unreachable networks is 0-999. 0 is
-     * the highest priority. 0 is also the default value. Virtual network supports only the default
-     * value.
-     *
-     * @param NativeUidRangeConfig a parcel contains netId, UID ranges, subsidiary priority, etc.
-     *
-     * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
-     *         unix errno.
-     */
-    void networkRemoveUidRangesParcel(in NativeUidRangeConfig uidRangesConfig);
-}
diff --git a/server/binder/android/net/INetdUnsolicitedEventListener.aidl b/server/binder/android/net/INetdUnsolicitedEventListener.aidl
deleted file mode 100644
index 652a79c..0000000
--- a/server/binder/android/net/INetdUnsolicitedEventListener.aidl
+++ /dev/null
@@ -1,145 +0,0 @@
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-/**
- * Unsolicited netd events which are reported by the kernel via netlink.
- * This one-way interface groups asynchronous notifications sent
- * by netd to any process that registered itself via INetd.registerUnsolEventListener.
- *
- * {@hide}
- */
-oneway interface INetdUnsolicitedEventListener {
-
-    /**
-     * Notifies that an interface has been idle/active for a certain period of time.
-     * It is the event for idletimer.
-     *
-     * @param isActive true for active status, false for idle
-     * @param timerLabel unique identifier of the idletimer.
-     *              Since NMS only set the identifier as int, only report event with int label.
-     * @param timestampNs kernel timestamp of this event, 0 for no timestamp
-     * @param uid uid of this event, -1 for no uid.
-     *            It represents the uid that was responsible for waking the radio.
-     */
-    void onInterfaceClassActivityChanged(
-            boolean isActive,
-            int timerLabel,
-            long timestampNs,
-            int uid);
-
-    /**
-     * Notifies that a specific interface reached its quota limit.
-     *
-     * @param alertName alert name of the quota limit
-     * @param ifName interface which reached the limit
-     */
-    void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName);
-
-    /**
-     * Provides information on IPv6 DNS servers on a specific interface.
-     *
-     * @param ifName interface name
-     * @param lifetimeS lifetime for the DNS servers in seconds
-     * @param servers the address of servers.
-     *                  e.g. IpV6: "2001:4860:4860::6464"
-     *
-     */
-    void onInterfaceDnsServerInfo(
-            @utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers);
-
-    /**
-     * Notifies that an address has updated on a specific interface.
-     *
-     * @param addr address that is being updated
-     * @param ifName the name of the interface on which the address is configured
-     * @param flags address flags, see ifa_flags in if_addr.h
-     * @param scope current scope of the address
-     */
-    void onInterfaceAddressUpdated(
-            @utf8InCpp String addr,
-            @utf8InCpp String ifName,
-            int flags,
-            int scope);
-
-    /**
-     * Notifies that an address has been removed on a specific interface.
-     *
-     * @param addr address of this change
-     * @param ifName the name of the interface that changed addresses
-     * @param flags address flags, see ifa_flags in if_addr.h
-     * @param scope address address scope
-     */
-    void onInterfaceAddressRemoved(
-            @utf8InCpp String addr,
-            @utf8InCpp String ifName,
-            int flags,
-            int scope);
-
-    /**
-     * Notifies that an interface has been added.
-     *
-     * @param ifName the name of the added interface
-     */
-    void onInterfaceAdded(@utf8InCpp String ifName);
-
-    /**
-     * Notifies that an interface has been removed.
-     *
-     * @param ifName the name of the removed interface
-     */
-    void onInterfaceRemoved(@utf8InCpp String ifName);
-
-    /**
-     * Notifies that the status of the specific interface has changed.
-     *
-     * @param ifName the name of the interface that changed status
-     * @param up true for interface up, false for down
-     */
-    void onInterfaceChanged(@utf8InCpp String ifName, boolean up);
-
-    /**
-     * Notifies that the link state of the specific interface has changed.
-     *
-     * @param ifName the name of the interface whose link state has changed
-     * @param up true for interface link state up, false for link state down
-     */
-    void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up);
-
-    /**
-     * Notifies that an IP route has changed.
-     *
-     * @param updated true for update, false for remove
-     * @param route destination prefix of this route, e.g., "2001:db8::/64"
-     * @param gateway address of gateway, empty string for no gateway
-     * @param ifName interface name of this route, empty string for no interface
-     */
-    void onRouteChanged(
-            boolean updated,
-            @utf8InCpp String route,
-            @utf8InCpp String gateway,
-            @utf8InCpp String ifName);
-
-    /**
-     * Notifies that kernel has detected a socket sending data not wrapped
-     * inside a layer of SSL/TLS encryption.
-     *
-     * @param uid uid of this event
-     * @param hex packet content in hex format
-     */
-    void onStrictCleartextDetected(int uid, @utf8InCpp String hex);
-}
diff --git a/server/binder/android/net/InterfaceConfigurationParcel.aidl b/server/binder/android/net/InterfaceConfigurationParcel.aidl
deleted file mode 100644
index c20792c..0000000
--- a/server/binder/android/net/InterfaceConfigurationParcel.aidl
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-/**
- * Configuration details for a network interface.
- *
- * {@hide}
- */
-parcelable InterfaceConfigurationParcel {
-    @utf8InCpp String ifName;
-    @utf8InCpp String hwAddr;
-    @utf8InCpp String ipv4Addr;
-    int prefixLength;
-    /**
-    * Interface flags, String versions of IFF_* defined in netd/if.h
-    */
-    @utf8InCpp String[] flags;
-}
diff --git a/server/binder/android/net/MarkMaskParcel.aidl b/server/binder/android/net/MarkMaskParcel.aidl
deleted file mode 100644
index 932b7bf..0000000
--- a/server/binder/android/net/MarkMaskParcel.aidl
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-/**
- * Structure that stores a firewall mark and its mask.
- *
- * {@hide}
- */
-parcelable MarkMaskParcel {
-    // The fwmark.
-    int mark;
-    // Net id mask of fwmark.
-    int mask;
-}
diff --git a/server/binder/android/net/NativeNetworkConfig.aidl b/server/binder/android/net/NativeNetworkConfig.aidl
deleted file mode 100644
index 2c4f83a..0000000
--- a/server/binder/android/net/NativeNetworkConfig.aidl
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.net.NativeNetworkType;
-import android.net.NativeVpnType;
-
-/**
- * The configuration to create a network.
- *
- * {@hide}
- */
-@JavaDerive(toString=true, equals=true)
-@JavaOnlyImmutable
-parcelable NativeNetworkConfig {
-    /** The networkId to create. */
-    int netId;
-
-    /**
-     *  The type of network, e.g. physical network or virtual network.
-     */
-    NativeNetworkType networkType = NativeNetworkType.PHYSICAL;
-
-    /**
-     * For physical networks. The permission necessary to use the network. Must be one of
-     * PERMISSION_NONE/PERMISSION_NETWORK/PERMISSION_SYSTEM. Ignored for all other network types.
-     */
-    int permission;
-
-    /**
-     *  For virtual networks. Whether unprivileged apps are allowed to bypass the VPN. Ignored for
-     *  all other network types.
-     */
-    boolean secure;
-
-    /** For virtual networks. The type of VPN to create.  Ignored for all other network types. */
-    NativeVpnType vpnType = NativeVpnType.PLATFORM;
-}
diff --git a/server/binder/android/net/NativeNetworkType.aidl b/server/binder/android/net/NativeNetworkType.aidl
deleted file mode 100644
index d667029..0000000
--- a/server/binder/android/net/NativeNetworkType.aidl
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-@Backing(type="int")
-enum NativeNetworkType {
-  /**
-   * Physical network type.
-   */
-  PHYSICAL = 0,
-
-  /**
-   * Virtual private network type.
-   */
-  VIRTUAL = 1,
-}
\ No newline at end of file
diff --git a/server/binder/android/net/NativeVpnType.aidl b/server/binder/android/net/NativeVpnType.aidl
deleted file mode 100644
index cd1b447..0000000
--- a/server/binder/android/net/NativeVpnType.aidl
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-@Backing(type="int")
-enum NativeVpnType {
-  /**
-   * A VPN created by an app using the VpnService API.
-   */
-  SERVICE = 1,
-
-  /**
-   * A VPN created using a VpnManager API such as startProvisionedVpnProfile.
-   */
-  PLATFORM = 2,
-
-  /**
-   * An IPsec VPN created by the built-in LegacyVpnRunner.
-   */
-  LEGACY = 3,
-
-  /**
-   * An VPN created by OEM code through other means than VpnService or VpnManager.
-   */
-  OEM = 4,
-}
\ No newline at end of file
diff --git a/server/binder/android/net/RouteInfoParcel.aidl b/server/binder/android/net/RouteInfoParcel.aidl
deleted file mode 100644
index fcc86e3..0000000
--- a/server/binder/android/net/RouteInfoParcel.aidl
+++ /dev/null
@@ -1,28 +0,0 @@
-/**
- * Copyright (c) 2020, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-parcelable RouteInfoParcel {
-  // The destination of the route.
-  @utf8InCpp String destination;
-  // The name of interface of the route. This interface should be assigned to the netID.
-  @utf8InCpp String ifName;
-  // The route's next hop address, or one of the NEXTHOP_* constants defined in INetd.aidl.
-  @utf8InCpp String nextHop;
-  // The MTU of the route.
-  int mtu;
-}
diff --git a/server/binder/android/net/TetherConfigParcel.aidl b/server/binder/android/net/TetherConfigParcel.aidl
deleted file mode 100644
index 9f371ce..0000000
--- a/server/binder/android/net/TetherConfigParcel.aidl
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-/**
- * The configuration to start tethering.
- *
- * {@hide}
- */
-parcelable TetherConfigParcel {
-    // Whether to enable or disable legacy DNS proxy server.
-    boolean usingLegacyDnsProxy;
-    // DHCP ranges to set.
-    // dhcpRanges might contain many addresss {addr1, addr2, addr3, addr4...}
-    // Netd splits them into ranges: addr1-addr2, addr3-addr4, etc.
-    // An odd number of addrs will fail.
-    @utf8InCpp String[] dhcpRanges;
-}
diff --git a/server/binder/android/net/TetherOffloadRuleParcel.aidl b/server/binder/android/net/TetherOffloadRuleParcel.aidl
deleted file mode 100644
index c549e61..0000000
--- a/server/binder/android/net/TetherOffloadRuleParcel.aidl
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-/**
- * Represents a forwarding rule for tethering offload.
- *
- * {@hide}
- */
-parcelable TetherOffloadRuleParcel {
-    /** The interface index of the input interface. */
-    int inputInterfaceIndex;
-
-    /** The interface index of the output interface. */
-    int outputInterfaceIndex;
-
-    /** The base IP address of the destination prefix as a byte array. */
-    byte[] destination;
-
-    /** The destination prefix length. */
-    int prefixLength;
-
-    /** The source link-layer address. Currently, must be a 6-byte MAC address.*/
-    byte[] srcL2Address;
-
-    /** The destination link-layer address. Currently, must be a 6-byte MAC address. */
-    byte[] dstL2Address;
-
-    /** The outbound path mtu. */
-    int pmtu = 1500;
-}
diff --git a/server/binder/android/net/TetherStatsParcel.aidl b/server/binder/android/net/TetherStatsParcel.aidl
deleted file mode 100644
index 6bf60a8..0000000
--- a/server/binder/android/net/TetherStatsParcel.aidl
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-/**
- * The statistics of tethering interface
- *
- * {@hide}
- */
-parcelable TetherStatsParcel {
-    /**
-     * Parcel representing tethering interface statistics.
-     *
-     * This parcel is used by tetherGetStats, tetherOffloadGetStats and
-     * tetherOffloadGetAndClearStats in INetd.aidl. tetherGetStats uses this parcel to return the
-     * tethering statistics since netd startup and presents the interface via its interface name.
-     * Both tetherOffloadGetStats and tetherOffloadGetAndClearStats use this parcel to return
-     * the tethering statistics since tethering was first started. They present the interface via
-     * its interface index. Note that the interface must be presented by either interface name
-     * |iface| or interface index |ifIndex| in this parcel. The unused interface name is set to
-     * an empty string "" by default and the unused interface index is set to 0 by default.
-     */
-
-    /** The interface name. */
-    @utf8InCpp String iface;
-
-    /** Total number of received bytes. */
-    long rxBytes;
-
-    /** Total number of received packets. */
-    long rxPackets;
-
-    /** Total number of transmitted bytes. */
-    long txBytes;
-
-    /** Total number of transmitted packets. */
-    long txPackets;
-
-    /** The interface index. */
-    int ifIndex = 0;
-}
diff --git a/server/binder/android/net/UidRangeParcel.aidl b/server/binder/android/net/UidRangeParcel.aidl
deleted file mode 100644
index 8f1fef6..0000000
--- a/server/binder/android/net/UidRangeParcel.aidl
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-/**
- * An inclusive range of UIDs.
- *
- * {@hide}
- */
-@JavaOnlyImmutable @JavaDerive(toString=true, equals=true)
-parcelable UidRangeParcel {
-    int start;
-    int stop;
-}
diff --git a/server/binder/android/net/metrics/INetdEventListener.aidl b/server/binder/android/net/metrics/INetdEventListener.aidl
deleted file mode 100644
index ef1b2cb..0000000
--- a/server/binder/android/net/metrics/INetdEventListener.aidl
+++ /dev/null
@@ -1,128 +0,0 @@
-/**
- * Copyright (c) 2016, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.metrics;
-
-/**
- * Logs netd events.
- *
- * {@hide}
- */
-oneway interface INetdEventListener {
-    const int EVENT_GETADDRINFO = 1;
-    const int EVENT_GETHOSTBYNAME = 2;
-    const int EVENT_GETHOSTBYADDR = 3;
-    const int EVENT_RES_NSEND = 4;
-
-    const int REPORTING_LEVEL_NONE = 0;
-    const int REPORTING_LEVEL_METRICS = 1;
-    const int REPORTING_LEVEL_FULL = 2;
-
-    // Maximum number of IP addresses logged for DNS lookups before we truncate the full list.
-    const int DNS_REPORTED_IP_ADDRESSES_LIMIT = 10;
-
-    /**
-     * Logs a DNS lookup function call (getaddrinfo and gethostbyname).
-     *
-     * @param netId the ID of the network the lookup was performed on.
-     * @param eventType one of the EVENT_* constants in this interface.
-     * @param returnCode the return value of the function call.
-     * @param latencyMs the latency of the function call.
-     * @param hostname the name that was looked up.
-     * @param ipAddresses (possibly a subset of) the IP addresses returned.
-     *        At most {@link #DNS_REPORTED_IP_ADDRESSES_LIMIT} addresses are logged.
-     * @param ipAddressesCount the number of IP addresses returned. May be different from the length
-     *        of ipAddresses if there were too many addresses to log.
-     * @param uid the UID of the application that performed the query.
-     */
-    void onDnsEvent(int netId, int eventType, int returnCode, int latencyMs,
-            @utf8InCpp String hostname, in @utf8InCpp String[] ipAddresses,
-            int ipAddressesCount, int uid);
-
-    /**
-     * Represents a private DNS validation success or failure.
-     *
-     * @param netId the ID of the network the validation was performed on.
-     * @param ipAddress the IP address for which validation was performed.
-     * @param hostname the hostname for which validation was performed.
-     * @param validated whether or not validation was successful.
-     */
-    void onPrivateDnsValidationEvent(int netId, String ipAddress, String hostname,
-            boolean validated);
-
-    /**
-     * Logs a single connect library call.
-     *
-     * @param netId the ID of the network the connect was performed on.
-     * @param error 0 if the connect call succeeded, otherwise errno if it failed.
-     * @param latencyMs the latency of the connect call.
-     * @param ipAddr destination IP address.
-     * @param port destination port number.
-     * @param uid the UID of the application that performed the connection.
-     */
-    void onConnectEvent(int netId, int error, int latencyMs, String ipAddr, int port, int uid);
-
-    /**
-     * Logs a single RX packet which caused the main CPU to exit sleep state.
-     * @param prefix arbitrary string provided via wakeupAddInterface()
-     * @param uid UID of the destination process or -1 if no UID is available.
-     * @param ethertype of the RX packet encoded in an int in native order, or -1 if not available.
-     * @param ipNextHeader ip protocol of the RX packet as IPPROTO_* number,
-              or -1 if the packet was not IPv4 or IPv6.
-     * @param dstHw destination hardware address, or 0 if not available.
-     * @param srcIp source IP address, or null if not available.
-     * @param dstIp destination IP address, or null if not available.
-     * @param srcPort src port of RX packet in native order, or -1 if the packet was not UDP or TCP.
-     * @param dstPort dst port of RX packet in native order, or -1 if the packet was not UDP or TCP.
-     * @param timestampNs receive timestamp for the offending packet. In units of nanoseconds and
-     *        synchronized to CLOCK_MONOTONIC.
-     */
-    void onWakeupEvent(String prefix, int uid, int ethertype, int ipNextHeader, in byte[] dstHw,
-            String srcIp, String dstIp, int srcPort, int dstPort, long timestampNs);
-
-    /**
-     * An event sent after every Netlink sock_diag poll performed by Netd. This reported batch
-     * groups TCP socket stats aggregated by network id. Per-network data are stored in a
-     * structure-of-arrays style where networkIds, sentPackets, lostPackets, rttUs, and
-     * sentAckDiffMs have the same length. Stats for the i-th network is spread across all these
-     * arrays at index i.
-     * @param networkIds an array of network ids for which there was tcp socket stats to collect in
-     *        the last sock_diag poll.
-     * @param sentPackets an array of packet sent across all TCP sockets still alive and new
-              TCP sockets since the last sock_diag poll, summed per network id.
-     * @param lostPackets, an array of packet lost across all TCP sockets still alive and new
-              TCP sockets since the last sock_diag poll, summed per network id.
-     * @param rttUs an array of smoothed round trip times in microseconds, averaged across all TCP
-              sockets since the last sock_diag poll for a given network id.
-     * @param sentAckDiffMs an array of milliseconds duration between the last packet sent and the
-              last ack received for a socket, averaged across all TCP sockets for a network id.
-     */
-    void onTcpSocketStatsEvent(in int[] networkIds, in int[] sentPackets,
-            in int[] lostPackets, in int[] rttUs, in int[] sentAckDiffMs);
-
-    /**
-     * Represents adding or removing a NAT64 prefix.
-     *
-     * @param netId the ID of the network the prefix was discovered on.
-     * @param added true if the NAT64 prefix was added, or false if the NAT64 prefix was removed.
-     *        There is only one prefix at a time for each netId. If a prefix is added, it replaces
-     *        the previous-added prefix.
-     * @param prefixString the detected NAT64 prefix as a string literal.
-     * @param prefixLength the prefix length associated with this NAT64 prefix.
-     */
-    void onNat64PrefixEvent(int netId, boolean added, @utf8InCpp String prefixString,
-            int prefixLength);
-}
diff --git a/server/binder/android/net/netd/aidl/NativeUidRangeConfig.aidl b/server/binder/android/net/netd/aidl/NativeUidRangeConfig.aidl
deleted file mode 100644
index 99497a8..0000000
--- a/server/binder/android/net/netd/aidl/NativeUidRangeConfig.aidl
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.netd.aidl;
-
-import android.net.UidRangeParcel;
-
-/**
- * The configuration to add or remove UID ranges.
- *
- * {@hide}
- */
-@JavaDerive(toString=true, equals=true)
-@JavaOnlyImmutable
-parcelable NativeUidRangeConfig {
-    /** The network ID of the network to add/remove the ranges to/from. */
-    int netId;
-
-    /** A set of non-overlapping ranges of UIDs. */
-    UidRangeParcel[] uidRanges;
-
-    /**
-     * The priority of this UID range config. 0 is the highest priority; 999 is the lowest priority.
-     * The function of this parameter is to adjust the priority when the same UID is set to
-     * different networks for different features.
-     */
-    int subPriority;
-}
\ No newline at end of file
diff --git a/server/main.cpp b/server/main.cpp
index bc48ac2..0e81d4e 100644
--- a/server/main.cpp
+++ b/server/main.cpp
@@ -34,12 +34,13 @@
 
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
-#include <libbpf_android.h>
 #include <netdutils/Stopwatch.h>
+#include <processgroup/processgroup.h>
 
 #include "Controllers.h"
 #include "FwmarkServer.h"
 #include "MDnsSdListener.h"
+#include "MDnsService.h"
 #include "NFLogListener.h"
 #include "NetdConstants.h"
 #include "NetdHwService.h"
@@ -47,6 +48,7 @@
 #include "NetlinkManager.h"
 #include "Process.h"
 
+#include "NetdUpdatablePublic.h"
 #include "netd_resolv/resolv.h"
 
 using android::IPCThreadState;
@@ -57,6 +59,7 @@
 using android::net::gCtls;
 using android::net::gLog;
 using android::net::makeNFLogListener;
+using android::net::MDnsService;
 using android::net::NetdHwService;
 using android::net::NetdNativeService;
 using android::net::NetlinkManager;
@@ -85,7 +88,7 @@
 int tagSocketCallback(int sockFd, uint32_t tag, uid_t uid, pid_t) {
     // Workaround for secureVPN with VpnIsolation enabled, refer to b/159994981 for details.
     if (tag == TAG_SYSTEM_DNS) uid = AID_DNS;
-    return gCtls->trafficCtrl.tagSocket(sockFd, tag, uid, geteuid());
+    return libnetd_updatable_tagSocket(sockFd, tag, uid, AID_DNS);
 }
 
 bool evaluateDomainNameCallback(const android_net_context&, const char* /*name*/) {
@@ -123,9 +126,17 @@
         gLog.info("setCloseOnExec(%s)", sock);
     }
 
-    // Make sure BPF programs are loaded before doing anything
-    android::bpf::waitForProgsLoaded();
-    gLog.info("BPF programs are loaded");
+    std::string cg2_path;
+    if (!CgroupGetControllerPath(CGROUPV2_CONTROLLER_NAME, &cg2_path)) {
+        ALOGE("Failed to find cgroup v2 root %s", strerror(errno));
+        exit(1);
+    }
+
+    if (libnetd_updatable_init(cg2_path.c_str())) {
+        ALOGE("libnetd_updatable_init failed");
+        exit(1);
+    }
+    gLog.info("libnetd_updatable_init success");
 
     NetlinkManager *nm = NetlinkManager::Instance();
     if (nm == nullptr) {
@@ -168,13 +179,7 @@
         exit(1);
     }
 
-    MDnsSdListener mdnsl;
-    if (mdnsl.startListener()) {
-        ALOGE("Unable to start MDnsSdListener (%s)", strerror(errno));
-        exit(1);
-    }
-
-    FwmarkServer fwmarkServer(&gCtls->netCtrl, &gCtls->eventReporter, &gCtls->trafficCtrl);
+    FwmarkServer fwmarkServer(&gCtls->netCtrl, &gCtls->eventReporter);
     if (fwmarkServer.startListener()) {
         ALOGE("Unable to start FwmarkServer (%s)", strerror(errno));
         exit(1);
@@ -188,6 +193,12 @@
     }
     gLog.info("Registering NetdNativeService: %" PRId64 "us", subTime.getTimeAndResetUs());
 
+    if ((ret = MDnsService::start()) != android::OK) {
+        ALOGE("Unable to start MDnsService: %d", ret);
+        exit(1);
+    }
+    gLog.info("Registering MDnsService: %" PRId64 "us", subTime.getTimeAndResetUs());
+
     android::net::process::ScopedPidFile pidFile(PID_FILE_PATH);
 
     // Now that netd is ready to process commands, advertise service availability for HAL clients.
diff --git a/server/netd.rc b/server/netd.rc
index e6316c1..3e7aa40 100644
--- a/server/netd.rc
+++ b/server/netd.rc
@@ -1,6 +1,7 @@
 service netd /system/bin/netd
     class main
     capabilities CHOWN DAC_OVERRIDE DAC_READ_SEARCH FOWNER IPC_LOCK KILL NET_ADMIN NET_BIND_SERVICE NET_RAW SETUID SETGID
+    group root net_admin
     socket dnsproxyd stream 0660 root inet
     socket mdns stream 0660 root system
     socket fwmarkd stream 0660 root inet
@@ -10,3 +11,23 @@
     # from the DNS resolver APEX. Mark it as updatable so init won't start it until all APEX
     # packages are ready.
     updatable
+
+# Moved from external/android-clat/vendor-464xlat.rc. Since
+# clatd is modularized and shipped in apex, migrate the
+# clat vendor property to netd.
+#
+# Certain vendors disable 464xlat by setting a vendor property.
+# The connectivity code in the Tethering APEX needs to disable
+# 464xlat when the property is set, but it is only allowed to
+# access non-vendor system properties. So copy the property to
+# a property available to system APIs in android.sysprop.
+#
+# Arguably this script should live close to the code that uses
+# it, but scrips in APEXes are not allowed to use "on property".
+# So put it here close to clatd, which is at least related to
+# 464xlat.
+on property:persist.vendor.net.doxlat=true
+    setprop net.464xlat.cellular.enabled true
+
+on property:persist.vendor.net.doxlat=false
+    setprop net.464xlat.cellular.enabled false
diff --git a/tests/Android.bp b/tests/Android.bp
index c5d9bb5..ff918cc 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -37,7 +37,10 @@
 
 cc_test_library {
     name: "libnetd_test_unsol_service",
-    defaults: ["netd_defaults"],
+    defaults: [
+        "netd_aidl_interface_lateststable_cpp_shared",
+        "netd_defaults",
+    ],
     srcs: [
         "TestUnsolService.cpp"
     ],
@@ -52,7 +55,6 @@
         "libnetutils",
         "libsysutils",
         "libutils",
-        "netd_aidl_interface-V7-cpp",
     ],
 }
 
@@ -74,17 +76,21 @@
         "vts"
     ],
     require_root: true,
-    defaults: ["netd_defaults"],
+    defaults: [
+        "netd_aidl_interface_lateststable_cpp_static",
+        "netd_defaults",
+    ],
     tidy: false,  // cuts test build time by almost 1 minute
     srcs: [
         ":netd_integration_test_shared",
         "binder_test.cpp",
         "bpf_base_test.cpp",
+        "kernel_test.cpp",
         "netd_client_test.cpp",
         "netd_test.cpp",
-        "netlink_listener_test.cpp",
     ],
     include_dirs: ["system/netd/server"],
+    header_libs: ["bpf_connectivity_headers"],
     shared_libs: [
         "libbase",
         "libbinder",
@@ -97,17 +103,17 @@
         "libssl",
         "libsysutils",
         "libutils",
+        "libvintf",
     ],
     static_libs: [
         "libcap",
         "libnetd_test_tun_interface",
         "libnetd_test_unsol_service",
         "libnetd_test_utils",
-        "libbpf_android",
-        "libnetdbpf",
         "libnetdutils",
-        "libqtaguid",
-        "netd_aidl_interface-V7-cpp",
+        "libnettestutils",
+        "libtcutils",
+        "mdns_aidl_interface-V1-cpp",
         "netd_event_listener_interface-V1-cpp",
         "oemnetd_aidl_interface-cpp",
     ],
diff --git a/tests/benchmarks/Android.bp b/tests/benchmarks/Android.bp
index 00c28eb..13c8105 100644
--- a/tests/benchmarks/Android.bp
+++ b/tests/benchmarks/Android.bp
@@ -11,7 +11,10 @@
 
 cc_benchmark {
     name: "netd_benchmark",
-    defaults: ["netd_defaults"],
+    defaults: [
+        "netd_aidl_interface_lateststable_cpp_static",
+        "netd_defaults",
+    ],
     shared_libs: [
         "libbase",
         "libbinder_ndk",
@@ -22,10 +25,9 @@
     ],
     static_libs: [
         "libnetd_test_dnsresponder_ndk",
-        "dnsresolver_aidl_interface-lateststable-ndk_platform",
-        "netd_aidl_interface-lateststable-cpp", //  system/netd/server/UidRanges.h
-        "netd_aidl_interface-lateststable-ndk_platform",
-        "netd_event_listener_interface-lateststable-ndk_platform",
+        "dnsresolver_aidl_interface-lateststable-ndk",
+        "netd_aidl_interface-lateststable-ndk",
+        "netd_event_listener_interface-lateststable-ndk",
     ],
     aidl: {
         include_dirs: ["system/netd/server/binder"],
@@ -47,9 +49,10 @@
     name: "bpf_benchmark",
     defaults: ["netd_defaults"],
     require_root: true,
+    header_libs: ["bpf_headers"],
     shared_libs: [
         "libbase",
-        "libbpf_android",
+        "liblog",
         "libnetdutils",
     ],
     srcs: [
diff --git a/tests/binder_test.cpp b/tests/binder_test.cpp
index e80296a..a97af85 100644
--- a/tests/binder_test.cpp
+++ b/tests/binder_test.cpp
@@ -24,10 +24,10 @@
 #include <cstdlib>
 #include <iostream>
 #include <mutex>
+#include <numeric>
 #include <regex>
 #include <set>
 #include <string>
-#include <thread>
 #include <vector>
 
 #include <dirent.h>
@@ -54,11 +54,11 @@
 #include <binder/IPCThreadState.h>
 #include <bpf/BpfMap.h>
 #include <bpf/BpfUtils.h>
+#include <bpf_shared.h>
 #include <com/android/internal/net/BnOemNetdUnsolicitedEventListener.h>
 #include <com/android/internal/net/IOemNetd.h>
 #include <cutils/multiuser.h>
 #include <gtest/gtest.h>
-#include <netdbpf/bpf_shared.h>
 #include <netutils/ifc.h>
 #include <utils/Errors.h>
 #include "Fwmark.h"
@@ -71,11 +71,19 @@
 #include "TestUnsolService.h"
 #include "XfrmController.h"
 #include "android/net/INetd.h"
+#include "android/net/mdns/aidl/BnMDnsEventListener.h"
+#include "android/net/mdns/aidl/DiscoveryInfo.h"
+#include "android/net/mdns/aidl/GetAddressInfo.h"
+#include "android/net/mdns/aidl/IMDns.h"
+#include "android/net/mdns/aidl/RegistrationInfo.h"
+#include "android/net/mdns/aidl/ResolutionInfo.h"
 #include "binder/IServiceManager.h"
 #include "netdutils/InternetAddresses.h"
 #include "netdutils/Stopwatch.h"
 #include "netdutils/Syscalls.h"
+#include "netdutils/Utils.h"
 #include "netid_client.h"  // NETID_UNSET
+#include "nettestutils/DumpService.h"
 #include "test_utils.h"
 #include "tun_interface.h"
 
@@ -95,12 +103,12 @@
 using android::String8;
 using android::base::Join;
 using android::base::make_scope_guard;
-using android::base::ReadFdToString;
 using android::base::ReadFileToString;
 using android::base::StartsWith;
 using android::base::StringPrintf;
 using android::base::Trim;
 using android::base::unique_fd;
+using android::binder::Status;
 using android::net::INetd;
 using android::net::InterfaceConfigurationParcel;
 using android::net::InterfaceController;
@@ -108,9 +116,11 @@
 using android::net::NativeNetworkConfig;
 using android::net::NativeNetworkType;
 using android::net::NativeVpnType;
-using android::net::RULE_PRIORITY_BYPASSABLE_VPN;
+using android::net::RULE_PRIORITY_BYPASSABLE_VPN_LOCAL_EXCLUSION;
+using android::net::RULE_PRIORITY_BYPASSABLE_VPN_NO_LOCAL_EXCLUSION;
 using android::net::RULE_PRIORITY_DEFAULT_NETWORK;
 using android::net::RULE_PRIORITY_EXPLICIT_NETWORK;
+using android::net::RULE_PRIORITY_LOCAL_ROUTES;
 using android::net::RULE_PRIORITY_OUTPUT_INTERFACE;
 using android::net::RULE_PRIORITY_PROHIBIT_NON_VPN;
 using android::net::RULE_PRIORITY_SECURE_VPN;
@@ -126,7 +136,13 @@
 using android::net::TunInterface;
 using android::net::UidRangeParcel;
 using android::net::UidRanges;
+using android::net::mdns::aidl::DiscoveryInfo;
+using android::net::mdns::aidl::GetAddressInfo;
+using android::net::mdns::aidl::IMDns;
+using android::net::mdns::aidl::RegistrationInfo;
+using android::net::mdns::aidl::ResolutionInfo;
 using android::net::netd::aidl::NativeUidRangeConfig;
+using android::netdutils::getIfaceNames;
 using android::netdutils::IPAddress;
 using android::netdutils::ScopedAddrinfo;
 using android::netdutils::sSyscalls;
@@ -209,7 +225,8 @@
                                      unique_fd* acceptedSocket);
 
     void createVpnNetworkWithUid(bool secure, uid_t uid, int vpnNetId = TEST_NETID2,
-                                 int fallthroughNetId = TEST_NETID1);
+                                 int fallthroughNetId = TEST_NETID1,
+                                 int nonDefaultNetId = TEST_NETID3);
 
     void createAndSetDefaultNetwork(int netId, const std::string& interface,
                                     int permission = INetd::PERMISSION_NONE);
@@ -226,7 +243,6 @@
                                               int vpnNetId, bool secure,
                                               std::vector<UidRangeParcel>&& appDefaultUidRanges,
                                               std::vector<UidRangeParcel>&& vpnUidRanges);
-
   protected:
     // Use -1 to represent that default network was not modified because
     // real netId must be an unsigned value.
@@ -264,7 +280,7 @@
 namespace {
 
 NativeNetworkConfig makeNativeNetworkConfig(int netId, NativeNetworkType networkType,
-                                            int permission, bool secure) {
+                                            int permission, bool secure, bool excludeLocalRoutes) {
     NativeNetworkConfig config = {};
     config.netId = netId;
     config.networkType = networkType;
@@ -272,6 +288,7 @@
     config.secure = secure;
     // The vpnType doesn't matter in AOSP. Just pick a well defined one from INetd.
     config.vpnType = NativeVpnType::PLATFORM;
+    config.excludeLocalRoutes = excludeLocalRoutes;
     return config;
 }
 
@@ -282,7 +299,7 @@
     // Note that this networkCreate is never allowed to create reserved network IDs, so
     // this call may fail for other reasons than the network already existing.
     const auto& config = makeNativeNetworkConfig(netId, NativeNetworkType::PHYSICAL,
-                                                 INetd::PERMISSION_NONE, false);
+                                                 INetd::PERMISSION_NONE, false, false);
     EXPECT_FALSE(netd->networkCreate(config).isOk());
     // Test if the network exist by adding interface. INetd has no dedicated method to query. When
     // the network exists and the interface can be added, the function succeeds. When the network
@@ -612,12 +629,15 @@
     return res;
 }
 
-NativeUidRangeConfig makeNativeUidRangeConfig(unsigned netId,
-                                              std::vector<UidRangeParcel>&& uidRanges,
-                                              uint32_t subPriority) {
+UidRangeParcel makeUidRangeParcel(int uid) {
+    return makeUidRangeParcel(uid, uid);
+}
+
+NativeUidRangeConfig makeNativeUidRangeConfig(unsigned netId, std::vector<UidRangeParcel> uidRanges,
+                                              int32_t subPriority) {
     NativeUidRangeConfig res;
     res.netId = netId;
-    res.uidRanges = uidRanges;
+    res.uidRanges = move(uidRanges);
     res.subPriority = subPriority;
 
     return res;
@@ -627,7 +647,7 @@
 
 TEST_F(NetdBinderTest, NetworkInterfaces) {
     auto config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
-                                          INetd::PERMISSION_NONE, false);
+                                          INetd::PERMISSION_NONE, false, false);
     EXPECT_TRUE(mNetd->networkCreate(config).isOk());
     EXPECT_EQ(EEXIST, mNetd->networkCreate(config).serviceSpecificErrorCode());
 
@@ -650,7 +670,7 @@
 
 TEST_F(NetdBinderTest, NetworkUidRules) {
     auto config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::VIRTUAL,
-                                          INetd::PERMISSION_NONE, true);
+                                          INetd::PERMISSION_NONE, true, false);
     EXPECT_TRUE(mNetd->networkCreate(config).isOk());
     EXPECT_EQ(EEXIST, mNetd->networkCreate(config).serviceSpecificErrorCode());
     EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
@@ -817,11 +837,12 @@
     sin6_1.sin6_scope_id = if_nametoindex(sTun.name().c_str());
     sin6_2.sin6_scope_id = if_nametoindex(sTun2.name().c_str());
 
-    int s1 = socket(AF_INET6, SOCK_STREAM, 0);
+    int s1 = socket(AF_INET6, SOCK_STREAM | SOCK_NONBLOCK, 0);
     ASSERT_EQ(0, bind(s1, reinterpret_cast<sockaddr*>(&sin6_1), len));
     ASSERT_EQ(0, getsockname(s1, reinterpret_cast<sockaddr*>(&sin6_1), &len));
+    // getsockname technically writes to len, but sizeof(sockaddr_in6) doesn't change.
 
-    int s2 = socket(AF_INET6, SOCK_STREAM, 0);
+    int s2 = socket(AF_INET6, SOCK_STREAM | SOCK_NONBLOCK, 0);
     ASSERT_EQ(0, bind(s2, reinterpret_cast<sockaddr*>(&sin6_2), len));
     ASSERT_EQ(0, getsockname(s2, reinterpret_cast<sockaddr*>(&sin6_2), &len));
 
@@ -842,7 +863,7 @@
     status = mNetd->interfaceDelAddress(sTun2.name(), kLinkLocalAddress, 64);
     EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
 
-    // The sockets on sTun2 are closed, but the ones on sTun1 remain open.
+    // The client sockets on sTun2 are closed, but the ones on sTun1 remain open.
     char buf[1024];
     EXPECT_EQ(-1, read(c2, buf, sizeof(buf)));
     EXPECT_EQ(ECONNABORTED, errno);
@@ -852,6 +873,12 @@
     EXPECT_EQ(3, read(c1, buf, sizeof(buf)));
     EXPECT_EQ(-1, write(a2, "foo", 3));
     EXPECT_TRUE(errno == ECONNABORTED || errno == ECONNRESET);
+
+    // Check the server sockets too.
+    EXPECT_EQ(-1, accept(s1, nullptr, 0));
+    EXPECT_EQ(EAGAIN, errno);
+    EXPECT_EQ(-1, accept(s2, nullptr, 0));
+    EXPECT_EQ(EINVAL, errno);
 }
 
 namespace {
@@ -1296,6 +1323,63 @@
 constexpr char STRICT_OUTPUT[] = "st_OUTPUT";
 constexpr char STRICT_CLEAR_CAUGHT[] = "st_clear_caught";
 
+// Output looks like this:
+//
+// IPv4:
+//
+// throw        dst                         proto static    scope link
+// unreachable  dst                         proto static    scope link
+//              dst via nextHop dev ifName  proto static
+//              dst             dev ifName  proto static    scope link
+//
+// IPv6:
+//
+// throw        dst             dev lo      proto static    metric 1024
+// unreachable  dst             dev lo      proto static    metric 1024
+//              dst via nextHop dev ifName  proto static    metric 1024
+//              dst             dev ifName  proto static    metric 1024
+std::string ipRoutePrefix(const std::string& ifName, const std::string& dst,
+                          const std::string& nextHop) {
+    std::string prefixString;
+
+    bool isThrow = nextHop == "throw";
+    bool isUnreachable = nextHop == "unreachable";
+    bool isDefault = (dst == "0.0.0.0/0" || dst == "::/0");
+    bool isIPv6 = dst.find(':') != std::string::npos;
+    bool isThrowOrUnreachable = isThrow || isUnreachable;
+
+    if (isThrowOrUnreachable) {
+        prefixString += nextHop + " ";
+    }
+
+    prefixString += isDefault ? "default" : dst;
+
+    if (!nextHop.empty() && !isThrowOrUnreachable) {
+        prefixString += " via " + nextHop;
+    }
+
+    if (isThrowOrUnreachable) {
+        if (isIPv6) {
+            prefixString += " dev lo";
+        }
+    } else {
+        prefixString += " dev " + ifName;
+    }
+
+    prefixString += " proto static";
+
+    // IPv6 routes report the metric, IPv4 routes report the scope.
+    if (isIPv6) {
+        prefixString += " metric 1024";
+    } else {
+        if (nextHop.empty() || isThrowOrUnreachable) {
+            prefixString += " scope link";
+        }
+    }
+
+    return prefixString;
+}
+
 void expectStrictSetUidAccept(const int uid) {
     std::string uidRule = StringPrintf("owner UID match %u", uid);
     std::string perUidChain = StringPrintf("st_clear_caught_%u", uid);
@@ -1328,6 +1412,153 @@
     }
 }
 
+bool ipRuleExists(const char* ipVersion, const std::string& ipRule) {
+    std::vector<std::string> rules = listIpRules(ipVersion);
+    for (const auto& rule : rules) {
+        if (rule.find(ipRule) != std::string::npos) {
+            return true;
+        }
+    }
+    return false;
+}
+
+std::vector<std::string> ipRouteSubstrings(const std::string& ifName, const std::string& dst,
+                                           const std::string& nextHop, const std::string& mtu) {
+    std::vector<std::string> routeSubstrings;
+
+    routeSubstrings.push_back(ipRoutePrefix(ifName, dst, nextHop));
+
+    if (!mtu.empty()) {
+        // Add separate substring to match mtu value.
+        // This is needed because on some devices "error -11"/"error -113" appears between ip prefix
+        // and mtu for throw/unreachable routes.
+        routeSubstrings.push_back("mtu " + mtu);
+    }
+
+    return routeSubstrings;
+}
+
+void expectNetworkRouteDoesNotExistWithMtu(const char* ipVersion, const std::string& ifName,
+                                           const std::string& dst, const std::string& nextHop,
+                                           const std::string& mtu, const char* table) {
+    std::vector<std::string> routeSubstrings = ipRouteSubstrings(ifName, dst, nextHop, mtu);
+    EXPECT_FALSE(ipRouteExists(ipVersion, table, routeSubstrings))
+            << "Found unexpected route [" << Join(routeSubstrings, ", ") << "] in table " << table;
+}
+
+void expectNetworkRouteExistsWithMtu(const char* ipVersion, const std::string& ifName,
+                                     const std::string& dst, const std::string& nextHop,
+                                     const std::string& mtu, const char* table) {
+    std::vector<std::string> routeSubstrings = ipRouteSubstrings(ifName, dst, nextHop, mtu);
+    EXPECT_TRUE(ipRouteExists(ipVersion, table, routeSubstrings))
+            << "Couldn't find route to " << dst << ": [" << Join(routeSubstrings, ", ")
+            << "] in table " << table;
+}
+
+void expectVpnLocalExclusionRuleExists(const std::string& ifName, bool expectExists) {
+    std::string tableName = std::string(ifName + "_local");
+    // Check if rule exists
+    std::string vpnLocalExclusionRule =
+            StringPrintf("%d:\tfrom all fwmark 0x0/0x10000 iif lo lookup %s",
+                         RULE_PRIORITY_LOCAL_ROUTES, tableName.c_str());
+    for (const auto& ipVersion : {IP_RULE_V4, IP_RULE_V6}) {
+        EXPECT_EQ(expectExists, ipRuleExists(ipVersion, vpnLocalExclusionRule));
+    }
+}
+
+void expectNetworkRouteExists(const char* ipVersion, const std::string& ifName,
+                              const std::string& dst, const std::string& nextHop,
+                              const char* table) {
+    expectNetworkRouteExistsWithMtu(ipVersion, ifName, dst, nextHop, "", table);
+}
+
+void expectNetworkRouteDoesNotExist(const char* ipVersion, const std::string& ifName,
+                                    const std::string& dst, const std::string& nextHop,
+                                    const char* table) {
+    expectNetworkRouteDoesNotExistWithMtu(ipVersion, ifName, dst, nextHop, "", table);
+}
+
+void expectNetworkDefaultIpRuleExists(const char* ifName) {
+    std::string networkDefaultRule =
+            StringPrintf("%u:\tfrom all fwmark 0x0/0xffff iif lo lookup %s",
+                         RULE_PRIORITY_DEFAULT_NETWORK, ifName);
+
+    for (const auto& ipVersion : {IP_RULE_V4, IP_RULE_V6}) {
+        EXPECT_TRUE(ipRuleExists(ipVersion, networkDefaultRule));
+    }
+}
+
+void expectNetworkDefaultIpRuleDoesNotExist() {
+    std::string networkDefaultRule =
+            StringPrintf("%u:\tfrom all fwmark 0x0/0xffff iif lo", RULE_PRIORITY_DEFAULT_NETWORK);
+
+    for (const auto& ipVersion : {IP_RULE_V4, IP_RULE_V6}) {
+        EXPECT_FALSE(ipRuleExists(ipVersion, networkDefaultRule));
+    }
+}
+
+void expectNetworkPermissionIpRuleExists(const char* ifName, int permission) {
+    std::string networkPermissionRule = "";
+    switch (permission) {
+        case INetd::PERMISSION_NONE:
+            networkPermissionRule =
+                    StringPrintf("%u:\tfrom all fwmark 0x1ffdd/0x1ffff iif lo lookup %s",
+                                 RULE_PRIORITY_EXPLICIT_NETWORK, ifName);
+            break;
+        case INetd::PERMISSION_NETWORK:
+            networkPermissionRule =
+                    StringPrintf("%u:\tfrom all fwmark 0x5ffdd/0x5ffff iif lo lookup %s",
+                                 RULE_PRIORITY_EXPLICIT_NETWORK, ifName);
+            break;
+        case INetd::PERMISSION_SYSTEM:
+            networkPermissionRule =
+                    StringPrintf("%u:\tfrom all fwmark 0xdffdd/0xdffff iif lo lookup %s",
+                                 RULE_PRIORITY_EXPLICIT_NETWORK, ifName);
+            break;
+    }
+
+    for (const auto& ipVersion : {IP_RULE_V4, IP_RULE_V6}) {
+        EXPECT_TRUE(ipRuleExists(ipVersion, networkPermissionRule));
+    }
+}
+
+// TODO: It is a duplicate function, need to remove it
+bool iptablesNetworkPermissionIptablesRuleExists(const char* binary, const char* chainName,
+                                                 const std::string& expectedInterface,
+                                                 const std::string& expectedRule,
+                                                 const char* table) {
+    std::vector<std::string> rules = listIptablesRuleByTable(binary, table, chainName);
+    for (const auto& rule : rules) {
+        if (rule.find(expectedInterface) != std::string::npos) {
+            if (rule.find(expectedRule) != std::string::npos) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+void expectNetworkPermissionIptablesRuleExists(const char* ifName, int permission) {
+    static const char ROUTECTRL_INPUT[] = "routectrl_mangle_INPUT";
+    std::string networkIncomingPacketMarkRule = "";
+    switch (permission) {
+        case INetd::PERMISSION_NONE:
+            networkIncomingPacketMarkRule = "MARK xset 0x3ffdd/0xffefffff";
+            break;
+        case INetd::PERMISSION_NETWORK:
+            networkIncomingPacketMarkRule = "MARK xset 0x7ffdd/0xffefffff";
+            break;
+        case INetd::PERMISSION_SYSTEM:
+            networkIncomingPacketMarkRule = "MARK xset 0xfffdd/0xffefffff";
+            break;
+    }
+
+    for (const auto& binary : {IPTABLES_PATH, IP6TABLES_PATH}) {
+        EXPECT_TRUE(iptablesNetworkPermissionIptablesRuleExists(
+                binary, ROUTECTRL_INPUT, ifName, networkIncomingPacketMarkRule, MANGLE_TABLE));
+    }
+}
+
 }  // namespace
 
 TEST_F(NetdBinderTest, StrictSetUidCleartextPenalty) {
@@ -1395,75 +1626,6 @@
 
 }  // namespace
 
-TEST_F(NetdBinderTest, ClatdStartStop) {
-    binder::Status status;
-
-    const std::string clatdName = StringPrintf("clatd-%s", sTun.name().c_str());
-    std::string clatAddress;
-    std::string nat64Prefix = "2001:db8:cafe:f00d:1:2::/96";
-
-    // Can't start clatd on an interface that's not part of any network...
-    status = mNetd->clatdStart(sTun.name(), nat64Prefix, &clatAddress);
-    EXPECT_FALSE(status.isOk());
-    EXPECT_EQ(ENODEV, status.serviceSpecificErrorCode());
-
-    // ... so create a test physical network and add our tun to it.
-    const auto& config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
-                                                 INetd::PERMISSION_NONE, false);
-    EXPECT_TRUE(mNetd->networkCreate(config).isOk());
-    EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
-
-    // Prefix must be 96 bits long.
-    status = mNetd->clatdStart(sTun.name(), "2001:db8:cafe:f00d::/64", &clatAddress);
-    EXPECT_FALSE(status.isOk());
-    EXPECT_EQ(EINVAL, status.serviceSpecificErrorCode());
-
-    // Can't start clatd unless there's a default route...
-    status = mNetd->clatdStart(sTun.name(), nat64Prefix, &clatAddress);
-    EXPECT_FALSE(status.isOk());
-    EXPECT_EQ(EADDRNOTAVAIL, status.serviceSpecificErrorCode());
-
-    // so add a default route.
-    EXPECT_TRUE(mNetd->networkAddRoute(TEST_NETID1, sTun.name(), "::/0", "").isOk());
-
-    // Can't start clatd unless there's a global address...
-    status = mNetd->clatdStart(sTun.name(), nat64Prefix, &clatAddress);
-    EXPECT_FALSE(status.isOk());
-    EXPECT_EQ(EADDRNOTAVAIL, status.serviceSpecificErrorCode());
-
-    // ... so add a global address.
-    const std::string v6 = "2001:db8:1:2:f076:ae99:124e:aa99";
-    EXPECT_EQ(0, sTun.addAddress(v6.c_str(), 64));
-
-    // Now expect clatd to start successfully.
-    status = mNetd->clatdStart(sTun.name(), nat64Prefix, &clatAddress);
-    EXPECT_TRUE(status.isOk());
-    EXPECT_EQ(0, status.serviceSpecificErrorCode());
-
-    // Starting it again returns EBUSY.
-    status = mNetd->clatdStart(sTun.name(), nat64Prefix, &clatAddress);
-    EXPECT_FALSE(status.isOk());
-    EXPECT_EQ(EBUSY, status.serviceSpecificErrorCode());
-
-    expectProcessExists(clatdName);
-
-    // Expect clatd to stop successfully.
-    status = mNetd->clatdStop(sTun.name());
-    EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
-    expectProcessDoesNotExist(clatdName);
-
-    // Stopping a clatd that doesn't exist returns ENODEV.
-    status = mNetd->clatdStop(sTun.name());
-    EXPECT_FALSE(status.isOk());
-    EXPECT_EQ(ENODEV, status.serviceSpecificErrorCode());
-    expectProcessDoesNotExist(clatdName);
-
-    // Clean up.
-    EXPECT_TRUE(mNetd->networkRemoveRoute(TEST_NETID1, sTun.name(), "::/0", "").isOk());
-    EXPECT_EQ(0, ifc_del_address(sTun.name().c_str(), v6.c_str(), 64));
-    EXPECT_TRUE(mNetd->networkDestroy(TEST_NETID1).isOk());
-}
-
 namespace {
 
 bool getIpfwdV4Enable() {
@@ -1575,7 +1737,7 @@
 TEST_F(NetdBinderTest, TestIpfwdAddRemoveInterfaceForward) {
     // Add test physical network
     auto config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
-                                          INetd::PERMISSION_NONE, false);
+                                          INetd::PERMISSION_NONE, false, false);
     EXPECT_TRUE(mNetd->networkCreate(config).isOk());
     EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
 
@@ -1697,7 +1859,7 @@
 
     // Add test physical network
     const auto& config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
-                                                 INetd::PERMISSION_NONE, false);
+                                                 INetd::PERMISSION_NONE, false, false);
     EXPECT_TRUE(mNetd->networkCreate(config).isOk());
     EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
 
@@ -1717,7 +1879,7 @@
     long testAlertBytes = 373;
     // Add test physical network
     const auto& config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
-                                                 INetd::PERMISSION_NONE, false);
+                                                 INetd::PERMISSION_NONE, false, false);
     EXPECT_TRUE(mNetd->networkCreate(config).isOk());
     EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
     // Need to have a prior interface quota set to set an alert
@@ -1752,150 +1914,6 @@
     expectBandwidthGlobalAlertRuleExists(testAlertBytes);
 }
 
-namespace {
-
-std::string ipRouteString(const std::string& ifName, const std::string& dst,
-                          const std::string& nextHop, const std::string& mtu) {
-    std::string dstString = (dst == "0.0.0.0/0" || dst == "::/0") ? "default" : dst;
-
-    if (!nextHop.empty()) {
-        dstString += " via " + nextHop;
-    }
-
-    dstString += " dev " + ifName;
-
-    if (!mtu.empty()) {
-        dstString += " proto static";
-        // IPv6 routes report the metric, IPv4 routes report the scope.
-        // TODO: move away from specifying the entire string and use a regexp instead.
-        if (dst.find(':') != std::string::npos) {
-            dstString += " metric 1024";
-        } else {
-            if (nextHop.empty()) {
-                dstString += " scope link";
-            }
-        }
-        dstString += " mtu " + mtu;
-    }
-
-    return dstString;
-}
-
-void expectNetworkRouteExistsWithMtu(const char* ipVersion, const std::string& ifName,
-                                     const std::string& dst, const std::string& nextHop,
-                                     const std::string& mtu, const char* table) {
-    std::string routeString = ipRouteString(ifName, dst, nextHop, mtu);
-    EXPECT_TRUE(ipRouteExists(ipVersion, table, ipRouteString(ifName, dst, nextHop, mtu)))
-            << "Couldn't find route to " << dst << ": '" << routeString << "' in table " << table;
-}
-
-void expectNetworkRouteExists(const char* ipVersion, const std::string& ifName,
-                              const std::string& dst, const std::string& nextHop,
-                              const char* table) {
-    expectNetworkRouteExistsWithMtu(ipVersion, ifName, dst, nextHop, "", table);
-}
-
-void expectNetworkRouteDoesNotExist(const char* ipVersion, const std::string& ifName,
-                                    const std::string& dst, const std::string& nextHop,
-                                    const char* table) {
-    std::string routeString = ipRouteString(ifName, dst, nextHop, "");
-    EXPECT_FALSE(ipRouteExists(ipVersion, table, ipRouteString(ifName, dst, nextHop, "")))
-            << "Found unexpected route " << routeString << " in table " << table;
-}
-
-bool ipRuleExists(const char* ipVersion, const std::string& ipRule) {
-    std::vector<std::string> rules = listIpRules(ipVersion);
-    for (const auto& rule : rules) {
-        if (rule.find(ipRule) != std::string::npos) {
-            return true;
-        }
-    }
-    return false;
-}
-
-void expectNetworkDefaultIpRuleExists(const char* ifName) {
-    std::string networkDefaultRule =
-            StringPrintf("%u:\tfrom all fwmark 0x0/0xffff iif lo lookup %s",
-                         RULE_PRIORITY_DEFAULT_NETWORK, ifName);
-
-    for (const auto& ipVersion : {IP_RULE_V4, IP_RULE_V6}) {
-        EXPECT_TRUE(ipRuleExists(ipVersion, networkDefaultRule));
-    }
-}
-
-void expectNetworkDefaultIpRuleDoesNotExist() {
-    std::string networkDefaultRule =
-            StringPrintf("%u:\tfrom all fwmark 0x0/0xffff iif lo", RULE_PRIORITY_DEFAULT_NETWORK);
-
-    for (const auto& ipVersion : {IP_RULE_V4, IP_RULE_V6}) {
-        EXPECT_FALSE(ipRuleExists(ipVersion, networkDefaultRule));
-    }
-}
-
-void expectNetworkPermissionIpRuleExists(const char* ifName, int permission) {
-    std::string networkPermissionRule = "";
-    switch (permission) {
-        case INetd::PERMISSION_NONE:
-            networkPermissionRule =
-                    StringPrintf("%u:\tfrom all fwmark 0x1ffdd/0x1ffff iif lo lookup %s",
-                                 RULE_PRIORITY_EXPLICIT_NETWORK, ifName);
-            break;
-        case INetd::PERMISSION_NETWORK:
-            networkPermissionRule =
-                    StringPrintf("%u:\tfrom all fwmark 0x5ffdd/0x5ffff iif lo lookup %s",
-                                 RULE_PRIORITY_EXPLICIT_NETWORK, ifName);
-            break;
-        case INetd::PERMISSION_SYSTEM:
-            networkPermissionRule =
-                    StringPrintf("%u:\tfrom all fwmark 0xdffdd/0xdffff iif lo lookup %s",
-                                 RULE_PRIORITY_EXPLICIT_NETWORK, ifName);
-            break;
-    }
-
-    for (const auto& ipVersion : {IP_RULE_V4, IP_RULE_V6}) {
-        EXPECT_TRUE(ipRuleExists(ipVersion, networkPermissionRule));
-    }
-}
-
-// TODO: It is a duplicate function, need to remove it
-bool iptablesNetworkPermissionIptablesRuleExists(const char* binary, const char* chainName,
-                                                 const std::string& expectedInterface,
-                                                 const std::string& expectedRule,
-                                                 const char* table) {
-    std::vector<std::string> rules = listIptablesRuleByTable(binary, table, chainName);
-    for (const auto& rule : rules) {
-        if (rule.find(expectedInterface) != std::string::npos) {
-            if (rule.find(expectedRule) != std::string::npos) {
-                return true;
-            }
-        }
-    }
-    return false;
-}
-
-void expectNetworkPermissionIptablesRuleExists(const char* ifName, int permission) {
-    static const char ROUTECTRL_INPUT[] = "routectrl_mangle_INPUT";
-    std::string networkIncomingPacketMarkRule = "";
-    switch (permission) {
-        case INetd::PERMISSION_NONE:
-            networkIncomingPacketMarkRule = "MARK xset 0x3ffdd/0xffefffff";
-            break;
-        case INetd::PERMISSION_NETWORK:
-            networkIncomingPacketMarkRule = "MARK xset 0x7ffdd/0xffefffff";
-            break;
-        case INetd::PERMISSION_SYSTEM:
-            networkIncomingPacketMarkRule = "MARK xset 0xfffdd/0xffefffff";
-            break;
-    }
-
-    for (const auto& binary : {IPTABLES_PATH, IP6TABLES_PATH}) {
-        EXPECT_TRUE(iptablesNetworkPermissionIptablesRuleExists(
-                binary, ROUTECTRL_INPUT, ifName, networkIncomingPacketMarkRule, MANGLE_TABLE));
-    }
-}
-
-}  // namespace
-
 TEST_F(NetdBinderTest, NetworkAddRemoveRouteUserPermission) {
     static const struct {
         const char* ipVersion;
@@ -1912,6 +1930,14 @@
             {IP_RULE_V6, "::/0", "2001:db8::", true},
             {IP_RULE_V6, "2001:db8:cafe::/64", "2001:db8::", true},
             {IP_RULE_V4, "fe80::/64", "0.0.0.0", false},
+            {IP_RULE_V4, "10.251.10.2/31", "throw", true},
+            {IP_RULE_V4, "10.251.10.2/31", "unreachable", true},
+            {IP_RULE_V4, "0.0.0.0/0", "throw", true},
+            {IP_RULE_V4, "0.0.0.0/0", "unreachable", true},
+            {IP_RULE_V6, "::/0", "throw", true},
+            {IP_RULE_V6, "::/0", "unreachable", true},
+            {IP_RULE_V6, "2001:db8:cafe::/64", "throw", true},
+            {IP_RULE_V6, "2001:db8:cafe::/64", "unreachable", true},
     };
 
     static const struct {
@@ -1930,7 +1956,7 @@
 
     // Add test physical network
     const auto& config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
-                                                 INetd::PERMISSION_NONE, false);
+                                                 INetd::PERMISSION_NONE, false, false);
     EXPECT_TRUE(mNetd->networkCreate(config).isOk());
     EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
 
@@ -2039,6 +2065,12 @@
         }
     }
 
+    /*
+     * Test networkUpdateRouteParcel behavior in case of route MTU change.
+     *
+     * Change of route MTU should be treated as an update of the route:
+     * - networkUpdateRouteParcel should succeed and update route MTU.
+     */
     for (size_t i = 0; i < std::size(kTestData); i++) {
         const auto& td = kTestData[i];
         int mtu = (i % 2) ? 1480 : 1280;
@@ -2079,6 +2111,61 @@
             EXPECT_NE(0, status.serviceSpecificErrorCode());
         }
     }
+
+    /*
+     * Test network[Update|Add]RouteParcel behavior in case of route type change.
+     *
+     * Change of route type should be treated as an update of the route:
+     * - networkUpdateRouteParcel should succeed and update route type.
+     * - networkAddRouteParcel should silently fail, because the route already exists. Route type
+     *   should not be changed in this case.
+     */
+    for (size_t i = 0; i < std::size(kTestData); i++) {
+        const auto& td = kTestData[i];
+
+        if (!td.expectSuccess) {
+            continue;
+        }
+
+        android::net::RouteInfoParcel parcel;
+        parcel.ifName = sTun.name();
+        parcel.destination = td.testDest;
+        parcel.nextHop = td.testNextHop;
+        parcel.mtu = 1280;
+        binder::Status status = mNetd->networkAddRouteParcel(TEST_NETID1, parcel);
+        EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+        expectNetworkRouteExistsWithMtu(td.ipVersion, sTun.name(), td.testDest, td.testNextHop,
+                                        std::to_string(parcel.mtu), sTun.name().c_str());
+
+        parcel.nextHop = parcel.nextHop == "throw" ? "unreachable" : "throw";
+        const char* oldNextHop = td.testNextHop;
+        const char* newNextHop = parcel.nextHop.c_str();
+
+        // Trying to add same route with changed type, this should silently fail.
+        status = mNetd->networkAddRouteParcel(TEST_NETID1, parcel);
+        // No error reported.
+        EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+        // Old route still exists.
+        expectNetworkRouteExistsWithMtu(td.ipVersion, sTun.name(), td.testDest, oldNextHop,
+                                        std::to_string(parcel.mtu), sTun.name().c_str());
+        // New route was not actually added.
+        expectNetworkRouteDoesNotExistWithMtu(td.ipVersion, sTun.name(), td.testDest, newNextHop,
+                                              std::to_string(parcel.mtu), sTun.name().c_str());
+
+        // Update should succeed.
+        status = mNetd->networkUpdateRouteParcel(TEST_NETID1, parcel);
+        EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+        expectNetworkRouteExistsWithMtu(td.ipVersion, sTun.name(), td.testDest, newNextHop,
+                                        std::to_string(parcel.mtu), sTun.name().c_str());
+        expectNetworkRouteDoesNotExistWithMtu(td.ipVersion, sTun.name(), td.testDest, oldNextHop,
+                                              std::to_string(parcel.mtu), sTun.name().c_str());
+
+        status = mNetd->networkRemoveRouteParcel(TEST_NETID1, parcel);
+        EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+        expectNetworkRouteDoesNotExistWithMtu(td.ipVersion, sTun.name(), td.testDest, newNextHop,
+                                              std::to_string(parcel.mtu), sTun.name().c_str());
+    }
+
     // Remove test physical network
     EXPECT_TRUE(mNetd->networkDestroy(TEST_NETID1).isOk());
 }
@@ -2086,7 +2173,7 @@
 TEST_F(NetdBinderTest, NetworkPermissionDefault) {
     // Add test physical network
     const auto& config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
-                                                 INetd::PERMISSION_NONE, false);
+                                                 INetd::PERMISSION_NONE, false, false);
     EXPECT_TRUE(mNetd->networkCreate(config).isOk());
     EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
 
@@ -2627,7 +2714,7 @@
 }
 
 bool compareListInterface(const std::vector<std::string>& interfaceList) {
-    const auto& res = InterfaceController::getIfaceNames();
+    const auto& res = getIfaceNames();
     EXPECT_TRUE(isOk(res));
 
     std::vector<std::string> resIfList;
@@ -2740,7 +2827,7 @@
 
     // Add test physical network
     const auto& config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
-                                                 INetd::PERMISSION_NONE, false);
+                                                 INetd::PERMISSION_NONE, false, false);
     EXPECT_TRUE(mNetd->networkCreate(config).isOk());
     EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
 
@@ -2761,7 +2848,7 @@
 
     // Add test physical network
     const auto& config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
-                                                 INetd::PERMISSION_NONE, false);
+                                                 INetd::PERMISSION_NONE, false, false);
     EXPECT_TRUE(mNetd->networkCreate(config).isOk());
     EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
 
@@ -2801,7 +2888,7 @@
 
     // Add test physical network
     const auto& config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
-                                                 INetd::PERMISSION_NONE, false);
+                                                 INetd::PERMISSION_NONE, false, false);
     EXPECT_TRUE(mNetd->networkCreate(config).isOk());
     EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
 
@@ -2821,7 +2908,7 @@
 TEST_F(NetdBinderTest, InterfaceSetEnableIPv6) {
     // Add test physical network
     const auto& config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
-                                                 INetd::PERMISSION_NONE, false);
+                                                 INetd::PERMISSION_NONE, false, false);
     EXPECT_TRUE(mNetd->networkCreate(config).isOk());
     EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
 
@@ -2844,7 +2931,7 @@
 
     // Add test physical network
     const auto& config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
-                                                 INetd::PERMISSION_NONE, false);
+                                                 INetd::PERMISSION_NONE, false, false);
     EXPECT_TRUE(mNetd->networkCreate(config).isOk());
     EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
 
@@ -2992,35 +3079,6 @@
     updateAndCheckTcpBuffer(mNetd, rmemValue, wmemValue);
 }
 
-namespace {
-
-void checkUidsInPermissionMap(std::vector<int32_t>& uids, bool exist) {
-    android::bpf::BpfMap<uint32_t, uint8_t> uidPermissionMap(UID_PERMISSION_MAP_PATH);
-    for (int32_t uid : uids) {
-        android::base::Result<uint8_t> permission = uidPermissionMap.readValue(uid);
-        if (exist) {
-            ASSERT_RESULT_OK(permission);
-            EXPECT_EQ(INetd::PERMISSION_NONE, permission.value());
-        } else {
-            ASSERT_FALSE(permission.ok());
-            EXPECT_EQ(ENOENT, permission.error().code());
-        }
-    }
-}
-
-}  // namespace
-
-TEST_F(NetdBinderTest, TestInternetPermission) {
-    std::vector<int32_t> appUids = {TEST_UID1, TEST_UID2};
-
-    mNetd->trafficSetNetPermForUids(INetd::PERMISSION_INTERNET, appUids);
-    checkUidsInPermissionMap(appUids, false);
-    mNetd->trafficSetNetPermForUids(INetd::PERMISSION_NONE, appUids);
-    checkUidsInPermissionMap(appUids, true);
-    mNetd->trafficSetNetPermForUids(INetd::PERMISSION_UNINSTALLED, appUids);
-    checkUidsInPermissionMap(appUids, false);
-}
-
 TEST_F(NetdBinderTest, UnsolEvents) {
     auto testUnsolService = android::net::TestUnsolService::start();
     std::string oldTunName = sTun.name();
@@ -3132,7 +3190,7 @@
 
     // Add test physical network
     const auto& config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
-                                                 INetd::PERMISSION_NONE, false);
+                                                 INetd::PERMISSION_NONE, false, false);
     EXPECT_TRUE(mNetd->networkCreate(config).isOk());
     EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
 
@@ -3215,18 +3273,26 @@
 }
 
 void NetdBinderTest::createVpnNetworkWithUid(bool secure, uid_t uid, int vpnNetId,
-                                             int fallthroughNetId) {
+                                             int fallthroughNetId, int nonDefaultNetId) {
     // Re-init sTun* to ensure route rule exists.
     sTun.destroy();
     sTun.init();
     sTun2.destroy();
     sTun2.init();
+    sTun3.destroy();
+    sTun3.init();
 
     // Create physical network with fallthroughNetId but not set it as default network
     auto config = makeNativeNetworkConfig(fallthroughNetId, NativeNetworkType::PHYSICAL,
-                                          INetd::PERMISSION_NONE, false);
+                                          INetd::PERMISSION_NONE, false, false);
     EXPECT_TRUE(mNetd->networkCreate(config).isOk());
     EXPECT_TRUE(mNetd->networkAddInterface(fallthroughNetId, sTun.name()).isOk());
+    // Create a physical network to test that local network access does not include the non-default
+    // networks.
+    auto nonDefaultNetworkConfig = makeNativeNetworkConfig(
+            nonDefaultNetId, NativeNetworkType::PHYSICAL, INetd::PERMISSION_NONE, false, false);
+    EXPECT_TRUE(mNetd->networkCreate(nonDefaultNetworkConfig).isOk());
+    EXPECT_TRUE(mNetd->networkAddInterface(nonDefaultNetId, sTun3.name()).isOk());
 
     // Create VPN with vpnNetId
     config.netId = vpnNetId;
@@ -3250,7 +3316,7 @@
     ASSERT_TRUE(mNetd->networkGetDefault(&mStoredDefaultNetwork).isOk());
 
     const auto& config =
-            makeNativeNetworkConfig(netId, NativeNetworkType::PHYSICAL, permission, false);
+            makeNativeNetworkConfig(netId, NativeNetworkType::PHYSICAL, permission, false, false);
     EXPECT_TRUE(mNetd->networkCreate(config).isOk());
     EXPECT_TRUE(mNetd->networkAddInterface(netId, interface).isOk());
     EXPECT_TRUE(mNetd->networkSetDefault(netId).isOk());
@@ -3259,7 +3325,7 @@
 void NetdBinderTest::createPhysicalNetwork(int netId, const std::string& interface,
                                            int permission) {
     const auto& config =
-            makeNativeNetworkConfig(netId, NativeNetworkType::PHYSICAL, permission, false);
+            makeNativeNetworkConfig(netId, NativeNetworkType::PHYSICAL, permission, false, false);
     EXPECT_TRUE(mNetd->networkCreate(config).isOk());
     EXPECT_TRUE(mNetd->networkAddInterface(netId, interface).isOk());
 }
@@ -3281,7 +3347,7 @@
     createDefaultAndOtherPhysicalNetwork(systemDefaultNetId, otherNetId);
 
     auto config = makeNativeNetworkConfig(vpnNetId, NativeNetworkType::VIRTUAL,
-                                          INetd::PERMISSION_NONE, secure);
+                                          INetd::PERMISSION_NONE, secure, false);
     EXPECT_TRUE(mNetd->networkCreate(config).isOk());
     EXPECT_TRUE(mNetd->networkAddInterface(vpnNetId, sTun3.name()).isOk());
     EXPECT_TRUE(mNetd->networkAddRoute(vpnNetId, sTun3.name(), "2001:db8::/32", "").isOk());
@@ -3407,7 +3473,8 @@
 
 void expectVpnFallthroughWorks(android::net::INetd* netdService, bool bypassable, uid_t uid,
                                const TunInterface& fallthroughNetwork,
-                               const TunInterface& vpnNetwork, int vpnNetId = TEST_NETID2,
+                               const TunInterface& vpnNetwork,
+                               const TunInterface& nonDefaultNetwork, int vpnNetId = TEST_NETID2,
                                int fallthroughNetId = TEST_NETID1) {
     // Set default network to NETID_UNSET
     EXPECT_TRUE(netdService->networkSetDefault(NETID_UNSET).isOk());
@@ -3442,6 +3509,11 @@
     // Check if fallthrough rule exists
     expectVpnFallthroughRuleExists(fallthroughNetwork.name(), vpnNetId);
 
+    // Check if local exclusion rule exists for default network
+    expectVpnLocalExclusionRuleExists(fallthroughNetwork.name(), true);
+    // No local exclusion rule for non-default network
+    expectVpnLocalExclusionRuleExists(nonDefaultNetwork.name(), false);
+
     // Expect fallthrough to default network
     // The fwmark differs depending on whether the VPN is bypassable or not.
     EXPECT_TRUE(sendIPv6PacketFromUid(uid, outsideVpnAddr, &fwmark, fallthroughFd));
@@ -3488,14 +3560,14 @@
     createVpnNetworkWithUid(true /* secure */, TEST_UID1);
     // Get current default network NetId
     ASSERT_TRUE(mNetd->networkGetDefault(&mStoredDefaultNetwork).isOk());
-    expectVpnFallthroughWorks(mNetd.get(), false /* bypassable */, TEST_UID1, sTun, sTun2);
+    expectVpnFallthroughWorks(mNetd.get(), false /* bypassable */, TEST_UID1, sTun, sTun2, sTun3);
 }
 
 TEST_F(NetdBinderTest, BypassableVPNFallthrough) {
     createVpnNetworkWithUid(false /* secure */, TEST_UID1);
     // Get current default network NetId
     ASSERT_TRUE(mNetd->networkGetDefault(&mStoredDefaultNetwork).isOk());
-    expectVpnFallthroughWorks(mNetd.get(), true /* bypassable */, TEST_UID1, sTun, sTun2);
+    expectVpnFallthroughWorks(mNetd.get(), true /* bypassable */, TEST_UID1, sTun, sTun2, sTun3);
 }
 
 namespace {
@@ -3527,7 +3599,7 @@
 
     // Add test physical network 1 and set as default network.
     auto config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
-                                          INetd::PERMISSION_NONE, false);
+                                          INetd::PERMISSION_NONE, false, false);
     EXPECT_TRUE(mNetd->networkCreate(config).isOk());
     EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
     EXPECT_TRUE(mNetd->networkAddRoute(TEST_NETID1, sTun.name(), "2001:db8::/32", "").isOk());
@@ -3557,307 +3629,6 @@
     EXPECT_TRUE(mNetd->networkDestroy(TEST_NETID1).isOk());
 }
 
-namespace {
-
-TetherOffloadRuleParcel makeTetherOffloadRule(int inputInterfaceIndex, int outputInterfaceIndex,
-                                              const std::vector<uint8_t>& destination,
-                                              int prefixLength,
-                                              const std::vector<uint8_t>& srcL2Address,
-                                              const std::vector<uint8_t>& dstL2Address, int pmtu) {
-    android::net::TetherOffloadRuleParcel parcel;
-    parcel.inputInterfaceIndex = inputInterfaceIndex;
-    parcel.outputInterfaceIndex = outputInterfaceIndex;
-    parcel.destination = destination;
-    parcel.prefixLength = prefixLength;
-    parcel.srcL2Address = srcL2Address;
-    parcel.dstL2Address = dstL2Address;
-    parcel.pmtu = pmtu;
-    return parcel;
-}
-
-}  // namespace
-
-// TODO: probably remove the test because TetherOffload* binder calls are deprecated.
-TEST_F(NetdBinderTest, DISABLED_TetherOffloadRule) {
-    // TODO: Perhaps verify invalid interface index once the netd handle the error in methods.
-    constexpr uint32_t kIfaceInt = 101;
-    constexpr uint32_t kIfaceExt = 102;
-    constexpr uint32_t kIfaceNonExistent = 103;
-
-    const std::vector<uint8_t> kAddr6 = {0x20, 0x01, 0x0d, 0xb8, 0xca, 0xfe, 0x00, 0x00,
-                                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x88};
-    const std::vector<uint8_t> kSrcMac = {0x00, 0x00, 0x00, 0x00, 0x00, 0x0a};
-    const std::vector<uint8_t> kDstMac = {0x00, 0x00, 0x00, 0x00, 0x00, 0x0b};
-
-    const std::vector<uint8_t> kInvalidAddr4 = {0xac, 0x0a, 0x0d, 0xb8};  // should be IPv6 address
-    const std::vector<uint8_t> kInvalidMac = {0xde, 0xad, 0xbe, 0xef};    // should be 6-byte length
-
-    // Invalid IP address, add rule
-    TetherOffloadRuleParcel rule = makeTetherOffloadRule(
-            kIfaceExt, kIfaceInt, kInvalidAddr4 /*bad*/, 128, kSrcMac, kDstMac, 1500);
-    auto status = mNetd->tetherOffloadRuleAdd(rule);
-    EXPECT_FALSE(status.isOk());
-    EXPECT_EQ(EAFNOSUPPORT, status.serviceSpecificErrorCode());
-
-    // Invalid source L2 address, add rule
-    rule = makeTetherOffloadRule(kIfaceExt, kIfaceInt, kAddr6, 128, kInvalidMac /*bad*/, kDstMac,
-                                 1500);
-    status = mNetd->tetherOffloadRuleAdd(rule);
-    EXPECT_FALSE(status.isOk());
-    EXPECT_EQ(ENXIO, status.serviceSpecificErrorCode());
-
-    // Invalid destination L2 address, add rule
-    rule = makeTetherOffloadRule(kIfaceExt, kIfaceInt, kAddr6, 128, kSrcMac, kInvalidMac /*bad*/,
-                                 1500);
-    status = mNetd->tetherOffloadRuleAdd(rule);
-    EXPECT_FALSE(status.isOk());
-    EXPECT_EQ(ENXIO, status.serviceSpecificErrorCode());
-
-    // Invalid IP address, remove rule
-    rule = makeTetherOffloadRule(kIfaceExt, kIfaceInt, kInvalidAddr4 /*bad*/, 128, kSrcMac, kDstMac,
-                                 1500);
-    status = mNetd->tetherOffloadRuleRemove(rule);
-    EXPECT_FALSE(status.isOk());
-    EXPECT_EQ(EAFNOSUPPORT, status.serviceSpecificErrorCode());
-
-    // Invalid prefix length
-    rule = makeTetherOffloadRule(kIfaceExt, kIfaceInt, kAddr6, 64 /*bad*/, kSrcMac, kDstMac, 1500);
-    status = mNetd->tetherOffloadRuleAdd(rule);
-    EXPECT_FALSE(status.isOk());
-    EXPECT_EQ(EINVAL, status.serviceSpecificErrorCode());
-    status = mNetd->tetherOffloadRuleRemove(rule);
-    EXPECT_FALSE(status.isOk());
-    EXPECT_EQ(EINVAL, status.serviceSpecificErrorCode());
-
-    // Invalid interface index
-    rule = makeTetherOffloadRule(kIfaceExt, 0, kAddr6, 128, kSrcMac, kDstMac, 1500);
-    status = mNetd->tetherOffloadRuleAdd(rule);
-    EXPECT_FALSE(status.isOk());
-    EXPECT_EQ(ENODEV, status.serviceSpecificErrorCode());
-    rule = makeTetherOffloadRule(0, kIfaceInt, kAddr6, 64, kSrcMac, kDstMac, 1500);
-    status = mNetd->tetherOffloadRuleRemove(rule);
-    EXPECT_FALSE(status.isOk());
-    EXPECT_EQ(ENODEV, status.serviceSpecificErrorCode());
-
-    // Invalid pmtu (too low)
-    rule = makeTetherOffloadRule(kIfaceExt, kIfaceInt, kAddr6, 128, kSrcMac, kDstMac, 1279);
-    status = mNetd->tetherOffloadRuleAdd(rule);
-    EXPECT_FALSE(status.isOk());
-    EXPECT_EQ(EINVAL, status.serviceSpecificErrorCode());
-
-    // Invalid pmtu (too high)
-    rule = makeTetherOffloadRule(kIfaceExt, kIfaceInt, kAddr6, 128, kSrcMac, kDstMac, 65536);
-    status = mNetd->tetherOffloadRuleAdd(rule);
-    EXPECT_FALSE(status.isOk());
-    EXPECT_EQ(EINVAL, status.serviceSpecificErrorCode());
-
-    // Remove non existent rule. Expect that silently return success if the rule did not exist.
-    rule = makeTetherOffloadRule(kIfaceNonExistent, kIfaceInt, kAddr6, 128, kSrcMac, kDstMac, 1500);
-    EXPECT_TRUE(mNetd->tetherOffloadRuleRemove(rule).isOk());
-
-    // Add and remove rule normally.
-    rule = makeTetherOffloadRule(kIfaceExt, kIfaceInt, kAddr6, 128, kSrcMac, kDstMac, 1500);
-    EXPECT_TRUE(mNetd->tetherOffloadRuleAdd(rule).isOk());
-    EXPECT_TRUE(mNetd->tetherOffloadRuleRemove(rule).isOk());
-}
-
-static bool expectPacket(int fd, uint8_t* ipPacket, ssize_t ipLen) {
-    constexpr bool kDebug = false;
-
-    uint8_t buf[ETHER_HDR_LEN + 1500];
-
-    // Wait a bit to ensure that the packet we're interested in has arrived.
-    // TODO: speed this up.
-    usleep(100 * 1000);
-
-    ssize_t bytesRead;
-    ssize_t expectedLen = ipLen + ETHER_HDR_LEN;
-    while ((bytesRead = read(fd, buf, sizeof(buf))) >= 0) {
-        if (kDebug) {
-            std::cerr << fmt::format(
-                    "Expected: {:02x}\n  Actual: {:02x}\n",
-                    fmt::join(ipPacket, ipPacket + ipLen, " "),
-                    fmt::join(buf + ETHER_HDR_LEN, buf + ETHER_HDR_LEN + ipLen, " "));
-        }
-
-        if (bytesRead != expectedLen) {
-            continue;
-        }
-
-        if (!memcmp(ipPacket, buf + ETHER_HDR_LEN, ipLen)) {
-            return true;
-        }
-    }
-
-    return false;
-}
-
-static bool tcQdiscExists(const std::string& interface) {
-    std::string command = StringPrintf("tc qdisc show dev %s", interface.c_str());
-    std::vector<std::string> lines = runCommand(command);
-    for (const auto& line : lines) {
-        if (StartsWith(line, "qdisc clsact ffff:")) return true;
-    }
-    return false;
-}
-
-static bool tcFilterExists(const std::string& interface) {
-    std::string command = StringPrintf("tc filter show dev %s ingress", interface.c_str());
-    std::vector<std::string> lines = runCommand(command);
-    const std::basic_regex regex("^filter .* bpf .* prog_offload_schedcls_tether_.*$");
-    for (const auto& line : lines) {
-        if (std::regex_match(Trim(line), regex)) return true;
-    }
-    return false;
-}
-
-// TODO: probably remove the test because TetherOffload* binder calls are deprecated.
-TEST_F(NetdBinderTest, DISABLED_TetherOffloadForwarding) {
-    SKIP_IF_EXTENDED_BPF_NOT_SUPPORTED;
-
-    constexpr const char* kDownstreamPrefix = "2001:db8:2::/64";
-
-    // 1500-byte packet.
-    constexpr unsigned short kPayloadLen = 1500 - sizeof(ipv6hdr);
-    struct packet {
-        ipv6hdr hdr;
-        char data[kPayloadLen];
-    } __attribute__((packed)) pkt = {
-            .hdr =
-                    {
-                            .version = 6,
-                            .payload_len = htons(kPayloadLen),
-                            .nexthdr = 59,  // No next header.
-                            .hop_limit = 64,
-                            .saddr = {{{0x20, 0x01, 0x0d, 0xb8, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
-                                        0x00, 0x00, 0x00, 0x00, 0x00, 0x01}}},
-                            .daddr = {{{0x20, 0x01, 0x0d, 0xb8, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
-                                        0x00, 0x00, 0x0f, 0x00, 0xca, 0xfe}}},
-                    },
-    };
-    ASSERT_EQ(1500U, sizeof(pkt));
-
-    // Use one of the test's tun interfaces as upstream.
-    // It must be part of a network or it will not have the clsact attached.
-    const auto& config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
-                                                 INetd::PERMISSION_NONE, false);
-    EXPECT_TRUE(mNetd->networkCreate(config).isOk());
-    EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
-    int fd1 = sTun.getFdForTesting();
-    EXPECT_TRUE(tcQdiscExists(sTun.name()));
-
-    // Create our own tap as a downstream.
-    TunInterface tap;
-    ASSERT_EQ(0, tap.init(true /* isTap */));
-    ASSERT_LE(tap.name().size(), static_cast<size_t>(IFNAMSIZ));
-    int fd2 = tap.getFdForTesting();
-
-    // Set it to nonblocking so that expectPacket can work.
-    int flags = fcntl(fd2, F_GETFL, 0);
-    fcntl(fd2, F_SETFL, flags | O_NONBLOCK);
-
-    // Downstream interface setup. Add to local network, add directly-connected route, etc.
-    binder::Status status = mNetd->networkAddInterface(INetd::LOCAL_NET_ID, tap.name());
-    EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
-    status = mNetd->tetherInterfaceAdd(tap.name());
-    EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
-    expectTetherInterfaceConfigureForIPv6Router(tap.name());
-    EXPECT_TRUE(tcQdiscExists(tap.name()));
-
-    // Can't easily use INetd::NEXTHOP_NONE because it is a String16 constant. Use "" instead.
-    status = mNetd->networkAddRoute(INetd::LOCAL_NET_ID, tap.name(), kDownstreamPrefix, "");
-    EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
-
-    // Set up forwarding. All methods take intIface first and extIface second.
-    status = mNetd->tetherAddForward(tap.name(), sTun.name());
-    EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
-    status = mNetd->ipfwdAddInterfaceForward(tap.name(), sTun.name());
-    EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
-    EXPECT_TRUE(tcFilterExists(sTun.name()));
-
-    std::vector<uint8_t> kDummyMac = {02, 00, 00, 00, 00, 00};
-    uint8_t* daddr = reinterpret_cast<uint8_t*>(&pkt.hdr.daddr);
-    std::vector<uint8_t> dstAddr(daddr, daddr + sizeof(pkt.hdr.daddr));
-
-    TetherOffloadRuleParcel rule = makeTetherOffloadRule(sTun.ifindex(), tap.ifindex(), dstAddr,
-                                                         128, kDummyMac, kDummyMac, sizeof(pkt));
-    status = mNetd->tetherOffloadRuleAdd(rule);
-    EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
-
-    // Set data limit to one byte less than two packets.
-    // If you get rid of the '- 1' then the second packet will get forwarded
-    // and the EXPECT_FALSE(expectPacket(...)) a dozen lines down will fail.
-    status = mNetd->tetherOffloadSetInterfaceQuota(sTun.ifindex(), sizeof(pkt) * 2 - 1);
-    EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
-
-    // Receive a packet on sTun.
-    EXPECT_EQ((ssize_t)sizeof(pkt), write(fd1, &pkt, sizeof(pkt)));
-
-    // Expect a packet identical to pkt, except with a TTL of 63.
-    struct packet pkt2 = pkt;
-    ASSERT_EQ(1500U, sizeof(pkt2));
-    pkt2.hdr.hop_limit = pkt.hdr.hop_limit - 1;
-    EXPECT_TRUE(expectPacket(fd2, (uint8_t*)&pkt2, sizeof(pkt2)));
-
-    // Receive a second packet on sTun.
-    EXPECT_EQ((ssize_t)sizeof(pkt), write(fd1, &pkt, sizeof(pkt)));
-
-    // Should fail to forward due to quota limit.
-    EXPECT_FALSE(expectPacket(fd2, (uint8_t*)&pkt2, sizeof(pkt2)));
-
-    // Clean up.
-    EXPECT_TRUE(mNetd->tetherOffloadRuleRemove(rule).isOk());
-
-    TetherStatsParcel tetherStats;
-    EXPECT_TRUE(mNetd->tetherOffloadGetAndClearStats(sTun.ifindex(), &tetherStats).isOk());
-    EXPECT_EQ("", tetherStats.iface);
-    EXPECT_EQ(static_cast<int64_t>(sizeof(pkt)), tetherStats.rxBytes);
-    EXPECT_EQ(1, tetherStats.rxPackets);
-    EXPECT_EQ(0, tetherStats.txBytes);
-    EXPECT_EQ(0, tetherStats.txPackets);
-    EXPECT_EQ(sTun.ifindex(), tetherStats.ifIndex);
-
-    EXPECT_TRUE(mNetd->ipfwdRemoveInterfaceForward(tap.name(), sTun.name()).isOk());
-    EXPECT_TRUE(mNetd->tetherRemoveForward(tap.name(), sTun.name()).isOk());
-    EXPECT_TRUE(mNetd->networkRemoveRoute(INetd::LOCAL_NET_ID, tap.name(), kDownstreamPrefix, "")
-                        .isOk());
-    EXPECT_TRUE(mNetd->tetherInterfaceRemove(tap.name()).isOk());
-    EXPECT_TRUE(mNetd->networkRemoveInterface(INetd::LOCAL_NET_ID, tap.name()).isOk());
-    EXPECT_TRUE(mNetd->networkRemoveInterface(TEST_NETID1, sTun.name()).isOk());
-}
-
-namespace {
-
-std::vector<std::string> dumpService(const sp<IBinder>& binder) {
-    unique_fd localFd, remoteFd;
-    bool success = Pipe(&localFd, &remoteFd);
-    EXPECT_TRUE(success) << "Failed to open pipe for dumping: " << strerror(errno);
-    if (!success) return {};
-
-    // dump() blocks until another thread has consumed all its output.
-    std::thread dumpThread = std::thread([binder, remoteFd{std::move(remoteFd)}]() {
-        android::status_t ret = binder->dump(remoteFd, {});
-        EXPECT_EQ(android::OK, ret) << "Error dumping service: " << android::statusToString(ret);
-    });
-
-    std::string dumpContent;
-
-    EXPECT_TRUE(ReadFdToString(localFd.get(), &dumpContent))
-            << "Error during dump: " << strerror(errno);
-    dumpThread.join();
-
-    std::stringstream dumpStream(std::move(dumpContent));
-    std::vector<std::string> lines;
-    std::string line;
-    while (std::getline(dumpStream, line)) {
-        lines.push_back(line);
-    }
-
-    return lines;
-}
-
-}  // namespace
-
 TEST_F(NetdBinderTest, TestServiceDump) {
     sp<IBinder> binder = INetd::asBinder(mNetd);
     ASSERT_NE(nullptr, binder);
@@ -3873,17 +3644,17 @@
 
     // Send some IPCs and for each one add an element to testData telling us what to expect.
     const auto& config = makeNativeNetworkConfig(TEST_DUMP_NETID, NativeNetworkType::PHYSICAL,
-                                                 INetd::PERMISSION_NONE, false);
+                                                 INetd::PERMISSION_NONE, false, false);
     EXPECT_TRUE(mNetd->networkCreate(config).isOk());
     testData.push_back(
             {"networkCreate(NativeNetworkConfig{netId: 65123, networkType: PHYSICAL, "
-             "permission: 0, secure: false, vpnType: PLATFORM})",
+             "permission: 0, secure: false, vpnType: PLATFORM, excludeLocalRoutes: false})",
              "networkCreate.*65123"});
 
     EXPECT_EQ(EEXIST, mNetd->networkCreate(config).serviceSpecificErrorCode());
     testData.push_back(
             {"networkCreate(NativeNetworkConfig{netId: 65123, networkType: PHYSICAL, "
-             "permission: 0, secure: false, vpnType: PLATFORM}) "
+             "permission: 0, secure: false, vpnType: PLATFORM, excludeLocalRoutes: false}) "
              "-> ServiceSpecificException(17, \"File exists\")",
              "networkCreate.*65123.*17"});
 
@@ -3908,7 +3679,9 @@
     testData.push_back({"networkDestroy(65123)", "networkDestroy.*65123"});
 
     // Send the service dump request to netd.
-    std::vector<std::string> lines = dumpService(binder);
+    std::vector<std::string> lines = {};
+    android::status_t ret = dumpService(binder, {}, lines);
+    ASSERT_EQ(android::OK, ret) << "Error dumping service: " << android::statusToString(ret);
 
     // Basic regexp to match dump output lines. Matches the beginning and end of the line, and
     // puts the output of the command itself into the first match group.
@@ -3937,40 +3710,6 @@
     }
 }
 
-TEST_F(NetdBinderTest, DeprecatedTetherOffloadRuleAdd) {
-    TetherOffloadRuleParcel emptyRule;
-    auto status = mNetd->tetherOffloadRuleAdd(emptyRule);
-    ASSERT_FALSE(status.isOk());
-    ASSERT_EQ(status.exceptionCode(), binder::Status::EX_UNSUPPORTED_OPERATION);
-}
-
-TEST_F(NetdBinderTest, DeprecatedTetherOffloadRuleRemove) {
-    TetherOffloadRuleParcel emptyRule;
-    auto status = mNetd->tetherOffloadRuleRemove(emptyRule);
-    ASSERT_FALSE(status.isOk());
-    ASSERT_EQ(status.exceptionCode(), binder::Status::EX_UNSUPPORTED_OPERATION);
-}
-
-TEST_F(NetdBinderTest, DeprecatedTetherOffloadGetStats) {
-    std::vector<TetherStatsParcel> tetherStatsList;
-    auto status = mNetd->tetherOffloadGetStats(&tetherStatsList);
-    ASSERT_FALSE(status.isOk());
-    ASSERT_EQ(status.exceptionCode(), binder::Status::EX_UNSUPPORTED_OPERATION);
-}
-
-TEST_F(NetdBinderTest, DeprecatedTetherOffloadSetInterfaceQuota) {
-    auto status = mNetd->tetherOffloadSetInterfaceQuota(0 /* ifIndex */, 0 /* quotaBytes */);
-    ASSERT_FALSE(status.isOk());
-    ASSERT_EQ(status.exceptionCode(), binder::Status::EX_UNSUPPORTED_OPERATION);
-}
-
-TEST_F(NetdBinderTest, DeprecatedTetherOffloadGetAndClearStats) {
-    TetherStatsParcel tetherStats;
-    auto status = mNetd->tetherOffloadGetAndClearStats(0 /* ifIndex */, &tetherStats);
-    ASSERT_FALSE(status.isOk());
-    ASSERT_EQ(status.exceptionCode(), binder::Status::EX_UNSUPPORTED_OPERATION);
-}
-
 namespace {
 
 // aliases for better reading
@@ -3979,7 +3718,7 @@
 #define VPN_NETID TEST_NETID3
 
 void verifyAppUidRules(std::vector<bool>&& expectedResults, std::vector<UidRangeParcel>& uidRanges,
-                       const std::string& iface, uint32_t subPriority) {
+                       const std::string& iface, int32_t subPriority) {
     ASSERT_EQ(expectedResults.size(), uidRanges.size());
     if (iface.size()) {
         std::string action = StringPrintf("lookup %s ", iface.c_str());
@@ -4017,15 +3756,17 @@
 }
 
 void verifyVpnUidRules(std::vector<bool>&& expectedResults, NativeUidRangeConfig& uidRangeConfig,
-                       const std::string& iface, bool secure) {
+                       const std::string& iface, bool secure, bool excludeLocalRoutes) {
     ASSERT_EQ(expectedResults.size(), uidRangeConfig.uidRanges.size());
     std::string action = StringPrintf("lookup %s ", iface.c_str());
 
-    uint32_t priority;
+    int32_t priority;
     if (secure) {
         priority = RULE_PRIORITY_SECURE_VPN;
     } else {
-        priority = RULE_PRIORITY_BYPASSABLE_VPN;
+        // Set to no local exclusion here to reflect the default value of local exclusion.
+        priority = excludeLocalRoutes ? RULE_PRIORITY_BYPASSABLE_VPN_LOCAL_EXCLUSION
+                                      : RULE_PRIORITY_BYPASSABLE_VPN_NO_LOCAL_EXCLUSION;
     }
     for (unsigned long i = 0; i < uidRangeConfig.uidRanges.size(); i++) {
         EXPECT_EQ(expectedResults[i], ipRuleExistsForRange(priority + uidRangeConfig.subPriority,
@@ -4039,8 +3780,8 @@
     }
 }
 
-constexpr int SUB_PRIORITY_1 = UidRanges::DEFAULT_SUB_PRIORITY + 1;
-constexpr int SUB_PRIORITY_2 = UidRanges::DEFAULT_SUB_PRIORITY + 2;
+constexpr int SUB_PRIORITY_1 = UidRanges::SUB_PRIORITY_HIGHEST + 1;
+constexpr int SUB_PRIORITY_2 = UidRanges::SUB_PRIORITY_HIGHEST + 2;
 
 constexpr int IMPLICITLY_SELECT = 0;
 constexpr int EXPLICITLY_SELECT = 1;
@@ -4102,7 +3843,7 @@
 // Verify whether API reject overlapped UID ranges
 TEST_F(NetdBinderTest, PerAppDefaultNetwork_OverlappedUidRanges) {
     const auto& config = makeNativeNetworkConfig(APP_DEFAULT_NETID, NativeNetworkType::PHYSICAL,
-                                                 INetd::PERMISSION_NONE, false);
+                                                 INetd::PERMISSION_NONE, false, false);
     EXPECT_TRUE(mNetd->networkCreate(config).isOk());
     EXPECT_TRUE(mNetd->networkAddInterface(APP_DEFAULT_NETID, sTun.name()).isOk());
 
@@ -4147,7 +3888,7 @@
 // Verify whether IP rules for app default network are correctly configured.
 TEST_F(NetdBinderTest, PerAppDefaultNetwork_VerifyIpRules) {
     const auto& config = makeNativeNetworkConfig(APP_DEFAULT_NETID, NativeNetworkType::PHYSICAL,
-                                                 INetd::PERMISSION_NONE, false);
+                                                 INetd::PERMISSION_NONE, false, false);
     EXPECT_TRUE(mNetd->networkCreate(config).isOk());
     EXPECT_TRUE(mNetd->networkAddInterface(APP_DEFAULT_NETID, sTun.name()).isOk());
 
@@ -4156,23 +3897,23 @@
 
     EXPECT_TRUE(mNetd->networkAddUidRanges(APP_DEFAULT_NETID, uidRanges).isOk());
     verifyAppUidRules({true, true} /*expectedResults*/, uidRanges, sTun.name(),
-                      UidRanges::DEFAULT_SUB_PRIORITY);
+                      UidRanges::SUB_PRIORITY_HIGHEST);
     EXPECT_TRUE(mNetd->networkRemoveUidRanges(APP_DEFAULT_NETID, {uidRanges.at(0)}).isOk());
     verifyAppUidRules({false, true} /*expectedResults*/, uidRanges, sTun.name(),
-                      UidRanges::DEFAULT_SUB_PRIORITY);
+                      UidRanges::SUB_PRIORITY_HIGHEST);
     EXPECT_TRUE(mNetd->networkRemoveUidRanges(APP_DEFAULT_NETID, {uidRanges.at(1)}).isOk());
     verifyAppUidRules({false, false} /*expectedResults*/, uidRanges, sTun.name(),
-                      UidRanges::DEFAULT_SUB_PRIORITY);
+                      UidRanges::SUB_PRIORITY_HIGHEST);
 
     EXPECT_TRUE(mNetd->networkAddUidRanges(INetd::UNREACHABLE_NET_ID, uidRanges).isOk());
     verifyAppUidRules({true, true} /*expectedResults*/, uidRanges, "",
-                      UidRanges::DEFAULT_SUB_PRIORITY);
+                      UidRanges::SUB_PRIORITY_HIGHEST);
     EXPECT_TRUE(mNetd->networkRemoveUidRanges(INetd::UNREACHABLE_NET_ID, {uidRanges.at(0)}).isOk());
     verifyAppUidRules({false, true} /*expectedResults*/, uidRanges, "",
-                      UidRanges::DEFAULT_SUB_PRIORITY);
+                      UidRanges::SUB_PRIORITY_HIGHEST);
     EXPECT_TRUE(mNetd->networkRemoveUidRanges(INetd::UNREACHABLE_NET_ID, {uidRanges.at(1)}).isOk());
     verifyAppUidRules({false, false} /*expectedResults*/, uidRanges, "",
-                      UidRanges::DEFAULT_SUB_PRIORITY);
+                      UidRanges::SUB_PRIORITY_HIGHEST);
 }
 
 // Verify whether packets go through the right network with and without per-app default network.
@@ -4475,7 +4216,7 @@
 
 TEST_F(NetdBinderTest, NetworkCreate) {
     auto config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
-                                          INetd::PERMISSION_NONE, false);
+                                          INetd::PERMISSION_NONE, false, false);
     EXPECT_TRUE(mNetd->networkCreate(config).isOk());
     EXPECT_TRUE(mNetd->networkDestroy(config.netId).isOk());
 
@@ -4486,7 +4227,7 @@
 
     // invalid network type
     auto wrongConfig = makeNativeNetworkConfig(TEST_NETID2, static_cast<NativeNetworkType>(-1),
-                                               INetd::PERMISSION_NONE, false);
+                                               INetd::PERMISSION_NONE, false, false);
     EXPECT_EQ(EINVAL, mNetd->networkCreate(wrongConfig).serviceSpecificErrorCode());
 
     // invalid VPN type
@@ -4499,16 +4240,16 @@
 TEST_F(NetdBinderTest, UidRangeSubPriority_ValidateInputs) {
     createVpnAndOtherPhysicalNetwork(SYSTEM_DEFAULT_NETID, APP_DEFAULT_NETID, VPN_NETID,
                                      /*isSecureVPN=*/true);
-    // Invalid priority -1 on a physical network.
+    // Invalid priority -10 on a physical network.
     NativeUidRangeConfig uidRangeConfig =
             makeNativeUidRangeConfig(APP_DEFAULT_NETID, {makeUidRangeParcel(BASE_UID, BASE_UID)},
-                                     UidRanges::DEFAULT_SUB_PRIORITY - 1);
+                                     UidRanges::SUB_PRIORITY_HIGHEST - 10);
     binder::Status status = mNetd->networkAddUidRangesParcel(uidRangeConfig);
     EXPECT_FALSE(status.isOk());
     EXPECT_EQ(EINVAL, status.serviceSpecificErrorCode());
 
     // Invalid priority 1000 on a physical network.
-    uidRangeConfig.subPriority = UidRanges::LOWEST_SUB_PRIORITY + 1;
+    uidRangeConfig.subPriority = UidRanges::SUB_PRIORITY_NO_DEFAULT + 1;
     status = mNetd->networkAddUidRangesParcel(uidRangeConfig);
     EXPECT_FALSE(status.isOk());
     EXPECT_EQ(EINVAL, status.serviceSpecificErrorCode());
@@ -4587,34 +4328,54 @@
 
     // Create 2 VPNs, using sTun and sTun2.
     auto config = makeNativeNetworkConfig(VPN_NETID, NativeNetworkType::VIRTUAL,
-                                          INetd::PERMISSION_NONE, isSecureVPN);
+                                          INetd::PERMISSION_NONE, isSecureVPN, false);
     EXPECT_TRUE(mNetd->networkCreate(config).isOk());
     EXPECT_TRUE(mNetd->networkAddInterface(VPN_NETID, sTun.name()).isOk());
 
     config = makeNativeNetworkConfig(VPN_NETID2, NativeNetworkType::VIRTUAL, INetd::PERMISSION_NONE,
-                                     isSecureVPN);
+                                     isSecureVPN, false);
     EXPECT_TRUE(mNetd->networkCreate(config).isOk());
     EXPECT_TRUE(mNetd->networkAddInterface(VPN_NETID2, sTun2.name()).isOk());
 
     // Assign uid ranges to different VPNs. Check if rules match.
     NativeUidRangeConfig uidRangeConfig1 = makeNativeUidRangeConfig(
-            VPN_NETID, {makeUidRangeParcel(BASE_UID, BASE_UID)}, UidRanges::DEFAULT_SUB_PRIORITY);
+            VPN_NETID, {makeUidRangeParcel(BASE_UID, BASE_UID)}, UidRanges::SUB_PRIORITY_HIGHEST);
     EXPECT_TRUE(mNetd->networkAddUidRangesParcel(uidRangeConfig1).isOk());
-    verifyVpnUidRules({true}, uidRangeConfig1, sTun.name(), isSecureVPN);
+    verifyVpnUidRules({true}, uidRangeConfig1, sTun.name(), isSecureVPN, false);
 
     NativeUidRangeConfig uidRangeConfig2 =
             makeNativeUidRangeConfig(VPN_NETID2, {makeUidRangeParcel(BASE_UID + 1, BASE_UID + 1)},
-                                     UidRanges::DEFAULT_SUB_PRIORITY);
+                                     UidRanges::SUB_PRIORITY_HIGHEST);
     EXPECT_TRUE(mNetd->networkAddUidRangesParcel(uidRangeConfig2).isOk());
-    verifyVpnUidRules({true}, uidRangeConfig2, sTun2.name(), isSecureVPN);
+    verifyVpnUidRules({true}, uidRangeConfig2, sTun2.name(), isSecureVPN, false);
 
     // Remove uid configs one-by-one. Check if rules match.
     EXPECT_TRUE(mNetd->networkRemoveUidRangesParcel(uidRangeConfig1).isOk());
-    verifyVpnUidRules({false}, uidRangeConfig1, sTun.name(), isSecureVPN);
-    verifyVpnUidRules({true}, uidRangeConfig2, sTun2.name(), isSecureVPN);
+    verifyVpnUidRules({false}, uidRangeConfig1, sTun.name(), isSecureVPN, false);
+    verifyVpnUidRules({true}, uidRangeConfig2, sTun2.name(), isSecureVPN, false);
     EXPECT_TRUE(mNetd->networkRemoveUidRangesParcel(uidRangeConfig2).isOk());
-    verifyVpnUidRules({false}, uidRangeConfig1, sTun.name(), isSecureVPN);
-    verifyVpnUidRules({false}, uidRangeConfig2, sTun2.name(), isSecureVPN);
+    verifyVpnUidRules({false}, uidRangeConfig1, sTun.name(), isSecureVPN, false);
+    verifyVpnUidRules({false}, uidRangeConfig2, sTun2.name(), isSecureVPN, false);
+}
+
+// Verify VPN ip rule on bypassable/secureVPN virtual network with local routes excluded
+TEST_P(VpnParameterizedTest, VerifyVpnIpRules_excludeLocalRoutes) {
+    const bool isSecureVPN = GetParam();
+    // Create VPN with local route excluded
+    auto config = makeNativeNetworkConfig(VPN_NETID, NativeNetworkType::VIRTUAL,
+                                          INetd::PERMISSION_NONE, isSecureVPN, true);
+    EXPECT_TRUE(mNetd->networkCreate(config).isOk());
+    EXPECT_TRUE(mNetd->networkAddInterface(VPN_NETID, sTun.name()).isOk());
+
+    // Assign uid ranges to VPN. Check if rules match.
+    NativeUidRangeConfig uidRangeConfig1 = makeNativeUidRangeConfig(
+            VPN_NETID, {makeUidRangeParcel(BASE_UID, BASE_UID)}, UidRanges::SUB_PRIORITY_HIGHEST);
+    EXPECT_TRUE(mNetd->networkAddUidRangesParcel(uidRangeConfig1).isOk());
+    verifyVpnUidRules({true}, uidRangeConfig1, sTun.name(), isSecureVPN, true);
+
+    // Remove uid configs. Check if rules match.
+    EXPECT_TRUE(mNetd->networkRemoveUidRangesParcel(uidRangeConfig1).isOk());
+    verifyVpnUidRules({false}, uidRangeConfig1, sTun.name(), isSecureVPN, true);
 }
 
 // Verify if packets go through the right network when subsidiary priority and VPN works together.
@@ -4654,38 +4415,34 @@
     constexpr int APP_DEFAULT_1_NETID = TEST_NETID2;
     constexpr int APP_DEFAULT_2_NETID = TEST_NETID4;
 
+    static const struct TestData {
+        uint32_t subPriority;
+        std::vector<UidRangeParcel> uidRanges;
+        unsigned int netId;
+    } kTestData[] = {
+            {UidRanges::SUB_PRIORITY_HIGHEST, {makeUidRangeParcel(TEST_UID1)}, VPN_NETID},
+            {SUB_PRIORITY_1,
+             {makeUidRangeParcel(TEST_UID1), makeUidRangeParcel(TEST_UID2)},
+             APP_DEFAULT_1_NETID},
+            {SUB_PRIORITY_1, {makeUidRangeParcel(TEST_UID3)}, APP_DEFAULT_2_NETID},
+            {SUB_PRIORITY_1, {makeUidRangeParcel(TEST_UID5)}, INetd::UNREACHABLE_NET_ID},
+            {SUB_PRIORITY_2, {makeUidRangeParcel(TEST_UID3)}, APP_DEFAULT_1_NETID},
+            {SUB_PRIORITY_2,
+             {makeUidRangeParcel(TEST_UID4), makeUidRangeParcel(TEST_UID5)},
+             APP_DEFAULT_2_NETID},
+    };
+
     // Creates 4 networks.
     createVpnAndOtherPhysicalNetwork(SYSTEM_DEFAULT_NETID, APP_DEFAULT_1_NETID, VPN_NETID,
                                      /*isSecureVPN=*/false);
     createPhysicalNetwork(APP_DEFAULT_2_NETID, sTun4.name());
     EXPECT_TRUE(mNetd->networkAddRoute(APP_DEFAULT_2_NETID, sTun4.name(), "::/0", "").isOk());
 
-    // Adds VPN setting.
-    NativeUidRangeConfig uidRangeConfigVpn = makeNativeUidRangeConfig(
-            VPN_NETID, {makeUidRangeParcel(TEST_UID1, TEST_UID1)}, UidRanges::DEFAULT_SUB_PRIORITY);
-    EXPECT_TRUE(mNetd->networkAddUidRangesParcel(uidRangeConfigVpn).isOk());
-
-    // Adds uidRangeConfig1 setting.
-    NativeUidRangeConfig uidRangeConfig1 = makeNativeUidRangeConfig(
-            APP_DEFAULT_1_NETID,
-            {makeUidRangeParcel(TEST_UID1, TEST_UID1), makeUidRangeParcel(TEST_UID2, TEST_UID2)},
-            SUB_PRIORITY_1);
-    EXPECT_TRUE(mNetd->networkAddUidRangesParcel(uidRangeConfig1).isOk());
-    uidRangeConfig1.netId = APP_DEFAULT_2_NETID;
-    uidRangeConfig1.uidRanges = {makeUidRangeParcel(TEST_UID3, TEST_UID3)};
-    EXPECT_TRUE(mNetd->networkAddUidRangesParcel(uidRangeConfig1).isOk());
-    uidRangeConfig1.netId = INetd::UNREACHABLE_NET_ID;
-    uidRangeConfig1.uidRanges = {makeUidRangeParcel(TEST_UID5, TEST_UID5)};
-    EXPECT_TRUE(mNetd->networkAddUidRangesParcel(uidRangeConfig1).isOk());
-
-    // Adds uidRangeConfig2 setting.
-    NativeUidRangeConfig uidRangeConfig2 = makeNativeUidRangeConfig(
-            APP_DEFAULT_1_NETID, {makeUidRangeParcel(TEST_UID3, TEST_UID3)}, SUB_PRIORITY_2);
-    EXPECT_TRUE(mNetd->networkAddUidRangesParcel(uidRangeConfig2).isOk());
-    uidRangeConfig2.netId = APP_DEFAULT_2_NETID;
-    uidRangeConfig2.uidRanges = {makeUidRangeParcel(TEST_UID4, TEST_UID4),
-                                 makeUidRangeParcel(TEST_UID5, TEST_UID5)};
-    EXPECT_TRUE(mNetd->networkAddUidRangesParcel(uidRangeConfig2).isOk());
+    for (const auto& td : kTestData) {
+        NativeUidRangeConfig uidRangeConfig =
+                makeNativeUidRangeConfig(td.netId, td.uidRanges, td.subPriority);
+        EXPECT_TRUE(mNetd->networkAddUidRangesParcel(uidRangeConfig).isOk());
+    }
 
     int systemDefaultFd = sTun.getFdForTesting();
     int appDefault_1_Fd = sTun2.getFdForTesting();
@@ -4700,5 +4457,252 @@
     expectPacketSentOnNetId(TEST_UID6, SYSTEM_DEFAULT_NETID, systemDefaultFd, IMPLICITLY_SELECT);
 
     // Remove test rules from the unreachable network.
-    EXPECT_TRUE(mNetd->networkRemoveUidRangesParcel(uidRangeConfig1).isOk());
-}
\ No newline at end of file
+    for (const auto& td : kTestData) {
+        if (td.netId == INetd::UNREACHABLE_NET_ID) {
+            NativeUidRangeConfig uidRangeConfig =
+                    makeNativeUidRangeConfig(td.netId, td.uidRanges, td.subPriority);
+            EXPECT_TRUE(mNetd->networkRemoveUidRangesParcel(uidRangeConfig).isOk());
+        }
+    }
+}
+
+class PerAppNetworkPermissionsTest : public NetdBinderTest {
+  public:
+    int bindSocketToNetwork(int sock, int netId, bool explicitlySelected) {
+        ScopedUidChange uidChange(AID_ROOT);
+        Fwmark fwmark;
+        fwmark.explicitlySelected = explicitlySelected;
+        fwmark.netId = netId;
+        return setsockopt(sock, SOL_SOCKET, SO_MARK, &(fwmark.intValue), sizeof(fwmark.intValue));
+    }
+
+    void changeNetworkPermissionForUid(int netId, int uid, bool add) {
+        auto nativeUidRangeConfig = makeNativeUidRangeConfig(netId, {makeUidRangeParcel(uid, uid)},
+                                                             UidRanges::SUB_PRIORITY_NO_DEFAULT);
+        ScopedUidChange rootUid(AID_ROOT);
+        if (add) {
+            EXPECT_TRUE(mNetd->networkAddUidRangesParcel(nativeUidRangeConfig).isOk());
+        } else {
+            EXPECT_TRUE(mNetd->networkRemoveUidRangesParcel(nativeUidRangeConfig).isOk());
+        }
+    }
+
+  protected:
+    static inline const sockaddr_in6 TEST_SOCKADDR_IN6 = {
+            .sin6_family = AF_INET6,
+            .sin6_port = 42,
+            .sin6_addr = V6_ADDR,
+    };
+    std::array<char, 4096> mTestBuf;
+};
+
+TEST_F(PerAppNetworkPermissionsTest, HasExplicitAccess) {
+    // TEST_NETID1 -> restricted network
+    createPhysicalNetwork(TEST_NETID1, sTun.name(), INetd::PERMISSION_SYSTEM);
+    EXPECT_TRUE(mNetd->networkAddRoute(TEST_NETID1, sTun.name(), "::/0", "").isOk());
+
+    // Change uid to uid without PERMISSION_SYSTEM
+    ScopedUidChange testUid(TEST_UID1);
+    unique_fd sock(socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0));
+    EXPECT_EQ(bindSocketToNetwork(sock, TEST_NETID1, true /*explicitlySelected*/), 0);
+
+    // Test without permissions should fail
+    EXPECT_EQ(connect(sock, (sockaddr*)&TEST_SOCKADDR_IN6, sizeof(TEST_SOCKADDR_IN6)), -1);
+
+    // Test access with permission succeeds and packet is routed correctly
+    changeNetworkPermissionForUid(TEST_NETID1, TEST_UID1, true /*add*/);
+    EXPECT_EQ(connect(sock, (sockaddr*)&TEST_SOCKADDR_IN6, sizeof(TEST_SOCKADDR_IN6)), 0);
+    EXPECT_EQ(send(sock, "foo", sizeof("foo"), 0), (int)sizeof("foo"));
+    EXPECT_GT(read(sTun.getFdForTesting(), mTestBuf.data(), mTestBuf.size()), 0);
+
+    // Test removing permissions.
+    // Note: Send will still succeed as the destination is cached in
+    // sock.sk_dest_cache. Try another connect instead.
+    changeNetworkPermissionForUid(TEST_NETID1, TEST_UID1, false /*add*/);
+    EXPECT_EQ(-1, connect(sock, (sockaddr*)&TEST_SOCKADDR_IN6, sizeof(TEST_SOCKADDR_IN6)));
+}
+
+TEST_F(PerAppNetworkPermissionsTest, HasImplicitAccess) {
+    // TEST_NETID1 -> restricted network
+    createPhysicalNetwork(TEST_NETID1, sTun.name(), INetd::PERMISSION_SYSTEM);
+    EXPECT_TRUE(mNetd->networkAddRoute(TEST_NETID1, sTun.name(), "::/0", "").isOk());
+
+    // Change uid to uid without PERMISSION_SYSTEM
+    ScopedUidChange testUid(TEST_UID1);
+    unique_fd sock(socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0));
+    EXPECT_EQ(bindSocketToNetwork(sock, TEST_NETID1, false /*explicitlySelected*/), 0);
+
+    // Note: we cannot call connect() when implicitly selecting the network as
+    // the fwmark would get reset to the default network.
+    // Call connect which should bind socket to default network
+    EXPECT_EQ(sendto(sock, "foo", sizeof("foo"), 0, (sockaddr*)&TEST_SOCKADDR_IN6,
+                     sizeof(TEST_SOCKADDR_IN6)),
+              -1);
+
+    // Test access with permission succeeds and packet is routed correctly
+    changeNetworkPermissionForUid(TEST_NETID1, TEST_UID1, true /*add*/);
+    EXPECT_EQ(sendto(sock, "foo", sizeof("foo"), 0, (sockaddr*)&TEST_SOCKADDR_IN6,
+                     sizeof(TEST_SOCKADDR_IN6)),
+              (int)sizeof("foo"));
+    EXPECT_GT(read(sTun.getFdForTesting(), mTestBuf.data(), mTestBuf.size()), 0);
+}
+
+TEST_F(PerAppNetworkPermissionsTest, DoesNotAffectDefaultNetworkSelection) {
+    // TEST_NETID1 -> default network
+    // TEST_NETID2 -> restricted network
+    createPhysicalNetwork(TEST_NETID1, sTun.name(), INetd::PERMISSION_NONE);
+    createPhysicalNetwork(TEST_NETID2, sTun2.name(), INetd::PERMISSION_SYSTEM);
+    EXPECT_TRUE(mNetd->networkAddRoute(TEST_NETID1, sTun.name(), "::/0", "").isOk());
+    EXPECT_TRUE(mNetd->networkAddRoute(TEST_NETID2, sTun2.name(), "::/0", "").isOk());
+    mNetd->networkSetDefault(TEST_NETID1);
+
+    changeNetworkPermissionForUid(TEST_NETID2, TEST_UID1, true /*add*/);
+
+    // Change uid to uid without PERMISSION_SYSTEM
+    ScopedUidChange testUid(TEST_UID1);
+    unique_fd sock(socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0));
+
+    // Connect should select default network
+    EXPECT_EQ(connect(sock, (sockaddr*)&TEST_SOCKADDR_IN6, sizeof(TEST_SOCKADDR_IN6)), 0);
+    EXPECT_EQ(send(sock, "foo", sizeof("foo"), 0), (int)sizeof("foo"));
+    EXPECT_GT(read(sTun.getFdForTesting(), mTestBuf.data(), mTestBuf.size()), 0);
+}
+
+TEST_F(PerAppNetworkPermissionsTest, PermissionDoesNotAffectPerAppDefaultNetworkSelection) {
+    // TEST_NETID1 -> restricted app default network
+    // TEST_NETID2 -> restricted network
+    createPhysicalNetwork(TEST_NETID1, sTun.name(), INetd::PERMISSION_SYSTEM);
+    createPhysicalNetwork(TEST_NETID2, sTun2.name(), INetd::PERMISSION_SYSTEM);
+    EXPECT_TRUE(mNetd->networkAddRoute(TEST_NETID1, sTun.name(), "::/0", "").isOk());
+    EXPECT_TRUE(mNetd->networkAddRoute(TEST_NETID2, sTun2.name(), "::/0", "").isOk());
+
+    auto nativeUidRangeConfig = makeNativeUidRangeConfig(
+            TEST_NETID1, {makeUidRangeParcel(TEST_UID1, TEST_UID1)}, 0 /*subPriority*/);
+    EXPECT_TRUE(mNetd->networkAddUidRangesParcel(nativeUidRangeConfig).isOk());
+    changeNetworkPermissionForUid(TEST_NETID2, TEST_UID1, true /*add*/);
+
+    // Change uid to uid without PERMISSION_SYSTEM
+    ScopedUidChange testUid(TEST_UID1);
+    unique_fd sock(socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0));
+
+    // Connect should select app default network
+    EXPECT_EQ(connect(sock, (sockaddr*)&TEST_SOCKADDR_IN6, sizeof(TEST_SOCKADDR_IN6)), 0);
+    EXPECT_EQ(send(sock, "foo", sizeof("foo"), 0), (int)sizeof("foo"));
+    EXPECT_GT(read(sTun.getFdForTesting(), mTestBuf.data(), mTestBuf.size()), 0);
+}
+
+TEST_F(PerAppNetworkPermissionsTest, PermissionOnlyAffectsUid) {
+    // TEST_NETID1 -> restricted network
+    // TEST_NETID2 -> restricted network
+    createPhysicalNetwork(TEST_NETID1, sTun.name(), INetd::PERMISSION_SYSTEM);
+    createPhysicalNetwork(TEST_NETID2, sTun2.name(), INetd::PERMISSION_SYSTEM);
+    EXPECT_TRUE(mNetd->networkAddRoute(TEST_NETID1, sTun.name(), "::/0", "").isOk());
+    EXPECT_TRUE(mNetd->networkAddRoute(TEST_NETID2, sTun2.name(), "::/0", "").isOk());
+
+    // test that neither TEST_UID1, nor TEST_UID2 have access without permission
+    {
+        // TEST_UID1
+        ScopedUidChange testUid(TEST_UID1);
+        unique_fd sock(socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0));
+        // TEST_NETID1
+        EXPECT_EQ(bindSocketToNetwork(sock, TEST_NETID1, true /*explicitlySelected*/), 0);
+        EXPECT_EQ(connect(sock, (sockaddr*)&TEST_SOCKADDR_IN6, sizeof(TEST_SOCKADDR_IN6)), -1);
+        // TEST_NETID2
+        EXPECT_EQ(bindSocketToNetwork(sock, TEST_NETID2, true /*explicitlySelected*/), 0);
+        EXPECT_EQ(connect(sock, (sockaddr*)&TEST_SOCKADDR_IN6, sizeof(TEST_SOCKADDR_IN6)), -1);
+    }
+    {
+        // TEST_UID2
+        ScopedUidChange testUid(TEST_UID2);
+        unique_fd sock(socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0));
+        // TEST_NETID1
+        EXPECT_EQ(bindSocketToNetwork(sock, TEST_NETID1, true /*explicitlySelected*/), 0);
+        EXPECT_EQ(connect(sock, (sockaddr*)&TEST_SOCKADDR_IN6, sizeof(TEST_SOCKADDR_IN6)), -1);
+        // TEST_NETID2
+        EXPECT_EQ(bindSocketToNetwork(sock, TEST_NETID2, true /*explicitlySelected*/), 0);
+        EXPECT_EQ(connect(sock, (sockaddr*)&TEST_SOCKADDR_IN6, sizeof(TEST_SOCKADDR_IN6)), -1);
+    }
+
+    changeNetworkPermissionForUid(TEST_NETID1, TEST_UID1, true);
+
+    // test that TEST_UID1 has access to TEST_UID1
+    {
+        // TEST_UID1
+        ScopedUidChange testUid(TEST_UID1);
+        unique_fd sock(socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0));
+        // TEST_NETID1
+        EXPECT_EQ(bindSocketToNetwork(sock, TEST_NETID1, true /*explicitlySelected*/), 0);
+        EXPECT_EQ(connect(sock, (sockaddr*)&TEST_SOCKADDR_IN6, sizeof(TEST_SOCKADDR_IN6)), 0);
+        // TEST_NETID2
+        EXPECT_EQ(bindSocketToNetwork(sock, TEST_NETID2, true /*explicitlySelected*/), 0);
+        EXPECT_EQ(connect(sock, (sockaddr*)&TEST_SOCKADDR_IN6, sizeof(TEST_SOCKADDR_IN6)), -1);
+    }
+    {
+        // TEST_UID2
+        ScopedUidChange testUid(TEST_UID2);
+        unique_fd sock(socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0));
+        // TEST_NETID1
+        EXPECT_EQ(bindSocketToNetwork(sock, TEST_NETID1, true /*explicitlySelected*/), 0);
+        EXPECT_EQ(connect(sock, (sockaddr*)&TEST_SOCKADDR_IN6, sizeof(TEST_SOCKADDR_IN6)), -1);
+        // TEST_NETID2
+        EXPECT_EQ(bindSocketToNetwork(sock, TEST_NETID2, true /*explicitlySelected*/), 0);
+        EXPECT_EQ(connect(sock, (sockaddr*)&TEST_SOCKADDR_IN6, sizeof(TEST_SOCKADDR_IN6)), -1);
+    }
+}
+
+class MDnsBinderTest : public ::testing::Test {
+  public:
+    MDnsBinderTest() {
+        sp<IServiceManager> sm = android::defaultServiceManager();
+        sp<IBinder> binder = sm->getService(String16("mdns"));
+        if (binder != nullptr) {
+            mMDns = android::interface_cast<IMDns>(binder);
+        }
+    }
+
+    void SetUp() override { ASSERT_NE(nullptr, mMDns.get()); }
+
+    void TearDown() override {}
+
+  protected:
+    sp<IMDns> mMDns;
+};
+
+class TestMDnsListener : public android::net::mdns::aidl::BnMDnsEventListener {
+  public:
+    Status onServiceRegistrationStatus(const RegistrationInfo& /* status */) override {
+        return Status::ok();
+    }
+    Status onServiceDiscoveryStatus(const DiscoveryInfo& /* status */) override {
+        return Status::ok();
+    }
+    Status onServiceResolutionStatus(const ResolutionInfo& /* status */) override {
+        return Status::ok();
+    }
+    Status onGettingServiceAddressStatus(const GetAddressInfo& /* status */) override {
+        return Status::ok();
+    }
+};
+
+TEST_F(MDnsBinderTest, EventListenerTest) {
+    // Register a null listener.
+    binder::Status status = mMDns->registerEventListener(nullptr);
+    EXPECT_FALSE(status.isOk());
+
+    // Unregister a null listener.
+    status = mMDns->unregisterEventListener(nullptr);
+    EXPECT_FALSE(status.isOk());
+
+    // Register the test listener.
+    android::sp<TestMDnsListener> testListener = new TestMDnsListener();
+    status = mMDns->registerEventListener(testListener);
+    EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+
+    // Register the duplicated listener
+    status = mMDns->registerEventListener(testListener);
+    EXPECT_FALSE(status.isOk());
+
+    // Unregister the test listener
+    status = mMDns->unregisterEventListener(testListener);
+    EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+}
diff --git a/tests/bpf_base_test.cpp b/tests/bpf_base_test.cpp
index 7ab4290..e402e08 100644
--- a/tests/bpf_base_test.cpp
+++ b/tests/bpf_base_test.cpp
@@ -36,7 +36,7 @@
 
 #include "bpf/BpfMap.h"
 #include "bpf/BpfUtils.h"
-#include "netdbpf/bpf_shared.h"
+#include "bpf_shared.h"
 
 using android::base::Result;
 
@@ -47,8 +47,6 @@
 // it's -1, which is INVALID_UID.
 constexpr uid_t TEST_UID = UID_MAX - 1;
 constexpr uint32_t TEST_TAG = 42;
-constexpr int TEST_COUNTERSET = 1;
-constexpr int DEFAULT_COUNTERSET = 0;
 
 class BpfBasicTest : public testing::Test {
   protected:
@@ -127,47 +125,5 @@
     FAIL() << "socket tag still exist after 50ms";
 }
 
-TEST_F(BpfBasicTest, TestChangeCounterSet) {
-    BpfMap<uint32_t, uint8_t> uidCounterSetMap(UID_COUNTERSET_MAP_PATH);
-    ASSERT_LE(0, uidCounterSetMap.getMap());
-    ASSERT_EQ(0, qtaguid_setCounterSet(TEST_COUNTERSET, TEST_UID));
-    uid_t uid = TEST_UID;
-    Result<uint8_t> counterSetResult = uidCounterSetMap.readValue(uid);
-    ASSERT_RESULT_OK(counterSetResult);
-    ASSERT_EQ(TEST_COUNTERSET, counterSetResult.value());
-    ASSERT_EQ(0, qtaguid_setCounterSet(DEFAULT_COUNTERSET, TEST_UID));
-    counterSetResult = uidCounterSetMap.readValue(uid);
-    ASSERT_FALSE(counterSetResult.ok());
-    ASSERT_EQ(ENOENT, counterSetResult.error().code());
-}
-
-TEST_F(BpfBasicTest, TestDeleteTagData) {
-    BpfMap<StatsKey, StatsValue> statsMapA(STATS_MAP_A_PATH);
-    ASSERT_LE(0, statsMapA.getMap());
-    BpfMap<StatsKey, StatsValue> statsMapB(STATS_MAP_B_PATH);
-    ASSERT_LE(0, statsMapB.getMap());
-    BpfMap<uint32_t, StatsValue> appUidStatsMap(APP_UID_STATS_MAP_PATH);
-    ASSERT_LE(0, appUidStatsMap.getMap());
-
-    StatsKey key = {.uid = TEST_UID, .tag = TEST_TAG, .counterSet = TEST_COUNTERSET,
-                    .ifaceIndex = 1};
-    StatsValue statsMapValue = {.rxPackets = 1, .rxBytes = 100};
-    EXPECT_RESULT_OK(statsMapB.writeValue(key, statsMapValue, BPF_ANY));
-    key.tag = 0;
-    EXPECT_RESULT_OK(statsMapA.writeValue(key, statsMapValue, BPF_ANY));
-    EXPECT_RESULT_OK(appUidStatsMap.writeValue(TEST_UID, statsMapValue, BPF_ANY));
-    ASSERT_EQ(0, qtaguid_deleteTagData(0, TEST_UID));
-    Result<StatsValue> statsResult = statsMapA.readValue(key);
-    ASSERT_FALSE(statsResult.ok());
-    ASSERT_EQ(ENOENT, statsResult.error().code());
-    statsResult = appUidStatsMap.readValue(TEST_UID);
-    ASSERT_FALSE(statsResult.ok());
-    ASSERT_EQ(ENOENT, statsResult.error().code());
-    key.tag = TEST_TAG;
-    statsResult = statsMapB.readValue(key);
-    ASSERT_FALSE(statsResult.ok());
-    ASSERT_EQ(ENOENT, statsResult.error().code());
-}
-
 }
 }
diff --git a/tests/kernel_test.cpp b/tests/kernel_test.cpp
new file mode 100644
index 0000000..2cc5c99
--- /dev/null
+++ b/tests/kernel_test.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <gtest/gtest.h>
+#include <vintf/VintfObject.h>
+
+#include <fstream>
+#include <string>
+
+namespace android {
+namespace net {
+
+namespace {
+
+using ::android::vintf::RuntimeInfo;
+using ::android::vintf::VintfObject;
+
+class KernelConfigVerifier final {
+  public:
+    KernelConfigVerifier() : mRuntimeInfo(VintfObject::GetRuntimeInfo()) {}
+
+    bool hasOption(const std::string& option) const {
+        const auto& configMap = mRuntimeInfo->kernelConfigs();
+        auto it = configMap.find(option);
+        if (it != configMap.cend()) {
+            return it->second == "y";
+        }
+        return false;
+    }
+
+  private:
+    std::shared_ptr<const RuntimeInfo> mRuntimeInfo;
+};
+
+bool isGsiImage() {
+    std::ifstream ifs("/system/system_ext/etc/init/init.gsi.rc");
+    return ifs.good();
+}
+
+}  // namespace
+
+/**
+ * If this test fails, enable the following kernel modules in your kernel config:
+ * CONFIG_NET_CLS_MATCHALL=y
+ * CONFIG_NET_ACT_POLICE=y
+ * CONFIG_NET_ACT_BPF=y
+ */
+TEST(KernelTest, TestRateLimitingSupport) {
+    if (isGsiImage()) {
+        // skip test on gsi images
+        GTEST_SKIP() << "GSI Image";
+    }
+    KernelConfigVerifier configVerifier;
+    ASSERT_TRUE(configVerifier.hasOption("CONFIG_NET_CLS_MATCHALL"));
+    ASSERT_TRUE(configVerifier.hasOption("CONFIG_NET_ACT_POLICE"));
+    ASSERT_TRUE(configVerifier.hasOption("CONFIG_NET_ACT_BPF"));
+}
+
+}  // namespace net
+}  // namespace android
diff --git a/tests/netd_client_test.cpp b/tests/netd_client_test.cpp
index c8af408..844616b 100644
--- a/tests/netd_client_test.cpp
+++ b/tests/netd_client_test.cpp
@@ -25,12 +25,9 @@
 
 #include "NetdClient.h"
 
-#define SKIP_IF_NO_NETWORK_CONNECTIVITY                                    \
-    do {                                                                   \
-        if (!checkNetworkConnectivity()) {                                 \
-            GTEST_LOG_(INFO) << "Skip. Required Network Connectivity. \n"; \
-            return;                                                        \
-        }                                                                  \
+#define SKIP_IF_NO_NETWORK_CONNECTIVITY                                                          \
+    do {                                                                                         \
+        if (!checkNetworkConnectivity()) GTEST_SKIP() << "Skip. Requires Network Connectivity."; \
     } while (0)
 
 namespace {
diff --git a/tests/netd_test.cpp b/tests/netd_test.cpp
index fcd538e..8d5d8bc 100644
--- a/tests/netd_test.cpp
+++ b/tests/netd_test.cpp
@@ -32,10 +32,8 @@
 #include <android-base/unique_fd.h>
 
 #define LOG_TAG "NetdTest"
-#include "bpf/BpfMap.h"
-#include "netdbpf/bpf_shared.h"
 
-#include "OffloadUtils.h"
+#include "TcUtils.h"
 
 namespace android {
 namespace net {
diff --git a/tests/netlink_listener_test.cpp b/tests/netlink_listener_test.cpp
deleted file mode 100644
index 249bdfb..0000000
--- a/tests/netlink_listener_test.cpp
+++ /dev/null
@@ -1,172 +0,0 @@
-//
-// Copyright (C) 2018 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-#include <errno.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <linux/inet_diag.h>
-#include <linux/netlink.h>
-#include <linux/sock_diag.h>
-#include <linux/unistd.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-
-#include <gtest/gtest.h>
-
-#include <cutils/qtaguid.h>
-
-#include <netdutils/Misc.h>
-#include <netdutils/Syscalls.h>
-#include "NetlinkListener.h"
-#include "TrafficController.h"
-#include "bpf/BpfMap.h"
-#include "bpf/BpfUtils.h"
-#include "netdutils/Netlink.h"
-
-// A test uid that is large enough so normal apps are not likely to take,
-constexpr uid_t TEST_UID = UID_MAX - 2;
-// A test tag arbitrarily selected.
-constexpr uint32_t TEST_TAG = 0xFF0F0F0F;
-
-constexpr uint32_t SOCK_CLOSE_WAIT_US = 30 * 1000;
-constexpr uint32_t ENOBUFS_POLL_WAIT_US = 10 * 1000;
-
-using android::base::Result;
-using android::base::ResultError;
-
-// This test set up a SkDestroyListener that is runing parallel with the production
-// SkDestroyListener. The test will create thousands of sockets and tag them on the
-// production cookieUidTagMap and close them in a short time. When the number of
-// sockets get closed exceeds the buffer size, it will start to return ENOBUFF
-// error. The error will be ignored by the production SkDestroyListener and the
-// test will clean up the tags in tearDown if there is any remains.
-
-// TODO: Instead of test the ENOBUFF error, we can test the production
-// SkDestroyListener to see if it failed to delete a tagged socket when ENOBUFF
-// triggerred.
-class NetlinkListenerTest : public testing::Test {
-  protected:
-    NetlinkListenerTest() {}
-    BpfMap<uint64_t, UidTagValue> mCookieTagMap;
-
-    void SetUp() {
-        mCookieTagMap.reset(android::bpf::mapRetrieveRW(COOKIE_TAG_MAP_PATH));
-        ASSERT_TRUE(mCookieTagMap.isValid());
-    }
-
-    void TearDown() {
-        const auto deleteTestCookieEntries = [](const uint64_t& key, const UidTagValue& value,
-                                                BpfMap<uint64_t, UidTagValue>& map) {
-            if ((value.uid == TEST_UID) && (value.tag == TEST_TAG)) {
-                Result<void> res = map.deleteValue(key);
-                if (res.ok() || (res.error().code() == ENOENT)) {
-                    return Result<void>();
-                }
-                ALOGE("Failed to delete data(cookie = %" PRIu64 "): %s\n", key,
-                      strerror(res.error().code()));
-            }
-            // Move forward to next cookie in the map.
-            return Result<void>();
-        };
-        EXPECT_RESULT_OK(mCookieTagMap.iterateWithValue(deleteTestCookieEntries));
-    }
-
-    Result<void> checkNoGarbageTagsExist() {
-        const auto checkGarbageTags = [](const uint64_t&, const UidTagValue& value,
-                                         const BpfMap<uint64_t, UidTagValue>&) -> Result<void> {
-            if ((TEST_UID == value.uid) && (TEST_TAG == value.tag)) {
-                return ResultError("Closed socket is not untagged", EUCLEAN);
-            }
-            return Result<void>();
-        };
-        return mCookieTagMap.iterateWithValue(checkGarbageTags);
-    }
-
-    bool checkMassiveSocketDestroy(int totalNumber, bool expectError) {
-        std::unique_ptr<android::net::NetlinkListenerInterface> skDestroyListener;
-        auto result = android::net::TrafficController::makeSkDestroyListener();
-        if (!isOk(result)) {
-            ALOGE("Unable to create SkDestroyListener: %s", toString(result).c_str());
-        } else {
-            skDestroyListener = std::move(result.value());
-        }
-        int rxErrorCount = 0;
-        // Rx handler extracts nfgenmsg looks up and invokes registered dispatch function.
-        const auto rxErrorHandler = [&rxErrorCount](const int, const int) { rxErrorCount++; };
-        skDestroyListener->registerSkErrorHandler(rxErrorHandler);
-        int fds[totalNumber];
-        for (int i = 0; i < totalNumber; i++) {
-            fds[i] = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
-            // The likely reason for a failure is running out of available file descriptors.
-            EXPECT_LE(0, fds[i]) << i << " of " << totalNumber;
-            if (fds[i] < 0) {
-                // EXPECT_LE already failed above, so test case is a failure, but we don't
-                // want potentially tens of thousands of extra failures creating and then
-                // closing all these fds cluttering up the logs.
-                totalNumber = i;
-                break;
-            };
-            qtaguid_tagSocket(fds[i], TEST_TAG, TEST_UID);
-        }
-
-        // TODO: Use a separate thread that has it's own fd table so we can
-        // close sockets even faster simply by terminating that thread.
-        for (int i = 0; i < totalNumber; i++) {
-            EXPECT_EQ(0, close(fds[i]));
-        }
-        // wait a bit for netlink listener to handle all the messages.
-        usleep(SOCK_CLOSE_WAIT_US);
-        if (expectError) {
-            // If ENOBUFS triggered, check it only called into the handler once, ie.
-            // that the netlink handler is not spinning.
-            int currentErrorCount = rxErrorCount;
-            // 0 error count is acceptable because the system has chances to close all sockets
-            // normally.
-            EXPECT_LE(0, rxErrorCount);
-            if (!rxErrorCount) return true;
-
-            usleep(ENOBUFS_POLL_WAIT_US);
-            EXPECT_EQ(currentErrorCount, rxErrorCount);
-        } else {
-            EXPECT_RESULT_OK(checkNoGarbageTagsExist());
-            EXPECT_EQ(0, rxErrorCount);
-        }
-        return false;
-    }
-};
-
-TEST_F(NetlinkListenerTest, TestAllSocketUntagged) {
-    checkMassiveSocketDestroy(10, false);
-    checkMassiveSocketDestroy(100, false);
-}
-
-// Disabled because flaky on blueline-userdebug; this test relies on the main thread
-// winning a race against the NetlinkListener::run() thread. There's no way to ensure
-// things will be scheduled the same way across all architectures and test environments.
-TEST_F(NetlinkListenerTest, DISABLED_TestSkDestroyError) {
-    bool needRetry = false;
-    int retryCount = 0;
-    do {
-        needRetry = checkMassiveSocketDestroy(32500, true);
-        if (needRetry) retryCount++;
-    } while (needRetry && retryCount < 3);
-    // Should review test if it can always close all sockets correctly.
-    EXPECT_GT(3, retryCount);
-}
diff --git a/tests/test_utils.cpp b/tests/test_utils.cpp
index 27b17c5..93c7dd8 100644
--- a/tests/test_utils.cpp
+++ b/tests/test_utils.cpp
@@ -88,10 +88,19 @@
     return runCommand(command);
 }
 
-bool ipRouteExists(const char* ipVersion, const char* table, const std::string& ipRoute) {
+bool ipRouteExists(const char* ipVersion, const char* table,
+                   const std::vector<std::string>& ipRouteSubstrings) {
     std::vector<std::string> routes = listIpRoutes(ipVersion, table);
     for (const auto& route : routes) {
-        if (route.find(ipRoute) != std::string::npos) {
+        bool matched = true;
+        for (const auto& substring : ipRouteSubstrings) {
+            if (route.find(substring) == std::string::npos) {
+                matched = false;
+                break;
+            }
+        }
+
+        if (matched) {
             return true;
         }
     }
diff --git a/tests/test_utils.h b/tests/test_utils.h
index c8cd6ce..de6c221 100644
--- a/tests/test_utils.h
+++ b/tests/test_utils.h
@@ -35,4 +35,5 @@
 
 std::vector<std::string> listIpRoutes(const char* ipVersion, const char* table);
 
-bool ipRouteExists(const char* ipVersion, const char* table, const std::string& ipRoute);
+bool ipRouteExists(const char* ipVersion, const char* table,
+                   const std::vector<std::string>& ipRouteSubstrings);