Merge "Implement Discovery PLATFORM logic in Rust" into main
diff --git a/bpf_progs/netd.c b/bpf_progs/netd.c
index 74b09e7..e2e6d02 100644
--- a/bpf_progs/netd.c
+++ b/bpf_progs/netd.c
@@ -92,6 +92,8 @@
 DEFINE_BPF_MAP_NO_NETD(iface_stats_map, HASH, uint32_t, StatsValue, IFACE_STATS_MAP_SIZE)
 DEFINE_BPF_MAP_NO_NETD(uid_owner_map, HASH, uint32_t, UidOwnerValue, UID_OWNER_MAP_SIZE)
 DEFINE_BPF_MAP_RW_NETD(uid_permission_map, HASH, uint32_t, uint8_t, UID_OWNER_MAP_SIZE)
+DEFINE_BPF_MAP_NO_NETD(ingress_discard_map, HASH, IngressDiscardKey, IngressDiscardValue,
+                       INGRESS_DISCARD_MAP_SIZE)
 
 /* never actually used from ebpf */
 DEFINE_BPF_MAP_NO_NETD(iface_index_name_map, HASH, uint32_t, IfaceValue, IFACE_INDEX_NAME_MAP_SIZE)
@@ -343,6 +345,35 @@
     return *config;
 }
 
+static __always_inline inline bool ingress_should_discard(struct __sk_buff* skb,
+                                                          const unsigned kver) {
+    // Require 4.19, since earlier kernels don't have bpf_skb_load_bytes_relative() which
+    // provides relative to L3 header reads.  Without that we could fetch the wrong bytes.
+    // Additionally earlier bpf verifiers are much harder to please.
+    if (kver < KVER(4, 19, 0)) return false;
+
+    IngressDiscardKey k = {};
+    if (skb->protocol == htons(ETH_P_IP)) {
+        k.daddr.s6_addr32[2] = htonl(0xFFFF);
+        (void)bpf_skb_load_bytes_net(skb, IP4_OFFSET(daddr), &k.daddr.s6_addr32[3], 4, kver);
+    } else if (skb->protocol == htons(ETH_P_IPV6)) {
+        (void)bpf_skb_load_bytes_net(skb, IP6_OFFSET(daddr), &k.daddr, sizeof(k.daddr), kver);
+    } else {
+        return false; // non IPv4/IPv6, so no IP to match on
+    }
+
+    // we didn't check for load success, because destination bytes will be zeroed if
+    // bpf_skb_load_bytes_net() fails, instead we rely on daddr of '::' and '::ffff:0.0.0.0'
+    // never being present in the map itself
+
+    IngressDiscardValue* v = bpf_ingress_discard_map_lookup_elem(&k);
+    if (!v) return false;  // lookup failure -> no protection in place -> allow
+    // if (skb->ifindex == 1) return false;  // allow 'lo', but can't happen - see callsite
+    if (skb->ifindex == v->iif[0]) return false;  // allowed interface
+    if (skb->ifindex == v->iif[1]) return false;  // allowed interface
+    return true;  // disallowed interface
+}
+
 // DROP_IF_SET is set of rules that DROP if rule is globally enabled, and per-uid bit is set
 #define DROP_IF_SET (STANDBY_MATCH | OEM_DENY_1_MATCH | OEM_DENY_2_MATCH | OEM_DENY_3_MATCH)
 // DROP_IF_UNSET is set of rules that should DROP if globally enabled, and per-uid bit is NOT set
