Merge "Use java BpfMap in BpfNetMaps#replaceUidChain"
diff --git a/Tethering/tests/privileged/src/com/android/networkstack/tethering/BpfMapTest.java b/Tethering/tests/privileged/src/com/android/networkstack/tethering/BpfMapTest.java
index 68c1c57..536ab2d 100644
--- a/Tethering/tests/privileged/src/com/android/networkstack/tethering/BpfMapTest.java
+++ b/Tethering/tests/privileged/src/com/android/networkstack/tethering/BpfMapTest.java
@@ -30,6 +30,7 @@
 import android.net.MacAddress;
 import android.os.Build;
 import android.system.ErrnoException;
+import android.system.Os;
 import android.system.OsConstants;
 import android.util.ArrayMap;
 
@@ -42,6 +43,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.io.File;
 import java.net.InetAddress;
 import java.util.NoSuchElementException;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -393,4 +395,34 @@
             assertEquals(OsConstants.ENOENT, expected.errno);
         }
     }
+
+    private static int getNumOpenFds() {
+        return new File("/proc/" + Os.getpid() + "/fd").listFiles().length;
+    }
+
+    @Test
+    public void testNoFdLeaks() throws Exception {
+        // Due to #setUp has called #initTestMap to open map and BpfMap is using persistent fd
+        // cache, expect that the fd amount is not increased in the iterations.
+        // See the comment of BpfMap#close.
+        final int iterations = 1000;
+        final int before = getNumOpenFds();
+        for (int i = 0; i < iterations; i++) {
+            try (BpfMap<TetherDownstream6Key, Tether6Value> map = new BpfMap<>(
+                TETHER_DOWNSTREAM6_FS_PATH, BpfMap.BPF_F_RDWR,
+                TetherDownstream6Key.class, Tether6Value.class)) {
+                // do nothing
+            }
+        }
+        final int after = getNumOpenFds();
+
+        // Check that the number of open fds is the same as before.
+        // If this exact match becomes flaky, we probably need to distinguish that fd is belong
+        // to "bpf-map".
+        // ex:
+        // $ adb shell ls -all /proc/16196/fd
+        // [..] network_stack 64 2022-07-26 22:01:02.300002956 +0800 749 -> anon_inode:bpf-map
+        // [..] network_stack 64 2022-07-26 22:01:02.188002956 +0800 75 -> anon_inode:[eventfd]
+        assertEquals("Fd leak after " + iterations + " iterations: ", before, after);
+    }
 }
diff --git a/bpf_progs/dscpPolicy.c b/bpf_progs/dscpPolicy.c
index 25abd2b..f2116f2 100644
--- a/bpf_progs/dscpPolicy.c
+++ b/bpf_progs/dscpPolicy.c
@@ -36,8 +36,6 @@
 #define ECN_MASK 3
 #define IP4_OFFSET(field, header) (header + offsetof(struct iphdr, field))
 #define UPDATE_TOS(dscp, tos) (dscp << 2) | (tos & ECN_MASK)
-#define UPDATE_PRIORITY(dscp) ((dscp >> 2) + 0x60)
-#define UPDATE_FLOW_LABEL(dscp, flow_lbl) ((dscp & 0xf) << 6) + (flow_lbl >> 6)
 
 DEFINE_BPF_MAP_GRW(switch_comp_map, ARRAY, int, uint64_t, 1, AID_SYSTEM)
 
@@ -53,12 +51,12 @@
 DEFINE_BPF_MAP_GRW(ipv4_dscp_policies_map, ARRAY, uint32_t, DscpPolicy, MAX_POLICIES, AID_SYSTEM)
 DEFINE_BPF_MAP_GRW(ipv6_dscp_policies_map, ARRAY, uint32_t, DscpPolicy, MAX_POLICIES, AID_SYSTEM)
 
-static inline __always_inline void match_policy(struct __sk_buff* skb, bool ipv4, bool is_eth) {
+static inline __always_inline void match_policy(struct __sk_buff* skb, bool ipv4) {
     void* data = (void*)(long)skb->data;
     const void* data_end = (void*)(long)skb->data_end;
 
-    const int l2_header_size = is_eth ? sizeof(struct ethhdr) : 0;
-    struct ethhdr* eth = is_eth ? data : NULL;
+    const int l2_header_size = sizeof(struct ethhdr);
+    struct ethhdr* eth = data;
 
     if (data + l2_header_size > data_end) return;
 
@@ -80,11 +78,10 @@
     uint8_t protocol = 0;  // TODO: Use are reserved value? Or int (-1) and cast to uint below?
     struct in6_addr src_ip = {};
     struct in6_addr dst_ip = {};
-    uint8_t tos = 0;       // Only used for IPv4
-    uint8_t priority = 0;  // Only used for IPv6
-    uint8_t flow_lbl = 0;  // Only used for IPv6
+    uint8_t tos = 0;             // Only used for IPv4
+    uint32_t old_first_u32 = 0;  // Only used for IPv6
     if (ipv4) {
-        const struct iphdr* const iph = is_eth ? (void*)(eth + 1) : data;
+        const struct iphdr* const iph = (void*)(eth + 1);
         hdr_size = l2_header_size + sizeof(struct iphdr);
         // Must have ipv4 header
         if (data + hdr_size > data_end) return;
@@ -105,7 +102,7 @@
         protocol = iph->protocol;
         tos = iph->tos;
     } else {
-        struct ipv6hdr* ip6h = is_eth ? (void*)(eth + 1) : data;
+        struct ipv6hdr* ip6h = (void*)(eth + 1);
         hdr_size = l2_header_size + sizeof(struct ipv6hdr);
         // Must have ipv6 header
         if (data + hdr_size > data_end) return;
@@ -115,8 +112,7 @@
         src_ip = ip6h->saddr;
         dst_ip = ip6h->daddr;
         protocol = ip6h->nexthdr;
-        priority = ip6h->priority;
-        flow_lbl = ip6h->flow_lbl[0];
+        old_first_u32 = *(uint32_t*)ip6h;
     }
 
     switch (protocol) {
@@ -164,10 +160,10 @@
                                 sizeof(uint16_t));
             bpf_skb_store_bytes(skb, IP4_OFFSET(tos, l2_header_size), &newTos, sizeof(newTos), 0);
         } else {
-            uint8_t new_priority = UPDATE_PRIORITY(existing_rule->dscp_val);
-            uint8_t new_flow_label = UPDATE_FLOW_LABEL(existing_rule->dscp_val, flow_lbl);
-            bpf_skb_store_bytes(skb, 0 + l2_header_size, &new_priority, sizeof(uint8_t), 0);
-            bpf_skb_store_bytes(skb, 1 + l2_header_size, &new_flow_label, sizeof(uint8_t), 0);
+            uint32_t new_first_u32 =
+                htonl(ntohl(old_first_u32) & 0xF03FFFFF | (existing_rule->dscp_val << 22));
+            bpf_skb_store_bytes(skb, l2_header_size, &new_first_u32, sizeof(uint32_t),
+                BPF_F_RECOMPUTE_CSUM);
         }
         return;
     }
@@ -227,10 +223,7 @@
         }
     }
 
-    uint8_t new_tos = 0;  // Can 0 be used as default forwarding value?
     uint8_t new_dscp = 0;
-    uint8_t new_priority = 0;
-    uint8_t new_flow_lbl = 0;
     if (best_score > 0) {
         DscpPolicy* policy;
         if (ipv4) {
@@ -241,12 +234,6 @@
 
         if (policy) {
             new_dscp = policy->dscp_val;
-            if (ipv4) {
-                new_tos = UPDATE_TOS(new_dscp, tos);
-            } else {
-                new_priority = UPDATE_PRIORITY(new_dscp);
-                new_flow_lbl = UPDATE_FLOW_LABEL(new_dscp, flow_lbl);
-            }
         }
     } else
         return;
@@ -277,38 +264,27 @@
     }
 
     // Need to store bytes after updating map or program will not load.
-    if (ipv4 && new_tos != (tos & 252)) {
+    if (ipv4) {
+        uint8_t new_tos = UPDATE_TOS(new_dscp, tos);
         bpf_l3_csum_replace(skb, IP4_OFFSET(check, l2_header_size), htons(tos), htons(new_tos), 2);
         bpf_skb_store_bytes(skb, IP4_OFFSET(tos, l2_header_size), &new_tos, sizeof(new_tos), 0);
-    } else if (!ipv4 && (new_priority != priority || new_flow_lbl != flow_lbl)) {
-        bpf_skb_store_bytes(skb, l2_header_size, &new_priority, sizeof(new_priority), 0);
-        bpf_skb_store_bytes(skb, l2_header_size + 1, &new_flow_lbl, sizeof(new_flow_lbl), 0);
+    } else {
+        uint32_t new_first_u32 = htonl(ntohl(old_first_u32) & 0xF03FFFFF | (new_dscp << 22));
+        bpf_skb_store_bytes(skb, l2_header_size, &new_first_u32, sizeof(uint32_t),
+            BPF_F_RECOMPUTE_CSUM);
     }
     return;
 }
 
