diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 738070b092..a94109dae7 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -35,6 +35,9 @@ import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.StringJoiner;
@@ -83,6 +86,7 @@ public final class NetworkCapabilities implements Parcelable {
mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED;
mUids = null;
mEstablishingVpnAppUid = INVALID_UID;
+ mAdministratorUids.clear();
mSSID = null;
mPrivateDnsBroken = false;
}
@@ -101,6 +105,7 @@ public final class NetworkCapabilities implements Parcelable {
mSignalStrength = nc.mSignalStrength;
setUids(nc.mUids); // Will make the defensive copy
mEstablishingVpnAppUid = nc.mEstablishingVpnAppUid;
+ setAdministratorUids(nc.mAdministratorUids);
mUnwantedNetworkCapabilities = nc.mUnwantedNetworkCapabilities;
mSSID = nc.mSSID;
mPrivateDnsBroken = nc.mPrivateDnsBroken;
@@ -832,6 +837,56 @@ public final class NetworkCapabilities implements Parcelable {
return mEstablishingVpnAppUid;
}
+ /**
+ * UIDs of packages that are administrators of this network, or empty if none.
+ *
+ *
This field tracks the UIDs of packages that have permission to manage this network.
+ *
+ *
Network owners will also be listed as administrators.
+ *
+ *
For NetworkCapability instances being sent from the System Server, this value MUST be
+ * empty unless the destination is 1) the System Server, or 2) Telephony. In either case, the
+ * receiving entity must have the ACCESS_FINE_LOCATION permission and target R+.
+ */
+ private final List mAdministratorUids = new ArrayList<>();
+
+ /**
+ * Sets the list of UIDs that are administrators of this network.
+ *
+ * UIDs included in administratorUids gain administrator privileges over this Network.
+ * Examples of UIDs that should be included in administratorUids are:
+ *
+ * - Carrier apps with privileges for the relevant subscription
+ *
- Active VPN apps
+ *
- Other application groups with a particular Network-related role
+ *
+ *
+ * In general, user-supplied networks (such as WiFi networks) do not have an administrator.
+ *
+ *
An app is granted owner privileges over Networks that it supplies. Owner privileges
+ * implicitly include administrator privileges.
+ *
+ * @param administratorUids the UIDs to be set as administrators of this Network.
+ * @hide
+ */
+ @SystemApi
+ public void setAdministratorUids(@NonNull final List administratorUids) {
+ mAdministratorUids.clear();
+ mAdministratorUids.addAll(administratorUids);
+ }
+
+ /**
+ * Retrieves the list of UIDs that are administrators of this Network.
+ *
+ * @return the List of UIDs that are administrators of this Network
+ * @hide
+ */
+ @NonNull
+ @SystemApi
+ public List getAdministratorUids() {
+ return Collections.unmodifiableList(mAdministratorUids);
+ }
+
/**
* Value indicating that link bandwidth is unspecified.
* @hide
@@ -1471,6 +1526,7 @@ public final class NetworkCapabilities implements Parcelable {
public int describeContents() {
return 0;
}
+
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(mNetworkCapabilities);
@@ -1484,6 +1540,7 @@ public final class NetworkCapabilities implements Parcelable {
dest.writeArraySet(mUids);
dest.writeString(mSSID);
dest.writeBoolean(mPrivateDnsBroken);
+ dest.writeList(mAdministratorUids);
}
public static final @android.annotation.NonNull Creator CREATOR =
@@ -1504,6 +1561,7 @@ public final class NetworkCapabilities implements Parcelable {
null /* ClassLoader, null for default */);
netCap.mSSID = in.readString();
netCap.mPrivateDnsBroken = in.readBoolean();
+ netCap.setAdministratorUids(in.readArrayList(null));
return netCap;
}
@Override
@@ -1557,6 +1615,10 @@ public final class NetworkCapabilities implements Parcelable {
sb.append(" EstablishingAppUid: ").append(mEstablishingVpnAppUid);
}
+ if (!mAdministratorUids.isEmpty()) {
+ sb.append(" AdministratorUids: ").append(mAdministratorUids);
+ }
+
if (null != mSSID) {
sb.append(" SSID: ").append(mSSID);
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 1c9f5dc9c2..882b417dd6 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -210,6 +210,7 @@ import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.Comparator;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
@@ -1632,6 +1633,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (newNc.getNetworkSpecifier() != null) {
newNc.setNetworkSpecifier(newNc.getNetworkSpecifier().redact());
}
+ newNc.setAdministratorUids(Collections.EMPTY_LIST);
return newNc;
}
@@ -1662,6 +1664,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (!checkSettingsPermission()) {
nc.setSingleUid(Binder.getCallingUid());
}
+ nc.setAdministratorUids(Collections.EMPTY_LIST);
}
private void restrictBackgroundRequestForCaller(NetworkCapabilities nc) {
diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
index 15691127ca..797fd83321 100644
--- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
@@ -271,7 +271,7 @@ public class NetworkCapabilitiesTest {
.addCapability(NET_CAPABILITY_NOT_METERED);
assertParcelingIsLossless(netCap);
netCap.setSSID(TEST_SSID);
- assertParcelSane(netCap, 12);
+ assertParcelSane(netCap, 13);
}
@Test