@@ -368,6 +399,7 @@
     if (enabledRules & (DROP_IF_SET | DROP_IF_UNSET) & (uidRules ^ DROP_IF_UNSET)) return DROP;
 
     if (!egress && skb->ifindex != 1) {
+        if (ingress_should_discard(skb, kver)) return DROP;
         if (uidRules & IIF_MATCH) {
             if (allowed_iif && skb->ifindex != allowed_iif) {
                 // Drops packets not coming from lo nor the allowed interface
@@ -413,7 +445,8 @@
     // Always allow and never count clat traffic. Only the IPv4 traffic on the stacked
     // interface is accounted for and subject to usage restrictions.
     // CLAT IPv6 TX sockets are *always* tagged with CLAT uid, see tagSocketAsClat()
-    if (uid == AID_CLAT) return PASS;
+    // CLAT daemon receives via an untagged AF_PACKET socket.
+    if (egress && uid == AID_CLAT) return PASS;
 
     int match = bpf_owner_match(skb, sock_uid, egress, kver);
 
diff --git a/bpf_progs/netd.h b/bpf_progs/netd.h
index dcf6d6a..836e998 100644
--- a/bpf_progs/netd.h
+++ b/bpf_progs/netd.h
@@ -122,6 +122,7 @@
 static const int IFACE_STATS_MAP_SIZE = 1000;
 static const int CONFIGURATION_MAP_SIZE = 2;
 static const int UID_OWNER_MAP_SIZE = 4000;
+static const int INGRESS_DISCARD_MAP_SIZE = 100;
 static const int PACKET_TRACE_BUF_SIZE = 32 * 1024;
 
 #ifdef __cplusplus
@@ -166,6 +167,7 @@
 #define CONFIGURATION_MAP_PATH BPF_NETD_PATH "map_netd_configuration_map"
 #define UID_OWNER_MAP_PATH BPF_NETD_PATH "map_netd_uid_owner_map"
 #define UID_PERMISSION_MAP_PATH BPF_NETD_PATH "map_netd_uid_permission_map"
+#define INGRESS_DISCARD_MAP_PATH BPF_NETD_PATH "map_netd_ingress_discard_map"
 #define PACKET_TRACE_RINGBUF_PATH BPF_NETD_PATH "map_netd_packet_trace_ringbuf"
 #define PACKET_TRACE_ENABLED_MAP_PATH BPF_NETD_PATH "map_netd_packet_trace_enabled_map"
 
@@ -214,6 +216,18 @@
 } UidOwnerValue;
 STRUCT_SIZE(UidOwnerValue, 2 * 4);  // 8
 
+typedef struct {
+    // The destination ip of the incoming packet.  IPv4 uses IPv4-mapped IPv6 address format.
+    struct in6_addr daddr;
+} IngressDiscardKey;
+STRUCT_SIZE(IngressDiscardKey, 16);  // 16
+
+typedef struct {
+    // Allowed interface indexes.  Use same value multiple times if you just want to match 1 value.
+    uint32_t iif[2];
+} IngressDiscardValue;
+STRUCT_SIZE(IngressDiscardValue, 2 * 4);  // 8
+
 // Entry in the configuration map that stores which UID rules are enabled.
 #define UID_RULES_CONFIGURATION_KEY 0
 // Entry in the configuration map that stores which stats map is currently in use.
diff --git a/framework/Android.bp b/framework/Android.bp
index 813e296..e663764 100644
--- a/framework/Android.bp
+++ b/framework/Android.bp
@@ -82,7 +82,6 @@
         // framework-connectivity and framework-tethering are in the same APEX.
         "framework-tethering.impl",
         "framework-wifi.stubs.module_lib",
-        "net-utils-device-common",
     ],
     static_libs: [
         "mdns_aidl_interface-lateststable-java",
@@ -91,6 +90,9 @@
         "modules-utils-preconditions",
         "framework-connectivity-javastream-protos",
     ],
+    impl_only_static_libs: [
+        "net-utils-device-common-struct",
+    ],
     libs: [
         "androidx.annotation_annotation",
         "app-compat-annotations",
@@ -112,6 +114,13 @@
         "httpclient_api",
         "httpclient_impl",
         "http_client_logging",
+        // Framework-connectivity-pre-jarjar is identical to framework-connectivity
+        // implementation, but without the jarjar rules. However, framework-connectivity
+        // is not based on framework-connectivity-pre-jarjar, it's rebuilt from source
+        // to generate the SDK stubs.
+        // Even if the library is included in "impl_only_static_libs" of defaults. This is still
+        // needed because java_library which doesn't understand "impl_only_static_libs".
+        "net-utils-device-common-struct",
     ],
     libs: [
         // This cannot be in the defaults clause above because if it were, it would be used
diff --git a/framework/src/android/net/BpfNetMapsConstants.java b/framework/src/android/net/BpfNetMapsConstants.java
new file mode 100644
index 0000000..2191682
--- /dev/null
+++ b/framework/src/android/net/BpfNetMapsConstants.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2023 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.util.Pair;
+
+import com.android.net.module.util.Struct;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * BpfNetMaps related constants that can be shared among modules.
+ *
+ * @hide
+ */
+// Note that this class should be put into bootclasspath instead of static libraries.
+// Because modules could have different copies of this class if this is statically linked,
+// which would be problematic if the definitions in these modules are not synchronized.
+public class BpfNetMapsConstants {
+    // Prevent this class from being accidental instantiated.
+    private BpfNetMapsConstants() {}
+
+    public static final String CONFIGURATION_MAP_PATH =
+            "/sys/fs/bpf/netd_shared/map_netd_configuration_map";
+    public static final String UID_OWNER_MAP_PATH =
+            "/sys/fs/bpf/netd_shared/map_netd_uid_owner_map";
+    public static final String UID_PERMISSION_MAP_PATH =
+            "/sys/fs/bpf/netd_shared/map_netd_uid_permission_map";
+    public static final String COOKIE_TAG_MAP_PATH =
+            "/sys/fs/bpf/netd_shared/map_netd_cookie_tag_map";
+    public static final Struct.S32 UID_RULES_CONFIGURATION_KEY = new Struct.S32(0);
+    public static final Struct.S32 CURRENT_STATS_MAP_CONFIGURATION_KEY = new Struct.S32(1);
+
+    // LINT.IfChange(match_type)
+    public static final long NO_MATCH = 0;
+    public static final long HAPPY_BOX_MATCH = (1 << 0);
+    public static final long PENALTY_BOX_MATCH = (1 << 1);
+    public static final long DOZABLE_MATCH = (1 << 2);
+    public static final long STANDBY_MATCH = (1 << 3);
+    public static final long POWERSAVE_MATCH = (1 << 4);
+    public static final long RESTRICTED_MATCH = (1 << 5);
+    public static final long LOW_POWER_STANDBY_MATCH = (1 << 6);
+    public static final long IIF_MATCH = (1 << 7);
+    public static final long LOCKDOWN_VPN_MATCH = (1 << 8);
+    public static final long OEM_DENY_1_MATCH = (1 << 9);
+    public static final long OEM_DENY_2_MATCH = (1 << 10);
+    public static final long OEM_DENY_3_MATCH = (1 << 11);
+    // LINT.ThenChange(packages/modules/Connectivity/bpf_progs/netd.h)
+
+    public static final List<Pair<Long, String>> MATCH_LIST = Arrays.asList(
+            Pair.create(HAPPY_BOX_MATCH, "HAPPY_BOX_MATCH"),
+            Pair.create(PENALTY_BOX_MATCH, "PENALTY_BOX_MATCH"),
+            Pair.create(DOZABLE_MATCH, "DOZABLE_MATCH"),
+            Pair.create(STANDBY_MATCH, "STANDBY_MATCH"),
+            Pair.create(POWERSAVE_MATCH, "POWERSAVE_MATCH"),
+            Pair.create(RESTRICTED_MATCH, "RESTRICTED_MATCH"),
+            Pair.create(LOW_POWER_STANDBY_MATCH, "LOW_POWER_STANDBY_MATCH"),
+            Pair.create(IIF_MATCH, "IIF_MATCH"),
+            Pair.create(LOCKDOWN_VPN_MATCH, "LOCKDOWN_VPN_MATCH"),
+            Pair.create(OEM_DENY_1_MATCH, "OEM_DENY_1_MATCH"),
+            Pair.create(OEM_DENY_2_MATCH, "OEM_DENY_2_MATCH"),
+            Pair.create(OEM_DENY_3_MATCH, "OEM_DENY_3_MATCH")
+    );
+}
diff --git a/framework/src/android/net/BpfNetMapsUtils.java b/framework/src/android/net/BpfNetMapsUtils.java
new file mode 100644
index 0000000..d464e3d
--- /dev/null
+++ b/framework/src/android/net/BpfNetMapsUtils.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2023 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 static android.net.BpfNetMapsConstants.DOZABLE_MATCH;
+import static android.net.BpfNetMapsConstants.LOW_POWER_STANDBY_MATCH;
+import static android.net.BpfNetMapsConstants.MATCH_LIST;
+import static android.net.BpfNetMapsConstants.NO_MATCH;
+import static android.net.BpfNetMapsConstants.OEM_DENY_1_MATCH;
+import static android.net.BpfNetMapsConstants.OEM_DENY_2_MATCH;
+import static android.net.BpfNetMapsConstants.OEM_DENY_3_MATCH;
+import static android.net.BpfNetMapsConstants.POWERSAVE_MATCH;
+import static android.net.BpfNetMapsConstants.RESTRICTED_MATCH;
+import static android.net.BpfNetMapsConstants.STANDBY_MATCH;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_DOZABLE;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_1;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_2;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_3;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_POWERSAVE;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_RESTRICTED;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_STANDBY;
+import static android.system.OsConstants.EINVAL;
+
+import android.os.ServiceSpecificException;
+import android.util.Pair;
+
+import java.util.StringJoiner;
+
+/**
+ * The classes and the methods for BpfNetMaps utilization.
+ *
+ * @hide
+ */
+// Note that this class should be put into bootclasspath instead of static libraries.
+// Because modules could have different copies of this class if this is statically linked,
+// which would be problematic if the definitions in these modules are not synchronized.
+public class BpfNetMapsUtils {
+    // Prevent this class from being accidental instantiated.
+    private BpfNetMapsUtils() {}
+
+    /**
+     * Get corresponding match from firewall chain.
+     */
+    public static long getMatchByFirewallChain(final int chain) {
+        switch (chain) {
+            case FIREWALL_CHAIN_DOZABLE:
+                return DOZABLE_MATCH;
+            case FIREWALL_CHAIN_STANDBY:
+                return STANDBY_MATCH;
+            case FIREWALL_CHAIN_POWERSAVE:
+                return POWERSAVE_MATCH;
+            case FIREWALL_CHAIN_RESTRICTED:
+                return RESTRICTED_MATCH;
+            case FIREWALL_CHAIN_LOW_POWER_STANDBY:
+                return LOW_POWER_STANDBY_MATCH;
+            case FIREWALL_CHAIN_OEM_DENY_1:
+                return OEM_DENY_1_MATCH;
+            case FIREWALL_CHAIN_OEM_DENY_2:
+                return OEM_DENY_2_MATCH;
+            case FIREWALL_CHAIN_OEM_DENY_3:
+                return OEM_DENY_3_MATCH;
+            default:
+                throw new ServiceSpecificException(EINVAL, "Invalid firewall chain: " + chain);
+        }
+    }
+
+    /**
+     * Get if the chain is allow list or not.
+     *
+     * 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
+     */
+    public static boolean isFirewallAllowList(final int chain) {
+        switch (chain) {
+            case FIREWALL_CHAIN_DOZABLE:
+            case FIREWALL_CHAIN_POWERSAVE:
+            case FIREWALL_CHAIN_RESTRICTED:
+            case FIREWALL_CHAIN_LOW_POWER_STANDBY:
+                return true;
+            case FIREWALL_CHAIN_STANDBY:
+            case FIREWALL_CHAIN_OEM_DENY_1:
+            case FIREWALL_CHAIN_OEM_DENY_2:
+            case FIREWALL_CHAIN_OEM_DENY_3:
+                return false;
+            default:
+                throw new ServiceSpecificException(EINVAL, "Invalid firewall chain: " + chain);
+        }
+    }
+
+    /**
+     * Get match string representation from the given match bitmap.
+     */
+    public static String matchToString(long matchMask) {
+        if (matchMask == NO_MATCH) {
+            return "NO_MATCH";
+        }
+
+        final StringJoiner sj = new StringJoiner(" ");
+        for (final Pair<Long, String> match : MATCH_LIST) {
+            final long matchFlag = match.first;
+            final String matchName = match.second;
+            if ((matchMask & matchFlag) != 0) {
+                sj.add(matchName);
+                matchMask &= ~matchFlag;
+            }
+        }
+        if (matchMask != 0) {
+            sj.add("UNKNOWN_MATCH(" + matchMask + ")");
+        }
+        return sj.toString();
+    }
+}
diff --git a/remoteauth/service/Android.bp b/remoteauth/service/Android.bp
index f42388a..2ba59da 100644
--- a/remoteauth/service/Android.bp
+++ b/remoteauth/service/Android.bp
@@ -27,7 +27,7 @@
     srcs: [":remoteauth-service-srcs"],
     required: ["libremoteauth_jni_rust_defaults"],
     defaults: [
-        "framework-system-server-module-defaults"
+        "framework-system-server-module-defaults",
     ],
     libs: [
         "androidx.annotation_annotation",
@@ -39,6 +39,7 @@
         "framework-statsd",
     ],
     static_libs: [
+        "guava",
         "libprotobuf-java-lite",
         "fast-pair-lite-protos",
         "modules-utils-build",
@@ -69,7 +70,7 @@
     name: "statslog-remoteauth-java-gen",
     tools: ["stats-log-api-gen"],
     cmd: "$(location stats-log-api-gen) --java $(out) --module remoteauth " +
-         " --javaPackage com.android.server.remoteauth.proto --javaClass RemoteAuthStatsLog" +
-         " --minApiLevel 33",
+        " --javaPackage com.android.server.remoteauth.proto --javaClass RemoteAuthStatsLog" +
+        " --minApiLevel 33",
     out: ["com/android/server/remoteauth/proto/RemoteAuthStatsLog.java"],
 }
diff --git a/remoteauth/service/java/com/android/server/remoteauth/README.md b/remoteauth/service/java/com/android/server/remoteauth/README.md
index 2f8b096..b2b5aab 100644
--- a/remoteauth/service/java/com/android/server/remoteauth/README.md
+++ b/remoteauth/service/java/com/android/server/remoteauth/README.md
@@ -1,4 +1,8 @@
 This is the source root for the RemoteAuthService
 
-## Remote connectivity manager
+## Connectivity
 Provides the connectivity manager to manage connections with the peer device.
+
+## Ranging
+Provides the ranging manager to perform ranging with the peer devices.
+
diff --git a/remoteauth/service/java/com/android/server/remoteauth/ranging/RangingCapabilities.java b/remoteauth/service/java/com/android/server/remoteauth/ranging/RangingCapabilities.java
new file mode 100644
index 0000000..2b5efff
--- /dev/null
+++ b/remoteauth/service/java/com/android/server/remoteauth/ranging/RangingCapabilities.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2023 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.server.remoteauth.ranging;
+
+import androidx.annotation.IntDef;
+
+import com.google.common.collect.ImmutableList;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+
+/** The ranging capabilities of the device. */
+public class RangingCapabilities {
+
+    /** Possible ranging methods */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(
+            value = {
+                RANGING_METHOD_UNKNOWN,
+                RANGING_METHOD_UWB,
+            })
+    public @interface RangingMethod {}
+
+    /** Unknown ranging method. */
+    public static final int RANGING_METHOD_UNKNOWN = 0x0;
+
+    /** Ultra-wideband ranging. */
+    public static final int RANGING_METHOD_UWB = 0x1;
+
+    private final ImmutableList<Integer> mSupportedRangingMethods;
+
+    /**
+     * Gets the list of supported ranging methods of the device.
+     *
+     * @return list of {@link RangingMethod}
+     */
+    public ImmutableList<Integer> getSupportedRangingMethods() {
+        return mSupportedRangingMethods;
+    }
+
+    private RangingCapabilities(List<Integer> supportedRangingMethods) {
+        mSupportedRangingMethods = ImmutableList.copyOf(supportedRangingMethods);
+    }
+
+    /** Builder class for {@link RangingCapabilities}. */
+    public static final class Builder {
+        private List<Integer> mSupportedRangingMethods = new ArrayList<>();
+
+        /** Adds a supported {@link RangingMethod} */
+        public Builder addSupportedRangingMethods(@RangingMethod int rangingMethod) {
+            mSupportedRangingMethods.add(rangingMethod);
+            return this;
+        }
+
+        /** Builds {@link RangingCapabilities}. */
+        public RangingCapabilities build() {
+            return new RangingCapabilities(mSupportedRangingMethods);
+        }
+    }
+}
diff --git a/remoteauth/service/java/com/android/server/remoteauth/ranging/RangingManager.java b/remoteauth/service/java/com/android/server/remoteauth/ranging/RangingManager.java
new file mode 100644
index 0000000..989b5ed
--- /dev/null
+++ b/remoteauth/service/java/com/android/server/remoteauth/ranging/RangingManager.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 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.server.remoteauth.ranging;
+
+import android.content.Context;
+
+/**
+ * Manages the creation of generic device to device ranging session and obtaining device's ranging
+ * capabilities.
+ *
+ * <p>Out-of-band channel for ranging capabilities/parameters exchange is assumed being handled
+ * outside of this class.
+ */
+public class RangingManager {
+
+    public RangingManager(Context context) {}
+
+    /**
+     * Gets the {@link RangingCapabilities} of this device.
+     *
+     * @return RangingCapabilities.
+     */
+    public RangingCapabilities getRangingCapabilities() {
+        return null;
+    }
+
+    /**
+     * Creates a {@link RangingSession} based on the given {@link SessionParameters}, which shall be
+     * provided based on the rangingCapabilities of the device.
+     *
+     * @param sessionParameters parameters used to setup the session.
+     * @return the created RangingSession.
+     */
+    public RangingSession createSession(SessionParameters sessionParameters) {
+        return null;
+    }
+}
diff --git a/remoteauth/service/java/com/android/server/remoteauth/ranging/RangingParameters.java b/remoteauth/service/java/com/android/server/remoteauth/ranging/RangingParameters.java
new file mode 100644
index 0000000..923730c
--- /dev/null
+++ b/remoteauth/service/java/com/android/server/remoteauth/ranging/RangingParameters.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2023 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.server.remoteauth.ranging;
+
+/** The set of parameters to start ranging. */
+public class RangingParameters {}
diff --git a/remoteauth/service/java/com/android/server/remoteauth/ranging/RangingReport.java b/remoteauth/service/java/com/android/server/remoteauth/ranging/RangingReport.java
new file mode 100644
index 0000000..5e582b1
--- /dev/null
+++ b/remoteauth/service/java/com/android/server/remoteauth/ranging/RangingReport.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2023 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.server.remoteauth.ranging;
+
+import androidx.annotation.IntDef;
+
+/** Holds ranging report data. */
+public class RangingReport {
+
+    /**
+     * State of the proximity based on detected distance compared against specified near and far
+     * boundaries.
+     */
+    @IntDef(
+            value = {
+                PROXIMITY_STATE_UNKNOWN,
+                PROXIMITY_STATE_INSIDE,
+                PROXIMITY_STATE_OUTSIDE,
+            })
+    public @interface ProximityState {}
+
+    /** Unknown proximity state. */
+    public static final int PROXIMITY_STATE_UNKNOWN = 0x0;
+
+    /**
+     * Proximity is inside the lower and upper proximity boundary. lowerProximityBoundaryM <=
+     * proximity <= upperProximityBoundaryM
+     */
+    public static final int PROXIMITY_STATE_INSIDE = 0x1;
+
+    /**
+     * Proximity is outside the lower and upper proximity boundary. proximity <
+     * lowerProximityBoundaryM OR upperProximityBoundaryM < proximity
+     */
+    public static final int PROXIMITY_STATE_OUTSIDE = 0x2;
+
+    private final float mDistanceM;
+    @ProximityState private final int mProximityState;
+
+    /**
+     * Gets the distance measurement in meters.
+     *
+     * <p>Value may be negative for devices in very close proximity.
+     *
+     * @return distance in meters
+     */
+    public float getDistanceM() {
+        return mDistanceM;
+    }
+
+    /**
+     * Gets the {@link ProximityState}.
+     *
+     * <p>The state is computed based on {@link #getDistanceM} and proximity related session
+     * parameters.
+     *
+     * @return proximity state
+     */
+    @ProximityState
+    public int getProximityState() {
+        return mProximityState;
+    }
+
+    private RangingReport(float distanceM, @ProximityState int proximityState) {
+        mDistanceM = distanceM;
+        mProximityState = proximityState;
+    }
+
+    /** Builder class for {@link RangingReport}. */
+    public static final class Builder {
+        private float mDistanceM;
+        @ProximityState private int mProximityState;
+
+        /** Sets the distance in meters. */
+        public Builder setDistanceM(float distanceM) {
+            mDistanceM = distanceM;
+            return this;
+        }
+
+        /** Sets the proximity state. */
+        public Builder setProximityState(@ProximityState int proximityState) {
+            mProximityState = proximityState;
+            return this;
+        }
+
+        /** Builds {@link RangingReport}. */
+        public RangingReport build() {
+            return new RangingReport(mDistanceM, mProximityState);
+        }
+    }
+}
diff --git a/remoteauth/service/java/com/android/server/remoteauth/ranging/RangingSession.java b/remoteauth/service/java/com/android/server/remoteauth/ranging/RangingSession.java
new file mode 100644
index 0000000..9ef6bda
--- /dev/null
+++ b/remoteauth/service/java/com/android/server/remoteauth/ranging/RangingSession.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2023 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.server.remoteauth.ranging;
+
+import android.annotation.NonNull;
+
+import androidx.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.Executor;
+
+/**
+ * The controller for starting and stopping ranging during which callers receive callbacks with
+ * {@link RangingReport}s and {@link RangingError}s."
+ *
+ * <p>A session can be started and stopped multiple times. After starting, updates ({@link
+ * RangingReport}, {@link RangingError}, etc) will be reported via the provided {@link
+ * RangingCallback}. BaseKey and SyncData are used for auto derivation of supported ranging
+ * parameters, which will be implementation specific.
+ *
+ * <p>Ranging method specific implementation shall be implemented in the extended class.
+ */
+public abstract class RangingSession {
+
+    /** Types of ranging error. */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(
+            value = {
+                RANGING_ERROR_UNKNOWN,
+            })
+    public @interface RangingError {}
+
+    /** Unknown ranging error type. */
+    public static final int RANGING_ERROR_UNKNOWN = 0x0;
+
+    /** Interface for ranging update callbacks. */
+    public interface RangingCallback {
+        /**
+         * Call upon new {@link RangingReport}.
+         *
+         * @param sessionInfo info about this ranging session.
+         * @param rangingReport new ranging report
+         */
+        void onRangingReport(SessionInfo sessionInfo, RangingReport rangingReport);
+
+        /**
+         * Call upon any ranging error events.
+         *
+         * @param sessionInfo info about this ranging session.
+         * @param rangingError error type
+         */
+        void onError(SessionInfo sessionInfo, @RangingError int rangingError);
+    }
+
+    /**
+     * Starts ranging based on the given {@link RangingParameters}.
+     *
+     * <p>Start can be called again after {@link #stop()} has been called, else it will result in a
+     * no-op.
+     *
+     * @param rangingParameters parameters to start the ranging.
+     * @param executor Executor to run the rangingCallback.
+     * @param rangingCallback callback to notify of ranging events.
+     */
+    public abstract void start(
+            @NonNull RangingParameters rangingParameters,
+            @NonNull Executor executor,
+            @NonNull RangingCallback rangingCallback);
+
+    /**
+     * Stops ranging.
+     *
+     * <p>Calling stop without first calling {@link #start()} will result in a no-op.
+     */
+    public abstract void stop();
+
+    /**
+     * Resets the base key that's used to derive all possible ranging parameters. The baseKey shall
+     * be reset whenever there is a risk that it may no longer be valid and secured. For example,
+     * the secure connection between the devices is lost.
+     *
+     * @param baseKey new baseKey must be 16 or 32 bytes.
+     */
+    public void resetBaseKey(byte[] baseKey) {}
+
+    /**
+     * Resets the synchronization by giving a new syncData used for ranging parameters derivation.
+     * Resetting the syncData is not required before each {@link #start}, but the more time the
+     * derivations are done before resetting syncData, the higher the risk the derivation will be
+     * out of sync between the devices. Therefore, syncData shall be refreshed in a best effort
+     * manner.
+     *
+     * @param syncData new syncData must be 16 bytes.
+     */
+    public void resetSyncData(byte[] syncData) {}
+}
diff --git a/remoteauth/service/java/com/android/server/remoteauth/ranging/SessionInfo.java b/remoteauth/service/java/com/android/server/remoteauth/ranging/SessionInfo.java
new file mode 100644
index 0000000..5e4fc48
--- /dev/null
+++ b/remoteauth/service/java/com/android/server/remoteauth/ranging/SessionInfo.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2023 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.server.remoteauth.ranging;
+
+import static com.android.server.remoteauth.ranging.RangingCapabilities.RANGING_METHOD_UNKNOWN;
+
+import com.android.internal.util.Preconditions;
+import com.android.server.remoteauth.ranging.RangingCapabilities.RangingMethod;
+
+/** Information about the {@link RangingSession}. */
+public class SessionInfo {
+
+    private final String mDeviceId;
+    @RangingMethod private final int mRangingMethod;
+
+    public String getDeviceId() {
+        return mDeviceId;
+    }
+
+    @RangingMethod
+    public int getRangingMethod() {
+        return mRangingMethod;
+    }
+
+    private SessionInfo(String deviceId, @RangingMethod int rangingMethod) {
+        mDeviceId = deviceId;
+        mRangingMethod = rangingMethod;
+    }
+
+    /** Builder class for {@link SessionInfo}. */
+    public static final class Builder {
+        private String mDeviceId = "";
+        @RangingMethod private int mRangingMethod = RANGING_METHOD_UNKNOWN;
+
+        /** Sets the device id. */
+        public Builder setDeviceId(String deviceId) {
+            mDeviceId = deviceId;
+            return this;
+        }
+
+        /** Sets the ranging method. */
+        public Builder setRangingMethod(@RangingMethod int rangingMethod) {
+            mRangingMethod = rangingMethod;
+            return this;
+        }
+
+        /** Builds {@link SessionInfo}. */
+        public SessionInfo build() {
+            Preconditions.checkArgument(!mDeviceId.isEmpty(), "deviceId must not be empty.");
+            Preconditions.checkArgument(
+                    mRangingMethod != RANGING_METHOD_UNKNOWN, "Unknown rangingMethod");
+            return new SessionInfo(mDeviceId, mRangingMethod);
+        }
+    }
+}
diff --git a/remoteauth/service/java/com/android/server/remoteauth/ranging/SessionParameters.java b/remoteauth/service/java/com/android/server/remoteauth/ranging/SessionParameters.java
new file mode 100644
index 0000000..33c3203
--- /dev/null
+++ b/remoteauth/service/java/com/android/server/remoteauth/ranging/SessionParameters.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2023 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.server.remoteauth.ranging;
+
+import static com.android.server.remoteauth.ranging.RangingCapabilities.RANGING_METHOD_UNKNOWN;
+
+import android.annotation.NonNull;
+
+import com.android.internal.util.Preconditions;
+import com.android.server.remoteauth.ranging.RangingCapabilities.RangingMethod;
+
+/**
+ * The set of parameters to create a ranging session.
+ *
+ * <p>Required parameters must be provided, else {@link Builder} will throw an exception. The
+ * optional parameters only need to be provided if the functionality is necessary to the session,
+ * see the setter functions of the {@link Builder} for detailed info of each parameter.
+ */
+public class SessionParameters {
+
+    /* Required parameters */
+    private final String mDeviceId;
+    @RangingMethod private final int mRangingMethod;
+
+    /* Optional parameters */
+    private final float mLowerProximityBoundaryM;
+    private final float mUpperProximityBoundaryM;
+    private final boolean mAutoDeriveParams;
+    private final byte[] mBaseKey;
+    private final byte[] mSyncData;
+
+    public String getDeviceId() {
+        return mDeviceId;
+    }
+
+    @RangingMethod
+    public int getRangingMethod() {
+        return mRangingMethod;
+    }
+
+    public float getLowerProximityBoundaryM() {
+        return mLowerProximityBoundaryM;
+    }
+
+    public float getUpperProximityBoundaryM() {
+        return mUpperProximityBoundaryM;
+    }
+
+    public boolean getAutoDeriveParams() {
+        return mAutoDeriveParams;
+    }
+
+    public byte[] getBaseKey() {
+        return mBaseKey;
+    }
+
+    public byte[] getSyncData() {
+        return mSyncData;
+    }
+
+    private SessionParameters(
+            String deviceId,
+            @RangingMethod int rangingMethod,
+            float lowerProximityBoundaryM,
+            float upperProximityBoundaryM,
+            boolean autoDeriveParams,
+            byte[] baseKey,
+            byte[] syncData) {
+        mDeviceId = deviceId;
+        mRangingMethod = rangingMethod;
+        mLowerProximityBoundaryM = lowerProximityBoundaryM;
+        mUpperProximityBoundaryM = upperProximityBoundaryM;
+        mAutoDeriveParams = autoDeriveParams;
+        mBaseKey = baseKey;
+        mSyncData = syncData;
+    }
+
+    /** Builder class for {@link SessionParameters}. */
+    public static final class Builder {
+        private String mDeviceId = new String("");
+        @RangingMethod private int mRangingMethod = RANGING_METHOD_UNKNOWN;
+        private float mLowerProximityBoundaryM;
+        private float mUpperProximityBoundaryM;
+        private boolean mAutoDeriveParams = false;
+        private byte[] mBaseKey = new byte[] {};
+        private byte[] mSyncData = new byte[] {};
+
+        /**
+         * Sets the device id.
+         *
+         * <p>This is used as the identity included in the {@link SessionInfo} for all {@link
+         * RangingCallback}s.
+         */
+        public Builder setDeviceId(@NonNull String deviceId) {
+            mDeviceId = deviceId;
+            return this;
+        }
+
+        /**
+         * Sets the {@link RangingMethod} to be used for the {@link RangingSession}.
+         *
+         * <p>Note: The ranging method should be ones in the list return by {@link
+         * RangingCapabilities#getSupportedRangingMethods};
+         */
+        public Builder setRangingMethod(@RangingMethod int rangingMethod) {
+            mRangingMethod = rangingMethod;
+            return this;
+        }
+
+        /**
+         * Sets the lower proximity boundary in meters, must be greater than or equals to zero.
+         *
+         * <p>This value is used to compute the {@link ProximityState} = {@link
+         * PROXIMITY_STATE_INSIDE} if lowerProximityBoundaryM <= proximity <=
+         * upperProximityBoundaryM, else {@link PROXIMITY_STATE_OUTSIDE}.
+         */
+        public Builder setLowerProximityBoundaryM(float lowerProximityBoundaryM) {
+            mLowerProximityBoundaryM = lowerProximityBoundaryM;
+            return this;
+        }
+
+        /**
+         * Sets the upper proximity boundary in meters, must be greater than or equals to
+         * lowerProximityBoundaryM.
+         *
+         * <p>This value is used to compute the {@link ProximityState} = {@link
+         * PROXIMITY_STATE_INSIDE} if lowerProximityBoundaryM <= proximity <=
+         * upperProximityBoundaryM, else {@link PROXIMITY_STATE_OUTSIDE}.
+         */
+        public Builder setUpperProximityBoundaryM(float upperProximityBoundaryM) {
+            mUpperProximityBoundaryM = upperProximityBoundaryM;
+            return this;
+        }
+
+        /**
+         * Sets the auto derive ranging parameters flag. Defaults to false.
+         *
+         * <p>This enables the {@link RangingSession} to automatically derive all possible {@link
+         * RangingParameters} at each {@link RangingSession#start} using the provided {@link
+         * #setBaseKey} and {@link #setSyncData}, which shall be securely shared between the ranging
+         * devices out of band.
+         */
+        public Builder setAutoDeriveParams(boolean autoDeriveParams) {
+            mAutoDeriveParams = autoDeriveParams;
+            return this;
+        }
+
+        /**
+         * Sets the base key. Only required if {@link #setAutoDeriveParams} is set to true.
+         *
+         * @param baseKey baseKey must be 16 or 32 bytes.
+         * @throws NullPointerException if baseKey is null
+         */
+        public Builder setBaseKey(@NonNull byte[] baseKey) {
+            Preconditions.checkNotNull(baseKey);
+            mBaseKey = baseKey;
+            return this;
+        }
+
+        /**
+         * Sets the sync data. Only required if {@link #setAutoDeriveParams} is set to true.
+         *
+         * @param syncData syncData must be 16 bytes.
+         * @throws NullPointerException if syncData is null
+         */
+        public Builder setSyncData(@NonNull byte[] syncData) {
+            Preconditions.checkNotNull(syncData);
+            mSyncData = syncData;
+            return this;
+        }
+
+        /**
+         * Builds {@link SessionParameters}.
+         *
+         * @throws IllegalArgumentException if any parameter is invalid.
+         */
+        public SessionParameters build() {
+            Preconditions.checkArgument(!mDeviceId.isEmpty(), "deviceId must not be empty.");
+            Preconditions.checkArgument(
+                    mRangingMethod != RANGING_METHOD_UNKNOWN, "Unknown rangingMethod");
+            Preconditions.checkArgument(
+                    mLowerProximityBoundaryM >= 0,
+                    "Negative lowerProximityBoundaryM: " + mLowerProximityBoundaryM);
+            Preconditions.checkArgument(
+                    mLowerProximityBoundaryM <= mUpperProximityBoundaryM,
+                    "lowerProximityBoundaryM is greater than upperProximityBoundaryM: "
+                            + mLowerProximityBoundaryM
+                            + " > "
+                            + mUpperProximityBoundaryM);
+            // If mAutoDeriveParams is false, mBaseKey and mSyncData will not be used.
+            if (mAutoDeriveParams) {
+                Preconditions.checkArgument(
+                        mBaseKey.length == 16 || mBaseKey.length == 32,
+                        "Invalid baseKey length: " + mBaseKey.length);
+                Preconditions.checkArgument(
+                        mSyncData.length == 16, "Invalid syncData length: " + mSyncData.length);
+            }
+
+            return new SessionParameters(
+                    mDeviceId,
+                    mRangingMethod,
+                    mLowerProximityBoundaryM,
+                    mUpperProximityBoundaryM,
+                    mAutoDeriveParams,
+                    mBaseKey,
+                    mSyncData);
+        }
+    }
+}
diff --git a/remoteauth/tests/unit/src/com/android/server/remoteauth/ranging/RangingCapabilitiesTest.java b/remoteauth/tests/unit/src/com/android/server/remoteauth/ranging/RangingCapabilitiesTest.java
new file mode 100644
index 0000000..e6b6e3b
--- /dev/null
+++ b/remoteauth/tests/unit/src/com/android/server/remoteauth/ranging/RangingCapabilitiesTest.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 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.server.remoteauth.ranging;
+
+import static com.android.server.remoteauth.ranging.RangingCapabilities.RANGING_METHOD_UWB;
+
+import static org.junit.Assert.assertEquals;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Unit test for {@link RangingCapabilities}. */
+@RunWith(AndroidJUnit4.class)
+public class RangingCapabilitiesTest {
+
+    @Test
+    public void testBuildingRangingCapabilities_success() {
+        final RangingCapabilities rangingCapabilities =
+                new RangingCapabilities.Builder()
+                        .addSupportedRangingMethods(RANGING_METHOD_UWB)
+                        .build();
+
+        assertEquals(rangingCapabilities.getSupportedRangingMethods().size(), 1);
+        assertEquals(
+                (int) rangingCapabilities.getSupportedRangingMethods().get(0), RANGING_METHOD_UWB);
+    }
+}
diff --git a/remoteauth/tests/unit/src/com/android/server/remoteauth/ranging/RangingReportTest.java b/remoteauth/tests/unit/src/com/android/server/remoteauth/ranging/RangingReportTest.java
new file mode 100644
index 0000000..6ac56ea
--- /dev/null
+++ b/remoteauth/tests/unit/src/com/android/server/remoteauth/ranging/RangingReportTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2023 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.server.remoteauth.ranging;
+
+import static com.android.server.remoteauth.ranging.RangingReport.PROXIMITY_STATE_INSIDE;
+
+import static org.junit.Assert.assertEquals;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.server.remoteauth.ranging.RangingReport.ProximityState;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Unit test for {@link RangingReport}. */
+@RunWith(AndroidJUnit4.class)
+public class RangingReportTest {
+
+    private static final float TEST_DISTANCE_M = 1.5f;
+    @ProximityState private static final int TEST_PROXIMITY_STATE = PROXIMITY_STATE_INSIDE;
+
+    @Test
+    public void testBuildingRangingReport_success() {
+        final RangingReport rangingReport =
+                new RangingReport.Builder()
+                        .setDistanceM(TEST_DISTANCE_M)
+                        .setProximityState(TEST_PROXIMITY_STATE)
+                        .build();
+
+        assertEquals(rangingReport.getDistanceM(), TEST_DISTANCE_M, 0.0f);
+        assertEquals(rangingReport.getProximityState(), TEST_PROXIMITY_STATE);
+    }
+}
diff --git a/remoteauth/tests/unit/src/com/android/server/remoteauth/ranging/SessionInfoTest.java b/remoteauth/tests/unit/src/com/android/server/remoteauth/ranging/SessionInfoTest.java
new file mode 100644
index 0000000..9364092
--- /dev/null
+++ b/remoteauth/tests/unit/src/com/android/server/remoteauth/ranging/SessionInfoTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2023 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.server.remoteauth.ranging;
+
+import static com.android.server.remoteauth.ranging.RangingCapabilities.RANGING_METHOD_UWB;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.server.remoteauth.ranging.RangingCapabilities.RangingMethod;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Unit test for {@link SessionInfo}. */
+@RunWith(AndroidJUnit4.class)
+public class SessionInfoTest {
+
+    private static final String TEST_DEVICE_ID = new String("test_device_id");
+    private static final @RangingMethod int TEST_RANGING_METHOD = RANGING_METHOD_UWB;
+
+    @Test
+    public void testBuildingSessionInfo_success() {
+        final SessionInfo sessionInfo =
+                new SessionInfo.Builder()
+                        .setDeviceId(TEST_DEVICE_ID)
+                        .setRangingMethod(TEST_RANGING_METHOD)
+                        .build();
+
+        assertEquals(sessionInfo.getDeviceId(), TEST_DEVICE_ID);
+        assertEquals(sessionInfo.getRangingMethod(), TEST_RANGING_METHOD);
+    }
+
+    @Test
+    public void testBuildingSessionInfo_invalidDeviceId() {
+        final SessionInfo.Builder builder =
+                new SessionInfo.Builder().setRangingMethod(TEST_RANGING_METHOD);
+
+        assertThrows(IllegalArgumentException.class, () -> builder.build());
+    }
+
+    @Test
+    public void testBuildingSessionInfo_invalidRangingMethod() {
+        final SessionInfo.Builder builder = new SessionInfo.Builder().setDeviceId(TEST_DEVICE_ID);
+
+        assertThrows(IllegalArgumentException.class, () -> builder.build());
+    }
+}
diff --git a/remoteauth/tests/unit/src/com/android/server/remoteauth/ranging/SessionParametersTest.java b/remoteauth/tests/unit/src/com/android/server/remoteauth/ranging/SessionParametersTest.java
new file mode 100644
index 0000000..357fdf9
--- /dev/null
+++ b/remoteauth/tests/unit/src/com/android/server/remoteauth/ranging/SessionParametersTest.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2023 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.server.remoteauth.ranging;
+
+import static com.android.server.remoteauth.ranging.RangingCapabilities.RANGING_METHOD_UWB;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.server.remoteauth.ranging.RangingCapabilities.RangingMethod;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Unit tests for {@link SessionParameters}. */
+@RunWith(AndroidJUnit4.class)
+public class SessionParametersTest {
+
+    private static final String TEST_DEVICE_ID = "test_device_id";
+    @RangingMethod private static final int TEST_RANGING_METHOD = RANGING_METHOD_UWB;
+    private static final float TEST_LOWER_PROXIMITY_BOUNDARY_M = 1.0f;
+    private static final float TEST_UPPER_PROXIMITY_BOUNDARY_M = 2.5f;
+    private static final boolean TEST_AUTO_DERIVE_PARAMS = true;
+    private static final byte[] TEST_BASE_KEY =
+            new byte[] {
+                0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
+                0x0e, 0x0f
+            };
+    private static final byte[] TEST_SYNC_DATA =
+            new byte[] {
+                0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+                0x0f, 0x00
+            };
+
+    @Test
+    public void testBuildingSessionParameters_success() {
+        final SessionParameters sessionParameters =
+                new SessionParameters.Builder()
+                        .setDeviceId(TEST_DEVICE_ID)
+                        .setRangingMethod(TEST_RANGING_METHOD)
+                        .setLowerProximityBoundaryM(TEST_LOWER_PROXIMITY_BOUNDARY_M)
+                        .setUpperProximityBoundaryM(TEST_UPPER_PROXIMITY_BOUNDARY_M)
+                        .setAutoDeriveParams(TEST_AUTO_DERIVE_PARAMS)
+                        .setBaseKey(TEST_BASE_KEY)
+                        .setSyncData(TEST_SYNC_DATA)
+                        .build();
+
+        assertEquals(sessionParameters.getDeviceId(), TEST_DEVICE_ID);
+        assertEquals(sessionParameters.getRangingMethod(), TEST_RANGING_METHOD);
+        assertEquals(
+                sessionParameters.getLowerProximityBoundaryM(),
+                TEST_LOWER_PROXIMITY_BOUNDARY_M,
+                0.0f);
+        assertEquals(
+                sessionParameters.getUpperProximityBoundaryM(),
+                TEST_UPPER_PROXIMITY_BOUNDARY_M,
+                0.0f);
+        assertEquals(sessionParameters.getAutoDeriveParams(), TEST_AUTO_DERIVE_PARAMS);
+        assertArrayEquals(sessionParameters.getBaseKey(), TEST_BASE_KEY);
+        assertArrayEquals(sessionParameters.getSyncData(), TEST_SYNC_DATA);
+    }
+
+    @Test
+    public void testBuildingSessionParameters_invalidDeviceId() {
+        final SessionParameters.Builder builder =
+                new SessionParameters.Builder()
+                        .setRangingMethod(TEST_RANGING_METHOD)
+                        .setLowerProximityBoundaryM(TEST_LOWER_PROXIMITY_BOUNDARY_M)
+                        .setUpperProximityBoundaryM(TEST_UPPER_PROXIMITY_BOUNDARY_M)
+                        .setBaseKey(TEST_BASE_KEY)
+                        .setSyncData(TEST_SYNC_DATA);
+
+        assertThrows(IllegalArgumentException.class, () -> builder.build());
+    }
+
+    @Test
+    public void testBuildingSessionParameters_invalidRangingMethod() {
+        final SessionParameters.Builder builder =
+                new SessionParameters.Builder()
+                        .setDeviceId(TEST_DEVICE_ID)
+                        .setLowerProximityBoundaryM(TEST_LOWER_PROXIMITY_BOUNDARY_M)
+                        .setUpperProximityBoundaryM(TEST_UPPER_PROXIMITY_BOUNDARY_M)
+                        .setBaseKey(TEST_BASE_KEY)
+                        .setSyncData(TEST_SYNC_DATA);
+
+        assertThrows(IllegalArgumentException.class, () -> builder.build());
+    }
+
+    @Test
+    public void testBuildingSessionParameters_invalidLowerProximityBoundaryM() {
+        final SessionParameters.Builder builder =
+                new SessionParameters.Builder()
+                        .setDeviceId(TEST_DEVICE_ID)
+                        .setRangingMethod(TEST_RANGING_METHOD)
+                        .setLowerProximityBoundaryM(-1.0f)
+                        .setUpperProximityBoundaryM(TEST_UPPER_PROXIMITY_BOUNDARY_M)
+                        .setBaseKey(TEST_BASE_KEY)
+                        .setSyncData(TEST_SYNC_DATA);
+
+        assertThrows(IllegalArgumentException.class, () -> builder.build());
+    }
+
+    @Test
+    public void testBuildingSessionParameters_invalidUpperProximityBoundaryM() {
+        final SessionParameters.Builder builder =
+                new SessionParameters.Builder()
+                        .setDeviceId(TEST_DEVICE_ID)
+                        .setRangingMethod(TEST_RANGING_METHOD)
+                        .setLowerProximityBoundaryM(TEST_LOWER_PROXIMITY_BOUNDARY_M)
+                        .setUpperProximityBoundaryM(TEST_LOWER_PROXIMITY_BOUNDARY_M - 0.1f)
+                        .setBaseKey(TEST_BASE_KEY)
+                        .setSyncData(TEST_SYNC_DATA);
+
+        assertThrows(IllegalArgumentException.class, () -> builder.build());
+    }
+
+    @Test
+    public void testBuildingSessionParameters_disableAutoDeriveParams() {
+        final boolean autoDeriveParams = false;
+        final SessionParameters sessionParameters =
+                new SessionParameters.Builder()
+                        .setDeviceId(TEST_DEVICE_ID)
+                        .setRangingMethod(TEST_RANGING_METHOD)
+                        .setLowerProximityBoundaryM(TEST_LOWER_PROXIMITY_BOUNDARY_M)
+                        .setUpperProximityBoundaryM(TEST_UPPER_PROXIMITY_BOUNDARY_M)
+                        .setAutoDeriveParams(autoDeriveParams)
+                        .build();
+
+        assertEquals(sessionParameters.getAutoDeriveParams(), autoDeriveParams);
+        assertArrayEquals(sessionParameters.getBaseKey(), new byte[] {});
+        assertArrayEquals(sessionParameters.getSyncData(), new byte[] {});
+    }
+
+    @Test
+    public void testBuildingSessionParameters_emptyBaseKey() {
+        final SessionParameters.Builder builder =
+                new SessionParameters.Builder()
+                        .setDeviceId(TEST_DEVICE_ID)
+                        .setRangingMethod(TEST_RANGING_METHOD)
+                        .setLowerProximityBoundaryM(TEST_LOWER_PROXIMITY_BOUNDARY_M)
+                        .setUpperProximityBoundaryM(TEST_UPPER_PROXIMITY_BOUNDARY_M)
+                        .setAutoDeriveParams(TEST_AUTO_DERIVE_PARAMS)
+                        .setSyncData(TEST_SYNC_DATA);
+
+        assertThrows(IllegalArgumentException.class, () -> builder.build());
+    }
+
+    @Test
+    public void testBuildingSessionParameters_invalidBaseKey() {
+        final SessionParameters.Builder builder =
+                new SessionParameters.Builder()
+                        .setDeviceId(TEST_DEVICE_ID)
+                        .setRangingMethod(TEST_RANGING_METHOD)
+                        .setLowerProximityBoundaryM(TEST_LOWER_PROXIMITY_BOUNDARY_M)
+                        .setUpperProximityBoundaryM(TEST_UPPER_PROXIMITY_BOUNDARY_M)
+                        .setAutoDeriveParams(TEST_AUTO_DERIVE_PARAMS)
+                        .setBaseKey(new byte[] {0x00, 0x01, 0x02, 0x13})
+                        .setSyncData(TEST_SYNC_DATA);
+
+        assertThrows(IllegalArgumentException.class, () -> builder.build());
+    }
+
+    @Test
+    public void testBuildingSessionParameters_emptySyncData() {
+        final SessionParameters.Builder builder =
+                new SessionParameters.Builder()
+                        .setDeviceId(TEST_DEVICE_ID)
+                        .setRangingMethod(TEST_RANGING_METHOD)
+                        .setLowerProximityBoundaryM(TEST_LOWER_PROXIMITY_BOUNDARY_M)
+                        .setUpperProximityBoundaryM(TEST_UPPER_PROXIMITY_BOUNDARY_M)
+                        .setAutoDeriveParams(TEST_AUTO_DERIVE_PARAMS)
+                        .setBaseKey(TEST_BASE_KEY);
+
+        assertThrows(IllegalArgumentException.class, () -> builder.build());
+    }
+
+    @Test
+    public void testBuildingSessionParameters_invalidSyncData() {
+        final SessionParameters.Builder builder =
+                new SessionParameters.Builder()
+                        .setDeviceId(TEST_DEVICE_ID)
+                        .setRangingMethod(TEST_RANGING_METHOD)
+                        .setLowerProximityBoundaryM(TEST_LOWER_PROXIMITY_BOUNDARY_M)
+                        .setUpperProximityBoundaryM(TEST_UPPER_PROXIMITY_BOUNDARY_M)
+                        .setAutoDeriveParams(TEST_AUTO_DERIVE_PARAMS)
+                        .setBaseKey(TEST_BASE_KEY)
+                        .setSyncData(new byte[] {0x00, 0x01, 0x02, 0x13});
+
+        assertThrows(IllegalArgumentException.class, () -> builder.build());
+    }
+}
diff --git a/service/src/com/android/server/BpfNetMaps.java b/service/src/com/android/server/BpfNetMaps.java
index 2842cc3..62520dc 100644
--- a/service/src/com/android/server/BpfNetMaps.java
+++ b/service/src/com/android/server/BpfNetMaps.java
@@ -16,6 +16,18 @@
 
 package com.android.server;
 
+import static android.net.BpfNetMapsConstants.CONFIGURATION_MAP_PATH;
+import static android.net.BpfNetMapsConstants.COOKIE_TAG_MAP_PATH;
+import static android.net.BpfNetMapsConstants.CURRENT_STATS_MAP_CONFIGURATION_KEY;
+import static android.net.BpfNetMapsConstants.HAPPY_BOX_MATCH;
+import static android.net.BpfNetMapsConstants.IIF_MATCH;
+import static android.net.BpfNetMapsConstants.LOCKDOWN_VPN_MATCH;
+import static android.net.BpfNetMapsConstants.PENALTY_BOX_MATCH;
+import static android.net.BpfNetMapsConstants.UID_OWNER_MAP_PATH;
+import static android.net.BpfNetMapsConstants.UID_PERMISSION_MAP_PATH;
+import static android.net.BpfNetMapsConstants.UID_RULES_CONFIGURATION_KEY;
+import static android.net.BpfNetMapsUtils.getMatchByFirewallChain;
+import static android.net.BpfNetMapsUtils.matchToString;
 import static android.net.ConnectivityManager.FIREWALL_CHAIN_DOZABLE;
 import static android.net.ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY;
 import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_1;
@@ -107,16 +119,6 @@
     // BpfNetMaps is an only writer of this entry.
     private static final Object sCurrentStatsMapConfigLock = new Object();
 
-    private static final String CONFIGURATION_MAP_PATH =
-            "/sys/fs/bpf/netd_shared/map_netd_configuration_map";
-    private static final String UID_OWNER_MAP_PATH =
-            "/sys/fs/bpf/netd_shared/map_netd_uid_owner_map";
-    private static final String UID_PERMISSION_MAP_PATH =
-            "/sys/fs/bpf/netd_shared/map_netd_uid_permission_map";
-    private static final String COOKIE_TAG_MAP_PATH =
-            "/sys/fs/bpf/netd_shared/map_netd_cookie_tag_map";
-    private static final S32 UID_RULES_CONFIGURATION_KEY = new S32(0);
-    private static final S32 CURRENT_STATS_MAP_CONFIGURATION_KEY = new S32(1);
     private static final long UID_RULES_DEFAULT_CONFIGURATION = 0;
     private static final long STATS_SELECT_MAP_A = 0;
     private static final long STATS_SELECT_MAP_B = 1;
@@ -127,40 +129,10 @@
     private static IBpfMap<S32, U8> sUidPermissionMap = null;
     private static IBpfMap<CookieTagMapKey, CookieTagMapValue> sCookieTagMap = null;
 
-    // LINT.IfChange(match_type)
-    @VisibleForTesting public static final long NO_MATCH = 0;
-    @VisibleForTesting public static final long HAPPY_BOX_MATCH = (1 << 0);
-    @VisibleForTesting public static final long PENALTY_BOX_MATCH = (1 << 1);
-    @VisibleForTesting public static final long DOZABLE_MATCH = (1 << 2);
-    @VisibleForTesting public static final long STANDBY_MATCH = (1 << 3);
-    @VisibleForTesting public static final long POWERSAVE_MATCH = (1 << 4);
-    @VisibleForTesting public static final long RESTRICTED_MATCH = (1 << 5);
-    @VisibleForTesting public static final long LOW_POWER_STANDBY_MATCH = (1 << 6);
-    @VisibleForTesting public static final long IIF_MATCH = (1 << 7);
-    @VisibleForTesting public static final long LOCKDOWN_VPN_MATCH = (1 << 8);
-    @VisibleForTesting public static final long OEM_DENY_1_MATCH = (1 << 9);
-    @VisibleForTesting public static final long OEM_DENY_2_MATCH = (1 << 10);
-    @VisibleForTesting public static final long OEM_DENY_3_MATCH = (1 << 11);
-    // LINT.ThenChange(packages/modules/Connectivity/bpf_progs/netd.h)
-
     private static final List<Pair<Integer, String>> PERMISSION_LIST = Arrays.asList(
             Pair.create(PERMISSION_INTERNET, "PERMISSION_INTERNET"),
             Pair.create(PERMISSION_UPDATE_DEVICE_STATS, "PERMISSION_UPDATE_DEVICE_STATS")
     );
-    private static final List<Pair<Long, String>> MATCH_LIST = Arrays.asList(
-            Pair.create(HAPPY_BOX_MATCH, "HAPPY_BOX_MATCH"),
-            Pair.create(PENALTY_BOX_MATCH, "PENALTY_BOX_MATCH"),
-            Pair.create(DOZABLE_MATCH, "DOZABLE_MATCH"),
-            Pair.create(STANDBY_MATCH, "STANDBY_MATCH"),
-            Pair.create(POWERSAVE_MATCH, "POWERSAVE_MATCH"),
-            Pair.create(RESTRICTED_MATCH, "RESTRICTED_MATCH"),
-            Pair.create(LOW_POWER_STANDBY_MATCH, "LOW_POWER_STANDBY_MATCH"),
-            Pair.create(IIF_MATCH, "IIF_MATCH"),
-            Pair.create(LOCKDOWN_VPN_MATCH, "LOCKDOWN_VPN_MATCH"),
-            Pair.create(OEM_DENY_1_MATCH, "OEM_DENY_1_MATCH"),
-            Pair.create(OEM_DENY_2_MATCH, "OEM_DENY_2_MATCH"),
-            Pair.create(OEM_DENY_3_MATCH, "OEM_DENY_3_MATCH")
-    );
 
     /**
      * Set sEnableJavaBpfMap for test.
@@ -353,33 +325,6 @@
     }
 
     /**
-     * Get corresponding match from firewall chain.
-     */
-    @VisibleForTesting
-    public long getMatchByFirewallChain(final int chain) {
-        switch (chain) {
-            case FIREWALL_CHAIN_DOZABLE:
-                return DOZABLE_MATCH;
-            case FIREWALL_CHAIN_STANDBY:
-                return STANDBY_MATCH;
-            case FIREWALL_CHAIN_POWERSAVE:
-                return POWERSAVE_MATCH;
-            case FIREWALL_CHAIN_RESTRICTED:
-                return RESTRICTED_MATCH;
-            case FIREWALL_CHAIN_LOW_POWER_STANDBY:
-                return LOW_POWER_STANDBY_MATCH;
-            case FIREWALL_CHAIN_OEM_DENY_1:
-                return OEM_DENY_1_MATCH;
-            case FIREWALL_CHAIN_OEM_DENY_2:
-                return OEM_DENY_2_MATCH;
-            case FIREWALL_CHAIN_OEM_DENY_3:
-                return OEM_DENY_3_MATCH;
-            default:
-                throw new ServiceSpecificException(EINVAL, "Invalid firewall chain: " + chain);
-        }
-    }
-
-    /**
      * Get if the chain is allow list or not.
      *
      * ALLOWLIST means the firewall denies all by default, uids must be explicitly allowed
@@ -1049,26 +994,6 @@
         return sj.toString();
     }
 
-    private String matchToString(long matchMask) {
-        if (matchMask == NO_MATCH) {
-            return "NO_MATCH";
-        }
-
-        final StringJoiner sj = new StringJoiner(" ");
-        for (Pair<Long, String> match: MATCH_LIST) {
-            final long matchFlag = match.first;
-            final String matchName = match.second;
-            if ((matchMask & matchFlag) != 0) {
-                sj.add(matchName);
-                matchMask &= ~matchFlag;
-            }
-        }
-        if (matchMask != 0) {
-            sj.add("UNKNOWN_MATCH(" + matchMask + ")");
-        }
-        return sj.toString();
-    }
-
     private void dumpOwnerMatchConfig(final IndentingPrintWriter pw) {
         try {
             final long match = sConfigurationMap.getValue(UID_RULES_CONFIGURATION_KEY).val;
diff --git a/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt b/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
index 3146b41..b7e5205 100644
--- a/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
+++ b/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
@@ -385,6 +385,9 @@
         }
         registeredCallbacks.forEach { cm.unregisterNetworkCallback(it) }
         releaseTetheredInterface()
+        // Force releaseTetheredInterface() to be processed before starting the next test by calling
+        // setEthernetEnabled(true) which always waits on a callback.
+        setEthernetEnabled(true)
     }
 
     // Setting the carrier up / down relies on TUNSETCARRIER which was added in kernel version 5.0.
@@ -635,6 +638,9 @@
             // do nothing -- the TimeoutException indicates that no interface is available for
             // tethering.
             releaseTetheredInterface()
+            // Force releaseTetheredInterface() to be processed before proceeding by calling
+            // setEthernetEnabled(true) which always waits on a callback.
+            setEthernetEnabled(true)
         }
     }
 
diff --git a/tests/cts/netpermission/internetpermission/AndroidTest.xml b/tests/cts/netpermission/internetpermission/AndroidTest.xml
index e326844..ad9a731 100644
--- a/tests/cts/netpermission/internetpermission/AndroidTest.xml
+++ b/tests/cts/netpermission/internetpermission/AndroidTest.xml
@@ -16,6 +16,7 @@
 <configuration description="Config for CTS internet permission test cases">
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="networking" />
+    <option name="config-descriptor:metadata" key="token" value="SIM_CARD" />
     <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
     <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
diff --git a/tests/cts/netpermission/updatestatspermission/AndroidTest.xml b/tests/cts/netpermission/updatestatspermission/AndroidTest.xml
index a1019fa..fb6c814 100644
--- a/tests/cts/netpermission/updatestatspermission/AndroidTest.xml
+++ b/tests/cts/netpermission/updatestatspermission/AndroidTest.xml
@@ -16,6 +16,7 @@
 <configuration description="Config for CTS update stats permission test cases">
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="networking" />
+    <option name="config-descriptor:metadata" key="token" value="SIM_CARD" />
     <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
     <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
diff --git a/tests/mts/bpf_existence_test.cpp b/tests/mts/bpf_existence_test.cpp
index 442d69f..15263cc 100644
--- a/tests/mts/bpf_existence_test.cpp
+++ b/tests/mts/bpf_existence_test.cpp
@@ -95,6 +95,7 @@
     NETD "map_netd_cookie_tag_map",
     NETD "map_netd_iface_index_name_map",
     NETD "map_netd_iface_stats_map",
+    NETD "map_netd_ingress_discard_map",
     NETD "map_netd_stats_map_A",
     NETD "map_netd_stats_map_B",
     NETD "map_netd_uid_counterset_map",
diff --git a/tests/unit/java/com/android/server/BpfNetMapsTest.java b/tests/unit/java/com/android/server/BpfNetMapsTest.java
index 19fa41d..5f280c6 100644
--- a/tests/unit/java/com/android/server/BpfNetMapsTest.java
+++ b/tests/unit/java/com/android/server/BpfNetMapsTest.java
@@ -16,6 +16,21 @@
 
 package com.android.server;
 
+import static android.net.BpfNetMapsConstants.CURRENT_STATS_MAP_CONFIGURATION_KEY;
+import static android.net.BpfNetMapsConstants.DOZABLE_MATCH;
+import static android.net.BpfNetMapsConstants.HAPPY_BOX_MATCH;
+import static android.net.BpfNetMapsConstants.IIF_MATCH;
+import static android.net.BpfNetMapsConstants.LOCKDOWN_VPN_MATCH;
+import static android.net.BpfNetMapsConstants.LOW_POWER_STANDBY_MATCH;
+import static android.net.BpfNetMapsConstants.NO_MATCH;
+import static android.net.BpfNetMapsConstants.OEM_DENY_1_MATCH;
+import static android.net.BpfNetMapsConstants.OEM_DENY_2_MATCH;
+import static android.net.BpfNetMapsConstants.OEM_DENY_3_MATCH;
+import static android.net.BpfNetMapsConstants.PENALTY_BOX_MATCH;
+import static android.net.BpfNetMapsConstants.POWERSAVE_MATCH;
+import static android.net.BpfNetMapsConstants.RESTRICTED_MATCH;
+import static android.net.BpfNetMapsConstants.STANDBY_MATCH;
+import static android.net.BpfNetMapsConstants.UID_RULES_CONFIGURATION_KEY;
 import static android.net.ConnectivityManager.FIREWALL_CHAIN_DOZABLE;
 import static android.net.ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY;
 import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_1;
@@ -33,19 +48,6 @@
 import static android.system.OsConstants.EINVAL;
 import static android.system.OsConstants.EPERM;
 
-import static com.android.server.BpfNetMaps.DOZABLE_MATCH;
-import static com.android.server.BpfNetMaps.HAPPY_BOX_MATCH;
-import static com.android.server.BpfNetMaps.IIF_MATCH;
-import static com.android.server.BpfNetMaps.LOCKDOWN_VPN_MATCH;
-import static com.android.server.BpfNetMaps.LOW_POWER_STANDBY_MATCH;
-import static com.android.server.BpfNetMaps.NO_MATCH;
-import static com.android.server.BpfNetMaps.OEM_DENY_1_MATCH;
-import static com.android.server.BpfNetMaps.OEM_DENY_2_MATCH;
-import static com.android.server.BpfNetMaps.OEM_DENY_3_MATCH;
-import static com.android.server.BpfNetMaps.PENALTY_BOX_MATCH;
-import static com.android.server.BpfNetMaps.POWERSAVE_MATCH;
-import static com.android.server.BpfNetMaps.RESTRICTED_MATCH;
-import static com.android.server.BpfNetMaps.STANDBY_MATCH;
 import static com.android.server.ConnectivityStatsLog.NETWORK_BPF_MAP_INFO;
 
 import static org.junit.Assert.assertEquals;
@@ -62,6 +64,7 @@
 
 import android.app.StatsManager;
 import android.content.Context;
+import android.net.BpfNetMapsUtils;
 import android.net.INetd;
 import android.os.Build;
 import android.os.ServiceSpecificException;
@@ -112,8 +115,6 @@
     private static final int NO_IIF = 0;
     private static final int NULL_IIF = 0;
     private static final String CHAINNAME = "fw_dozable";
-    private static final S32 UID_RULES_CONFIGURATION_KEY = new S32(0);
-    private static final S32 CURRENT_STATS_MAP_CONFIGURATION_KEY = new S32(1);
     private static final List<Integer> FIREWALL_CHAINS = List.of(
             FIREWALL_CHAIN_DOZABLE,
             FIREWALL_CHAIN_STANDBY,
@@ -170,7 +171,7 @@
     private long getMatch(final List<Integer> chains) {
         long match = 0;
         for (final int chain: chains) {
-            match |= mBpfNetMaps.getMatchByFirewallChain(chain);
+            match |= BpfNetMapsUtils.getMatchByFirewallChain(chain);
         }
         return match;
     }
@@ -239,7 +240,7 @@
     private void doTestSetChildChain(final List<Integer> testChains) throws Exception {
         long expectedMatch = 0;
         for (final int chain: testChains) {
-            expectedMatch |= mBpfNetMaps.getMatchByFirewallChain(chain);
+            expectedMatch |= BpfNetMapsUtils.getMatchByFirewallChain(chain);
         }
 
         assertEquals(0, mConfigurationMap.getValue(UID_RULES_CONFIGURATION_KEY).val);