Merge "Verify reevaluation triggered when VPN validation fails" 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 c3a9fb3..2ba59da 100644
--- a/remoteauth/service/Android.bp
+++ b/remoteauth/service/Android.bp
@@ -25,9 +25,9 @@
java_library {
name: "service-remoteauth-pre-jarjar",
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/service/jni/Android.bp b/remoteauth/service/jni/Android.bp
new file mode 100644
index 0000000..e6e8a43
--- /dev/null
+++ b/remoteauth/service/jni/Android.bp
@@ -0,0 +1,76 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+rust_defaults {
+ name: "libremoteauth_jni_rust_defaults",
+ crate_name: "remoteauth_jni_rust",
+ lints: "android",
+ clippy_lints: "android",
+ min_sdk_version: "35",
+ srcs: ["src/lib.rs"],
+ rustlibs: [
+ "libbinder_rs",
+ "libjni",
+ "liblazy_static",
+ "liblog_rust",
+ "liblogger",
+ "libnum_traits",
+ "libthiserror",
+ "libtokio",
+ "libanyhow",
+ ],
+ proc_macros: [
+ "libasync_trait",
+ ],
+ prefer_rlib: true,
+ apex_available: [
+ "com.android.remoteauth",
+ ],
+ host_supported: true,
+}
+
+rust_test {
+ name: "libremoteauth_jni_rust_tests",
+ defaults: ["libremoteauth_jni_rust_defaults"],
+ rustlibs: [
+ ],
+ target: {
+ android: {
+ test_suites: [
+ "general-tests",
+ ],
+ test_config_template: "remoteauth_rust_test_config_template.xml",
+ },
+ host: {
+ test_suites: [
+ "general-tests",
+ ],
+ data_libs: [
+ "libandroid_runtime_lazy",
+ "libbase",
+ "libbinder",
+ "libbinder_ndk",
+ "libcutils",
+ "liblog",
+ "libutils",
+ ],
+ },
+ },
+ test_options: {
+ unit_test: true,
+ },
+ // Support multilib variants (using different suffix per sub-architecture), which is needed on
+ // build targets with secondary architectures, as the MTS test suite packaging logic flattens
+ // all test artifacts into a single `testcases` directory.
+ compile_multilib: "both",
+ multilib: {
+ lib32: {
+ suffix: "32",
+ },
+ lib64: {
+ suffix: "64",
+ },
+ },
+ auto_gen_config: true,
+}
diff --git a/remoteauth/service/jni/remoteauth_rust_test_config_template.xml b/remoteauth/service/jni/remoteauth_rust_test_config_template.xml
new file mode 100644
index 0000000..673b451
--- /dev/null
+++ b/remoteauth/service/jni/remoteauth_rust_test_config_template.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<configuration description="Configuration for {MODULE} Rust tests">
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+ <option name="cleanup" value="true" />
+ <option name="push" value="{MODULE}->/data/local/tmp/{MODULE}" />
+ <option name="append-bitness" value="true" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.rust.RustBinaryTest" >
+ <option name="test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="{MODULE}" />
+ </test>
+ <object type="module_controller"
+ class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+ <option name="mainline-module-package-name" value="com.google.android.remoteauth" />
+ </object>
+</configuration>
\ No newline at end of file
diff --git a/remoteauth/service/jni/src/jnames.rs b/remoteauth/service/jni/src/jnames.rs
new file mode 100644
index 0000000..d7cc908
--- /dev/null
+++ b/remoteauth/service/jni/src/jnames.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 Google LLC
+//
+// 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.
+
+//! Name of java classes and methods for RemoteAuth platform:
+pub(crate) const SEND_REQUEST_MNAME: &str = "sendRequest";
+pub(crate) const SEND_REQUEST_MSIG: &str = "(I[BII)V";
diff --git a/remoteauth/service/jni/src/lib.rs b/remoteauth/service/jni/src/lib.rs
new file mode 100644
index 0000000..0c18679
--- /dev/null
+++ b/remoteauth/service/jni/src/lib.rs
@@ -0,0 +1,24 @@
+// Copyright 2023 Google LLC
+//
+// 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.
+
+//! New rust RemoteAuth JNI library.
+//!
+//! This library takes the JNI calls from RemoteAuthService to the remoteauth protocol library
+//! and from protocol library to platform (Java interface)
+
+mod jnames;
+mod unique_jvm;
+
+//pub mod remoteauth_jni_android_protocol;
+pub mod remoteauth_jni_android_platform;
diff --git a/remoteauth/service/jni/src/remoteauth_jni_android_platform.rs b/remoteauth/service/jni/src/remoteauth_jni_android_platform.rs
new file mode 100644
index 0000000..4597561
--- /dev/null
+++ b/remoteauth/service/jni/src/remoteauth_jni_android_platform.rs
@@ -0,0 +1,306 @@
+// Copyright 2023 Google LLC
+//
+// 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.
+
+use crate::jnames::{SEND_REQUEST_MNAME, SEND_REQUEST_MSIG};
+use crate::unique_jvm;
+use anyhow::anyhow;
+use async_trait::async_trait;
+use jni::errors::Error as JNIError;
+use jni::objects::{GlobalRef, JMethodID, JObject, JValue};
+use jni::signature::TypeSignature;
+use jni::sys::{jbyteArray, jint, jlong, jvalue};
+use jni::{JNIEnv, JavaVM};
+use lazy_static::lazy_static;
+use log::{debug, error, info};
+use std::collections::HashMap;
+use std::sync::{
+ atomic::{AtomicI64, Ordering},
+ Arc,
+};
+use tokio::{
+ runtime::Runtime,
+ sync::{mpsc, Mutex},
+};
+
+/// Macro capturing the name of the function calling this macro.
+///
+/// function_name()! -> &'static str
+/// Returns the function name as 'static reference.
+macro_rules! function_name {
+ () => {{
+ // Declares function f inside current function.
+ fn f() {}
+ fn type_name_of<T>(_: T) -> &'static str {
+ std::any::type_name::<T>()
+ }
+ // type name of f is struct_or_crate_name::calling_function_name::f
+ let name = type_name_of(f);
+ // Find and cut the rest of the path:
+ // Third to last character, up to the first semicolon: is calling_function_name
+ match &name[..name.len() - 3].rfind(':') {
+ Some(pos) => &name[pos + 1..name.len() - 3],
+ None => &name[..name.len() - 3],
+ }
+ }};
+}
+
+lazy_static! {
+ static ref HANDLE_MAPPING: Mutex<HashMap<i64, Arc<Mutex<JavaPlatform>>>> =
+ Mutex::new(HashMap::new());
+ static ref HANDLE_RN: AtomicI64 = AtomicI64::new(0);
+}
+
+fn generate_platform_handle() -> i64 {
+ HANDLE_RN.fetch_add(1, Ordering::SeqCst)
+}
+
+async fn insert_platform_handle(handle: i64, item: Arc<Mutex<JavaPlatform>>) {
+ if 0 == handle {
+ // Init once
+ logger::init(
+ logger::Config::default()
+ .with_tag_on_device("remoteauth")
+ .with_min_level(log::Level::Trace)
+ .with_filter("trace,jni=info"),
+ );
+ }
+ HANDLE_MAPPING.lock().await.insert(handle, Arc::clone(&item));
+}
+
+#[async_trait]
+pub trait Platform {
+ /// Send a binary message to the remote with the given connection id and return the response.
+ async fn send_request(&mut self, connection_id: i32, request: &[u8])
+ -> anyhow::Result<Vec<u8>>;
+}
+//////////////////////////////////
+
+pub struct JavaPlatform {
+ platform_handle: i64,
+ vm: &'static Arc<JavaVM>,
+ platform_native_obj: GlobalRef,
+ send_request_method_id: JMethodID,
+ map_futures: Mutex<HashMap<i64, mpsc::Sender<Vec<u8>>>>,
+ atomic_handle: AtomicI64,
+}
+
+impl JavaPlatform {
+ // Method to create JavaPlatform
+ pub async fn create<'a>(
+ env: JNIEnv<'a>,
+ java_platform_native: JObject<'a>,
+ ) -> Result<Arc<Mutex<impl Platform>>, JNIError> {
+ let jvm = env.get_java_vm()?;
+ let _ = unique_jvm::set_once(jvm);
+ let platform_handle = generate_platform_handle();
+ let platform = Arc::new(Mutex::new(JavaPlatform::new(
+ platform_handle,
+ unique_jvm::get_static_ref().ok_or(JNIError::InvalidCtorReturn)?,
+ java_platform_native,
+ )?));
+ insert_platform_handle(platform_handle, Arc::clone(&platform)).await;
+ Ok(Arc::clone(&platform))
+ }
+
+ fn new(
+ platform_handle: i64,
+ vm: &'static Arc<JavaVM>,
+ java_platform_native: JObject,
+ ) -> Result<JavaPlatform, JNIError> {
+ vm.attach_current_thread().and_then(|env| {
+ let platform_class = env.get_object_class(java_platform_native)?;
+ let platform_native_obj = env.new_global_ref(java_platform_native)?;
+ let send_request_method: JMethodID =
+ env.get_method_id(platform_class, SEND_REQUEST_MNAME, SEND_REQUEST_MSIG)?;
+
+ Ok(Self {
+ platform_handle,
+ vm,
+ platform_native_obj,
+ send_request_method_id: send_request_method,
+ map_futures: Mutex::new(HashMap::new()),
+ atomic_handle: AtomicI64::new(0),
+ })
+ })
+ }
+}
+
+#[async_trait]
+impl Platform for JavaPlatform {
+ async fn send_request(
+ &mut self,
+ connection_id: i32,
+ request: &[u8],
+ ) -> anyhow::Result<Vec<u8>> {
+ let type_signature = TypeSignature::from_str(SEND_REQUEST_MSIG)
+ .map_err(|e| anyhow!("JNI: Invalid type signature: {:?}", e))?;
+
+ let (tx, mut rx) = mpsc::channel(1);
+ let response_handle = self.atomic_handle.fetch_add(1, Ordering::SeqCst);
+ self.map_futures.lock().await.insert(response_handle, tx);
+ self.vm
+ .attach_current_thread()
+ .and_then(|env| {
+ let request_jbytearray = env.byte_array_from_slice(request)?;
+ // Safety: request_jbytearray is safely instantiated above.
+ let request_jobject = unsafe { JObject::from_raw(request_jbytearray) };
+
+ let _ = env.call_method_unchecked(
+ self.platform_native_obj.as_obj(),
+ self.send_request_method_id,
+ type_signature.ret,
+ &[
+ jvalue::from(JValue::Int(connection_id)),
+ jvalue::from(JValue::Object(request_jobject)),
+ jvalue::from(JValue::Long(response_handle)),
+ jvalue::from(JValue::Long(self.platform_handle)),
+ ],
+ );
+ Ok(info!(
+ "{} successfully sent-message, waiting for response {}:{}",
+ function_name!(),
+ self.platform_handle,
+ response_handle
+ ))
+ })
+ .map_err(|e| anyhow!("JNI: Failed to attach current thread: {:?}", e))?;
+
+ rx.recv().await.ok_or(anyhow!("{} failed in awaiting for a result", function_name!()))
+ }
+}
+
+impl JavaPlatform {
+ async fn on_send_request_success(&mut self, response: &[u8], response_handle: i64) {
+ info!(
+ "{} completed successfully {}:{}",
+ function_name!(),
+ self.platform_handle,
+ response_handle
+ );
+ if let Some(tx) = self.map_futures.lock().await.remove(&response_handle) {
+ let _ = tx.send(response.to_vec()).await;
+ } else {
+ error!(
+ "Failed to find TX for {} and {}:{}",
+ function_name!(),
+ self.platform_handle,
+ response_handle
+ );
+ }
+ }
+
+ async fn on_send_request_error(&self, error_code: i32, response_handle: i64) {
+ error!(
+ "{} completed with error {} {}:{}",
+ function_name!(),
+ error_code,
+ self.platform_handle,
+ response_handle
+ );
+ if let Some(tx) = self.map_futures.lock().await.remove(&response_handle) {
+ // `rx.recv()` ends with `Err`
+ drop(tx);
+ } else {
+ error!(
+ "Failed to find TX for {} and {}:{}",
+ function_name!(),
+ self.platform_handle,
+ response_handle
+ );
+ }
+ }
+}
+
+#[no_mangle]
+pub extern "system" fn Java_com_android_server_remoteauth_jni_NativeRemoteAuthJavaPlatform_native_on_send_request_success(
+ env: JNIEnv,
+ _: JObject,
+ app_response: jbyteArray,
+ platform_handle: jlong,
+ response_handle: jlong,
+) {
+ debug!("{}: enter", function_name!());
+ Runtime::new().unwrap().block_on(native_on_send_request_success(
+ env,
+ app_response,
+ platform_handle,
+ response_handle,
+ ));
+}
+
+async fn native_on_send_request_success(
+ env: JNIEnv<'_>,
+ app_response: jbyteArray,
+ platform_handle: jlong,
+ response_handle: jlong,
+) {
+ if let Some(platform) = HANDLE_MAPPING.lock().await.get(&platform_handle) {
+ let response =
+ env.convert_byte_array(app_response).map_err(|_| JNIError::InvalidCtorReturn).unwrap();
+ let mut platform = (*platform).lock().await;
+ platform.on_send_request_success(&response, response_handle).await;
+ } else {
+ let _ = env.throw_new(
+ "com/android/server/remoteauth/jni/BadHandleException",
+ format!("Failed to find Platform with ID {} in {}", platform_handle, function_name!()),
+ );
+ }
+}
+
+#[no_mangle]
+pub extern "system" fn Java_com_android_server_remoteauth_jni_NativeRemoteAuthJavaPlatform_native_on_send_request_error(
+ env: JNIEnv,
+ _: JObject,
+ error_code: jint,
+ platform_handle: jlong,
+ response_handle: jlong,
+) {
+ debug!("{}: enter", function_name!());
+ Runtime::new().unwrap().block_on(native_on_send_request_error(
+ env,
+ error_code,
+ platform_handle,
+ response_handle,
+ ));
+}
+
+async fn native_on_send_request_error(
+ env: JNIEnv<'_>,
+ error_code: jint,
+ platform_handle: jlong,
+ response_handle: jlong,
+) {
+ if let Some(platform) = HANDLE_MAPPING.lock().await.get(&platform_handle) {
+ let platform = (*platform).lock().await;
+ platform.on_send_request_error(error_code, response_handle).await;
+ } else {
+ let _ = env.throw_new(
+ "com/android/server/remoteauth/jni/BadHandleException",
+ format!("Failed to find Platform with ID {} in {}", platform_handle, function_name!()),
+ );
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ //use super::*;
+
+ //use tokio::runtime::Builder;
+
+ /// Checks validity of the function_name! macro.
+ #[test]
+ fn test_function_name() {
+ assert_eq!(function_name!(), "test_function_name");
+ }
+}
diff --git a/remoteauth/service/jni/src/unique_jvm.rs b/remoteauth/service/jni/src/unique_jvm.rs
new file mode 100644
index 0000000..46cc361
--- /dev/null
+++ b/remoteauth/service/jni/src/unique_jvm.rs
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+//! takes a JavaVM to a static reference.
+//!
+//! JavaVM is shared as multiple JavaVM within a single process is not allowed
+//! per [JNI spec](https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/invocation.html)
+//! The unique JavaVM need to be shared over (potentially) different threads.
+
+use std::sync::{Arc, Once};
+
+use anyhow::Result;
+use jni::JavaVM;
+
+static mut JVM: Option<Arc<JavaVM>> = None;
+static INIT: Once = Once::new();
+/// set_once sets the unique JavaVM that can be then accessed using get_static_ref()
+///
+/// The function shall only be called once.
+pub(crate) fn set_once(jvm: JavaVM) -> Result<()> {
+ // Safety: follows [this pattern](https://doc.rust-lang.org/std/sync/struct.Once.html).
+ // Modification to static mut is nested inside call_once.
+ unsafe {
+ INIT.call_once(|| {
+ JVM = Some(Arc::new(jvm));
+ });
+ }
+ Ok(())
+}
+/// Gets a 'static reference to the unique JavaVM. Returns None if set_once() was never called.
+pub(crate) fn get_static_ref() -> Option<&'static Arc<JavaVM>> {
+ // Safety: follows [this pattern](https://doc.rust-lang.org/std/sync/struct.Once.html).
+ // Modification to static mut is nested inside call_once.
+ unsafe { JVM.as_ref() }
+}
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/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index 77cea1a..3a76cc2 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -1132,7 +1132,6 @@
*/
@AppModeFull(reason = "Cannot get WifiManager in instant app mode")
@Test
- @SkipMainlinePresubmit(reason = "Out of SLO flakiness")
public void testRegisterNetworkCallback_withPendingIntent() {
assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
@@ -1276,7 +1275,6 @@
@AppModeFull(reason = "Cannot get WifiManager in instant app mode")
@Test
- @SkipMainlinePresubmit(reason = "Out of SLO flakiness")
public void testRegisterNetworkRequest_identicalPendingIntents() throws Exception {
runIdenticalPendingIntentsRequestTest(false /* useListen */);
}
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);
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index 708697c..9b99b81 100755
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -16390,6 +16390,15 @@
// Other callbacks will be unregistered by tearDown()
}
+ private NetworkCallback requestForEnterpriseId(@NetworkCapabilities.EnterpriseId final int id) {
+ final NetworkCapabilities nc = new NetworkCapabilities.Builder()
+ .addCapability(NET_CAPABILITY_ENTERPRISE).addEnterpriseId(id).build();
+ final NetworkRequest req = new NetworkRequest.Builder().setCapabilities(nc).build();
+ final NetworkCallback cb = new TestableNetworkCallback();
+ mCm.requestNetwork(req, cb);
+ return cb;
+ }
+
/**
* Make sure per profile network preferences behave as expected when multiple slices with
* multiple different apps within same user profile is configured.
@@ -16397,8 +16406,6 @@
@Test
public void testSetPreferenceWithMultiplePreferences()
throws Exception {
- final InOrder inOrder = inOrder(mMockNetd);
-
final UserHandle testHandle = setupEnterpriseNetwork();
mServiceContext.setWorkProfile(testHandle, true);
registerDefaultNetworkCallbacks();
@@ -16436,6 +16443,12 @@
final TestNetworkAgentWrapper workAgent4 = makeEnterpriseNetworkAgent(NET_ENTERPRISE_ID_4);
final TestNetworkAgentWrapper workAgent5 = makeEnterpriseNetworkAgent(NET_ENTERPRISE_ID_5);
+ final NetworkCallback keepupCb1 = requestForEnterpriseId(NET_ENTERPRISE_ID_1);
+ final NetworkCallback keepupCb2 = requestForEnterpriseId(NET_ENTERPRISE_ID_2);
+ final NetworkCallback keepupCb3 = requestForEnterpriseId(NET_ENTERPRISE_ID_3);
+ final NetworkCallback keepupCb4 = requestForEnterpriseId(NET_ENTERPRISE_ID_4);
+ final NetworkCallback keepupCb5 = requestForEnterpriseId(NET_ENTERPRISE_ID_5);
+
workAgent1.connect(true);
workAgent2.connect(true);
workAgent3.connect(true);
@@ -16594,6 +16607,12 @@
appCb4.expectAvailableCallbacksValidated(mCellAgent);
mCellAgent.disconnect();
+ mCm.unregisterNetworkCallback(keepupCb1);
+ mCm.unregisterNetworkCallback(keepupCb2);
+ mCm.unregisterNetworkCallback(keepupCb3);
+ mCm.unregisterNetworkCallback(keepupCb4);
+ mCm.unregisterNetworkCallback(keepupCb5);
+
mCm.unregisterNetworkCallback(appCb1);
mCm.unregisterNetworkCallback(appCb2);
mCm.unregisterNetworkCallback(appCb3);