[automerger skipped] Merge Android U (ab/10368041) am: 4a6c653160 -s ours
am skip reason: Merged-In Iff29b090c0b41d0103997a80788f09c2602df074 with SHA-1 efd7a3e313 is already in history
Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/modules/Connectivity/+/24180961
Change-Id: I4cd9d3dda0ea7e94922fed819d9061e14ec2c98e
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/.gitignore b/.gitignore
index ccff052..c9b6393 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,3 +6,7 @@
**/.idea
**/*.iml
**/*.ipr
+
+# VS Code project
+**/.vscode
+**/*.code-workspace
diff --git a/nearby/framework/java/android/nearby/PairStatusMetadata.java b/nearby/framework/java/android/nearby/PairStatusMetadata.java
index 438cd6b..a4cd134 100644
--- a/nearby/framework/java/android/nearby/PairStatusMetadata.java
+++ b/nearby/framework/java/android/nearby/PairStatusMetadata.java
@@ -106,11 +106,6 @@
}
@Override
- public int getStability() {
- return 0;
- }
-
- @Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mStatus);
}
diff --git a/remoteauth/service/Android.bp b/remoteauth/service/Android.bp
index c3a9fb3..3486d8c 100644
--- a/remoteauth/service/Android.bp
+++ b/remoteauth/service/Android.bp
@@ -27,7 +27,7 @@
srcs: [":remoteauth-service-srcs"],
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/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/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);
diff --git a/tests/unit/java/com/android/server/connectivity/VpnTest.java b/tests/unit/java/com/android/server/connectivity/VpnTest.java
index 385f831..b943bfc 100644
--- a/tests/unit/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/unit/java/com/android/server/connectivity/VpnTest.java
@@ -2500,6 +2500,40 @@
}
@Test
+ public void testStartPlatformVpn_underlyingNetworkNotChange() throws Exception {
+ final PlatformVpnSnapshot vpnSnapShot = verifySetupPlatformVpn(
+ createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */));
+ // Trigger update on the same network should not cause underlying network change in NC of
+ // the VPN network
+ vpnSnapShot.nwCb.onAvailable(TEST_NETWORK);
+ vpnSnapShot.nwCb.onCapabilitiesChanged(TEST_NETWORK,
+ new NetworkCapabilities.Builder()
+ .setSubscriptionIds(Set.of(TEST_SUB_ID))
+ .build());
+ // Verify setNetwork() called but no underlying network update
+ verify(mIkeSessionWrapper, timeout(TEST_TIMEOUT_MS)).setNetwork(eq(TEST_NETWORK),
+ eq(ESP_IP_VERSION_AUTO) /* ipVersion */,
+ eq(ESP_ENCAP_TYPE_AUTO) /* encapType */,
+ eq(DEFAULT_UDP_PORT_4500_NAT_TIMEOUT_SEC_INT) /* keepaliveDelay */);
+ verify(mMockNetworkAgent, never())
+ .doSetUnderlyingNetworks(any());
+
+ vpnSnapShot.nwCb.onAvailable(TEST_NETWORK_2);
+ vpnSnapShot.nwCb.onCapabilitiesChanged(TEST_NETWORK_2,
+ new NetworkCapabilities.Builder().build());
+
+ // A new network should trigger both setNetwork() and a underlying network update.
+ verify(mIkeSessionWrapper, timeout(TEST_TIMEOUT_MS)).setNetwork(eq(TEST_NETWORK_2),
+ eq(ESP_IP_VERSION_AUTO) /* ipVersion */,
+ eq(ESP_ENCAP_TYPE_AUTO) /* encapType */,
+ eq(DEFAULT_UDP_PORT_4500_NAT_TIMEOUT_SEC_INT) /* keepaliveDelay */);
+ verify(mMockNetworkAgent).doSetUnderlyingNetworks(
+ Collections.singletonList(TEST_NETWORK_2));
+
+ vpnSnapShot.vpn.mVpnRunner.exitVpnRunner();
+ }
+
+ @Test
public void testStartPlatformVpnMobility_mobikeEnabled() throws Exception {
final PlatformVpnSnapshot vpnSnapShot = verifySetupPlatformVpn(
createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */));
@@ -2523,6 +2557,12 @@
eq(ESP_IP_VERSION_AUTO) /* ipVersion */,
eq(ESP_ENCAP_TYPE_AUTO) /* encapType */,
eq(DEFAULT_UDP_PORT_4500_NAT_TIMEOUT_SEC_INT) /* keepaliveDelay */);
+ // Verify mNetworkCapabilities is updated
+ assertEquals(
+ Collections.singletonList(TEST_NETWORK_2),
+ vpnSnapShot.vpn.mNetworkCapabilities.getUnderlyingNetworks());
+ verify(mMockNetworkAgent)
+ .doSetUnderlyingNetworks(Collections.singletonList(TEST_NETWORK_2));
// Mock the MOBIKE procedure
vpnSnapShot.ikeCb.onIkeSessionConnectionInfoChanged(createIkeConnectInfo_2());
@@ -2535,15 +2575,11 @@
// Expect 2 times: one for initial setup and one for MOBIKE
verifyApplyTunnelModeTransforms(2);
- // Verify mNetworkCapabilities and mNetworkAgent are updated
- assertEquals(
- Collections.singletonList(TEST_NETWORK_2),
- vpnSnapShot.vpn.mNetworkCapabilities.getUnderlyingNetworks());
- verify(mMockNetworkAgent)
- .doSetUnderlyingNetworks(Collections.singletonList(TEST_NETWORK_2));
+ // Verify mNetworkAgent is updated
verify(mMockNetworkAgent).doSendLinkProperties(argThat(lp -> lp.getMtu() == newMtu));
verify(mMockNetworkAgent, never()).unregister();
-
+ // No further doSetUnderlyingNetworks interaction. The interaction count should stay one.
+ verify(mMockNetworkAgent, times(1)).doSetUnderlyingNetworks(any());
vpnSnapShot.vpn.mVpnRunner.exitVpnRunner();
}
@@ -2559,6 +2595,15 @@
// Mock new network available & MOBIKE procedures
vpnSnapShot.nwCb.onAvailable(TEST_NETWORK_2);
+ vpnSnapShot.nwCb.onCapabilitiesChanged(TEST_NETWORK_2,
+ new NetworkCapabilities.Builder().build());
+ // Verify mNetworkCapabilities is updated
+ verify(mMockNetworkAgent, timeout(TEST_TIMEOUT_MS))
+ .doSetUnderlyingNetworks(Collections.singletonList(TEST_NETWORK_2));
+ assertEquals(
+ Collections.singletonList(TEST_NETWORK_2),
+ vpnSnapShot.vpn.mNetworkCapabilities.getUnderlyingNetworks());
+
vpnSnapShot.ikeCb.onIkeSessionConnectionInfoChanged(createIkeConnectInfo_2());
vpnSnapShot.childCb.onIpSecTransformsMigrated(
createIpSecTransform(), createIpSecTransform());