diff --git a/common/TrunkStable.bp b/common/TrunkStable.bp index 772f79e8e0..56938fcf61 100644 --- a/common/TrunkStable.bp +++ b/common/TrunkStable.bp @@ -19,3 +19,8 @@ aconfig_declarations { package: "com.android.net.flags", srcs: ["flags.aconfig"], } + +java_aconfig_library { + name: "connectivity_flags_aconfig_lib", + aconfig_declarations: "com.android.net.flags-aconfig", +} diff --git a/common/flags.aconfig b/common/flags.aconfig index 4926503e08..cadc44f174 100644 --- a/common/flags.aconfig +++ b/common/flags.aconfig @@ -6,3 +6,10 @@ flag { description: "NetworkActivityTracker tracks multiple networks including non default networks" bug: "267870186" } + +flag { + name: "forbidden_capability" + namespace: "android_core_networking" + description: "This flag controls the forbidden capability API" + bug: "302997505" +} diff --git a/framework/src/android/net/NetworkCapabilities.java b/framework/src/android/net/NetworkCapabilities.java index abda1fa71f..74d50f8fd0 100644 --- a/framework/src/android/net/NetworkCapabilities.java +++ b/framework/src/android/net/NetworkCapabilities.java @@ -29,6 +29,9 @@ import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.compat.annotation.UnsupportedAppUsage; import android.net.ConnectivityManager.NetworkCallback; +// Can't be imported because aconfig tooling doesn't exist on udc-mainline-prod yet +// See inner class Flags which mimics this for the time being +// import android.net.flags.Flags; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; @@ -121,6 +124,14 @@ import java.util.StringJoiner; public final class NetworkCapabilities implements Parcelable { private static final String TAG = "NetworkCapabilities"; + // TODO : remove this class when udc-mainline-prod is abandoned and android.net.flags.Flags is + // available here + /** @hide */ + public static class Flags { + static final String FLAG_FORBIDDEN_CAPABILITY = + "com.android.net.flags.forbidden_capability"; + } + /** * Mechanism to support redaction of fields in NetworkCapabilities that are guarded by specific * app permissions. @@ -793,6 +804,10 @@ public final class NetworkCapabilities implements Parcelable { * Adds the given capability to this {@code NetworkCapability} instance. * Note that when searching for a network to satisfy a request, all capabilities * requested must be satisfied. + *
+ * If the capability was previously added to the list of forbidden capabilities (either
+ * by default or added using {@link #addForbiddenCapability(int)}), then it will be removed
+ * from the list of forbidden capabilities as well.
*
* @param capability the capability to be added.
* @return This NetworkCapabilities instance, to facilitate chaining.
@@ -801,8 +816,7 @@ public final class NetworkCapabilities implements Parcelable {
public @NonNull NetworkCapabilities addCapability(@NetCapability int capability) {
// If the given capability was previously added to the list of forbidden capabilities
// then the capability will also be removed from the list of forbidden capabilities.
- // TODO: Consider adding forbidden capabilities to the public API and mention this
- // in the documentation.
+ // TODO: Add forbidden capabilities to the public API
checkValidCapability(capability);
mNetworkCapabilities |= 1L << capability;
// remove from forbidden capability list
@@ -901,6 +915,8 @@ public final class NetworkCapabilities implements Parcelable {
* @return an array of forbidden capability values for this instance.
* @hide
*/
+ @NonNull
+ // TODO : @FlaggedApi(Flags.FLAG_FORBIDDEN_CAPABILITY) and public
public @NetCapability int[] getForbiddenCapabilities() {
return BitUtils.unpackBits(mForbiddenNetworkCapabilities);
}
@@ -1000,7 +1016,7 @@ public final class NetworkCapabilities implements Parcelable {
/**
* Tests for the presence of a capability on this instance.
*
- * @param capability the capabilities to be tested for.
+ * @param capability the capability to be tested for.
* @return {@code true} if set on this instance.
*/
public boolean hasCapability(@NetCapability int capability) {
@@ -1008,8 +1024,15 @@ public final class NetworkCapabilities implements Parcelable {
&& ((mNetworkCapabilities & (1L << capability)) != 0);
}
- /** @hide */
+ /**
+ * Tests for the presence of a forbidden capability on this instance.
+ *
+ * @param capability the capability to be tested for.
+ * @return {@code true} if this capability is set forbidden on this instance.
+ * @hide
+ */
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ // TODO : @FlaggedApi(Flags.FLAG_FORBIDDEN_CAPABILITY) and public
public boolean hasForbiddenCapability(@NetCapability int capability) {
return isValidCapability(capability)
&& ((mForbiddenNetworkCapabilities & (1L << capability)) != 0);
@@ -2888,6 +2911,44 @@ public final class NetworkCapabilities implements Parcelable {
return this;
}
+ /**
+ * Adds the given capability to the list of forbidden capabilities.
+ *
+ * A network with a capability will not match a {@link NetworkCapabilities} or
+ * {@link NetworkRequest} which has said capability set as forbidden. For example, if
+ * a request has NET_CAPABILITY_INTERNET in the list of forbidden capabilities, networks
+ * with NET_CAPABILITY_INTERNET will not match the request.
+ *
+ * If the capability was previously added to the list of required capabilities (for
+ * example, it was there by default or added using {@link #addCapability(int)} method), then
+ * it will be removed from the list of required capabilities as well.
+ *
+ * @param capability the capability
+ * @return this builder
+ * @hide
+ */
+ @NonNull
+ // TODO : @FlaggedApi(Flags.FLAG_FORBIDDEN_CAPABILITY) and public
+ public Builder addForbiddenCapability(@NetCapability final int capability) {
+ mCaps.addForbiddenCapability(capability);
+ return this;
+ }
+
+ /**
+ * Removes the given capability from the list of forbidden capabilities.
+ *
+ * @see #addForbiddenCapability(int)
+ * @param capability the capability
+ * @return this builder
+ * @hide
+ */
+ @NonNull
+ // TODO : @FlaggedApi(Flags.FLAG_FORBIDDEN_CAPABILITY) and public
+ public Builder removeForbiddenCapability(@NetCapability final int capability) {
+ mCaps.removeForbiddenCapability(capability);
+ return this;
+ }
+
/**
* Adds the given enterprise capability identifier.
* Note that when searching for a network to satisfy a request, all capabilities identifier
@@ -3235,4 +3296,4 @@ public final class NetworkCapabilities implements Parcelable {
return new NetworkCapabilities(mCaps);
}
}
-}
\ No newline at end of file
+}
diff --git a/framework/src/android/net/NetworkRequest.java b/framework/src/android/net/NetworkRequest.java
index 6c351d0548..5cc9f1b605 100644
--- a/framework/src/android/net/NetworkRequest.java
+++ b/framework/src/android/net/NetworkRequest.java
@@ -39,6 +39,8 @@ import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
+// TODO : replace with android.net.flags.Flags when aconfig is supported on udc-mainline-prod
+// import android.net.NetworkCapabilities.Flags;
import android.net.NetworkCapabilities.NetCapability;
import android.net.NetworkCapabilities.Transport;
import android.os.Build;
@@ -408,6 +410,7 @@ public class NetworkRequest implements Parcelable {
@NonNull
@SuppressLint("MissingGetterMatchingBuilder")
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ // TODO : @FlaggedApi(Flags.FLAG_FORBIDDEN_CAPABILITY) and public
public Builder addForbiddenCapability(@NetworkCapabilities.NetCapability int capability) {
mNetworkCapabilities.addForbiddenCapability(capability);
return this;
@@ -424,6 +427,7 @@ public class NetworkRequest implements Parcelable {
@NonNull
@SuppressLint("BuilderSetStyle")
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ // TODO : @FlaggedApi(Flags.FLAG_FORBIDDEN_CAPABILITY) and public
public Builder removeForbiddenCapability(
@NetworkCapabilities.NetCapability int capability) {
mNetworkCapabilities.removeForbiddenCapability(capability);
@@ -433,6 +437,7 @@ public class NetworkRequest implements Parcelable {
/**
* Completely clears all the {@code NetworkCapabilities} from this builder instance,
* removing even the capabilities that are set by default when the object is constructed.
+ * Also removes any set forbidden capabilities.
*
* @return The builder to facilitate chaining.
*/
@@ -721,6 +726,7 @@ public class NetworkRequest implements Parcelable {
* @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ // TODO : @FlaggedApi(Flags.FLAG_FORBIDDEN_CAPABILITY) and public instead of @SystemApi
public boolean hasForbiddenCapability(@NetCapability int capability) {
return networkCapabilities.hasForbiddenCapability(capability);
}
@@ -843,6 +849,7 @@ public class NetworkRequest implements Parcelable {
*/
@NonNull
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ // TODO : @FlaggedApi(Flags.FLAG_FORBIDDEN_CAPABILITY) and public instead of @SystemApi
public @NetCapability int[] getForbiddenCapabilities() {
// No need to make a defensive copy here as NC#getForbiddenCapabilities() already returns
// a new array.
diff --git a/framework/src/android/net/NetworkScore.java b/framework/src/android/net/NetworkScore.java
index 815e2b08e8..2522958310 100644
--- a/framework/src/android/net/NetworkScore.java
+++ b/framework/src/android/net/NetworkScore.java
@@ -44,7 +44,8 @@ public final class NetworkScore implements Parcelable {
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {
KEEP_CONNECTED_NONE,
- KEEP_CONNECTED_FOR_HANDOVER
+ KEEP_CONNECTED_FOR_HANDOVER,
+ KEEP_CONNECTED_FOR_TEST
})
public @interface KeepConnectedReason { }
@@ -57,6 +58,12 @@ public final class NetworkScore implements Parcelable {
* is being considered for handover.
*/
public static final int KEEP_CONNECTED_FOR_HANDOVER = 1;
+ /**
+ * Keep this network connected even if there is no outstanding request for it, because it
+ * is used in a test and it's not necessarily easy to file the right request for it.
+ * @hide
+ */
+ public static final int KEEP_CONNECTED_FOR_TEST = 2;
// Agent-managed policies
// This network should lose to a wifi that has ever been validated
diff --git a/tests/cts/net/src/android/net/cts/NetworkRequestTest.java b/tests/cts/net/src/android/net/cts/NetworkRequestTest.java
index 637ed26747..718ca6dea4 100644
--- a/tests/cts/net/src/android/net/cts/NetworkRequestTest.java
+++ b/tests/cts/net/src/android/net/cts/NetworkRequestTest.java
@@ -104,6 +104,23 @@ public class NetworkRequestTest {
verifyNoCapabilities(nr);
}
+ @Test @IgnoreUpTo(Build.VERSION_CODES.R)
+ public void testForbiddenCapabilities() {
+ final NetworkRequest.Builder builder = new NetworkRequest.Builder();
+ builder.addForbiddenCapability(NET_CAPABILITY_MMS);
+ assertTrue(builder.build().hasForbiddenCapability(NET_CAPABILITY_MMS));
+ builder.removeForbiddenCapability(NET_CAPABILITY_MMS);
+ assertFalse(builder.build().hasCapability(NET_CAPABILITY_MMS));
+ builder.addCapability(NET_CAPABILITY_MMS);
+ assertFalse(builder.build().hasForbiddenCapability(NET_CAPABILITY_MMS));
+ assertTrue(builder.build().hasCapability(NET_CAPABILITY_MMS));
+ builder.addForbiddenCapability(NET_CAPABILITY_MMS);
+ assertTrue(builder.build().hasForbiddenCapability(NET_CAPABILITY_MMS));
+ assertFalse(builder.build().hasCapability(NET_CAPABILITY_MMS));
+ builder.clearCapabilities();
+ verifyNoCapabilities(builder.build());
+ }
+
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
public void testTemporarilyNotMeteredCapability() {
assertTrue(new NetworkRequest.Builder()
diff --git a/tests/unit/java/com/android/server/connectivityservice/CSKeepConnectedTest.kt b/tests/unit/java/com/android/server/connectivityservice/CSKeepConnectedTest.kt
new file mode 100644
index 0000000000..a9b9896a09
--- /dev/null
+++ b/tests/unit/java/com/android/server/connectivityservice/CSKeepConnectedTest.kt
@@ -0,0 +1,58 @@
+/*
+ * 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
+
+import android.net.NetworkRequest
+import android.net.NetworkScore
+import android.net.NetworkScore.KEEP_CONNECTED_FOR_TEST
+import android.os.Build
+import androidx.test.filters.SmallTest
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
+import com.android.testutils.DevSdkIgnoreRunner
+import com.android.testutils.RecorderCallback.CallbackEntry.Lost
+import com.android.testutils.TestableNetworkCallback
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(DevSdkIgnoreRunner::class)
+@SmallTest
+@IgnoreUpTo(Build.VERSION_CODES.TIRAMISU)
+class CSKeepConnectedTest : CSTest() {
+ @Test
+ fun testKeepConnectedForTest() {
+ val keepAgent = Agent(score = FromS(NetworkScore.Builder()
+ .setKeepConnectedReason(KEEP_CONNECTED_FOR_TEST)
+ .build()))
+ val dontKeepAgent = Agent()
+ doTestKeepConnected(keepAgent, dontKeepAgent)
+ }
+
+ fun doTestKeepConnected(keepAgent: CSAgentWrapper, dontKeepAgent: CSAgentWrapper) {
+ val cb = TestableNetworkCallback()
+ cm.registerNetworkCallback(NetworkRequest.Builder().clearCapabilities().build(), cb)
+
+ keepAgent.connect()
+ dontKeepAgent.connect()
+
+ cb.expectAvailableCallbacks(keepAgent.network, validated = false)
+ cb.expectAvailableCallbacks(dontKeepAgent.network, validated = false)
+
+ // After the nascent timer, the agent without keep connected gets lost.
+ cb.expect