-DEFINE_BPF_PROG_KVER("schedcls/set_dscp_ether", AID_ROOT, AID_SYSTEM,
-                     schedcls_set_dscp_ether, KVER(5, 15, 0))
+DEFINE_BPF_PROG_KVER("schedcls/set_dscp_ether", AID_ROOT, AID_SYSTEM, schedcls_set_dscp_ether,
+                     KVER(5, 15, 0))
 (struct __sk_buff* skb) {
     if (skb->pkt_type != PACKET_HOST) return TC_ACT_PIPE;
 
     if (skb->protocol == htons(ETH_P_IP)) {
-        match_policy(skb, true, true);
+        match_policy(skb, true);
     } else if (skb->protocol == htons(ETH_P_IPV6)) {
-        match_policy(skb, false, true);
-    }
-
-    // Always return TC_ACT_PIPE
-    return TC_ACT_PIPE;
-}
-
-DEFINE_BPF_PROG_KVER("schedcls/set_dscp_raw_ip", AID_ROOT, AID_SYSTEM,
-                     schedcls_set_dscp_raw_ip, KVER(5, 15, 0))
-(struct __sk_buff* skb) {
-    if (skb->protocol == htons(ETH_P_IP)) {
-        match_policy(skb, true, false);
-    } else if (skb->protocol == htons(ETH_P_IPV6)) {
-        match_policy(skb, false, false);
+        match_policy(skb, false);
     }
 
     // Always return TC_ACT_PIPE
diff --git a/service-t/src/com/android/server/net/CookieTagMapKey.java b/common/src/com/android/net/module/util/bpf/CookieTagMapKey.java
similarity index 95%
rename from service-t/src/com/android/server/net/CookieTagMapKey.java
rename to common/src/com/android/net/module/util/bpf/CookieTagMapKey.java
index 443e5b3..17da7a0 100644
--- a/service-t/src/com/android/server/net/CookieTagMapKey.java
+++ b/common/src/com/android/net/module/util/bpf/CookieTagMapKey.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.net;
+package com.android.net.module.util.bpf;
 
 import com.android.net.module.util.Struct;
 import com.android.net.module.util.Struct.Field;
diff --git a/service-t/src/com/android/server/net/CookieTagMapValue.java b/common/src/com/android/net/module/util/bpf/CookieTagMapValue.java
similarity index 95%
rename from service-t/src/com/android/server/net/CookieTagMapValue.java
rename to common/src/com/android/net/module/util/bpf/CookieTagMapValue.java
index 93b9195..e1a221f 100644
--- a/service-t/src/com/android/server/net/CookieTagMapValue.java
+++ b/common/src/com/android/net/module/util/bpf/CookieTagMapValue.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.net;
+package com.android.net.module.util.bpf;
 
 import com.android.net.module.util.Struct;
 import com.android.net.module.util.Struct.Field;
diff --git a/framework-t/Android.bp b/framework-t/Android.bp
index 8c32ded..80477f1 100644
--- a/framework-t/Android.bp
+++ b/framework-t/Android.bp
@@ -116,6 +116,7 @@
         "//packages/modules/Connectivity/Tethering/apex",
         // In preparation for future move
         "//packages/modules/Connectivity/apex",
+        "//packages/modules/Connectivity/service", // For R8 only
         "//packages/modules/Connectivity/service-t",
         "//packages/modules/Nearby/service",
         "//frameworks/base",
diff --git a/framework-t/src/android/net/NetworkStatsCollection.java b/framework-t/src/android/net/NetworkStatsCollection.java
index 6a1d2dd..df42b58 100644
--- a/framework-t/src/android/net/NetworkStatsCollection.java
+++ b/framework-t/src/android/net/NetworkStatsCollection.java
@@ -28,6 +28,10 @@
 import static android.net.NetworkStats.SET_DEFAULT;
 import static android.net.NetworkStats.TAG_NONE;
 import static android.net.NetworkStats.UID_ALL;
+import static android.net.NetworkTemplate.MATCH_BLUETOOTH;
+import static android.net.NetworkTemplate.MATCH_ETHERNET;
+import static android.net.NetworkTemplate.MATCH_MOBILE;
+import static android.net.NetworkTemplate.MATCH_WIFI;
 import static android.net.TrafficStats.UID_REMOVED;
 import static android.text.format.DateUtils.WEEK_IN_MILLIS;
 
@@ -774,10 +778,11 @@
 
     /** @hide */
     public void dumpCheckin(PrintWriter pw, long start, long end) {
-        dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateMobileWildcard(), "cell");
-        dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateWifiWildcard(), "wifi");
-        dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateEthernet(), "eth");
-        dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateBluetooth(), "bt");
+        dumpCheckin(pw, start, end, new NetworkTemplate.Builder(MATCH_MOBILE)
+                .setMeteredness(METERED_YES).build(), "cell");
+        dumpCheckin(pw, start, end, new NetworkTemplate.Builder(MATCH_WIFI).build(), "wifi");
+        dumpCheckin(pw, start, end, new NetworkTemplate.Builder(MATCH_ETHERNET).build(), "eth");
+        dumpCheckin(pw, start, end, new NetworkTemplate.Builder(MATCH_BLUETOOTH).build(), "bt");
     }
 
     /**
diff --git a/framework/src/android/net/NetworkProvider.java b/framework/src/android/net/NetworkProvider.java
index 3615075..7edcbae 100644
--- a/framework/src/android/net/NetworkProvider.java
+++ b/framework/src/android/net/NetworkProvider.java
@@ -192,36 +192,21 @@
     private class NetworkOfferCallbackProxy extends INetworkOfferCallback.Stub {
         @NonNull public final NetworkOfferCallback callback;
         @NonNull private final Executor mExecutor;
-        /**
-         * Boolean flag that prevents onNetworkNeeded / onNetworkUnneeded callbacks from being
-         * propagated after unregisterNetworkOffer has been called. Since unregisterNetworkOffer
-         * runs on the CS handler thread, it will not go into effect immediately.
-         */
-        private volatile boolean mIsStale;
 
         NetworkOfferCallbackProxy(@NonNull final NetworkOfferCallback callback,
                 @NonNull final Executor executor) {
             this.callback = callback;
             this.mExecutor = executor;
-            this.mIsStale = false;
         }
 
         @Override
         public void onNetworkNeeded(final @NonNull NetworkRequest request) {
-            mExecutor.execute(() -> {
-                if (!mIsStale) callback.onNetworkNeeded(request);
-            });
+            mExecutor.execute(() -> callback.onNetworkNeeded(request));
         }
 
         @Override
         public void onNetworkUnneeded(final @NonNull NetworkRequest request) {
-            mExecutor.execute(() -> {
-                if (!mIsStale) callback.onNetworkUnneeded(request);
-            });
-        }
-
-        public void markStale() {
-            mIsStale = true;
+            mExecutor.execute(() -> callback.onNetworkUnneeded(request));
         }
     }
 
@@ -334,6 +319,11 @@
      * if it could beat any of them, and may be advantageous to the provider's implementation that
      * can rely on no longer receiving callbacks for a network that they can't bring up anyways.
      *
+     * Warning: This method executes asynchronously. The NetworkOfferCallback object can continue
+     * receiving onNetworkNeeded and onNetworkUnneeded callbacks even after this method has
+     * returned. In this case, it is on the caller to take appropriate steps in order to prevent
+     * bringing up a network.
+     *
      * @hide
      */
     @SystemApi
@@ -342,7 +332,6 @@
         final NetworkOfferCallbackProxy proxy = findProxyForCallback(callback);
         if (null == proxy) return;
         synchronized (mProxies) {
-            proxy.markStale();
             mProxies.remove(proxy);
         }
         mContext.getSystemService(ConnectivityManager.class).unofferNetwork(proxy);
diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java
index 08d2a3c..77931b1 100644
--- a/service-t/src/com/android/server/net/NetworkStatsService.java
+++ b/service-t/src/com/android/server/net/NetworkStatsService.java
@@ -31,6 +31,7 @@
 import static android.net.NetworkStats.IFACE_VT;
 import static android.net.NetworkStats.INTERFACES_ALL;
 import static android.net.NetworkStats.METERED_ALL;
+import static android.net.NetworkStats.METERED_YES;
 import static android.net.NetworkStats.ROAMING_ALL;
 import static android.net.NetworkStats.SET_ALL;
 import static android.net.NetworkStats.SET_DEFAULT;
@@ -41,8 +42,8 @@
 import static android.net.NetworkStats.TAG_NONE;
 import static android.net.NetworkStats.UID_ALL;
 import static android.net.NetworkStatsHistory.FIELD_ALL;
-import static android.net.NetworkTemplate.buildTemplateMobileWildcard;
-import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
+import static android.net.NetworkTemplate.MATCH_MOBILE;
+import static android.net.NetworkTemplate.MATCH_WIFI;
 import static android.net.TrafficStats.KB_IN_BYTES;
 import static android.net.TrafficStats.MB_IN_BYTES;
 import static android.net.TrafficStats.UID_TETHERING;
@@ -157,6 +158,8 @@
 import com.android.net.module.util.PermissionUtils;
 import com.android.net.module.util.Struct.U32;
 import com.android.net.module.util.Struct.U8;
+import com.android.net.module.util.bpf.CookieTagMapKey;
+import com.android.net.module.util.bpf.CookieTagMapValue;
 
 import java.io.File;
 import java.io.FileDescriptor;
@@ -2359,7 +2362,7 @@
         NetworkStats.Entry uidTotal;
 
         // collect mobile sample
-        template = buildTemplateMobileWildcard();
+        template = new NetworkTemplate.Builder(MATCH_MOBILE).setMeteredness(METERED_YES).build();
         devTotal = mDevRecorder.getTotalSinceBootLocked(template);
         xtTotal = mXtRecorder.getTotalSinceBootLocked(template);
         uidTotal = mUidRecorder.getTotalSinceBootLocked(template);
@@ -2371,7 +2374,7 @@
                 currentTime);
 
         // collect wifi sample
-        template = buildTemplateWifiWildcard();
+        template = new NetworkTemplate.Builder(MATCH_WIFI).build();
         devTotal = mDevRecorder.getTotalSinceBootLocked(template);
         xtTotal = mXtRecorder.getTotalSinceBootLocked(template);
         uidTotal = mUidRecorder.getTotalSinceBootLocked(template);
diff --git a/service/Android.bp b/service/Android.bp
index 499af25..7dcc888 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -225,12 +225,27 @@
     // This library combines system server jars that have access to different bootclasspath jars.
     // Lower SDK service jars must not depend on higher SDK jars as that would let them
     // transitively depend on the wrong bootclasspath jars. Sources also cannot be added here as
-    // they would transitively depend on bootclasspath jars that may not be available.
+    // they would depend on bootclasspath jars that may not be available.
     static_libs: [
         "service-connectivity-pre-jarjar",
         "service-connectivity-tiramisu-pre-jarjar",
         "service-nearby-pre-jarjar",
     ],
