Downgrade list of subIds in NetworkCapabilities to @SystemApi
This change downgrades API visibility for the list-of-subIds in the
NetworkCapabilities to SystemApi
Bug: 175662146
Test: atest NetworkCapabilitiesTest#testSubIds
Test: atest FrameworksNetTests
Change-Id: I372fa9eaa7585aefd1710948ca007456feedd578
diff --git a/framework/api/current.txt b/framework/api/current.txt
index 0a9560a..ab290f9 100644
--- a/framework/api/current.txt
+++ b/framework/api/current.txt
@@ -298,7 +298,6 @@
method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier();
method public int getOwnerUid();
method public int getSignalStrength();
- method @NonNull public java.util.Set<java.lang.Integer> getSubIds();
method @Nullable public android.net.TransportInfo getTransportInfo();
method public boolean hasCapability(int);
method public boolean hasTransport(int);
@@ -408,7 +407,6 @@
method public android.net.NetworkRequest.Builder removeTransportType(int);
method @Deprecated public android.net.NetworkRequest.Builder setNetworkSpecifier(String);
method public android.net.NetworkRequest.Builder setNetworkSpecifier(android.net.NetworkSpecifier);
- method @NonNull public android.net.NetworkRequest.Builder setSubIds(@NonNull java.util.Set<java.lang.Integer>);
}
public class ParseException extends java.lang.RuntimeException {
diff --git a/framework/api/system-current.txt b/framework/api/system-current.txt
index afd4fa0..251e5e8 100644
--- a/framework/api/system-current.txt
+++ b/framework/api/system-current.txt
@@ -274,6 +274,7 @@
public final class NetworkCapabilities implements android.os.Parcelable {
method @NonNull public int[] getAdministratorUids();
method @Nullable public String getSsid();
+ method @NonNull public java.util.Set<java.lang.Integer> getSubIds();
method @NonNull public int[] getTransportTypes();
method public boolean isPrivateDnsBroken();
method public boolean satisfiedByNetworkCapabilities(@Nullable android.net.NetworkCapabilities);
@@ -327,6 +328,7 @@
public static class NetworkRequest.Builder {
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkRequest.Builder setSignalStrength(int);
+ method @NonNull public android.net.NetworkRequest.Builder setSubIds(@NonNull java.util.Set<java.lang.Integer>);
}
public final class NetworkScore implements android.os.Parcelable {
diff --git a/framework/src/android/net/NetworkCapabilities.java b/framework/src/android/net/NetworkCapabilities.java
index 7e70891..4464b6e 100644
--- a/framework/src/android/net/NetworkCapabilities.java
+++ b/framework/src/android/net/NetworkCapabilities.java
@@ -2346,9 +2346,15 @@
/**
* Gets the subscription ID set that associated to this network or request.
+ *
+ * <p>Instances of NetworkCapabilities will only have this field populated by the system if the
+ * receiver holds the NETWORK_FACTORY permission. In all other cases, it will be the empty set.
+ *
* @return
+ * @hide
*/
@NonNull
+ @SystemApi
public Set<Integer> getSubIds() {
return new ArraySet<>(mSubIds);
}
@@ -2713,10 +2719,17 @@
/**
* Set the subscription ID set.
*
+ * <p>SubIds are populated in NetworkCapability instances from the system only for callers
+ * that hold the NETWORK_FACTORY permission. Similarly, the system will reject any
+ * NetworkRequests filed with a non-empty set of subIds unless the caller holds the
+ * NETWORK_FACTORY permission.
+ *
* @param subIds a set that represent the subscription IDs. Empty if clean up.
* @return this builder.
+ * @hide
*/
@NonNull
+ @SystemApi
public Builder setSubIds(@NonNull final Set<Integer> subIds) {
mCaps.setSubIds(subIds);
return this;
diff --git a/framework/src/android/net/NetworkRequest.java b/framework/src/android/net/NetworkRequest.java
index 38691ef..5d40417 100644
--- a/framework/src/android/net/NetworkRequest.java
+++ b/framework/src/android/net/NetworkRequest.java
@@ -501,9 +501,14 @@
* A network will satisfy this request only if it matches one of the subIds in this set.
* An empty set matches all networks, including those without a subId.
*
+ * <p>Registering a NetworkRequest with a non-empty set of subIds requires the
+ * NETWORK_FACTORY permission.
+ *
* @param subIds A {@code Set} that represents subscription IDs.
+ * @hide
*/
@NonNull
+ @SystemApi
public Builder setSubIds(@NonNull Set<Integer> subIds) {
mNetworkCapabilities.setSubIds(subIds);
return this;
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 70c9fe7..4e2d529 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1895,6 +1895,10 @@
newNc.setNetworkSpecifier(newNc.getNetworkSpecifier().redact());
}
newNc.setAdministratorUids(new int[0]);
+ if (!checkAnyPermissionOf(
+ callerPid, callerUid, android.Manifest.permission.NETWORK_FACTORY)) {
+ newNc.setSubIds(Collections.emptySet());
+ }
return newNc;
}
@@ -5666,6 +5670,10 @@
"Insufficient permissions to request a specific signal strength");
}
mAppOpsManager.checkPackage(callerUid, callerPackageName);
+
+ if (!nc.getSubIds().isEmpty()) {
+ enforceNetworkFactoryPermission();
+ }
}
private int[] getSignalStrengthThresholds(@NonNull final NetworkAgentInfo nai) {
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index ad93420..fc0392f 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -18,6 +18,7 @@
import static android.Manifest.permission.CHANGE_NETWORK_STATE;
import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
+import static android.Manifest.permission.NETWORK_FACTORY;
import static android.Manifest.permission.NETWORK_SETTINGS;
import static android.app.PendingIntent.FLAG_IMMUTABLE;
import static android.content.Intent.ACTION_USER_ADDED;
@@ -12186,4 +12187,68 @@
mCm.setProfileNetworkPreference(testHandle,
PROFILE_NETWORK_PREFERENCE_ENTERPRISE, null, null));
}
+
+ @Test
+ public void testSubIdsClearedWithoutNetworkFactoryPermission() throws Exception {
+ mServiceContext.setPermission(NETWORK_FACTORY, PERMISSION_DENIED);
+ final NetworkCapabilities nc = new NetworkCapabilities();
+ nc.setSubIds(Collections.singleton(Process.myUid()));
+
+ final NetworkCapabilities result =
+ mService.networkCapabilitiesRestrictedForCallerPermissions(
+ nc, Process.myPid(), Process.myUid());
+ assertTrue(result.getSubIds().isEmpty());
+ }
+
+ @Test
+ public void testSubIdsExistWithNetworkFactoryPermission() throws Exception {
+ mServiceContext.setPermission(NETWORK_FACTORY, PERMISSION_GRANTED);
+
+ final Set<Integer> subIds = Collections.singleton(Process.myUid());
+ final NetworkCapabilities nc = new NetworkCapabilities();
+ nc.setSubIds(subIds);
+
+ final NetworkCapabilities result =
+ mService.networkCapabilitiesRestrictedForCallerPermissions(
+ nc, Process.myPid(), Process.myUid());
+ assertEquals(subIds, result.getSubIds());
+ }
+
+ private NetworkRequest getRequestWithSubIds() {
+ return new NetworkRequest.Builder()
+ .setSubIds(Collections.singleton(Process.myUid()))
+ .build();
+ }
+
+ @Test
+ public void testNetworkRequestWithSubIdsWithNetworkFactoryPermission() throws Exception {
+ mServiceContext.setPermission(NETWORK_FACTORY, PERMISSION_GRANTED);
+ final PendingIntent pendingIntent = PendingIntent.getBroadcast(
+ mContext, 0 /* requestCode */, new Intent("a"), FLAG_IMMUTABLE);
+ final NetworkCallback networkCallback1 = new NetworkCallback();
+ final NetworkCallback networkCallback2 = new NetworkCallback();
+
+ mCm.requestNetwork(getRequestWithSubIds(), networkCallback1);
+ mCm.requestNetwork(getRequestWithSubIds(), pendingIntent);
+ mCm.registerNetworkCallback(getRequestWithSubIds(), networkCallback2);
+
+ mCm.unregisterNetworkCallback(networkCallback1);
+ mCm.releaseNetworkRequest(pendingIntent);
+ mCm.unregisterNetworkCallback(networkCallback2);
+ }
+
+ @Test
+ public void testNetworkRequestWithSubIdsWithoutNetworkFactoryPermission() throws Exception {
+ mServiceContext.setPermission(NETWORK_FACTORY, PERMISSION_DENIED);
+ final PendingIntent pendingIntent = PendingIntent.getBroadcast(
+ mContext, 0 /* requestCode */, new Intent("a"), FLAG_IMMUTABLE);
+
+ final Class<SecurityException> expected = SecurityException.class;
+ assertThrows(
+ expected, () -> mCm.requestNetwork(getRequestWithSubIds(), new NetworkCallback()));
+ assertThrows(expected, () -> mCm.requestNetwork(getRequestWithSubIds(), pendingIntent));
+ assertThrows(
+ expected,
+ () -> mCm.registerNetworkCallback(getRequestWithSubIds(), new NetworkCallback()));
+ }
}