+    // The below libraries are not actually needed to build since no source is compiled
+    // (only combining prebuilt static_libs), but they are necessary so that R8 has the right
+    // references to optimize the code. Without these, there will be missing class warnings and
+    // code may be wrongly optimized.
+    // R8 runs after jarjar, so the framework-X libraries need to be the post-jarjar artifacts
+    // (.impl), if they are not just stubs, so that the name of jarjared classes match.
+    libs: [
+        "androidx.annotation_annotation",
+        "framework-annotations-lib",
+        "framework-connectivity.impl",
+        "framework-connectivity-t.impl",
+        "framework-tethering.stubs.module_lib",
+        "framework-wifi.stubs.module_lib",
+        "libprotobuf-java-nano",
+    ],
     jarjar_rules: ":connectivity-jarjar-rules",
     apex_available: [
         "com.android.tethering",
diff --git a/service/jni/com_android_server_connectivity_ClatCoordinator.cpp b/service/jni/com_android_server_connectivity_ClatCoordinator.cpp
index e2c5a63..de0e20a 100644
--- a/service/jni/com_android_server_connectivity_ClatCoordinator.cpp
+++ b/service/jni/com_android_server_connectivity_ClatCoordinator.cpp
@@ -421,7 +421,7 @@
     stopClatdProcess(pid);
 }
 
-static jlong com_android_server_connectivity_ClatCoordinator_tagSocketAsClat(
+static jlong com_android_server_connectivity_ClatCoordinator_getSocketCookie(
         JNIEnv* env, jobject clazz, jobject sockJavaFd) {
     int sockFd = netjniutils::GetNativeFileDescriptor(env, sockJavaFd);
     if (sockFd < 0) {
@@ -435,58 +435,10 @@
         return -1;
     }
 
-    bpf::BpfMap<uint64_t, UidTagValue> cookieTagMap;
-    auto res = cookieTagMap.init(COOKIE_TAG_MAP_PATH);
-    if (!res.ok()) {
-        throwIOException(env, "failed to init the cookieTagMap", res.error().code());
-        return -1;
-    }
-
-    // Tag raw socket with uid AID_CLAT and set tag as zero because tag is unused in bpf
-    // program for counting data usage in netd.c. Tagging socket is used to avoid counting
-    // duplicated clat traffic in bpf stat.
-    UidTagValue newKey = {.uid = (uint32_t)AID_CLAT, .tag = 0 /* unused */};
-    res = cookieTagMap.writeValue(sock_cookie, newKey, BPF_ANY);
-    if (!res.ok()) {
-        jniThrowExceptionFmt(env, "java/io/IOException", "Failed to tag the socket: %s, fd: %d",
-                             strerror(res.error().code()), cookieTagMap.getMap().get());
-        return -1;
-    }
-
-    ALOGI("tag uid AID_CLAT to socket fd %d, cookie %" PRIu64 "", sockFd, sock_cookie);
+    ALOGI("Get cookie %" PRIu64 " for socket fd %d", sock_cookie, sockFd);
     return static_cast<jlong>(sock_cookie);
 }
 
-static void com_android_server_connectivity_ClatCoordinator_untagSocket(JNIEnv* env, jobject clazz,
-                                                                        jlong cookie) {
-    uint64_t sock_cookie = static_cast<uint64_t>(cookie);
-    if (sock_cookie == bpf::NONEXISTENT_COOKIE) {
-        jniThrowExceptionFmt(env, "java/io/IOException", "Invalid socket cookie");
-        return;
-    }
-
-    // The reason that deleting entry from cookie tag map directly is that the tag socket destroy
-    // listener only monitors on group INET_TCP, INET_UDP, INET6_TCP, INET6_UDP. The other socket
-    // types, ex: raw, are not able to be removed automatically by the listener.
-    // See TrafficController::makeSkDestroyListener.
-    bpf::BpfMap<uint64_t, UidTagValue> cookieTagMap;
-    auto res = cookieTagMap.init(COOKIE_TAG_MAP_PATH);
-    if (!res.ok()) {
-        throwIOException(env, "failed to init the cookieTagMap", res.error().code());
-        return;
-    }
-
-    res = cookieTagMap.deleteValue(sock_cookie);
-    if (!res.ok()) {
-        jniThrowExceptionFmt(env, "java/io/IOException", "Failed to untag the socket: %s",
-                             strerror(res.error().code()));
-        return;
-    }
-
-    ALOGI("untag socket cookie %" PRIu64 "", sock_cookie);
-    return;
-}
-
 /*
  * JNI registration.
  */
@@ -516,10 +468,8 @@
         {"native_stopClatd",
          "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)V",
          (void*)com_android_server_connectivity_ClatCoordinator_stopClatd},
-        {"native_tagSocketAsClat", "(Ljava/io/FileDescriptor;)J",
-         (void*)com_android_server_connectivity_ClatCoordinator_tagSocketAsClat},
-        {"native_untagSocket", "(J)V",
-         (void*)com_android_server_connectivity_ClatCoordinator_untagSocket},
+        {"native_getSocketCookie", "(Ljava/io/FileDescriptor;)J",
+         (void*)com_android_server_connectivity_ClatCoordinator_getSocketCookie},
 };
 
 int register_com_android_server_connectivity_ClatCoordinator(JNIEnv* env) {
diff --git a/service/src/com/android/server/connectivity/ClatCoordinator.java b/service/src/com/android/server/connectivity/ClatCoordinator.java
index 5ea586a..6c4a021 100644
--- a/service/src/com/android/server/connectivity/ClatCoordinator.java
+++ b/service/src/com/android/server/connectivity/ClatCoordinator.java
@@ -46,6 +46,8 @@
 import com.android.net.module.util.bpf.ClatEgress4Value;
 import com.android.net.module.util.bpf.ClatIngress6Key;
 import com.android.net.module.util.bpf.ClatIngress6Value;
+import com.android.net.module.util.bpf.CookieTagMapKey;
+import com.android.net.module.util.bpf.CookieTagMapValue;
 
 import java.io.FileDescriptor;
 import java.io.IOException;
@@ -63,6 +65,10 @@
 public class ClatCoordinator {
     private static final String TAG = ClatCoordinator.class.getSimpleName();
 
+    // Sync from system/core/libcutils/include/private/android_filesystem_config.h
+    @VisibleForTesting
+    static final int AID_CLAT = 1029;
+
     // Sync from external/android-clat/clatd.c
     // 40 bytes IPv6 header - 20 bytes IPv4 header + 8 bytes fragment header.
     @VisibleForTesting
@@ -97,6 +103,8 @@
     @VisibleForTesting
     static final int PRIO_CLAT = 4;
 
+    private static final String COOKIE_TAG_MAP_PATH =
+            "/sys/fs/bpf/netd_shared/map_netd_cookie_tag_map";
     private static final String CLAT_EGRESS4_MAP_PATH = makeMapPath("egress4");
     private static final String CLAT_INGRESS6_MAP_PATH = makeMapPath("ingress6");
 
@@ -121,6 +129,8 @@
     @Nullable
     private final IBpfMap<ClatEgress4Key, ClatEgress4Value> mEgressMap;
     @Nullable
+    private final IBpfMap<CookieTagMapKey, CookieTagMapValue> mCookieTagMap;
+    @Nullable
     private ClatdTracker mClatdTracker = null;
 
     /**
@@ -232,17 +242,10 @@
         }
 
         /**
-         * Tag socket as clat.
+         * Get socket cookie.
          */
-        public long tagSocketAsClat(@NonNull FileDescriptor sock) throws IOException {
-            return native_tagSocketAsClat(sock);
-        }
-
-        /**
-         * Untag socket.
-         */
-        public void untagSocket(long cookie) throws IOException {
-            native_untagSocket(cookie);
+        public long getSocketCookie(@NonNull FileDescriptor sock) throws IOException {
+            return native_getSocketCookie(sock);
         }
 
         /** Get ingress6 BPF map. */
@@ -279,6 +282,23 @@
             }
         }
 
+        /** Get cookie tag map */
+        @Nullable
+        public IBpfMap<CookieTagMapKey, CookieTagMapValue> getBpfCookieTagMap() {
+            // Pre-T devices don't use ClatCoordinator to access clat map. Since Nat464Xlat
+            // initializes a ClatCoordinator object to avoid redundant null pointer check
+            // while using, ignore the BPF map initialization on pre-T devices.
+            // TODO: probably don't initialize ClatCoordinator object on pre-T devices.
+            if (!SdkLevel.isAtLeastT()) return null;
+            try {
+                return new BpfMap<>(COOKIE_TAG_MAP_PATH,
+                        BpfMap.BPF_F_RDWR, CookieTagMapKey.class, CookieTagMapValue.class);
+            } catch (ErrnoException e) {
+                Log.wtf(TAG, "Cannot open cookie tag map: " + e);
+                return null;
+            }
+        }
+
         /** Checks if the network interface uses an ethernet L2 header. */
         public boolean isEthernet(String iface) throws IOException {
             return TcUtils.isEthernet(iface);
@@ -388,6 +408,7 @@
         mNetd = mDeps.getNetd();
         mIngressMap = mDeps.getBpfIngress6Map();
         mEgressMap = mDeps.getBpfEgress4Map();
+        mCookieTagMap = mDeps.getBpfCookieTagMap();
     }
 
     private void maybeStartBpf(final ClatdTracker tracker) {
@@ -536,6 +557,43 @@
         }
     }
 
+    private void tagSocketAsClat(long cookie) throws IOException {
+        if (mCookieTagMap == null) {
+            throw new IOException("Cookie tag map is not initialized");
+        }
+
+        // Tag raw socket with uid AID_CLAT and set tag as zero because tag is unused in bpf
+        // program for counting data usage in netd.c. Tagging socket is used to avoid counting
+        // duplicated clat traffic in bpf stat.
+        final CookieTagMapKey key = new CookieTagMapKey(cookie);
+        final CookieTagMapValue value = new CookieTagMapValue(AID_CLAT, 0 /* tag, unused */);
+        try {
+            mCookieTagMap.insertEntry(key, value);
+        } catch (ErrnoException | IllegalStateException e) {
+            throw new IOException("Could not insert entry (" + key + ", " + value
+                    + ") on cookie tag map: " + e);
+        }
+        Log.i(TAG, "tag socket cookie " + cookie);
+    }
+
+    private void untagSocket(long cookie) throws IOException {
+        if (mCookieTagMap == null) {
+            throw new IOException("Cookie tag map is not initialized");
+        }
+
+        // The reason that deleting entry from cookie tag map directly is that the tag socket
+        // destroy listener only monitors on group INET_TCP, INET_UDP, INET6_TCP, INET6_UDP.
+        // The other socket types, ex: raw, are not able to be removed automatically by the
+        // listener. See TrafficController::makeSkDestroyListener.
+        final CookieTagMapKey key = new CookieTagMapKey(cookie);
+        try {
+            mCookieTagMap.deleteEntry(key);
+        } catch (ErrnoException | IllegalStateException e) {
+            throw new IOException("Could not delete entry (" + key + ") on cookie tag map: " + e);
+        }
+        Log.i(TAG, "untag socket cookie " + cookie);
+    }
+
     /**
      * Start clatd for a given interface and NAT64 prefix.
      */
@@ -686,7 +744,8 @@
         // Tag socket as AID_CLAT to avoid duplicated CLAT data usage accounting.
         final long cookie;
         try {
-            cookie = mDeps.tagSocketAsClat(writeSock6.getFileDescriptor());
+            cookie = mDeps.getSocketCookie(writeSock6.getFileDescriptor());
+            tagSocketAsClat(cookie);
         } catch (IOException e) {
             maybeCleanUp(tunFd, readSock6, writeSock6);
             throw new IOException("tag raw socket failed: " + e);
@@ -696,6 +755,11 @@
         try {
             mDeps.configurePacketSocket(readSock6.getFileDescriptor(), v6Str, ifIndex);
         } catch (IOException e) {
+            try {
+                untagSocket(cookie);
+            } catch (IOException e2) {
+                Log.e(TAG, "untagSocket cookie " + cookie + " failed: " + e2);
+            }
             maybeCleanUp(tunFd, readSock6, writeSock6);
             throw new IOException("configure packet socket failed: " + e);
         }
@@ -706,8 +770,11 @@
             pid = mDeps.startClatd(tunFd.getFileDescriptor(), readSock6.getFileDescriptor(),
                     writeSock6.getFileDescriptor(), iface, pfx96Str, v4Str, v6Str);
         } catch (IOException e) {
-            // TODO: probably refactor to handle the exception of #untagSocket if any.
-            mDeps.untagSocket(cookie);
+            try {
+                untagSocket(cookie);
+            } catch (IOException e2) {
+                Log.e(TAG, "untagSocket cookie " + cookie + " failed: " + e2);
+            }
             throw new IOException("Error start clatd on " + iface + ": " + e);
         } finally {
             // The file descriptors have been duplicated (dup2) to clatd in native_startClatd().
@@ -774,7 +841,7 @@
         mDeps.stopClatd(mClatdTracker.iface, mClatdTracker.pfx96.getHostAddress(),
                 mClatdTracker.v4.getHostAddress(), mClatdTracker.v6.getHostAddress(),
                 mClatdTracker.pid);
-        mDeps.untagSocket(mClatdTracker.cookie);
+        untagSocket(mClatdTracker.cookie);
 
         Log.i(TAG, "clatd on " + mClatdTracker.iface + " stopped");
         mClatdTracker = null;
@@ -870,6 +937,5 @@
             throws IOException;
     private static native void native_stopClatd(String iface, String pfx96, String v4, String v6,
             int pid) throws IOException;
-    private static native long native_tagSocketAsClat(FileDescriptor sock) throws IOException;
-    private static native void native_untagSocket(long cookie) throws IOException;
+    private static native long native_getSocketCookie(FileDescriptor sock) throws IOException;
 }
diff --git a/service/src/com/android/server/connectivity/DscpPolicyTracker.java b/service/src/com/android/server/connectivity/DscpPolicyTracker.java
index 0e9b459..8cb3213 100644
--- a/service/src/com/android/server/connectivity/DscpPolicyTracker.java
+++ b/service/src/com/android/server/connectivity/DscpPolicyTracker.java
@@ -52,7 +52,7 @@
 
     private static final String TAG = DscpPolicyTracker.class.getSimpleName();
     private static final String PROG_PATH =
-            "/sys/fs/bpf/net_shared/prog_dscpPolicy_schedcls_set_dscp";
+            "/sys/fs/bpf/net_shared/prog_dscpPolicy_schedcls_set_dscp_ether";
     // Name is "map + *.o + map_name + map". Can probably shorten this
     private static final String IPV4_POLICY_MAP_PATH = makeMapPath(
             "dscpPolicy_ipv4_dscp_policies");
@@ -212,6 +212,15 @@
         return DSCP_POLICY_STATUS_SUCCESS;
     }
 
+    private boolean isEthernet(String iface) {
+        try {
+            return TcUtils.isEthernet(iface);
+        } catch (IOException e) {
+            Log.e(TAG, "Failed to check ether type", e);
+        }
+        return false;
+    }
+
     /**
      * Add the provided DSCP policy to the bpf map. Attach bpf program dscpPolicy to iface
      * if not already attached. Response will be sent back to nai with status.
@@ -221,13 +230,17 @@
      * DSCP_POLICY_STATUS_REQUEST_DECLINED - Interface index was invalid
      */
     public void addDscpPolicy(NetworkAgentInfo nai, DscpPolicy policy) {
-        if (!mAttachedIfaces.contains(nai.linkProperties.getInterfaceName())) {
-            if (!attachProgram(nai.linkProperties.getInterfaceName())) {
-                Log.e(TAG, "Unable to attach program");
-                sendStatus(nai, policy.getPolicyId(),
-                        DSCP_POLICY_STATUS_INSUFFICIENT_PROCESSING_RESOURCES);
-                return;
-            }
+        String iface = nai.linkProperties.getInterfaceName();
+        if (!isEthernet(iface)) {
+            Log.e(TAG, "DSCP policies are not supported on raw IP interfaces.");
+            sendStatus(nai, policy.getPolicyId(), DSCP_POLICY_STATUS_REQUEST_DECLINED);
+            return;
+        }
+        if (!mAttachedIfaces.contains(iface) && !attachProgram(iface)) {
+            Log.e(TAG, "Unable to attach program");
+            sendStatus(nai, policy.getPolicyId(),
+                    DSCP_POLICY_STATUS_INSUFFICIENT_PROCESSING_RESOURCES);
+            return;
         }
 
         final int ifIndex = getIfaceIndex(nai);
@@ -314,10 +327,8 @@
     private boolean attachProgram(@NonNull String iface) {
         try {
             NetworkInterface netIface = NetworkInterface.getByName(iface);
-            boolean isEth = TcUtils.isEthernet(iface);
-            String path = PROG_PATH + (isEth ? "_ether" : "_raw_ip");
             TcUtils.tcFilterAddDevBpf(netIface.getIndex(), false, PRIO_DSCP, (short) ETH_P_ALL,
-                    path);
+                    PROG_PATH);
         } catch (IOException e) {
             Log.e(TAG, "Unable to attach to TC on " + iface + ": " + e);
             return false;
diff --git a/tests/common/java/android/net/LinkPropertiesTest.java b/tests/common/java/android/net/LinkPropertiesTest.java
index 9506fc9..5ee375f 100644
--- a/tests/common/java/android/net/LinkPropertiesTest.java
+++ b/tests/common/java/android/net/LinkPropertiesTest.java
@@ -36,10 +36,10 @@
 import android.system.OsConstants;
 import android.util.ArraySet;
 
-import androidx.core.os.BuildCompat;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.modules.utils.build.SdkLevel;
 import com.android.net.module.util.LinkPropertiesUtils.CompareResult;
 import com.android.testutils.ConnectivityModuleTest;
 import com.android.testutils.DevSdkIgnoreRule;
@@ -114,11 +114,6 @@
         return InetAddresses.parseNumericAddress(addrString);
     }
 
-    private static boolean isAtLeastR() {
-        // BuildCompat.isAtLeastR is documented to return false on release SDKs (including R)
-        return Build.VERSION.SDK_INT > Build.VERSION_CODES.Q || BuildCompat.isAtLeastR();
-    }
-
     private void checkEmpty(final LinkProperties lp) {
         assertEquals(0, lp.getAllInterfaceNames().size());
         assertEquals(0, lp.getAllAddresses().size());
@@ -139,7 +134,7 @@
         assertFalse(lp.isIpv6Provisioned());
         assertFalse(lp.isPrivateDnsActive());
 
-        if (isAtLeastR()) {
+        if (SdkLevel.isAtLeastR()) {
             assertNull(lp.getDhcpServerAddress());
             assertFalse(lp.isWakeOnLanSupported());
             assertNull(lp.getCaptivePortalApiUrl());
@@ -166,7 +161,7 @@
         lp.setMtu(MTU);
         lp.setTcpBufferSizes(TCP_BUFFER_SIZES);
         lp.setNat64Prefix(new IpPrefix("2001:db8:0:64::/96"));
-        if (isAtLeastR()) {
+        if (SdkLevel.isAtLeastR()) {
             lp.setDhcpServerAddress(DHCPSERVER);
             lp.setWakeOnLanSupported(true);
             lp.setCaptivePortalApiUrl(CAPPORT_API_URL);
@@ -210,7 +205,7 @@
         assertTrue(source.isIdenticalTcpBufferSizes(target));
         assertTrue(target.isIdenticalTcpBufferSizes(source));
 
-        if (isAtLeastR()) {
+        if (SdkLevel.isAtLeastR()) {
             assertTrue(source.isIdenticalDhcpServerAddress(target));
             assertTrue(source.isIdenticalDhcpServerAddress(source));
 
@@ -1295,56 +1290,73 @@
         assertEquals(2, lp.getRoutes().size());
     }
 
-    @Test @IgnoreUpTo(Build.VERSION_CODES.R)
-    @CtsNetTestCasesMaxTargetSdk31(reason = "Compat change cannot be overridden when targeting T+")
-    @EnableCompatChanges({LinkProperties.EXCLUDED_ROUTES})
-    public void testExcludedRoutesEnabled() {
+    private void assertExcludeRoutesVisible() {
         final LinkProperties lp = new LinkProperties();
         assertEquals(0, lp.getRoutes().size());
 
-        lp.addRoute(new RouteInfo(new IpPrefix(ADDRV4, 0), RTN_UNREACHABLE));
+        lp.addRoute(new RouteInfo(new IpPrefix(ADDRV4, 31), RTN_UNREACHABLE));
         assertEquals(1, lp.getRoutes().size());
 
-        lp.addRoute(new RouteInfo(new IpPrefix(ADDRV6, 0), RTN_THROW));
+        lp.addRoute(new RouteInfo(new IpPrefix(ADDRV6, 127), RTN_THROW));
         assertEquals(2, lp.getRoutes().size());
 
         lp.addRoute(new RouteInfo(GATEWAY1));
         assertEquals(3, lp.getRoutes().size());
+
+        lp.addRoute(new RouteInfo(new IpPrefix(DNS6, 127), RTN_UNICAST));
+        assertEquals(4, lp.getRoutes().size());
     }
 
-    @Test @IgnoreUpTo(Build.VERSION_CODES.R) @IgnoreAfter(Build.VERSION_CODES.S_V2)
-    @CtsNetTestCasesMaxTargetSdk31(reason = "Compat change cannot be overridden when targeting T+")
-    @DisableCompatChanges({LinkProperties.EXCLUDED_ROUTES})
-    public void testExcludedRoutesDisabled_S() {
+    private void assertExcludeRoutesNotVisible() {
         final LinkProperties lp = new LinkProperties();
         assertEquals(0, lp.getRoutes().size());
 
-        lp.addRoute(new RouteInfo(new IpPrefix(ADDRV4, 0), RTN_UNREACHABLE));
+        lp.addRoute(new RouteInfo(new IpPrefix(ADDRV4, 31), RTN_UNREACHABLE));
+        assertEquals(0, lp.getRoutes().size());
+
+        lp.addRoute(new RouteInfo(new IpPrefix(ADDRV6, 127), RTN_THROW));
+        assertEquals(0, lp.getRoutes().size());
+
+        lp.addRoute(new RouteInfo(GATEWAY1));
         assertEquals(1, lp.getRoutes().size());
 
-        lp.addRoute(new RouteInfo(new IpPrefix(ADDRV6, 5), RTN_THROW));
-        // RTN_THROW routes are visible on S when added by the caller (but they are not added by
-        // the system). This is uncommon usage but was tested by CTSv12.
+        lp.addRoute(new RouteInfo(new IpPrefix(DNS6, 127), RTN_UNICAST));
         assertEquals(2, lp.getRoutes().size());
-
-        lp.addRoute(new RouteInfo(new IpPrefix(ADDRV6, 2), RTN_UNICAST));
-        assertEquals(3, lp.getRoutes().size());
     }
 
-    @Test @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+    private void checkExcludeRoutesNotVisibleAfterS() {
+        if (!SdkLevel.isAtLeastT()) {
+            // RTN_THROW routes are visible on R and S when added by the caller (but they are not
+            // added by the system except for legacy VPN).
+            // This is uncommon usage but was tested by CTSr12.
+            assertExcludeRoutesVisible();
+        } else {
+            assertExcludeRoutesNotVisible();
+        }
+    }
+
+    @Test @IgnoreUpTo(Build.VERSION_CODES.R)
+    @CtsNetTestCasesMaxTargetSdk31(reason = "Testing behaviour for target SDK 31")
+    public void testExcludedRoutesNotVisibleOnTargetSdk31() {
+        checkExcludeRoutesNotVisibleAfterS();
+    }
+
+    @Test
+    public void testExcludedRoutesVisibleOnTargetSdk33AndAbove() {
+        assertExcludeRoutesVisible();
+    }
+
+    @Test @IgnoreUpTo(Build.VERSION_CODES.R)
+    @CtsNetTestCasesMaxTargetSdk31(reason = "Compat change cannot be overridden when targeting T+")
+    @EnableCompatChanges({LinkProperties.EXCLUDED_ROUTES})
+    public void testExcludedRoutesEnabledByCompatChange() {
+        assertExcludeRoutesVisible();
+    }
+
+    @Test @IgnoreUpTo(Build.VERSION_CODES.R)
     @CtsNetTestCasesMaxTargetSdk31(reason = "Compat change cannot be overridden when targeting T+")
     @DisableCompatChanges({LinkProperties.EXCLUDED_ROUTES})
-    public void testExcludedRoutesDisabled() {
-        final LinkProperties lp = new LinkProperties();
-        assertEquals(0, lp.getRoutes().size());
-
-        lp.addRoute(new RouteInfo(new IpPrefix(ADDRV4, 0), RTN_UNREACHABLE));
-        assertEquals(0, lp.getRoutes().size());
-
-        lp.addRoute(new RouteInfo(new IpPrefix(ADDRV6, 5), RTN_THROW));
-        assertEquals(0, lp.getRoutes().size());
-
-        lp.addRoute(new RouteInfo(new IpPrefix(ADDRV6, 2), RTN_UNICAST));
-        assertEquals(1, lp.getRoutes().size());
+    public void testExcludedRoutesDisabledByCompatChange() {
+        checkExcludeRoutesNotVisibleAfterS();
     }
 }
diff --git a/tests/cts/hostside/Android.bp b/tests/cts/hostside/Android.bp
index ac84e57..47ea53e 100644
--- a/tests/cts/hostside/Android.bp
+++ b/tests/cts/hostside/Android.bp
@@ -26,7 +26,6 @@
         "tradefed",
     ],
     static_libs: [
-        "CompatChangeGatingTestBase",
         "modules-utils-build-testing",
     ],
     // Tag this module as a cts test artifact
@@ -38,8 +37,6 @@
     data: [
         ":CtsHostsideNetworkTestsApp",
         ":CtsHostsideNetworkTestsApp2",
-        ":CtsHostsideNetworkTestsApp3",
-        ":CtsHostsideNetworkTestsApp3PreT",
         ":CtsHostsideNetworkTestsAppNext",
     ],
     per_testcase_directory: true,
diff --git a/tests/cts/hostside/app3/Android.bp b/tests/cts/hostside/app3/Android.bp
deleted file mode 100644
index 141cf03..0000000
--- a/tests/cts/hostside/app3/Android.bp
+++ /dev/null
@@ -1,54 +0,0 @@
-//
-// 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.
-//
-
-package {
-    default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-java_defaults {
-    name: "CtsHostsideNetworkTestsApp3Defaults",
-    srcs: ["src/**/*.java"],
-    libs: [
-        "junit",
-    ],
-    static_libs: [
-        "ctstestrunner-axt",
-        "truth-prebuilt",
-    ],
-
-    // Tag this module as a cts test artifact
-    test_suites: [
-        "cts",
-        "general-tests",
-    ],
-}
-
-android_test_helper_app {
-    name: "CtsHostsideNetworkTestsApp3",
-    defaults: [
-        "cts_support_defaults",
-        "CtsHostsideNetworkTestsApp3Defaults",
-    ],
-}
-
-android_test_helper_app {
-    name: "CtsHostsideNetworkTestsApp3PreT",
-    target_sdk_version: "31",
-    defaults: [
-        "cts_support_defaults",
-        "CtsHostsideNetworkTestsApp3Defaults",
-    ],
-}
diff --git a/tests/cts/hostside/app3/AndroidManifest.xml b/tests/cts/hostside/app3/AndroidManifest.xml
deleted file mode 100644
index eabcacb..0000000
--- a/tests/cts/hostside/app3/AndroidManifest.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.android.cts.net.hostside.app3">
-
-    <application android:debuggable="true">
-        <uses-library android:name="android.test.runner" />
-    </application>
-
-    <instrumentation
-        android:name="androidx.test.runner.AndroidJUnitRunner"
-        android:targetPackage="com.android.cts.net.hostside.app3" />
-
-</manifest>
diff --git a/tests/cts/hostside/app3/src/com/android/cts/net/hostside/app3/ExcludedRoutesGatingTest.java b/tests/cts/hostside/app3/src/com/android/cts/net/hostside/app3/ExcludedRoutesGatingTest.java
deleted file mode 100644
index a1a8209..0000000
--- a/tests/cts/hostside/app3/src/com/android/cts/net/hostside/app3/ExcludedRoutesGatingTest.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.cts.net.hostside.app3;
-
-import static org.junit.Assert.assertEquals;
-
-import android.Manifest;
-import android.net.IpPrefix;
-import android.net.LinkProperties;
-import android.net.RouteInfo;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Tests to verify {@link LinkProperties#getRoutes} behavior, depending on
- * {@LinkProperties#EXCLUDED_ROUTES} change state.
- */
-@RunWith(AndroidJUnit4.class)
-public class ExcludedRoutesGatingTest {
-    @Before
-    public void setUp() {
-        InstrumentationRegistry.getInstrumentation().getUiAutomation()
-                .adoptShellPermissionIdentity(Manifest.permission.LOG_COMPAT_CHANGE,
-                        Manifest.permission.READ_COMPAT_CHANGE_CONFIG);
-    }
-
-    @After
-    public void tearDown() {
-        InstrumentationRegistry.getInstrumentation().getUiAutomation()
-                .dropShellPermissionIdentity();
-    }
-
-    @Test
-    public void testExcludedRoutesChangeEnabled() {
-        final LinkProperties lp = makeLinkPropertiesWithExcludedRoutes();
-
-        // Excluded routes change is enabled: non-RTN_UNICAST routes are visible.
-        assertEquals(2, lp.getRoutes().size());
-        assertEquals(2, lp.getAllRoutes().size());
-    }
-
-    @Test
-    public void testExcludedRoutesChangeDisabled() {
-        final LinkProperties lp = makeLinkPropertiesWithExcludedRoutes();
-
-        // Excluded routes change is disabled: non-RTN_UNICAST routes are filtered out.
-        assertEquals(0, lp.getRoutes().size());
-        assertEquals(0, lp.getAllRoutes().size());
-    }
-
-    private LinkProperties makeLinkPropertiesWithExcludedRoutes() {
-        final LinkProperties lp = new LinkProperties();
-
-        lp.addRoute(new RouteInfo(new IpPrefix("10.0.0.0/8"), null, null, RouteInfo.RTN_THROW));
-        lp.addRoute(new RouteInfo(new IpPrefix("2001:db8::/64"), null, null,
-                RouteInfo.RTN_UNREACHABLE));
-
-        return lp;
-    }
-}
diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideLinkPropertiesGatingTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideLinkPropertiesGatingTests.java
deleted file mode 100644
index 9a1fa42..0000000
--- a/tests/cts/hostside/src/com/android/cts/net/HostsideLinkPropertiesGatingTests.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.cts.net;
-
-import android.compat.cts.CompatChangeGatingTestCase;
-
-import java.util.Set;
-
-/**
- * Tests for the {@link android.net.LinkProperties#EXCLUDED_ROUTES} compatibility change.
- *
- * TODO: see if we can delete this cumbersome host test by moving the coverage to CtsNetTestCases
- * and CtsNetTestCasesMaxTargetSdk31.
- */
-public class HostsideLinkPropertiesGatingTests extends CompatChangeGatingTestCase {
-    private static final String TEST_APK = "CtsHostsideNetworkTestsApp3.apk";
-    private static final String TEST_APK_PRE_T = "CtsHostsideNetworkTestsApp3PreT.apk";
-    private static final String TEST_PKG = "com.android.cts.net.hostside.app3";
-    private static final String TEST_CLASS = ".ExcludedRoutesGatingTest";
-
-    private static final long EXCLUDED_ROUTES_CHANGE_ID = 186082280;
-
-    protected void tearDown() throws Exception {
-        uninstallPackage(TEST_PKG, true);
-    }
-
-    public void testExcludedRoutesChangeEnabled() throws Exception {
-        installPackage(TEST_APK, true);
-        runDeviceCompatTest("testExcludedRoutesChangeEnabled");
-    }
-
-    public void testExcludedRoutesChangeDisabledPreT() throws Exception {
-        installPackage(TEST_APK_PRE_T, true);
-        runDeviceCompatTest("testExcludedRoutesChangeDisabled");
-    }
-
-    public void testExcludedRoutesChangeDisabledByOverrideOnDebugBuild() throws Exception {
-        // Must install APK even when skipping test, because tearDown expects uninstall to succeed.
-        installPackage(TEST_APK, true);
-
-        // This test uses an app with a target SDK where the compat change is on by default.
-        // Because user builds do not allow overriding compat changes, only run this test on debug
-        // builds. This seems better than deleting this test and not running it anywhere because we
-        // could in the future run this test on userdebug builds in presubmit.
-        //
-        // We cannot use assumeXyz here because CompatChangeGatingTestCase ultimately inherits from
-        // junit.framework.TestCase, which does not understand assumption failures.
-        if ("user".equals(getDevice().getProperty("ro.build.type"))) return;
-
-        runDeviceCompatTestWithChangeDisabled("testExcludedRoutesChangeDisabled");
-    }
-
-    public void testExcludedRoutesChangeEnabledByOverridePreT() throws Exception {
-        installPackage(TEST_APK_PRE_T, true);
-        runDeviceCompatTestWithChangeEnabled("testExcludedRoutesChangeEnabled");
-    }
-
-    private void runDeviceCompatTest(String methodName) throws Exception {
-        runDeviceCompatTest(TEST_PKG, TEST_CLASS, methodName, Set.of(), Set.of());
-    }
-
-    private void runDeviceCompatTestWithChangeEnabled(String methodName) throws Exception {
-        runDeviceCompatTest(TEST_PKG, TEST_CLASS, methodName, Set.of(EXCLUDED_ROUTES_CHANGE_ID),
-                Set.of());
-    }
-
-    private void runDeviceCompatTestWithChangeDisabled(String methodName) throws Exception {
-        runDeviceCompatTest(TEST_PKG, TEST_CLASS, methodName, Set.of(),
-                Set.of(EXCLUDED_ROUTES_CHANGE_ID));
-    }
-}
diff --git a/tests/mts/bpf_existence_test.cpp b/tests/mts/bpf_existence_test.cpp
index 67b4f42..0911ecf 100644
--- a/tests/mts/bpf_existence_test.cpp
+++ b/tests/mts/bpf_existence_test.cpp
@@ -127,7 +127,6 @@
 // Provided by *current* mainline module for T+ devices with 5.15+ kernels
 static const set<string> MAINLINE_FOR_T_5_15_PLUS = {
     SHARED "prog_dscpPolicy_schedcls_set_dscp_ether",
-    SHARED "prog_dscpPolicy_schedcls_set_dscp_raw_ip",
 };
 
 void addAll(set<string>* a, const set<string>& b) {
diff --git a/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java b/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java
index feee293..bbb61cd 100644
--- a/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java
+++ b/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java
@@ -21,6 +21,7 @@
 import static android.system.OsConstants.ETH_P_IPV6;
 
 import static com.android.net.module.util.NetworkStackConstants.ETHER_MTU;
+import static com.android.server.connectivity.ClatCoordinator.AID_CLAT;
 import static com.android.server.connectivity.ClatCoordinator.CLAT_MAX_MTU;
 import static com.android.server.connectivity.ClatCoordinator.EGRESS;
 import static com.android.server.connectivity.ClatCoordinator.INGRESS;
@@ -56,6 +57,8 @@
 import com.android.net.module.util.bpf.ClatEgress4Value;
 import com.android.net.module.util.bpf.ClatIngress6Key;
 import com.android.net.module.util.bpf.ClatIngress6Value;
+import com.android.net.module.util.bpf.CookieTagMapKey;
+import com.android.net.module.util.bpf.CookieTagMapValue;
 import com.android.testutils.DevSdkIgnoreRule;
 import com.android.testutils.DevSdkIgnoreRunner;
 import com.android.testutils.TestBpfMap;
@@ -127,11 +130,16 @@
             INET6_PFX96, INET6_LOCAL6);
     private static final ClatIngress6Value INGRESS_VALUE = new ClatIngress6Value(STACKED_IFINDEX,
             INET4_LOCAL4);
+    private static final CookieTagMapKey COOKIE_TAG_KEY = new CookieTagMapKey(RAW_SOCK_COOKIE);
+    private static final CookieTagMapValue COOKIE_TAG_VALUE = new CookieTagMapValue(AID_CLAT,
+            0 /* tag, unused */);
 
     private final TestBpfMap<ClatIngress6Key, ClatIngress6Value> mIngressMap =
             spy(new TestBpfMap<>(ClatIngress6Key.class, ClatIngress6Value.class));
     private final TestBpfMap<ClatEgress4Key, ClatEgress4Value> mEgressMap =
             spy(new TestBpfMap<>(ClatEgress4Key.class, ClatEgress4Value.class));
+    private final TestBpfMap<CookieTagMapKey, CookieTagMapValue> mCookieTagMap =
+            spy(new TestBpfMap<>(CookieTagMapKey.class, CookieTagMapValue.class));
 
     @Mock private INetd mNetd;
     @Spy private TestDependencies mDeps = new TestDependencies();
@@ -313,25 +321,10 @@
         }
 
         /**
-         * Tag socket as clat.
+         * Get socket cookie.
          */
-        @Override
-        public long tagSocketAsClat(@NonNull FileDescriptor sock) throws IOException {
-            if (Objects.equals(RAW_SOCK_PFD.getFileDescriptor(), sock)) {
-                return RAW_SOCK_COOKIE;
-            }
-            fail("unsupported arg: " + sock);
-            return 0;
-        }
-
-        /**
-         * Untag socket.
-         */
-        @Override
-        public void untagSocket(long cookie) throws IOException {
-            if (cookie != RAW_SOCK_COOKIE) {
-                fail("unsupported arg: " + cookie);
-            }
+        public long getSocketCookie(@NonNull FileDescriptor sock) throws IOException {
+            return RAW_SOCK_COOKIE;
         }
 
         /** Get ingress6 BPF map. */
@@ -346,6 +339,12 @@
             return mEgressMap;
         }
 
+        /** Get cookie tag map */
+        @Override
+        public IBpfMap<CookieTagMapKey, CookieTagMapValue> getBpfCookieTagMap() {
+            return mCookieTagMap;
+        }
+
         /** Checks if the network interface uses an ethernet L2 header. */
         public boolean isEthernet(String iface) throws IOException {
             if (BASE_IFACE.equals(iface)) return true;
@@ -400,8 +399,8 @@
     @Test
     public void testStartStopClatd() throws Exception {
         final ClatCoordinator coordinator = makeClatCoordinator();
-        final InOrder inOrder = inOrder(mNetd, mDeps, mIngressMap, mEgressMap);
-        clearInvocations(mNetd, mDeps, mIngressMap, mEgressMap);
+        final InOrder inOrder = inOrder(mNetd, mDeps, mIngressMap, mEgressMap, mCookieTagMap);
+        clearInvocations(mNetd, mDeps, mIngressMap, mEgressMap, mCookieTagMap);
 
         // [1] Start clatd.
         final String addr6For464xlat = coordinator.clatStart(BASE_IFACE, NETID, NAT64_IP_PREFIX);
@@ -444,8 +443,9 @@
         inOrder.verify(mDeps).addAnycastSetsockopt(
                 argThat(fd -> Objects.equals(RAW_SOCK_PFD.getFileDescriptor(), fd)),
                 eq(XLAT_LOCAL_IPV6ADDR_STRING), eq(BASE_IFINDEX));
-        inOrder.verify(mDeps).tagSocketAsClat(
+        inOrder.verify(mDeps).getSocketCookie(
                 argThat(fd -> Objects.equals(RAW_SOCK_PFD.getFileDescriptor(), fd)));
+        inOrder.verify(mCookieTagMap).insertEntry(eq(COOKIE_TAG_KEY), eq(COOKIE_TAG_VALUE));
         inOrder.verify(mDeps).configurePacketSocket(
                 argThat(fd -> Objects.equals(PACKET_SOCK_PFD.getFileDescriptor(), fd)),
                 eq(XLAT_LOCAL_IPV6ADDR_STRING), eq(BASE_IFINDEX));
@@ -481,7 +481,7 @@
         inOrder.verify(mIngressMap).deleteEntry(eq(INGRESS_KEY));
         inOrder.verify(mDeps).stopClatd(eq(BASE_IFACE), eq(NAT64_PREFIX_STRING),
                 eq(XLAT_LOCAL_IPV4ADDR_STRING), eq(XLAT_LOCAL_IPV6ADDR_STRING), eq(CLATD_PID));
-        inOrder.verify(mDeps).untagSocket(eq(RAW_SOCK_COOKIE));
+        inOrder.verify(mCookieTagMap).deleteEntry(eq(COOKIE_TAG_KEY));
         assertNull(coordinator.getClatdTrackerForTesting());
         inOrder.verifyNoMoreInteractions();
 
@@ -680,18 +680,6 @@
     }
 
     @Test
-    public void testNotStartClatWithNativeFailureTagSocketAsClat() throws Exception {
-        class FailureDependencies extends TestDependencies {
-            @Override
-            public long tagSocketAsClat(@NonNull FileDescriptor sock) throws IOException {
-                throw new IOException();
-            }
-        }
-        checkNotStartClat(new FailureDependencies(), true /* needToCloseTunFd */,
-                true /* needToClosePacketSockFd */, true /* needToCloseRawSockFd */);
-    }
-
-    @Test
     public void testNotStartClatWithNativeFailureConfigurePacketSocket() throws Exception {
         class FailureDependencies extends TestDependencies {
             @Override
@@ -718,4 +706,28 @@
         checkNotStartClat(new FailureDependencies(), true /* needToCloseTunFd */,
                 true /* needToClosePacketSockFd */, true /* needToCloseRawSockFd */);
     }
+
+    @Test
+    public void testNotStartClatWithNativeFailureGetSocketCookie() throws Exception {
+        class FailureDependencies extends TestDependencies {
+            @Override
+            public long getSocketCookie(@NonNull FileDescriptor sock) throws IOException {
+                throw new IOException();
+            }
+        }
+        checkNotStartClat(new FailureDependencies(), true /* needToCloseTunFd */,
+                true /* needToClosePacketSockFd */, true /* needToCloseRawSockFd */);
+    }
+
+    @Test
+    public void testNotStartClatWithNullCookieTagMap() throws Exception {
+        class FailureDependencies extends TestDependencies {
+            @Override
+            public IBpfMap<CookieTagMapKey, CookieTagMapValue> getBpfCookieTagMap() {
+                return null;
+            }
+        }
+        checkNotStartClat(new FailureDependencies(), true /* needToCloseTunFd */,
+                true /* needToClosePacketSockFd */, true /* needToCloseRawSockFd */);
+    }
 }
diff --git a/tests/unit/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java b/tests/unit/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java
index b42058f..503d920 100644
--- a/tests/unit/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java
+++ b/tests/unit/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java
@@ -313,7 +313,7 @@
 
         assertTrue(ret);
         verify(mIpClient).shutdown();
-        assertEquals(listener.expectOnResult(), TEST_IFACE);
+        assertEquals(TEST_IFACE, listener.expectOnResult());
     }
 
     @Test
@@ -328,13 +328,13 @@
 
         assertTrue(retDown);
         verifyStop();
-        assertEquals(listenerDown.expectOnResult(), TEST_IFACE);
+        assertEquals(TEST_IFACE, listenerDown.expectOnResult());
 
         final boolean retUp =
                 mNetFactory.updateInterfaceLinkState(TEST_IFACE, true /* up */, listenerUp);
 
         assertTrue(retUp);
-        assertEquals(listenerUp.expectOnResult(), TEST_IFACE);
+        assertEquals(TEST_IFACE, listenerUp.expectOnResult());
     }
 
     @Test
@@ -351,7 +351,7 @@
         verify(mDeps, never()).makeIpClient(any(), any(), any());
         verify(mDeps, never())
                 .makeEthernetNetworkAgent(any(), any(), any(), any(), any(), any(), any());
-        assertEquals(listener.expectOnResult(), TEST_IFACE);
+        assertEquals(TEST_IFACE, listener.expectOnResult());
     }
 
     @Test
@@ -616,7 +616,7 @@
         mNetFactory.updateInterface(TEST_IFACE, ipConfiguration, capabilities, listener);
         triggerOnProvisioningSuccess();
 
-        assertEquals(listener.expectOnResult(), TEST_IFACE);
+        assertEquals(TEST_IFACE, listener.expectOnResult());
     }
 
     @Test
@@ -662,6 +662,7 @@
                 });
 
         assertEquals(successfulListener.expectOnResult(), TEST_IFACE);
+        assertEquals(TEST_IFACE, successfulListener.expectOnResult());
     }
 
     private void verifyNetworkManagementCallIsAbortedWhenInterrupted(
@@ -690,7 +691,7 @@
         mNetFactory.updateInterface(TEST_IFACE, ipConfiguration, capabilities, listener);
         triggerOnProvisioningSuccess();
 
-        assertEquals(listener.expectOnResult(), TEST_IFACE);
+        assertEquals(TEST_IFACE, listener.expectOnResult());
         verify(mDeps).makeEthernetNetworkAgent(any(), any(),
                 eq(capabilities), any(), any(), any(), any());
         verifyRestart(ipConfiguration);
diff --git a/tests/unit/java/com/android/server/net/NetworkStatsObserversTest.java b/tests/unit/java/com/android/server/net/NetworkStatsObserversTest.java
index 5747e10..292f77e 100644
--- a/tests/unit/java/com/android/server/net/NetworkStatsObserversTest.java
+++ b/tests/unit/java/com/android/server/net/NetworkStatsObserversTest.java
@@ -21,11 +21,12 @@
 import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
 import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
 import static android.net.NetworkStats.METERED_NO;
+import static android.net.NetworkStats.METERED_YES;
 import static android.net.NetworkStats.ROAMING_NO;
 import static android.net.NetworkStats.SET_DEFAULT;
 import static android.net.NetworkStats.TAG_NONE;
-import static android.net.NetworkTemplate.buildTemplateMobileAll;
-import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
+import static android.net.NetworkTemplate.MATCH_MOBILE;
+import static android.net.NetworkTemplate.MATCH_WIFI;
 import static android.net.TrafficStats.MB_IN_BYTES;
 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
 
@@ -67,6 +68,7 @@
 
 import java.util.ArrayList;
 import java.util.Objects;
+import java.util.Set;
 
 /**
  * Tests for {@link NetworkStatsObservers}.
@@ -84,10 +86,13 @@
     private static final int SUBID_1 = 1;
     private static final String TEST_SSID = "AndroidAP";
 
-    private static NetworkTemplate sTemplateWifi = buildTemplateWifiWildcard();
-    private static NetworkTemplate sTemplateImsi1 = buildTemplateMobileAll(IMSI_1);
-    private static NetworkTemplate sTemplateImsi2 = buildTemplateMobileAll(IMSI_2);
-
+    private static NetworkTemplate sTemplateWifi = new NetworkTemplate.Builder(MATCH_WIFI).build();
+    private static NetworkTemplate sTemplateImsi1 = new NetworkTemplate.Builder(MATCH_MOBILE)
+            .setSubscriberIds(Set.of(IMSI_1))
+            .setMeteredness(METERED_YES).build();
+    private static NetworkTemplate sTemplateImsi2 = new NetworkTemplate.Builder(MATCH_MOBILE)
+            .setSubscriberIds(Set.of(IMSI_2))
+            .setMeteredness(METERED_YES).build();
     private static final int PID_SYSTEM = 1234;
     private static final int PID_RED = 1235;
     private static final int PID_BLUE = 1236;
diff --git a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
index f9cbb10..484d717 100644
--- a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -46,14 +46,10 @@
 import static android.net.NetworkStats.TAG_NONE;
 import static android.net.NetworkStats.UID_ALL;
 import static android.net.NetworkStatsHistory.FIELD_ALL;
-import static android.net.NetworkTemplate.MATCH_MOBILE_WILDCARD;
-import static android.net.NetworkTemplate.NETWORK_TYPE_ALL;
+import static android.net.NetworkTemplate.MATCH_MOBILE;
+import static android.net.NetworkTemplate.MATCH_WIFI;
 import static android.net.NetworkTemplate.OEM_MANAGED_NO;
 import static android.net.NetworkTemplate.OEM_MANAGED_YES;
-import static android.net.NetworkTemplate.buildTemplateMobileAll;
-import static android.net.NetworkTemplate.buildTemplateMobileWithRatType;
-import static android.net.NetworkTemplate.buildTemplateWifi;
-import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
 import static android.net.TrafficStats.MB_IN_BYTES;
 import static android.net.TrafficStats.UID_REMOVED;
 import static android.net.TrafficStats.UID_TETHERING;
@@ -65,7 +61,6 @@
 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
 import static android.text.format.DateUtils.WEEK_IN_MILLIS;
 
-import static com.android.net.module.util.NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT;
 import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_POLL;
 import static com.android.server.net.NetworkStatsService.NETSTATS_IMPORT_ATTEMPTS_COUNTER_NAME;
 import static com.android.server.net.NetworkStatsService.NETSTATS_IMPORT_FALLBACKS_COUNTER_NAME;
@@ -138,6 +133,8 @@
 import com.android.net.module.util.LocationPermissionChecker;
 import com.android.net.module.util.Struct.U32;
 import com.android.net.module.util.Struct.U8;
+import com.android.net.module.util.bpf.CookieTagMapKey;
+import com.android.net.module.util.bpf.CookieTagMapValue;
 import com.android.server.net.NetworkStatsService.AlertObserver;
 import com.android.server.net.NetworkStatsService.NetworkStatsSettings;
 import com.android.server.net.NetworkStatsService.NetworkStatsSettings.Config;
@@ -192,11 +189,14 @@
     private static final String IMSI_2 = "310260";
     private static final String TEST_WIFI_NETWORK_KEY = "WifiNetworkKey";
 
-    private static NetworkTemplate sTemplateWifi = buildTemplateWifi(TEST_WIFI_NETWORK_KEY);
-    private static NetworkTemplate sTemplateCarrierWifi1 =
-            buildTemplateWifi(NetworkTemplate.WIFI_NETWORKID_ALL, IMSI_1);
-    private static NetworkTemplate sTemplateImsi1 = buildTemplateMobileAll(IMSI_1);
-    private static NetworkTemplate sTemplateImsi2 = buildTemplateMobileAll(IMSI_2);
+    private static NetworkTemplate sTemplateWifi = new NetworkTemplate.Builder(MATCH_WIFI)
+            .setWifiNetworkKeys(Set.of(TEST_WIFI_NETWORK_KEY)).build();
+    private static NetworkTemplate sTemplateCarrierWifi1 = new NetworkTemplate.Builder(MATCH_WIFI)
+            .setSubscriberIds(Set.of(IMSI_1)).build();
+    private static NetworkTemplate sTemplateImsi1 = new NetworkTemplate.Builder(MATCH_MOBILE)
+            .setMeteredness(METERED_YES).setSubscriberIds(Set.of(IMSI_1)).build();
+    private static NetworkTemplate sTemplateImsi2 = new NetworkTemplate.Builder(MATCH_MOBILE)
+            .setMeteredness(METERED_YES).setSubscriberIds(Set.of(IMSI_2)).build();
 
     private static final Network WIFI_NETWORK =  new Network(100);
     private static final Network MOBILE_NETWORK =  new Network(101);
@@ -833,15 +833,15 @@
 
     @Test
     public void testMobileStatsByRatType() throws Exception {
-        final NetworkTemplate template3g =
-                buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_UMTS,
-                METERED_YES);
-        final NetworkTemplate template4g =
-                buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_LTE,
-                METERED_YES);
-        final NetworkTemplate template5g =
-                buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_NR,
-                METERED_YES);
+        final NetworkTemplate template3g = new NetworkTemplate.Builder(MATCH_MOBILE)
+                .setRatType(TelephonyManager.NETWORK_TYPE_UMTS)
+                .setMeteredness(METERED_YES).build();
+        final NetworkTemplate template4g = new NetworkTemplate.Builder(MATCH_MOBILE)
+                .setRatType(TelephonyManager.NETWORK_TYPE_LTE)
+                .setMeteredness(METERED_YES).build();
+        final NetworkTemplate template5g = new NetworkTemplate.Builder(MATCH_MOBILE)
+                .setRatType(TelephonyManager.NETWORK_TYPE_NR)
+                .setMeteredness(METERED_YES).build();
         final NetworkStateSnapshot[] states =
                 new NetworkStateSnapshot[]{buildMobileState(IMSI_1)};
 
@@ -912,12 +912,13 @@
     @Test
     public void testMobileStatsMeteredness() throws Exception {
         // Create metered 5g template.
-        final NetworkTemplate templateMetered5g =
-                buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_NR,
-                METERED_YES);
+        final NetworkTemplate templateMetered5g = new NetworkTemplate.Builder(MATCH_MOBILE)
+                .setRatType(TelephonyManager.NETWORK_TYPE_NR)
+                .setMeteredness(METERED_YES).build();
         // Create non-metered 5g template
-        final NetworkTemplate templateNonMetered5g =
-                buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_NR, METERED_NO);
+        final NetworkTemplate templateNonMetered5g = new NetworkTemplate.Builder(MATCH_MOBILE)
+                .setRatType(TelephonyManager.NETWORK_TYPE_NR)
+                .setMeteredness(METERED_NO).build();
 
         expectDefaultSettings();
         expectNetworkStatsSummary(buildEmptyStats());
@@ -950,33 +951,20 @@
 
     @Test
     public void testMobileStatsOemManaged() throws Exception {
-        final NetworkTemplate templateOemPaid = new NetworkTemplate(MATCH_MOBILE_WILDCARD,
-                /*subscriberId=*/null, /*matchSubscriberIds=*/null,
-                /*matchWifiNetworkKeys=*/new String[0], METERED_ALL, ROAMING_ALL,
-                DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_PAID, SUBSCRIBER_ID_MATCH_RULE_EXACT);
+        final NetworkTemplate templateOemPaid = new NetworkTemplate.Builder(MATCH_MOBILE)
+                .setOemManaged(OEM_PAID).build();
 
-        final NetworkTemplate templateOemPrivate = new NetworkTemplate(MATCH_MOBILE_WILDCARD,
-                /*subscriberId=*/null, /*matchSubscriberIds=*/null,
-                /*matchWifiNetworkKeys=*/new String[0], METERED_ALL, ROAMING_ALL,
-                DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_PRIVATE, SUBSCRIBER_ID_MATCH_RULE_EXACT);
+        final NetworkTemplate templateOemPrivate = new NetworkTemplate.Builder(MATCH_MOBILE)
+                .setOemManaged(OEM_PRIVATE).build();
 
-        final NetworkTemplate templateOemAll = new NetworkTemplate(MATCH_MOBILE_WILDCARD,
-                /*subscriberId=*/null, /*matchSubscriberIds=*/null,
-                /*matchWifiNetworkKeys=*/new String[0], METERED_ALL, ROAMING_ALL,
-                DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_PAID | OEM_PRIVATE,
-                SUBSCRIBER_ID_MATCH_RULE_EXACT);
+        final NetworkTemplate templateOemAll = new NetworkTemplate.Builder(MATCH_MOBILE)
+                .setOemManaged(OEM_PAID | OEM_PRIVATE).build();
 
-        final NetworkTemplate templateOemYes = new NetworkTemplate(MATCH_MOBILE_WILDCARD,
-                /*subscriberId=*/null, /*matchSubscriberIds=*/null,
-                /*matchWifiNetworkKeys=*/new String[0], METERED_ALL, ROAMING_ALL,
-                DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_YES,
-                SUBSCRIBER_ID_MATCH_RULE_EXACT);
+        final NetworkTemplate templateOemYes = new NetworkTemplate.Builder(MATCH_MOBILE)
+                .setOemManaged(OEM_MANAGED_YES).build();
 
-        final NetworkTemplate templateOemNone = new NetworkTemplate(MATCH_MOBILE_WILDCARD,
-                /*subscriberId=*/null, /*matchSubscriberIds=*/null,
-                /*matchWifiNetworkKeys=*/new String[0], METERED_ALL, ROAMING_ALL,
-                DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_NO,
-                SUBSCRIBER_ID_MATCH_RULE_EXACT);
+        final NetworkTemplate templateOemNone = new NetworkTemplate.Builder(MATCH_MOBILE)
+                .setOemManaged(OEM_MANAGED_NO).build();
 
         // OEM_PAID network comes online.
         NetworkStateSnapshot[] states = new NetworkStateSnapshot[]{
@@ -1156,7 +1144,9 @@
         final ZonedDateTime end =
                 ZonedDateTime.ofInstant(mClock.instant(), ZoneId.systemDefault());
         final ZonedDateTime start = end.truncatedTo(ChronoUnit.HOURS);
-        NetworkStats stats = mSession.getSummaryForNetwork(buildTemplateWifi(TEST_WIFI_NETWORK_KEY),
+        NetworkStats stats = mSession.getSummaryForNetwork(
+                new NetworkTemplate.Builder(MATCH_WIFI)
+                .setWifiNetworkKeys(Set.of(TEST_WIFI_NETWORK_KEY)).build(),
                 start.toInstant().toEpochMilli(), end.toInstant().toEpochMilli());
         assertEquals(1, stats.size());
         assertValues(stats, IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
@@ -1668,14 +1658,14 @@
     public void testDynamicWatchForNetworkRatTypeChanges() throws Exception {
         // Build 3G template, type unknown template to get stats while network type is unknown
         // and type all template to get the sum of all network type stats.
-        final NetworkTemplate template3g =
-                buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_UMTS,
-                METERED_YES);
-        final NetworkTemplate templateUnknown =
-                buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_UNKNOWN,
-                METERED_YES);
-        final NetworkTemplate templateAll =
-                buildTemplateMobileWithRatType(null, NETWORK_TYPE_ALL, METERED_YES);
+        final NetworkTemplate template3g = new NetworkTemplate.Builder(MATCH_MOBILE)
+                .setRatType(TelephonyManager.NETWORK_TYPE_UMTS)
+                .setMeteredness(METERED_YES).build();
+        final NetworkTemplate templateUnknown = new NetworkTemplate.Builder(MATCH_MOBILE)
+                .setRatType(TelephonyManager.NETWORK_TYPE_UNKNOWN)
+                .setMeteredness(METERED_YES).build();
+        final NetworkTemplate templateAll = new NetworkTemplate.Builder(MATCH_MOBILE)
+                .setMeteredness(METERED_YES).build();
         final NetworkStateSnapshot[] states =
                 new NetworkStateSnapshot[]{buildMobileState(IMSI_1)};
 
@@ -1772,8 +1762,8 @@
         forcePollAndWaitForIdle();
 
         // Verify mobile summary is not changed by the operation count.
-        final NetworkTemplate templateMobile =
-                buildTemplateMobileWithRatType(null, NETWORK_TYPE_ALL, METERED_YES);
+        final NetworkTemplate templateMobile = new NetworkTemplate.Builder(MATCH_MOBILE)
+                .setMeteredness(METERED_YES).build();
         final NetworkStats statsMobile = mSession.getSummaryForAllUid(
                 templateMobile, Long.MIN_VALUE, Long.MAX_VALUE, true);
         assertValues(statsMobile, IFACE_ALL, UID_RED, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
@@ -1784,7 +1774,7 @@
         // Verify the operation count is blamed onto the default network.
         // TODO: Blame onto the default network is not very reasonable. Consider blame onto the
         //  network that generates the traffic.
-        final NetworkTemplate templateWifi = buildTemplateWifiWildcard();
+        final NetworkTemplate templateWifi = new NetworkTemplate.Builder(MATCH_WIFI).build();
         final NetworkStats statsWifi = mSession.getSummaryForAllUid(
                 templateWifi, Long.MIN_VALUE, Long.MAX_VALUE, true);
         assertValues(statsWifi, IFACE_ALL, UID_RED, SET_ALL, 0xF00D, METERED_ALL, ROAMING_ALL,