Merge "Add OWNERS for packages/Connectivity"
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 0676ad4..6780167 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -51,7 +51,7 @@
  * An agent manages the life cycle of a network. A network starts its
  * life cycle when {@link register} is called on NetworkAgent. The network
  * is then connecting. When full L3 connectivity has been established,
- * the agent shoud call {@link markConnected} to inform the system that
+ * the agent should call {@link markConnected} to inform the system that
  * this network is ready to use. When the network disconnects its life
  * ends and the agent should call {@link unregister}, at which point the
  * system will clean up and free resources.
@@ -94,12 +94,6 @@
     @Nullable
     private volatile Network mNetwork;
 
-    // Whether this NetworkAgent is using the legacy (never unhidden) API. The difference is
-    // that the legacy API uses NetworkInfo to convey the state, while the current API is
-    // exposing methods to manage it and generate it internally instead.
-    // TODO : remove this as soon as all agents have been converted.
-    private final boolean mIsLegacy;
-
     private final Handler mHandler;
     private volatile AsyncChannel mAsyncChannel;
     private final String LOG_TAG;
@@ -110,8 +104,6 @@
     private static final long BW_REFRESH_MIN_WIN_MS = 500;
     private boolean mBandwidthUpdateScheduled = false;
     private AtomicBoolean mBandwidthUpdatePending = new AtomicBoolean(false);
-    // Not used by legacy agents. Non-legacy agents use this to convert the NetworkAgent system API
-    // into the internal API of ConnectivityService.
     @NonNull
     private NetworkInfo mNetworkInfo;
     @NonNull
@@ -337,35 +329,6 @@
      */
     public static final int CMD_REMOVE_KEEPALIVE_PACKET_FILTER = BASE + 17;
 
-    /** @hide TODO: remove and replace usage with the public constructor. */
-    public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
-            NetworkCapabilities nc, LinkProperties lp, int score) {
-        this(looper, context, logTag, ni, nc, lp, score, null, NetworkProvider.ID_NONE);
-        // Register done by the constructor called in the previous line
-    }
-
-    /** @hide TODO: remove and replace usage with the public constructor. */
-    public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
-            NetworkCapabilities nc, LinkProperties lp, int score, NetworkAgentConfig config) {
-        this(looper, context, logTag, ni, nc, lp, score, config, NetworkProvider.ID_NONE);
-        // Register done by the constructor called in the previous line
-    }
-
-    /** @hide TODO: remove and replace usage with the public constructor. */
-    public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
-            NetworkCapabilities nc, LinkProperties lp, int score, int providerId) {
-        this(looper, context, logTag, ni, nc, lp, score, null, providerId);
-        // Register done by the constructor called in the previous line
-    }
-
-    /** @hide TODO: remove and replace usage with the public constructor. */
-    public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
-            NetworkCapabilities nc, LinkProperties lp, int score, NetworkAgentConfig config,
-            int providerId) {
-        this(looper, context, logTag, nc, lp, score, config, providerId, ni, true /* legacy */);
-        register();
-    }
-
     private static NetworkInfo getLegacyNetworkInfo(final NetworkAgentConfig config) {
         // The subtype can be changed with (TODO) setLegacySubtype, but it starts
         // with 0 (TelephonyManager.NETWORK_TYPE_UNKNOWN) and an empty description.
@@ -393,7 +356,7 @@
             @NonNull NetworkAgentConfig config, @Nullable NetworkProvider provider) {
         this(looper, context, logTag, nc, lp, score, config,
                 provider == null ? NetworkProvider.ID_NONE : provider.getProviderId(),
-                getLegacyNetworkInfo(config), false /* legacy */);
+                getLegacyNetworkInfo(config));
     }
 
     private static class InitialConfiguration {
@@ -418,11 +381,9 @@
 
     private NetworkAgent(@NonNull Looper looper, @NonNull Context context, @NonNull String logTag,
             @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp, int score,
-            @NonNull NetworkAgentConfig config, int providerId, @NonNull NetworkInfo ni,
-            boolean legacy) {
+            @NonNull NetworkAgentConfig config, int providerId, @NonNull NetworkInfo ni) {
         mHandler = new NetworkAgentHandler(looper);
         LOG_TAG = logTag;
-        mIsLegacy = legacy;
         mNetworkInfo = new NetworkInfo(ni);
         this.providerId = providerId;
         if (ni == null || nc == null || lp == null) {
@@ -696,11 +657,6 @@
      * Call {@link #unregister} to disconnect.
      */
     public void markConnected() {
-        if (mIsLegacy) {
-            throw new UnsupportedOperationException(
-                    "Legacy agents can't call markConnected.");
-        }
-        // |reason| cannot be used by the non-legacy agents
         mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null /* reason */,
                 mNetworkInfo.getExtraInfo());
         queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, mNetworkInfo);
@@ -713,9 +669,6 @@
      * the network is torn down and this agent can no longer be used.
      */
     public void unregister() {
-        if (mIsLegacy) {
-            throw new UnsupportedOperationException("Legacy agents can't call unregister.");
-        }
         // When unregistering an agent nobody should use the extrainfo (or reason) any more.
         mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null /* reason */,
                 null /* extraInfo */);
@@ -735,9 +688,6 @@
      */
     @Deprecated
     public void setLegacySubtype(final int legacySubtype, @NonNull final String legacySubtypeName) {
-        if (mIsLegacy) {
-            throw new UnsupportedOperationException("Legacy agents can't call setLegacySubtype.");
-        }
         mNetworkInfo.setSubtype(legacySubtype, legacySubtypeName);
         queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, mNetworkInfo);
     }
@@ -760,9 +710,6 @@
      */
     @Deprecated
     public void setLegacyExtraInfo(@Nullable final String extraInfo) {
-        if (mIsLegacy) {
-            throw new UnsupportedOperationException("Legacy agents can't call setLegacyExtraInfo.");
-        }
         mNetworkInfo.setExtraInfo(extraInfo);
         queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, mNetworkInfo);
     }
@@ -773,9 +720,6 @@
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public final void sendNetworkInfo(NetworkInfo networkInfo) {
-        if (!mIsLegacy) {
-            throw new UnsupportedOperationException("Only legacy agents can call sendNetworkInfo.");
-        }
         queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, new NetworkInfo(networkInfo));
     }
 
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 8dad11f..1a37fb9 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -975,6 +975,10 @@
         return mOwnerUid;
     }
 
+    private boolean equalsOwnerUid(@NonNull final NetworkCapabilities nc) {
+        return mOwnerUid == nc.mOwnerUid;
+    }
+
     /**
      * UIDs of packages that are administrators of this network, or empty if none.
      *
@@ -1684,6 +1688,7 @@
                 && equalsTransportInfo(that)
                 && equalsUids(that)
                 && equalsSSID(that)
+                && equalsOwnerUid(that)
                 && equalsPrivateDnsBroken(that)
                 && equalsRequestor(that)
                 && equalsAdministratorUids(that);
@@ -1697,17 +1702,18 @@
                 + ((int) (mUnwantedNetworkCapabilities >> 32) * 7)
                 + ((int) (mTransportTypes & 0xFFFFFFFF) * 11)
                 + ((int) (mTransportTypes >> 32) * 13)
-                + (mLinkUpBandwidthKbps * 17)
-                + (mLinkDownBandwidthKbps * 19)
+                + mLinkUpBandwidthKbps * 17
+                + mLinkDownBandwidthKbps * 19
                 + Objects.hashCode(mNetworkSpecifier) * 23
-                + (mSignalStrength * 29)
-                + Objects.hashCode(mUids) * 31
-                + Objects.hashCode(mSSID) * 37
-                + Objects.hashCode(mTransportInfo) * 41
-                + Objects.hashCode(mPrivateDnsBroken) * 43
-                + Objects.hashCode(mRequestorUid) * 47
-                + Objects.hashCode(mRequestorPackageName) * 53
-                + Arrays.hashCode(mAdministratorUids) * 59;
+                + mSignalStrength * 29
+                + mOwnerUid * 31
+                + Objects.hashCode(mUids) * 37
+                + Objects.hashCode(mSSID) * 41
+                + Objects.hashCode(mTransportInfo) * 43
+                + Objects.hashCode(mPrivateDnsBroken) * 47
+                + Objects.hashCode(mRequestorUid) * 53
+                + Objects.hashCode(mRequestorPackageName) * 59
+                + Arrays.hashCode(mAdministratorUids) * 61;
     }
 
     @Override
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index a0faafa..d84ee2a 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -35,7 +35,6 @@
 import java.net.InetAddress;
 import java.net.SocketException;
 import java.net.UnknownHostException;
-import java.util.Collection;
 import java.util.Locale;
 import java.util.TreeSet;
 
@@ -342,20 +341,6 @@
     }
 
     /**
-     * Create a string array of host addresses from a collection of InetAddresses
-     * @param addrs a Collection of InetAddresses
-     * @return an array of Strings containing their host addresses
-     */
-    public static String[] makeStrings(Collection<InetAddress> addrs) {
-        String[] result = new String[addrs.size()];
-        int i = 0;
-        for (InetAddress addr : addrs) {
-            result[i++] = addr.getHostAddress();
-        }
-        return result;
-    }
-
-    /**
      * Trim leading zeros from IPv4 address strings
      * Our base libraries will interpret that as octel..
      * Must leave non v4 addresses and host names alone.
diff --git a/core/java/android/net/TcpRepairWindow.java b/core/java/android/net/TcpRepairWindow.java
index 86034f0..f062fa9 100644
--- a/core/java/android/net/TcpRepairWindow.java
+++ b/core/java/android/net/TcpRepairWindow.java
@@ -16,12 +16,15 @@
 
 package android.net;
 
+import android.annotation.SystemApi;
+
 /**
  * Corresponds to C's {@code struct tcp_repair_window} from
  * include/uapi/linux/tcp.h
  *
  * @hide
  */
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
 public final class TcpRepairWindow {
     public final int sndWl1;
     public final int sndWnd;
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 58f1db3..4590aa2 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -129,6 +129,7 @@
 import android.net.SocketKeepalive;
 import android.net.TetheringManager;
 import android.net.UidRange;
+import android.net.UidRangeParcel;
 import android.net.Uri;
 import android.net.VpnManager;
 import android.net.VpnService;
@@ -186,7 +187,6 @@
 import com.android.internal.net.VpnProfile;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.AsyncChannel;
-import com.android.internal.util.DumpUtils;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.LocationPermissionChecker;
 import com.android.internal.util.MessageUtils;
@@ -1287,7 +1287,7 @@
         if (network == null) {
             return null;
         }
-        return getNetworkAgentInfoForNetId(network.netId);
+        return getNetworkAgentInfoForNetId(network.getNetId());
     }
 
     private NetworkAgentInfo getNetworkAgentInfoForNetId(int netId) {
@@ -1378,7 +1378,7 @@
         }
         final String action = blocked ? "BLOCKED" : "UNBLOCKED";
         mNetworkInfoBlockingLogs.log(String.format(
-                "%s %d(%d) on netId %d", action, nri.mUid, nri.request.requestId, net.netId));
+                "%s %d(%d) on netId %d", action, nri.mUid, nri.request.requestId, net.getNetId()));
     }
 
     /**
@@ -1890,7 +1890,7 @@
             int netId;
             synchronized (nai) {
                 lp = nai.linkProperties;
-                netId = nai.network.netId;
+                netId = nai.network.getNetId();
             }
             boolean ok = addLegacyRouteToHost(lp, addr, netId, uid);
             if (DBG) log("requestRouteToHostAddress ok=" + ok);
@@ -2525,9 +2525,21 @@
         PriorityDump.dump(mPriorityDumper, fd, writer, args);
     }
 
+    private boolean checkDumpPermission(Context context, String tag, PrintWriter pw) {
+        if (context.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+                != PackageManager.PERMISSION_GRANTED) {
+            pw.println("Permission Denial: can't dump " + tag + " from from pid="
+                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
+                    + " due to missing android.permission.DUMP permission");
+            return false;
+        } else {
+            return true;
+        }
+    }
+
     private void doDump(FileDescriptor fd, PrintWriter writer, String[] args, boolean asProto) {
         final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
-        if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+        if (!checkDumpPermission(mContext, TAG, pw)) return;
         if (asProto) return;
 
         if (ArrayUtils.contains(args, DIAG_ARG)) {
@@ -2553,7 +2565,7 @@
         if (defaultNai == null) {
             pw.println("none");
         } else {
-            pw.println(defaultNai.network.netId);
+            pw.println(defaultNai.network.getNetId());
         }
         pw.println();
 
@@ -2690,7 +2702,7 @@
     private NetworkAgentInfo[] networksSortedById() {
         NetworkAgentInfo[] networks = new NetworkAgentInfo[0];
         networks = mNetworkAgentInfos.values().toArray(networks);
-        Arrays.sort(networks, Comparator.comparingInt(nai -> nai.network.netId));
+        Arrays.sort(networks, Comparator.comparingInt(nai -> nai.network.getNetId()));
         return networks;
     }
 
@@ -2811,6 +2823,7 @@
                     break;
                 }
                 case NetworkAgent.EVENT_UNDERLYING_NETWORKS_CHANGED: {
+                    // TODO: prevent loops, e.g., if a network declares itself as underlying.
                     if (!nai.supportsUnderlyingNetworks()) {
                         Log.wtf(TAG, "Non-virtual networks cannot have underlying networks");
                         break;
@@ -2831,7 +2844,7 @@
                             log(nai.toShortString() + " changed underlying networks to "
                                     + Arrays.toString(nai.declaredUnderlyingNetworks));
                         }
-                        updateCapabilities(nai.getCurrentScore(), nai, nai.networkCapabilities);
+                        updateCapabilitiesForNetwork(nai);
                         notifyIfacesChangedForNetworkStats();
                     }
                 }
@@ -2855,8 +2868,7 @@
                     if (probePrivateDnsCompleted) {
                         if (nai.networkCapabilities.isPrivateDnsBroken() != privateDnsBroken) {
                             nai.networkCapabilities.setPrivateDnsBroken(privateDnsBroken);
-                            final int oldScore = nai.getCurrentScore();
-                            updateCapabilities(oldScore, nai, nai.networkCapabilities);
+                            updateCapabilitiesForNetwork(nai);
                         }
                         // Only show the notification when the private DNS is broken and the
                         // PRIVATE_DNS_BROKEN notification hasn't shown since last valid.
@@ -2871,8 +2883,7 @@
                         // done yet. In either case, the networkCapabilities should be updated to
                         // reflect the new status.
                         nai.networkCapabilities.setPrivateDnsBroken(false);
-                        final int oldScore = nai.getCurrentScore();
-                        updateCapabilities(oldScore, nai, nai.networkCapabilities);
+                        updateCapabilitiesForNetwork(nai);
                         nai.networkAgentConfig.hasShownBroken = false;
                     }
                     break;
@@ -2893,7 +2904,6 @@
                     final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(netId);
                     // If captive portal status has changed, update capabilities or disconnect.
                     if (nai != null && (visible != nai.lastCaptivePortalDetected)) {
-                        final int oldScore = nai.getCurrentScore();
                         nai.lastCaptivePortalDetected = visible;
                         nai.everCaptivePortalDetected |= visible;
                         if (nai.lastCaptivePortalDetected &&
@@ -2904,7 +2914,7 @@
                             teardownUnneededNetwork(nai);
                             break;
                         }
-                        updateCapabilities(oldScore, nai, nai.networkCapabilities);
+                        updateCapabilitiesForNetwork(nai);
                     }
                     if (!visible) {
                         // Only clear SIGN_IN and NETWORK_SWITCH notifications here, or else other
@@ -2974,13 +2984,13 @@
                     handleFreshlyValidatedNetwork(nai);
                     // Clear NO_INTERNET, PRIVATE_DNS_BROKEN, PARTIAL_CONNECTIVITY and
                     // LOST_INTERNET notifications if network becomes valid.
-                    mNotifier.clearNotification(nai.network.netId,
+                    mNotifier.clearNotification(nai.network.getNetId(),
                             NotificationType.NO_INTERNET);
-                    mNotifier.clearNotification(nai.network.netId,
+                    mNotifier.clearNotification(nai.network.getNetId(),
                             NotificationType.LOST_INTERNET);
-                    mNotifier.clearNotification(nai.network.netId,
+                    mNotifier.clearNotification(nai.network.getNetId(),
                             NotificationType.PARTIAL_CONNECTIVITY);
-                    mNotifier.clearNotification(nai.network.netId,
+                    mNotifier.clearNotification(nai.network.getNetId(),
                             NotificationType.PRIVATE_DNS_BROKEN);
                     // If network becomes valid, the hasShownBroken should be reset for
                     // that network so that the notification will be fired when the private
@@ -2988,7 +2998,7 @@
                     nai.networkAgentConfig.hasShownBroken = false;
                 }
             } else if (partialConnectivityChanged) {
-                updateCapabilities(nai.getCurrentScore(), nai, nai.networkCapabilities);
+                updateCapabilitiesForNetwork(nai);
             }
             updateInetCondition(nai);
             // Let the NetworkAgent know the state of its network
@@ -3051,7 +3061,7 @@
         private final AutodestructReference<NetworkAgentInfo> mNai;
 
         private NetworkMonitorCallbacks(NetworkAgentInfo nai) {
-            mNetId = nai.network.netId;
+            mNetId = nai.network.getNetId();
             mNai = new AutodestructReference<>(nai);
         }
 
@@ -3201,7 +3211,7 @@
         // in order to restart a validation pass from within netd.
         final PrivateDnsConfig cfg = mDnsManager.getPrivateDnsConfig();
         if (cfg.useTls && TextUtils.isEmpty(cfg.hostname)) {
-            updateDnses(nai.linkProperties, null, nai.network.netId);
+            updateDnses(nai.linkProperties, null, nai.network.getNetId());
         }
     }
 
@@ -3234,7 +3244,7 @@
 
     private void updatePrivateDns(NetworkAgentInfo nai, PrivateDnsConfig newCfg) {
         mDnsManager.updatePrivateDns(nai.network, newCfg);
-        updateDnses(nai.linkProperties, null, nai.network.netId);
+        updateDnses(nai.linkProperties, null, nai.network.getNetId());
     }
 
     private void handlePrivateDnsValidationUpdate(PrivateDnsValidationUpdate update) {
@@ -3330,9 +3340,9 @@
                 if (nai != null) {
                     final boolean wasDefault = isDefaultNetwork(nai);
                     synchronized (mNetworkForNetId) {
-                        mNetworkForNetId.remove(nai.network.netId);
+                        mNetworkForNetId.remove(nai.network.getNetId());
                     }
-                    mNetIdManager.releaseNetId(nai.network.netId);
+                    mNetIdManager.releaseNetId(nai.network.getNetId());
                     // Just in case.
                     mLegacyTypeTracker.remove(nai, wasDefault);
                 }
@@ -3362,7 +3372,7 @@
             log(nai.toShortString() + " disconnected, was satisfying " + nai.numNetworkRequests());
         }
         // Clear all notifications of this network.
-        mNotifier.clearNotification(nai.network.netId);
+        mNotifier.clearNotification(nai.network.getNetId());
         // A network agent has disconnected.
         // TODO - if we move the logic to the network agent (have them disconnect
         // because they lost all their requests or because their score isn't good)
@@ -3399,19 +3409,21 @@
         synchronized (mNetworkForNetId) {
             // Remove the NetworkAgent, but don't mark the netId as
             // available until we've told netd to delete it below.
-            mNetworkForNetId.remove(nai.network.netId);
+            mNetworkForNetId.remove(nai.network.getNetId());
         }
         // Remove all previously satisfied requests.
         for (int i = 0; i < nai.numNetworkRequests(); i++) {
             NetworkRequest request = nai.requestAt(i);
             final NetworkRequestInfo nri = mNetworkRequests.get(request);
             final NetworkAgentInfo currentNetwork = nri.mSatisfier;
-            if (currentNetwork != null && currentNetwork.network.netId == nai.network.netId) {
+            if (currentNetwork != null
+                    && currentNetwork.network.getNetId() == nai.network.getNetId()) {
                 nri.mSatisfier = null;
                 sendUpdatedScoreToFactories(request, null);
             }
         }
         nai.clearLingerState();
+        propagateUnderlyingNetworkCapabilities(nai.network);
         if (nai.isSatisfyingRequest(mDefaultRequest.requestId)) {
             mDefaultNetworkNai = null;
             updateDataActivityTracking(null /* newNetwork */, nai);
@@ -3419,9 +3431,6 @@
             ensureNetworkTransitionWakelock(nai.toShortString());
         }
         mLegacyTypeTracker.remove(nai, wasDefault);
-        if (!nai.networkCapabilities.hasTransport(TRANSPORT_VPN)) {
-            propagateUnderlyingNetworkCapabilities();
-        }
         rematchAllNetworksAndRequests();
         mLingerMonitor.noteDisconnect(nai);
         if (nai.created) {
@@ -3436,26 +3445,26 @@
             destroyNativeNetwork(nai);
             mDnsManager.removeNetwork(nai.network);
         }
-        mNetIdManager.releaseNetId(nai.network.netId);
+        mNetIdManager.releaseNetId(nai.network.getNetId());
     }
 
     private boolean createNativeNetwork(@NonNull NetworkAgentInfo networkAgent) {
         try {
             // This should never fail.  Specifying an already in use NetID will cause failure.
             if (networkAgent.isVPN()) {
-                mNetd.networkCreateVpn(networkAgent.network.netId,
+                mNetd.networkCreateVpn(networkAgent.network.getNetId(),
                         (networkAgent.networkAgentConfig == null
                                 || !networkAgent.networkAgentConfig.allowBypass));
             } else {
-                mNetd.networkCreatePhysical(networkAgent.network.netId,
+                mNetd.networkCreatePhysical(networkAgent.network.getNetId(),
                         getNetworkPermission(networkAgent.networkCapabilities));
             }
-            mDnsResolver.createNetworkCache(networkAgent.network.netId);
-            mDnsManager.updateTransportsForNetwork(networkAgent.network.netId,
+            mDnsResolver.createNetworkCache(networkAgent.network.getNetId());
+            mDnsManager.updateTransportsForNetwork(networkAgent.network.getNetId(),
                     networkAgent.networkCapabilities.getTransportTypes());
             return true;
         } catch (RemoteException | ServiceSpecificException e) {
-            loge("Error creating network " + networkAgent.network.netId + ": "
+            loge("Error creating network " + networkAgent.network.getNetId() + ": "
                     + e.getMessage());
             return false;
         }
@@ -3463,8 +3472,8 @@
 
     private void destroyNativeNetwork(@NonNull NetworkAgentInfo networkAgent) {
         try {
-            mNetd.networkDestroy(networkAgent.network.netId);
-            mDnsResolver.destroyNetworkCache(networkAgent.network.netId);
+            mNetd.networkDestroy(networkAgent.network.getNetId());
+            mDnsResolver.destroyNetworkCache(networkAgent.network.getNetId());
         } catch (RemoteException | ServiceSpecificException e) {
             loge("Exception destroying network: " + e);
         }
@@ -3656,7 +3665,7 @@
                 nri.mSatisfier = null;
                 if (!wasBackgroundNetwork && nai.isBackgroundNetwork()) {
                     // Went from foreground to background.
-                    updateCapabilities(nai.getCurrentScore(), nai, nai.networkCapabilities);
+                    updateCapabilitiesForNetwork(nai);
                 }
             }
 
@@ -4026,7 +4035,7 @@
 
         Intent intent = new Intent(action);
         if (type != NotificationType.PRIVATE_DNS_BROKEN) {
-            intent.setData(Uri.fromParts("netId", Integer.toString(nai.network.netId), null));
+            intent.setData(Uri.fromParts("netId", Integer.toString(nai.network.getNetId()), null));
             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
             // Some OEMs have their own Settings package. Thus, need to get the current using
             // Settings package name instead of just use default name "com.android.settings".
@@ -4041,7 +4050,8 @@
                 intent,
                 PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
 
-        mNotifier.showNotification(nai.network.netId, type, nai, null, pendingIntent, highPriority);
+        mNotifier.showNotification(
+                nai.network.getNetId(), type, nai, null, pendingIntent, highPriority);
     }
 
     private boolean shouldPromptUnvalidated(NetworkAgentInfo nai) {
@@ -4407,7 +4417,7 @@
             return;
         }
         if (DBG) {
-            int netid = nai.network.netId;
+            int netid = nai.network.getNetId();
             log("reportNetworkConnectivity(" + netid + ", " + hasConnectivity + ") by " + uid);
         }
         // Validating a network that has not yet connected could result in a call to
@@ -4442,7 +4452,7 @@
                 return null;
             }
             return getLinkPropertiesProxyInfo(activeNetwork);
-        } else if (mDeps.queryUserAccess(Binder.getCallingUid(), network.netId)) {
+        } else if (mDeps.queryUserAccess(Binder.getCallingUid(), network.getNetId())) {
             // Don't call getLinkProperties() as it requires ACCESS_NETWORK_STATE permission, which
             // caller may not have.
             return getLinkPropertiesProxyInfo(network);
@@ -4809,18 +4819,36 @@
         }
     }
 
+    private Network[] underlyingNetworksOrDefault(Network[] underlyingNetworks) {
+        final Network defaultNetwork = getNetwork(getDefaultNetwork());
+        if (underlyingNetworks == null && defaultNetwork != null) {
+            // null underlying networks means to track the default.
+            underlyingNetworks = new Network[] { defaultNetwork };
+        }
+        return underlyingNetworks;
+    }
+
+    // Returns true iff |network| is an underlying network of |nai|.
+    private boolean hasUnderlyingNetwork(NetworkAgentInfo nai, Network network) {
+        // TODO: support more than one level of underlying networks, either via a fixed-depth search
+        // (e.g., 2 levels of underlying networks), or via loop detection, or....
+        if (!nai.supportsUnderlyingNetworks()) return false;
+        final Network[] underlying = underlyingNetworksOrDefault(nai.declaredUnderlyingNetworks);
+        return ArrayUtils.contains(underlying, network);
+    }
+
     /**
-     * Ask all networks with underlying networks to recompute and update their capabilities.
+     * Recompute the capabilities for any networks that had a specific network as underlying.
      *
      * When underlying networks change, such networks may have to update capabilities to reflect
      * things like the metered bit, their transports, and so on. The capabilities are calculated
      * immediately. This method runs on the ConnectivityService thread.
      */
-    private void propagateUnderlyingNetworkCapabilities() {
+    private void propagateUnderlyingNetworkCapabilities(Network updatedNetwork) {
         ensureRunningOnConnectivityServiceThread();
         for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
-            if (nai.supportsUnderlyingNetworks()) {
-                updateCapabilities(nai.getCurrentScore(), nai, nai.networkCapabilities);
+            if (updatedNetwork == null || hasUnderlyingNetwork(nai, updatedNetwork)) {
+                updateCapabilitiesForNetwork(nai);
             }
         }
     }
@@ -5142,7 +5170,7 @@
                 loge("Starting user already has a VPN");
                 return;
             }
-            userVpn = new Vpn(mHandler.getLooper(), mContext, mNMS, userId, mKeyStore);
+            userVpn = new Vpn(mHandler.getLooper(), mContext, mNMS, mNetd, userId, mKeyStore);
             mVpns.put(userId, userVpn);
             if (mUserManager.getUserInfo(userId).isPrimary() && LockdownVpnTracker.isEnabled()) {
                 updateLockdownVpn();
@@ -5569,11 +5597,12 @@
     }
 
     private boolean checkUnsupportedStartingFrom(int version, String callingPackageName) {
-        final PackageManager pm = mContext.getPackageManager();
-        final int userId = UserHandle.getCallingUserId();
+        final UserHandle user = UserHandle.getUserHandleForUid(Binder.getCallingUid());
+        final PackageManager pm =
+                mContext.createContextAsUser(user, 0 /* flags */).getPackageManager();
         try {
-            final int callingVersion = pm.getApplicationInfoAsUser(
-                    callingPackageName, 0 /* flags */, userId).targetSdkVersion;
+            final int callingVersion = pm.getApplicationInfo(
+                    callingPackageName, 0 /* flags */).targetSdkVersion;
             if (callingVersion < version) return false;
         } catch (PackageManager.NameNotFoundException e) { }
         return true;
@@ -5653,7 +5682,7 @@
             return false;
         }
         synchronized (mNetworkForNetId) {
-            nai = mNetworkForNetId.get(network.netId);
+            nai = mNetworkForNetId.get(network.getNetId());
         }
         if (nai != null) {
             nai.asyncChannel.sendMessage(android.net.NetworkAgent.CMD_REQUEST_BANDWIDTH_UPDATE);
@@ -6033,7 +6062,7 @@
         if (VDBG) log("Got NetworkAgent Messenger");
         mNetworkAgentInfos.put(nai.messenger, nai);
         synchronized (mNetworkForNetId) {
-            mNetworkForNetId.put(nai.network.netId, nai);
+            mNetworkForNetId.put(nai.network.getNetId(), nai);
         }
 
         try {
@@ -6052,6 +6081,7 @@
      * Stores into |nai| any data coming from the agent that might also be written to the network's
      * LinkProperties by ConnectivityService itself. This ensures that the data provided by the
      * agent is not lost when updateLinkProperties is called.
+     * This method should never alter the agent's LinkProperties, only store data in |nai|.
      */
     private void processLinkPropertiesFromAgent(NetworkAgentInfo nai, LinkProperties lp) {
         lp.ensureDirectlyConnectedRoutes();
@@ -6060,7 +6090,7 @@
 
     private void updateLinkProperties(NetworkAgentInfo networkAgent, LinkProperties newLp,
             @NonNull LinkProperties oldLp) {
-        int netId = networkAgent.network.netId;
+        int netId = networkAgent.network.getNetId();
 
         // The NetworkAgent does not know whether clatd is running on its network or not, or whether
         // a NAT64 prefix was discovered by the DNS resolver. Before we do anything else, make sure
@@ -6341,7 +6371,7 @@
         final int newPermission = getNetworkPermission(newNc);
         if (oldPermission != newPermission && nai.created && !nai.isVPN()) {
             try {
-                mNetd.networkSetPermissionForNetwork(nai.network.netId, newPermission);
+                mNetd.networkSetPermissionForNetwork(nai.network.getNetId(), newPermission);
             } catch (RemoteException | ServiceSpecificException e) {
                 loge("Exception in networkSetPermissionForNetwork: " + e);
             }
@@ -6353,24 +6383,31 @@
      * Stores into |nai| any data coming from the agent that might also be written to the network's
      * NetworkCapabilities by ConnectivityService itself. This ensures that the data provided by the
      * agent is not lost when updateCapabilities is called.
+     * This method should never alter the agent's NetworkCapabilities, only store data in |nai|.
      */
     private void processCapabilitiesFromAgent(NetworkAgentInfo nai, NetworkCapabilities nc) {
-        nai.declaredMetered = !nc.hasCapability(NET_CAPABILITY_NOT_METERED);
+        // Note: resetting the owner UID before storing the agent capabilities in NAI means that if
+        // the agent attempts to change the owner UID, then nai.declaredCapabilities will not
+        // actually be the same as the capabilities sent by the agent. Still, it is safer to reset
+        // the owner UID here and behave as if the agent had never tried to change it.
+        if (nai.networkCapabilities.getOwnerUid() != nc.getOwnerUid()) {
+            Log.e(TAG, nai.toShortString() + ": ignoring attempt to change owner from "
+                    + nai.networkCapabilities.getOwnerUid() + " to " + nc.getOwnerUid());
+            nc.setOwnerUid(nai.networkCapabilities.getOwnerUid());
+        }
+        nai.declaredCapabilities = new NetworkCapabilities(nc);
     }
 
-    /** Modifies |caps| based on the capabilities of the specified underlying networks. */
+    /** Modifies |newNc| based on the capabilities of |underlyingNetworks| and |agentCaps|. */
     @VisibleForTesting
     void applyUnderlyingCapabilities(@Nullable Network[] underlyingNetworks,
-            @NonNull NetworkCapabilities caps,  boolean declaredMetered) {
-        final Network defaultNetwork = getNetwork(getDefaultNetwork());
-        if (underlyingNetworks == null && defaultNetwork != null) {
-            // null underlying networks means to track the default.
-            underlyingNetworks = new Network[] { defaultNetwork };
-        }
-        int[] transportTypes = new int[] { NetworkCapabilities.TRANSPORT_VPN };
+            @NonNull NetworkCapabilities agentCaps, @NonNull NetworkCapabilities newNc) {
+        underlyingNetworks = underlyingNetworksOrDefault(underlyingNetworks);
+        int[] transportTypes = agentCaps.getTransportTypes();
         int downKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
         int upKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
-        boolean metered = declaredMetered; // metered if any underlying is metered, or agentMetered
+        // metered if any underlying is metered, or originally declared metered by the agent.
+        boolean metered = !agentCaps.hasCapability(NET_CAPABILITY_NOT_METERED);
         boolean roaming = false; // roaming if any underlying is roaming
         boolean congested = false; // congested if any underlying is congested
         boolean suspended = true; // suspended if all underlying are suspended
@@ -6416,13 +6453,13 @@
             suspended = false;
         }
 
-        caps.setTransportTypes(transportTypes);
-        caps.setLinkDownstreamBandwidthKbps(downKbps);
-        caps.setLinkUpstreamBandwidthKbps(upKbps);
-        caps.setCapability(NET_CAPABILITY_NOT_METERED, !metered);
-        caps.setCapability(NET_CAPABILITY_NOT_ROAMING, !roaming);
-        caps.setCapability(NET_CAPABILITY_NOT_CONGESTED, !congested);
-        caps.setCapability(NET_CAPABILITY_NOT_SUSPENDED, !suspended);
+        newNc.setTransportTypes(transportTypes);
+        newNc.setLinkDownstreamBandwidthKbps(downKbps);
+        newNc.setLinkUpstreamBandwidthKbps(upKbps);
+        newNc.setCapability(NET_CAPABILITY_NOT_METERED, !metered);
+        newNc.setCapability(NET_CAPABILITY_NOT_ROAMING, !roaming);
+        newNc.setCapability(NET_CAPABILITY_NOT_CONGESTED, !congested);
+        newNc.setCapability(NET_CAPABILITY_NOT_SUSPENDED, !suspended);
     }
 
     /**
@@ -6479,7 +6516,8 @@
         }
 
         if (nai.supportsUnderlyingNetworks()) {
-            applyUnderlyingCapabilities(nai.declaredUnderlyingNetworks, newNc, nai.declaredMetered);
+            applyUnderlyingCapabilities(nai.declaredUnderlyingNetworks, nai.declaredCapabilities,
+                    newNc);
         }
 
         return newNc;
@@ -6558,17 +6596,20 @@
             }
         }
 
-        if (!newNc.hasTransport(TRANSPORT_VPN)) {
-            // Tell VPNs about updated capabilities, since they may need to
-            // bubble those changes through.
-            propagateUnderlyingNetworkCapabilities();
-        }
+        // This network might have been underlying another network. Propagate its capabilities.
+        propagateUnderlyingNetworkCapabilities(nai.network);
 
         if (!newNc.equalsTransportTypes(prevNc)) {
-            mDnsManager.updateTransportsForNetwork(nai.network.netId, newNc.getTransportTypes());
+            mDnsManager.updateTransportsForNetwork(
+                    nai.network.getNetId(), newNc.getTransportTypes());
         }
     }
 
+    /** Convenience method to update the capabilities for a given network. */
+    private void updateCapabilitiesForNetwork(NetworkAgentInfo nai) {
+        updateCapabilities(nai.getCurrentScore(), nai, nai.networkCapabilities);
+    }
+
     /**
      * Returns whether VPN isolation (ingress interface filtering) should be applied on the given
      * network.
@@ -6598,6 +6639,16 @@
                 && (lp.hasIpv6DefaultRoute() || lp.hasIpv6UnreachableDefaultRoute());
     }
 
+    private static UidRangeParcel[] toUidRangeStableParcels(final @NonNull Set<UidRange> ranges) {
+        final UidRangeParcel[] stableRanges = new UidRangeParcel[ranges.size()];
+        int index = 0;
+        for (UidRange range : ranges) {
+            stableRanges[index] = new UidRangeParcel(range.start, range.stop);
+            index++;
+        }
+        return stableRanges;
+    }
+
     private void updateUids(NetworkAgentInfo nai, NetworkCapabilities prevNc,
             NetworkCapabilities newNc) {
         Set<UidRange> prevRanges = null == prevNc ? null : prevNc.getUids();
@@ -6617,14 +6668,11 @@
             // removing old range works because, unlike the filtering rules below, it's possible to
             // add duplicate UID routing rules.
             if (!newRanges.isEmpty()) {
-                final UidRange[] addedRangesArray = new UidRange[newRanges.size()];
-                newRanges.toArray(addedRangesArray);
-                mNMS.addVpnUidRanges(nai.network.netId, addedRangesArray);
+                mNetd.networkAddUidRanges(nai.network.netId, toUidRangeStableParcels(newRanges));
             }
             if (!prevRanges.isEmpty()) {
-                final UidRange[] removedRangesArray = new UidRange[prevRanges.size()];
-                prevRanges.toArray(removedRangesArray);
-                mNMS.removeVpnUidRanges(nai.network.netId, removedRangesArray);
+                mNetd.networkRemoveUidRanges(
+                        nai.network.netId, toUidRangeStableParcels(prevRanges));
             }
             final boolean wasFiltering = requiresVpnIsolation(nai, prevNc, nai.linkProperties);
             final boolean shouldFilter = requiresVpnIsolation(nai, newNc, nai.linkProperties);
@@ -6655,7 +6703,7 @@
     public void handleUpdateLinkProperties(NetworkAgentInfo nai, LinkProperties newLp) {
         ensureRunningOnConnectivityServiceThread();
 
-        if (getNetworkAgentInfoForNetId(nai.network.netId) != nai) {
+        if (getNetworkAgentInfoForNetId(nai.network.getNetId()) != nai) {
             // Ignore updates for disconnected networks
             return;
         }
@@ -6854,8 +6902,7 @@
             teardownUnneededNetwork(oldNetwork);
         } else {
             // Put the network in the background.
-            updateCapabilities(oldNetwork.getCurrentScore(), oldNetwork,
-                    oldNetwork.networkCapabilities);
+            updateCapabilitiesForNetwork(oldNetwork);
         }
     }
 
@@ -6866,7 +6913,7 @@
 
         try {
             if (null != newNetwork) {
-                mNetd.networkSetDefault(newNetwork.network.netId);
+                mNetd.networkSetDefault(newNetwork.network.getNetId());
             } else {
                 mNetd.networkClearDefault();
             }
@@ -6880,8 +6927,10 @@
         updateTcpBufferSizes(null != newNetwork
                 ? newNetwork.linkProperties.getTcpBufferSizes() : null);
         notifyIfacesChangedForNetworkStats();
-        // Fix up the NetworkCapabilities of any VPNs that don't specify underlying networks.
-        propagateUnderlyingNetworkCapabilities();
+        // Fix up the NetworkCapabilities of any networks that have this network as underlying.
+        if (newNetwork != null) {
+            propagateUnderlyingNetworkCapabilities(newNetwork.network);
+        }
     }
 
     private void processListenRequests(@NonNull final NetworkAgentInfo nai) {
@@ -6929,8 +6978,8 @@
 
             public String toString() {
                 return mRequest.mRequests.get(0).requestId + " : "
-                        + (null != mOldNetwork ? mOldNetwork.network.netId : "null")
-                        + " → " + (null != mNewNetwork ? mNewNetwork.network.netId : "null");
+                        + (null != mOldNetwork ? mOldNetwork.network.getNetId() : "null")
+                        + " → " + (null != mNewNetwork ? mNewNetwork.network.getNetId() : "null");
             }
         }
 
@@ -7337,13 +7386,11 @@
             networkAgent.networkCapabilities.addCapability(NET_CAPABILITY_FOREGROUND);
 
             if (!createNativeNetwork(networkAgent)) return;
-            if (networkAgent.isVPN()) {
-                // Initialize the VPN capabilities to their starting values according to the
-                // underlying networks. This will avoid a spurious callback to
-                // onCapabilitiesUpdated being sent in updateAllVpnCapabilities below as
-                // the VPN would switch from its default, blank capabilities to those
-                // that reflect the capabilities of its underlying networks.
-                propagateUnderlyingNetworkCapabilities();
+            if (networkAgent.supportsUnderlyingNetworks()) {
+                // Initialize the network's capabilities to their starting values according to the
+                // underlying networks. This ensures that the capabilities are correct before
+                // anything happens to the network.
+                updateCapabilitiesForNetwork(networkAgent);
             }
             networkAgent.created = true;
         }
@@ -7385,10 +7432,6 @@
             // doing.
             updateSignalStrengthThresholds(networkAgent, "CONNECT", null);
 
-            if (networkAgent.supportsUnderlyingNetworks()) {
-                propagateUnderlyingNetworkCapabilities();
-            }
-
             // Consider network even though it is not yet validated.
             rematchAllNetworksAndRequests();
 
@@ -7794,7 +7837,7 @@
 
     private void logNetworkEvent(NetworkAgentInfo nai, int evtype) {
         int[] transports = nai.networkCapabilities.getTransportTypes();
-        mMetricsLog.log(nai.network.netId, transports, new NetworkEvent(evtype));
+        mMetricsLog.log(nai.network.getNetId(), transports, new NetworkEvent(evtype));
     }
 
     private static boolean toBool(int encodedBoolean) {
@@ -8416,6 +8459,6 @@
                     KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS);
         }
 
-        notifyDataStallSuspected(p, network.netId);
+        notifyDataStallSuspected(p, network.getNetId());
     }
 }
diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java
index a45466d..655d8ab 100644
--- a/services/core/java/com/android/server/TestNetworkService.java
+++ b/services/core/java/com/android/server/TestNetworkService.java
@@ -61,9 +61,8 @@
 
 /** @hide */
 class TestNetworkService extends ITestNetworkManager.Stub {
-    @NonNull private static final String TAG = TestNetworkService.class.getSimpleName();
     @NonNull private static final String TEST_NETWORK_LOGTAG = "TestNetworkAgent";
-    @NonNull private static final String TEST_NETWORK_PROVIDER_NAME = TAG;
+    @NonNull private static final String TEST_NETWORK_PROVIDER_NAME = "TestNetworkProvider";
     @NonNull private static final AtomicInteger sTestTunIndex = new AtomicInteger();
 
     @NonNull private final Context mContext;
@@ -168,17 +167,15 @@
         private TestNetworkAgent(
                 @NonNull Context context,
                 @NonNull Looper looper,
-                @NonNull NetworkAgentConfig config,
                 @NonNull NetworkCapabilities nc,
                 @NonNull LinkProperties lp,
+                @NonNull NetworkAgentConfig config,
                 int uid,
                 @NonNull IBinder binder,
                 @NonNull NetworkProvider np)
                 throws RemoteException {
             super(context, looper, TEST_NETWORK_LOGTAG, nc, lp, NETWORK_SCORE, config, np);
-
             mUid = uid;
-
             synchronized (mBinderLock) {
                 mBinder = binder; // Binder null-checks in create()
 
@@ -220,7 +217,7 @@
             // Has to be in TestNetworkAgent to ensure all teardown codepaths properly clean up
             // resources, even for binder death or unwanted calls.
             synchronized (mTestNetworkTracker) {
-                mTestNetworkTracker.remove(getNetwork().netId);
+                mTestNetworkTracker.remove(getNetwork().getNetId());
             }
         }
     }
@@ -286,8 +283,8 @@
             lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null, iface));
         }
 
-        final TestNetworkAgent agent = new TestNetworkAgent(context, looper,
-                new NetworkAgentConfig.Builder().build(), nc, lp, callingUid, binder,
+        final TestNetworkAgent agent = new TestNetworkAgent(context, looper, nc, lp,
+                new NetworkAgentConfig.Builder().build(), callingUid, binder,
                 mNetworkProvider);
         agent.register();
         agent.markConnected();
@@ -339,7 +336,7 @@
                                 administratorUids,
                                 binder);
 
-                mTestNetworkTracker.put(agent.getNetwork().netId, agent);
+                mTestNetworkTracker.put(agent.getNetwork().getNetId(), agent);
             }
         } catch (SocketException e) {
             throw new UncheckedIOException(e);
diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java
index 1f0fb5e..c70bb08 100644
--- a/services/core/java/com/android/server/connectivity/DnsManager.java
+++ b/services/core/java/com/android/server/connectivity/DnsManager.java
@@ -34,7 +34,6 @@
 import android.net.IDnsResolver;
 import android.net.LinkProperties;
 import android.net.Network;
-import android.net.NetworkUtils;
 import android.net.ResolverOptionsParcel;
 import android.net.ResolverParamsParcel;
 import android.net.Uri;
@@ -50,6 +49,7 @@
 
 import java.net.InetAddress;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -59,7 +59,6 @@
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.stream.Collectors;
 
-
 /**
  * Encapsulate the management of DNS settings for networks.
  *
@@ -266,23 +265,23 @@
     }
 
     public void removeNetwork(Network network) {
-        mPrivateDnsMap.remove(network.netId);
-        mPrivateDnsValidationMap.remove(network.netId);
-        mTransportsMap.remove(network.netId);
-        mLinkPropertiesMap.remove(network.netId);
+        mPrivateDnsMap.remove(network.getNetId());
+        mPrivateDnsValidationMap.remove(network.getNetId());
+        mTransportsMap.remove(network.getNetId());
+        mLinkPropertiesMap.remove(network.getNetId());
     }
 
     // This is exclusively called by ConnectivityService#dumpNetworkDiagnostics() which
     // is not on the ConnectivityService handler thread.
     public PrivateDnsConfig getPrivateDnsConfig(@NonNull Network network) {
-        return mPrivateDnsMap.getOrDefault(network.netId, PRIVATE_DNS_OFF);
+        return mPrivateDnsMap.getOrDefault(network.getNetId(), PRIVATE_DNS_OFF);
     }
 
     public PrivateDnsConfig updatePrivateDns(Network network, PrivateDnsConfig cfg) {
         Log.w(TAG, "updatePrivateDns(" + network + ", " + cfg + ")");
         return (cfg != null)
-                ? mPrivateDnsMap.put(network.netId, cfg)
-                : mPrivateDnsMap.remove(network.netId);
+                ? mPrivateDnsMap.put(network.getNetId(), cfg)
+                : mPrivateDnsMap.remove(network.getNetId());
     }
 
     public void updatePrivateDnsStatus(int netId, LinkProperties lp) {
@@ -309,8 +308,7 @@
     }
 
     public void updatePrivateDnsValidation(PrivateDnsValidationUpdate update) {
-        final PrivateDnsValidationStatuses statuses =
-                mPrivateDnsValidationMap.get(update.netId);
+        final PrivateDnsValidationStatuses statuses = mPrivateDnsValidationMap.get(update.netId);
         if (statuses == null) return;
         statuses.updateStatus(update);
     }
@@ -364,12 +362,11 @@
         paramsParcel.successThreshold = mSuccessThreshold;
         paramsParcel.minSamples = mMinSamples;
         paramsParcel.maxSamples = mMaxSamples;
-        paramsParcel.servers =
-                NetworkUtils.makeStrings(lp.getDnsServers());
+        paramsParcel.servers = makeStrings(lp.getDnsServers());
         paramsParcel.domains = getDomainStrings(lp.getDomains());
         paramsParcel.tlsName = strictMode ? privateDnsCfg.hostname : "";
         paramsParcel.tlsServers =
-                strictMode ? NetworkUtils.makeStrings(
+                strictMode ? makeStrings(
                         Arrays.stream(privateDnsCfg.ips)
                               .filter((ip) -> lp.isReachable(ip))
                               .collect(Collectors.toList()))
@@ -460,6 +457,21 @@
         return Settings.Global.getInt(mContentResolver, which, dflt);
     }
 
+    /**
+     * Create a string array of host addresses from a collection of InetAddresses
+     *
+     * @param addrs a Collection of InetAddresses
+     * @return an array of Strings containing their host addresses
+     */
+    private String[] makeStrings(Collection<InetAddress> addrs) {
+        String[] result = new String[addrs.size()];
+        int i = 0;
+        for (InetAddress addr : addrs) {
+            result[i++] = addr.getHostAddress();
+        }
+        return result;
+    }
+
     private static String getPrivateDnsMode(ContentResolver cr) {
         String mode = getStringSetting(cr, PRIVATE_DNS_MODE);
         if (TextUtils.isEmpty(mode)) mode = getStringSetting(cr, PRIVATE_DNS_DEFAULT_MODE);
diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
index 8625a6f..96cbfde 100644
--- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
+++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
@@ -40,11 +40,11 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.net.ISocketKeepaliveCallback;
+import android.net.InetAddresses;
 import android.net.InvalidPacketException;
 import android.net.KeepalivePacketData;
 import android.net.NattKeepalivePacketData;
 import android.net.NetworkAgent;
-import android.net.NetworkUtils;
 import android.net.SocketKeepalive.InvalidSocketException;
 import android.net.TcpKeepalivePacketData;
 import android.net.util.KeepaliveUtils;
@@ -625,8 +625,8 @@
 
         InetAddress srcAddress, dstAddress;
         try {
-            srcAddress = NetworkUtils.numericToInetAddress(srcAddrString);
-            dstAddress = NetworkUtils.numericToInetAddress(dstAddrString);
+            srcAddress = InetAddresses.parseNumericAddress(srcAddrString);
+            dstAddress = InetAddresses.parseNumericAddress(dstAddrString);
         } catch (IllegalArgumentException e) {
             notifyErrorCallback(cb, ERROR_INVALID_IP_ADDRESS);
             return;
diff --git a/services/core/java/com/android/server/connectivity/LingerMonitor.java b/services/core/java/com/android/server/connectivity/LingerMonitor.java
index f99f4c6..adec7ad 100644
--- a/services/core/java/com/android/server/connectivity/LingerMonitor.java
+++ b/services/core/java/com/android/server/connectivity/LingerMonitor.java
@@ -114,7 +114,7 @@
 
     private int getNotificationSource(NetworkAgentInfo toNai) {
         for (int i = 0; i < mNotifications.size(); i++) {
-            if (mNotifications.valueAt(i) == toNai.network.netId) {
+            if (mNotifications.valueAt(i) == toNai.network.getNetId()) {
                 return mNotifications.keyAt(i);
             }
         }
@@ -122,7 +122,7 @@
     }
 
     private boolean everNotified(NetworkAgentInfo nai) {
-        return mEverNotified.get(nai.network.netId, false);
+        return mEverNotified.get(nai.network.getNetId(), false);
     }
 
     @VisibleForTesting
@@ -153,7 +153,7 @@
     }
 
     private void showNotification(NetworkAgentInfo fromNai, NetworkAgentInfo toNai) {
-        mNotifier.showNotification(fromNai.network.netId, NotificationType.NETWORK_SWITCH,
+        mNotifier.showNotification(fromNai.network.getNetId(), NotificationType.NETWORK_SWITCH,
                 fromNai, toNai, createNotificationIntent(), true);
     }
 
@@ -208,8 +208,8 @@
                     + " type=" + sNotifyTypeNames.get(notifyType, "unknown(" + notifyType + ")"));
         }
 
-        mNotifications.put(fromNai.network.netId, toNai.network.netId);
-        mEverNotified.put(fromNai.network.netId, true);
+        mNotifications.put(fromNai.network.getNetId(), toNai.network.getNetId());
+        mEverNotified.put(fromNai.network.getNetId(), true);
     }
 
     /**
@@ -295,8 +295,8 @@
     }
 
     public void noteDisconnect(NetworkAgentInfo nai) {
-        mNotifications.delete(nai.network.netId);
-        mEverNotified.delete(nai.network.netId);
+        mNotifications.delete(nai.network.getNetId());
+        mEverNotified.delete(nai.network.getNetId());
         maybeStopNotifying(nai);
         // No need to cancel notifications on nai: NetworkMonitor does that on disconnect.
     }
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index d9c2e80..c1b1b6a 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -528,6 +528,6 @@
 
     @VisibleForTesting
     protected int getNetId() {
-        return mNetwork.network.netId;
+        return mNetwork.network.getNetId();
     }
 }
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 3270dd5..52b9f5c 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -138,9 +138,10 @@
     // not guaranteed to be current or correct, or even to exist.
     public @Nullable Network[] declaredUnderlyingNetworks;
 
-    // Whether this network is always metered even if its underlying networks are unmetered.
-    // Only relevant if #supportsUnderlyingNetworks is true.
-    public boolean declaredMetered;
+    // The capabilities originally announced by the NetworkAgent, regardless of any capabilities
+    // that were added or removed due to this network's underlying networks.
+    // Only set if #supportsUnderlyingNetworks is true.
+    public @Nullable NetworkCapabilities declaredCapabilities;
 
     // Indicates if netd has been told to create this Network. From this point on the appropriate
     // routing rules are setup and routes are added so packets can begin flowing over the Network.
@@ -610,7 +611,7 @@
         if (newExpiry > 0) {
             mLingerMessage = new WakeupMessage(
                     mContext, mHandler,
-                    "NETWORK_LINGER_COMPLETE." + network.netId /* cmdName */,
+                    "NETWORK_LINGER_COMPLETE." + network.getNetId() /* cmdName */,
                     EVENT_NETWORK_LINGER_COMPLETE /* cmd */,
                     0 /* arg1 (unused) */, 0 /* arg2 (unused) */,
                     this /* obj (NetworkAgentInfo) */);
@@ -701,7 +702,7 @@
      * This represents the network with something like "[100 WIFI|VPN]" or "[108 MOBILE]".
      */
     public String toShortString() {
-        return "[" + network.netId + " "
+        return "[" + network.getNetId() + " "
                 + transportNamesOf(networkCapabilities.getTransportTypes()) + "]";
     }
 
diff --git a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
index 49c16ad..a7be657 100644
--- a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
+++ b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
@@ -20,10 +20,10 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.net.InetAddresses;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.Network;
-import android.net.NetworkUtils;
 import android.net.RouteInfo;
 import android.net.TrafficStats;
 import android.net.shared.PrivateDnsConfig;
@@ -97,8 +97,8 @@
 public class NetworkDiagnostics {
     private static final String TAG = "NetworkDiagnostics";
 
-    private static final InetAddress TEST_DNS4 = NetworkUtils.numericToInetAddress("8.8.8.8");
-    private static final InetAddress TEST_DNS6 = NetworkUtils.numericToInetAddress(
+    private static final InetAddress TEST_DNS4 = InetAddresses.parseNumericAddress("8.8.8.8");
+    private static final InetAddress TEST_DNS6 = InetAddresses.parseNumericAddress(
             "2001:4860:4860::8888");
 
     // For brevity elsewhere.
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index 4c63eb4..d507b5f 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -35,7 +35,6 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.PackageManagerInternal;
-import android.content.pm.UserInfo;
 import android.net.INetd;
 import android.net.UidRange;
 import android.os.Build;
@@ -174,11 +173,9 @@
             netdPermsUids.put(uid, netdPermsUids.get(uid) | otherNetdPerms);
         }
 
-        List<UserInfo> users = mUserManager.getAliveUsers();
-        if (users != null) {
-            for (UserInfo user : users) {
-                mUsers.add(user.id);
-            }
+        final List<UserHandle> users = mUserManager.getUserHandles(true /* excludeDying */);
+        for (UserHandle user : users) {
+            mUsers.add(user.getIdentifier());
         }
 
         final SparseArray<ArraySet<String>> systemPermission =
diff --git a/tests/net/common/java/android/net/LinkAddressTest.java b/tests/net/common/java/android/net/LinkAddressTest.java
index 60308e3..1eaf30c 100644
--- a/tests/net/common/java/android/net/LinkAddressTest.java
+++ b/tests/net/common/java/android/net/LinkAddressTest.java
@@ -68,8 +68,8 @@
 
     private static final String V4 = "192.0.2.1";
     private static final String V6 = "2001:db8::1";
-    private static final InetAddress V4_ADDRESS = NetworkUtils.numericToInetAddress(V4);
-    private static final InetAddress V6_ADDRESS = NetworkUtils.numericToInetAddress(V6);
+    private static final InetAddress V4_ADDRESS = InetAddresses.parseNumericAddress(V4);
+    private static final InetAddress V6_ADDRESS = InetAddresses.parseNumericAddress(V6);
 
     @Test
     public void testConstants() {
@@ -131,10 +131,10 @@
             ipv6Loopback = new LinkAddress(addrs.get(0));
         }
 
-        assertEquals(NetworkUtils.numericToInetAddress("127.0.0.1"), ipv4Loopback.getAddress());
+        assertEquals(InetAddresses.parseNumericAddress("127.0.0.1"), ipv4Loopback.getAddress());
         assertEquals(8, ipv4Loopback.getPrefixLength());
 
-        assertEquals(NetworkUtils.numericToInetAddress("::1"), ipv6Loopback.getAddress());
+        assertEquals(InetAddresses.parseNumericAddress("::1"), ipv6Loopback.getAddress());
         assertEquals(128, ipv6Loopback.getPrefixLength());
 
         // Null addresses are rejected.
diff --git a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
index 2a24d1a..3d4dc4d 100644
--- a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
+++ b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
@@ -29,7 +29,7 @@
 import static junit.framework.Assert.assertTrue;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.fail;
 
 import android.content.Context;
 import android.net.ConnectivityManager;
@@ -38,7 +38,6 @@
 import android.net.NetworkAgent;
 import android.net.NetworkAgentConfig;
 import android.net.NetworkCapabilities;
-import android.net.NetworkInfo;
 import android.net.NetworkProvider;
 import android.net.NetworkSpecifier;
 import android.net.SocketKeepalive;
@@ -53,9 +52,9 @@
 import com.android.testutils.TestableNetworkCallback;
 
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork {
-    private final NetworkInfo mNetworkInfo;
     private final NetworkCapabilities mNetworkCapabilities;
     private final HandlerThread mHandlerThread;
     private final Context mContext;
@@ -63,6 +62,7 @@
 
     private final ConditionVariable mDisconnected = new ConditionVariable();
     private final ConditionVariable mPreventReconnectReceived = new ConditionVariable();
+    private final AtomicBoolean mConnected = new AtomicBoolean(false);
     private int mScore;
     private NetworkAgent mNetworkAgent;
     private int mStartKeepaliveError = SocketKeepalive.ERROR_UNSUPPORTED;
@@ -76,7 +76,6 @@
             NetworkCapabilities ncTemplate, Context context) throws Exception {
         final int type = transportToLegacyType(transport);
         final String typeName = ConnectivityManager.getNetworkTypeName(type);
-        mNetworkInfo = new NetworkInfo(type, 0, typeName, "Mock");
         mNetworkCapabilities = (ncTemplate != null) ? ncTemplate : new NetworkCapabilities();
         mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
         mNetworkCapabilities.addTransportType(transport);
@@ -108,22 +107,29 @@
         mHandlerThread = new HandlerThread(mLogTag);
         mHandlerThread.start();
 
-        mNetworkAgent = makeNetworkAgent(linkProperties);
+        mNetworkAgent = makeNetworkAgent(linkProperties, type, typeName);
     }
 
-    protected InstrumentedNetworkAgent makeNetworkAgent(LinkProperties linkProperties)
+    protected InstrumentedNetworkAgent makeNetworkAgent(LinkProperties linkProperties,
+            final int type, final String typeName)
             throws Exception {
-        return new InstrumentedNetworkAgent(this, linkProperties);
+        return new InstrumentedNetworkAgent(this, linkProperties, type, typeName);
     }
 
     public static class InstrumentedNetworkAgent extends NetworkAgent {
         private final NetworkAgentWrapper mWrapper;
+        private static final String PROVIDER_NAME = "InstrumentedNetworkAgentProvider";
 
-        public InstrumentedNetworkAgent(NetworkAgentWrapper wrapper, LinkProperties lp) {
-            super(wrapper.mHandlerThread.getLooper(), wrapper.mContext, wrapper.mLogTag,
-                    wrapper.mNetworkInfo, wrapper.mNetworkCapabilities, lp, wrapper.mScore,
-                    new NetworkAgentConfig(), NetworkProvider.ID_NONE);
+        public InstrumentedNetworkAgent(NetworkAgentWrapper wrapper, LinkProperties lp,
+                final int type, final String typeName) {
+            super(wrapper.mContext, wrapper.mHandlerThread.getLooper(), wrapper.mLogTag,
+                    wrapper.mNetworkCapabilities, lp, wrapper.mScore,
+                    new NetworkAgentConfig.Builder()
+                            .setLegacyType(type).setLegacyTypeName(typeName).build(),
+                    new NetworkProvider(wrapper.mContext, wrapper.mHandlerThread.getLooper(),
+                            PROVIDER_NAME));
             mWrapper = wrapper;
+            register();
         }
 
         @Override
@@ -212,10 +218,12 @@
     }
 
     public void connect() {
-        assertNotEquals("MockNetworkAgents can only be connected once",
-                mNetworkInfo.getDetailedState(), NetworkInfo.DetailedState.CONNECTED);
-        mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
-        mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+        if (!mConnected.compareAndSet(false /* expect */, true /* update */)) {
+            // compareAndSet returns false when the value couldn't be updated because it did not
+            // match the expected value.
+            fail("Test NetworkAgents can only be connected once");
+        }
+        mNetworkAgent.markConnected();
     }
 
     public void suspend() {
@@ -227,8 +235,7 @@
     }
 
     public void disconnect() {
-        mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null);
-        mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+        mNetworkAgent.unregister();
     }
 
     @Override
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 7a1cb25..8c403f1 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.app.PendingIntent.FLAG_IMMUTABLE;
 import static android.content.Intent.ACTION_USER_ADDED;
 import static android.content.Intent.ACTION_USER_REMOVED;
 import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
@@ -181,13 +182,13 @@
 import android.net.NetworkStackClient;
 import android.net.NetworkState;
 import android.net.NetworkTestResultParcelable;
-import android.net.NetworkUtils;
 import android.net.ProxyInfo;
 import android.net.ResolverParamsParcel;
 import android.net.RouteInfo;
 import android.net.RouteInfoParcel;
 import android.net.SocketKeepalive;
 import android.net.UidRange;
+import android.net.UidRangeParcel;
 import android.net.Uri;
 import android.net.VpnManager;
 import android.net.metrics.IpConnectivityLog;
@@ -646,8 +647,8 @@
         }
 
         @Override
-        protected InstrumentedNetworkAgent makeNetworkAgent(LinkProperties linkProperties)
-                throws Exception {
+        protected InstrumentedNetworkAgent makeNetworkAgent(LinkProperties linkProperties,
+                final int type, final String typeName) throws Exception {
             mNetworkMonitor = mock(INetworkMonitor.class);
 
             final Answer validateAnswer = inv -> {
@@ -666,7 +667,8 @@
                     any() /* name */,
                     nmCbCaptor.capture());
 
-            final InstrumentedNetworkAgent na = new InstrumentedNetworkAgent(this, linkProperties) {
+            final InstrumentedNetworkAgent na = new InstrumentedNetworkAgent(this, linkProperties,
+                    type, typeName) {
                 @Override
                 public void networkStatus(int status, String redirectUrl) {
                     mRedirectUrl = redirectUrl;
@@ -1054,7 +1056,7 @@
 
         public MockVpn(int userId) {
             super(startHandlerThreadAndReturnLooper(), mServiceContext, mNetworkManagementService,
-                    userId, mock(KeyStore.class));
+                    mMockNetd, userId, mock(KeyStore.class));
             mConfig = new VpnConfig();
         }
 
@@ -1093,10 +1095,11 @@
             mMockNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN, lp,
                     mNetworkCapabilities);
             mMockNetworkAgent.waitForIdle(TIMEOUT_MS);
-            verify(mNetworkManagementService, times(1))
-                    .addVpnUidRanges(eq(mMockVpn.getNetId()), eq(uids.toArray(new UidRange[0])));
-            verify(mNetworkManagementService, never())
-                    .removeVpnUidRanges(eq(mMockVpn.getNetId()), any());
+
+            verify(mMockNetd, times(1)).networkAddUidRanges(eq(mMockVpn.getNetId()),
+                    eq(toUidRangeStableParcels(uids)));
+            verify(mMockNetd, never())
+                    .networkRemoveUidRanges(eq(mMockVpn.getNetId()), any());
             mAgentRegistered = true;
             mNetworkCapabilities.set(mMockNetworkAgent.getNetworkCapabilities());
             mNetworkAgent = mMockNetworkAgent.getNetworkAgent();
@@ -1168,6 +1171,11 @@
         }
     }
 
+    private UidRangeParcel[] toUidRangeStableParcels(final @NonNull Set<UidRange> ranges) {
+        return ranges.stream().map(
+                r -> new UidRangeParcel(r.start, r.stop)).toArray(UidRangeParcel[]::new);
+    }
+
     private void mockVpn(int uid) {
         synchronized (mService.mVpns) {
             int userId = UserHandle.getUserId(uid);
@@ -1958,6 +1966,37 @@
     }
 
     @Test
+    public void testOwnerUidCannotChange() throws Exception {
+        // Owner UIDs are not visible without location permission.
+        setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
+                Manifest.permission.ACCESS_FINE_LOCATION);
+
+        final NetworkCapabilities ncTemplate = new NetworkCapabilities();
+        final int originalOwnerUid = Process.myUid();
+        ncTemplate.setOwnerUid(originalOwnerUid);
+
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, new LinkProperties(),
+                ncTemplate);
+        mWiFiNetworkAgent.connect(false);
+        waitForIdle();
+
+        // Send ConnectivityService an update to the mWiFiNetworkAgent's capabilities that changes
+        // the owner UID and an unrelated capability.
+        NetworkCapabilities agentCapabilities = mWiFiNetworkAgent.getNetworkCapabilities();
+        assertEquals(originalOwnerUid, agentCapabilities.getOwnerUid());
+        agentCapabilities.setOwnerUid(42);
+        assertFalse(agentCapabilities.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
+        agentCapabilities.addCapability(NET_CAPABILITY_NOT_CONGESTED);
+        mWiFiNetworkAgent.setNetworkCapabilities(agentCapabilities, true);
+        waitForIdle();
+
+        // Check that the capability change has been applied but the owner UID is not modified.
+        NetworkCapabilities nc = mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork());
+        assertEquals(originalOwnerUid, nc.getOwnerUid());
+        assertTrue(nc.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
+    }
+
+    @Test
     public void testMultipleLingering() throws Exception {
         // This test would be flaky with the default 120ms timer: that is short enough that
         // lingered networks are torn down before assertions can be run. We don't want to mock the
@@ -2517,7 +2556,8 @@
 
     @Test
     public void testNoMutableNetworkRequests() throws Exception {
-        PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, new Intent("a"), 0);
+        final PendingIntent pendingIntent = PendingIntent.getBroadcast(
+                mContext, 0 /* requestCode */, new Intent("a"), FLAG_IMMUTABLE);
         NetworkRequest request1 = new NetworkRequest.Builder()
                 .addCapability(NET_CAPABILITY_VALIDATED)
                 .build();
@@ -3179,7 +3219,7 @@
 
         assertThrows(SecurityException.class, () ->
                 mCm.registerNetworkCallback(r, PendingIntent.getService(
-                        mServiceContext, 0, new Intent(), 0)));
+                        mServiceContext, 0 /* requestCode */, new Intent(), FLAG_IMMUTABLE)));
 
         // Requesting a Network with signal strength should get IllegalArgumentException.
         assertThrows(IllegalArgumentException.class, () ->
@@ -3187,7 +3227,7 @@
 
         assertThrows(IllegalArgumentException.class, () ->
                 mCm.requestNetwork(r, PendingIntent.getService(
-                        mServiceContext, 0, new Intent(), 0)));
+                        mServiceContext, 0 /* requestCode */, new Intent(), FLAG_IMMUTABLE)));
     }
 
     @Test
@@ -4651,12 +4691,14 @@
         }
         j = 0;
         while (j++ < INTENTS / 2) {
-            PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, new Intent("a" + j), 0);
+            final PendingIntent pi = PendingIntent.getBroadcast(mContext, 0 /* requestCode */,
+                    new Intent("a" + j), FLAG_IMMUTABLE);
             mCm.requestNetwork(networkRequest, pi);
             registered.add(pi);
         }
         while (j++ < INTENTS) {
-            PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, new Intent("b" + j), 0);
+            final PendingIntent pi = PendingIntent.getBroadcast(mContext, 0 /* requestCode */,
+                    new Intent("b" + j), FLAG_IMMUTABLE);
             mCm.registerNetworkCallback(networkRequest, pi);
             registered.add(pi);
         }
@@ -4670,11 +4712,13 @@
         );
         assertThrows(TooManyRequestsException.class, () ->
                 mCm.requestNetwork(networkRequest,
-                        PendingIntent.getBroadcast(mContext, 0, new Intent("c"), 0))
+                        PendingIntent.getBroadcast(mContext, 0 /* requestCode */,
+                                new Intent("c"), FLAG_IMMUTABLE))
         );
         assertThrows(TooManyRequestsException.class, () ->
                 mCm.registerNetworkCallback(networkRequest,
-                        PendingIntent.getBroadcast(mContext, 0, new Intent("d"), 0))
+                        PendingIntent.getBroadcast(mContext, 0 /* requestCode */,
+                                new Intent("d"), FLAG_IMMUTABLE))
         );
 
         for (Object o : registered) {
@@ -4703,16 +4747,16 @@
         waitForIdle();
 
         for (int i = 0; i < MAX_REQUESTS; i++) {
-            PendingIntent pendingIntent =
-                    PendingIntent.getBroadcast(mContext, 0, new Intent("e" + i), 0);
+            final PendingIntent pendingIntent = PendingIntent.getBroadcast(
+                    mContext, 0 /* requestCode */, new Intent("e" + i), FLAG_IMMUTABLE);
             mCm.requestNetwork(networkRequest, pendingIntent);
             mCm.unregisterNetworkCallback(pendingIntent);
         }
         waitForIdle();
 
         for (int i = 0; i < MAX_REQUESTS; i++) {
-            PendingIntent pendingIntent =
-                    PendingIntent.getBroadcast(mContext, 0, new Intent("f" + i), 0);
+            final PendingIntent pendingIntent = PendingIntent.getBroadcast(
+                    mContext, 0 /* requestCode */, new Intent("f" + i), FLAG_IMMUTABLE);
             mCm.registerNetworkCallback(networkRequest, pendingIntent);
             mCm.unregisterNetworkCallback(pendingIntent);
         }
@@ -4790,7 +4834,7 @@
         lp.setInterfaceName(WIFI_IFNAME);
         LinkAddress myIpv4Address = new LinkAddress("192.168.12.3/24");
         RouteInfo myIpv4DefaultRoute = new RouteInfo((IpPrefix) null,
-                NetworkUtils.numericToInetAddress("192.168.12.1"), lp.getInterfaceName());
+                InetAddresses.parseNumericAddress("192.168.12.1"), lp.getInterfaceName());
         lp.addLinkAddress(myIpv4Address);
         lp.addRoute(myIpv4DefaultRoute);
 
@@ -4910,8 +4954,8 @@
         expectForceUpdateIfaces(onlyCell, MOBILE_IFNAME);
         reset(mStatsService);
 
-        // Captive portal change shouldn't update ifaces
-        mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL);
+        // Temp metered change shouldn't update ifaces
+        mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED);
         waitForIdle();
         verify(mStatsService, never())
                 .forceUpdateIfaces(eq(onlyCell), any(NetworkState[].class), eq(MOBILE_IFNAME),
@@ -5427,6 +5471,7 @@
         final Network wifi = mWiFiNetworkAgent.getNetwork();
 
         final NetworkCapabilities initialCaps = new NetworkCapabilities();
+        initialCaps.addTransportType(TRANSPORT_VPN);
         initialCaps.addCapability(NET_CAPABILITY_INTERNET);
         initialCaps.removeCapability(NET_CAPABILITY_NOT_VPN);
 
@@ -5458,44 +5503,45 @@
         withWifiAndMobileUnderlying.setLinkDownstreamBandwidthKbps(10);
         withWifiAndMobileUnderlying.setLinkUpstreamBandwidthKbps(20);
 
+        final NetworkCapabilities initialCapsNotMetered = new NetworkCapabilities(initialCaps);
+        initialCapsNotMetered.addCapability(NET_CAPABILITY_NOT_METERED);
+
         NetworkCapabilities caps = new NetworkCapabilities(initialCaps);
-        final boolean notDeclaredMetered = false;
-        mService.applyUnderlyingCapabilities(new Network[]{}, caps, notDeclaredMetered);
+        mService.applyUnderlyingCapabilities(new Network[]{}, initialCapsNotMetered, caps);
         assertEquals(withNoUnderlying, caps);
 
         caps = new NetworkCapabilities(initialCaps);
-        mService.applyUnderlyingCapabilities(new Network[]{null}, caps, notDeclaredMetered);
+        mService.applyUnderlyingCapabilities(new Network[]{null}, initialCapsNotMetered, caps);
         assertEquals(withNoUnderlying, caps);
 
         caps = new NetworkCapabilities(initialCaps);
-        mService.applyUnderlyingCapabilities(new Network[]{mobile}, caps, notDeclaredMetered);
+        mService.applyUnderlyingCapabilities(new Network[]{mobile}, initialCapsNotMetered, caps);
         assertEquals(withMobileUnderlying, caps);
 
-        mService.applyUnderlyingCapabilities(new Network[]{wifi}, caps, notDeclaredMetered);
+        mService.applyUnderlyingCapabilities(new Network[]{wifi}, initialCapsNotMetered, caps);
         assertEquals(withWifiUnderlying, caps);
 
-        final boolean isDeclaredMetered = true;
         withWifiUnderlying.removeCapability(NET_CAPABILITY_NOT_METERED);
         caps = new NetworkCapabilities(initialCaps);
-        mService.applyUnderlyingCapabilities(new Network[]{wifi}, caps, isDeclaredMetered);
+        mService.applyUnderlyingCapabilities(new Network[]{wifi}, initialCaps, caps);
         assertEquals(withWifiUnderlying, caps);
 
         caps = new NetworkCapabilities(initialCaps);
-        mService.applyUnderlyingCapabilities(new Network[]{mobile, wifi}, caps, isDeclaredMetered);
+        mService.applyUnderlyingCapabilities(new Network[]{mobile, wifi}, initialCaps, caps);
         assertEquals(withWifiAndMobileUnderlying, caps);
 
         withWifiUnderlying.addCapability(NET_CAPABILITY_NOT_METERED);
         caps = new NetworkCapabilities(initialCaps);
         mService.applyUnderlyingCapabilities(new Network[]{null, mobile, null, wifi},
-                caps, notDeclaredMetered);
+                initialCapsNotMetered, caps);
         assertEquals(withWifiAndMobileUnderlying, caps);
 
         caps = new NetworkCapabilities(initialCaps);
         mService.applyUnderlyingCapabilities(new Network[]{null, mobile, null, wifi},
-                caps, notDeclaredMetered);
+                initialCapsNotMetered, caps);
         assertEquals(withWifiAndMobileUnderlying, caps);
 
-        mService.applyUnderlyingCapabilities(null, caps, notDeclaredMetered);
+        mService.applyUnderlyingCapabilities(null, initialCapsNotMetered, caps);
         assertEquals(withWifiUnderlying, caps);
     }
 
diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
index 529d03c..799bcc8 100644
--- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
@@ -34,6 +34,7 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.net.INetd;
+import android.net.InetAddresses;
 import android.net.IpSecAlgorithm;
 import android.net.IpSecConfig;
 import android.net.IpSecManager;
@@ -44,7 +45,6 @@
 import android.net.IpSecUdpEncapResponse;
 import android.net.LinkAddress;
 import android.net.Network;
-import android.net.NetworkUtils;
 import android.os.Binder;
 import android.os.INetworkManagementService;
 import android.os.ParcelFileDescriptor;
@@ -272,7 +272,7 @@
 
         IpSecSpiResponse spi =
                 mIpSecService.allocateSecurityParameterIndex(
-                        NetworkUtils.numericToInetAddress(remoteAddress).getHostAddress(),
+                        InetAddresses.parseNumericAddress(remoteAddress).getHostAddress(),
                         IpSecManager.INVALID_SECURITY_PARAMETER_INDEX,
                         new Binder());
         return spi.resourceId;
diff --git a/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java b/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
index c53462c..950d716 100644
--- a/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
+++ b/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
@@ -130,6 +130,7 @@
 
         when(mContext.getResources()).thenReturn(mResources);
         when(mContext.getApplicationInfo()).thenReturn(new ApplicationInfo());
+        // Mock user id to all users that Context#registerReceiver will register with all users too.
         doReturn(UserHandle.ALL.getIdentifier()).when(mUserAllContext).getUserId();
         when(mContext.createContextAsUser(eq(UserHandle.ALL), anyInt()))
                 .thenReturn(mUserAllContext);
diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
index de35f91..3556c72 100644
--- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -58,7 +58,6 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
-import android.content.pm.UserInfo;
 import android.net.INetd;
 import android.net.UidRange;
 import android.os.Build;
@@ -123,10 +122,10 @@
         MockitoAnnotations.initMocks(this);
         when(mContext.getPackageManager()).thenReturn(mPackageManager);
         when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager);
-        when(mUserManager.getAliveUsers()).thenReturn(
-                Arrays.asList(new UserInfo[] {
-                        new UserInfo(MOCK_USER1, "", 0),
-                        new UserInfo(MOCK_USER2, "", 0),
+        when(mUserManager.getUserHandles(eq(true))).thenReturn(
+                Arrays.asList(new UserHandle[] {
+                        new UserHandle(MOCK_USER1),
+                        new UserHandle(MOCK_USER2),
                 }));
 
         mPermissionMonitor = spy(new PermissionMonitor(mContext, mNetdService, mDeps));
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index 337507a..6e380be 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -58,6 +58,7 @@
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.net.ConnectivityManager;
+import android.net.INetd;
 import android.net.Ikev2VpnProfile;
 import android.net.InetAddresses;
 import android.net.IpPrefix;
@@ -70,6 +71,7 @@
 import android.net.NetworkInfo.DetailedState;
 import android.net.RouteInfo;
 import android.net.UidRange;
+import android.net.UidRangeParcel;
 import android.net.VpnManager;
 import android.net.VpnService;
 import android.net.ipsec.ike.IkeSessionCallback;
@@ -172,11 +174,13 @@
             mPackages.put(PKGS[i], PKG_UIDS[i]);
         }
     }
+    private static final UidRange PRI_USER_RANGE = UidRange.createForUser(primaryUser.id);
 
     @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext;
     @Mock private UserManager mUserManager;
     @Mock private PackageManager mPackageManager;
     @Mock private INetworkManagementService mNetService;
+    @Mock private INetd mNetd;
     @Mock private AppOpsManager mAppOps;
     @Mock private NotificationManager mNotificationManager;
     @Mock private Vpn.SystemServices mSystemServices;
@@ -256,8 +260,7 @@
                 null, null);
 
         assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
-            UidRange.createForUser(primaryUser.id),
-            UidRange.createForUser(restrictedProfileA.id)
+                PRI_USER_RANGE, UidRange.createForUser(restrictedProfileA.id)
         })), ranges);
     }
 
@@ -269,9 +272,7 @@
         final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
                 null, null);
 
-        assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
-            UidRange.createForUser(primaryUser.id)
-        })), ranges);
+        assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] { PRI_USER_RANGE })), ranges);
     }
 
     @Test
@@ -282,15 +283,13 @@
         final Set<UidRange> ranges = new ArraySet<>();
         vpn.addUserToRanges(ranges, primaryUser.id, null, null);
 
-        assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
-            UidRange.createForUser(primaryUser.id)
-        })), ranges);
+        assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] { PRI_USER_RANGE })), ranges);
     }
 
     @Test
     public void testUidAllowAndDenylist() throws Exception {
         final Vpn vpn = createVpn(primaryUser.id);
-        final UidRange user = UidRange.createForUser(primaryUser.id);
+        final UidRange user = PRI_USER_RANGE;
         final String[] packages = {PKGS[0], PKGS[1], PKGS[2]};
 
         // Allowed list
@@ -339,62 +338,67 @@
     @Test
     public void testLockdownChangingPackage() throws Exception {
         final Vpn vpn = createVpn(primaryUser.id);
-        final UidRange user = UidRange.createForUser(primaryUser.id);
+        final UidRange user = PRI_USER_RANGE;
 
         // Default state.
-        assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
+        assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1],
+                user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
 
         // Set always-on without lockdown.
         assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, null, mKeyStore));
-        assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
+        assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1],
+                user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
 
         // Set always-on with lockdown.
         assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, null, mKeyStore));
-        verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
-            new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
-            new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
+        verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(new UidRangeParcel[] {
+                new UidRangeParcel(user.start, user.start + PKG_UIDS[1] - 1),
+                new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.stop)
         }));
-        assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
+
+        assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[2],
+                user.start + PKG_UIDS[3]);
         assertUnblocked(vpn, user.start + PKG_UIDS[1]);
 
         // Switch to another app.
         assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null, mKeyStore));
-        verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
-            new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
-            new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
+        verify(mNetd).networkRejectNonSecureVpn(eq(false), aryEq(new UidRangeParcel[] {
+                new UidRangeParcel(user.start, user.start + PKG_UIDS[1] - 1),
+                new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.stop)
         }));
-        verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
-            new UidRange(user.start, user.start + PKG_UIDS[3] - 1),
-            new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
+
+        verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(new UidRangeParcel[] {
+                new UidRangeParcel(user.start, user.start + PKG_UIDS[3] - 1),
+                new UidRangeParcel(user.start + PKG_UIDS[3] + 1, user.stop)
         }));
-        assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]);
+        assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1],
+                user.start + PKG_UIDS[2]);
         assertUnblocked(vpn, user.start + PKG_UIDS[3]);
     }
 
     @Test
     public void testLockdownAllowlist() throws Exception {
         final Vpn vpn = createVpn(primaryUser.id);
-        final UidRange user = UidRange.createForUser(primaryUser.id);
+        final UidRange user = PRI_USER_RANGE;
 
         // Set always-on with lockdown and allow app PKGS[2] from lockdown.
         assertTrue(vpn.setAlwaysOnPackage(
                 PKGS[1], true, Collections.singletonList(PKGS[2]), mKeyStore));
-        verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
-                new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
-                new UidRange(user.start + PKG_UIDS[2] + 1, user.stop)
+        verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(new UidRangeParcel[] {
+                new UidRangeParcel(user.start, user.start + PKG_UIDS[1] - 1),
+                new UidRangeParcel(user.start + PKG_UIDS[2] + 1, user.stop)
         }));
         assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[3]);
         assertUnblocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]);
-
         // Change allowed app list to PKGS[3].
         assertTrue(vpn.setAlwaysOnPackage(
                 PKGS[1], true, Collections.singletonList(PKGS[3]), mKeyStore));
-        verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
-                new UidRange(user.start + PKG_UIDS[2] + 1, user.stop)
+        verify(mNetd).networkRejectNonSecureVpn(eq(false), aryEq(new UidRangeParcel[] {
+                new UidRangeParcel(user.start + PKG_UIDS[2] + 1, user.stop)
         }));
-        verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
-                new UidRange(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1),
-                new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
+        verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(new UidRangeParcel[] {
+                new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1),
+                new UidRangeParcel(user.start + PKG_UIDS[3] + 1, user.stop)
         }));
         assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[2]);
         assertUnblocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[3]);
@@ -402,25 +406,25 @@
         // Change the VPN app.
         assertTrue(vpn.setAlwaysOnPackage(
                 PKGS[0], true, Collections.singletonList(PKGS[3]), mKeyStore));
-        verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
-                new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
-                new UidRange(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1)
+        verify(mNetd).networkRejectNonSecureVpn(eq(false), aryEq(new UidRangeParcel[] {
+                new UidRangeParcel(user.start, user.start + PKG_UIDS[1] - 1),
+                new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1)
         }));
-        verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
-                new UidRange(user.start, user.start + PKG_UIDS[0] - 1),
-                new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1)
+        verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(new UidRangeParcel[] {
+                new UidRangeParcel(user.start, user.start + PKG_UIDS[0] - 1),
+                new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1)
         }));
         assertBlocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]);
         assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[3]);
 
         // Remove the list of allowed packages.
         assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, null, mKeyStore));
-        verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
-                new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1),
-                new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
+        verify(mNetd).networkRejectNonSecureVpn(eq(false), aryEq(new UidRangeParcel[] {
+                new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1),
+                new UidRangeParcel(user.start + PKG_UIDS[3] + 1, user.stop)
         }));
-        verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
-                new UidRange(user.start + PKG_UIDS[0] + 1, user.stop),
+        verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(new UidRangeParcel[] {
+                new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.stop),
         }));
         assertBlocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2],
                 user.start + PKG_UIDS[3]);
@@ -429,12 +433,12 @@
         // Add the list of allowed packages.
         assertTrue(vpn.setAlwaysOnPackage(
                 PKGS[0], true, Collections.singletonList(PKGS[1]), mKeyStore));
-        verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
-                new UidRange(user.start + PKG_UIDS[0] + 1, user.stop)
+        verify(mNetd).networkRejectNonSecureVpn(eq(false), aryEq(new UidRangeParcel[] {
+                new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.stop)
         }));
-        verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
-                new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1),
-                new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
+        verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(new UidRangeParcel[] {
+                new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1),
+                new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.stop)
         }));
         assertBlocked(vpn, user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
         assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1]);
@@ -447,13 +451,13 @@
         // allowed package should change from PGKS[1] to PKGS[2].
         assertTrue(vpn.setAlwaysOnPackage(
                 PKGS[0], true, Arrays.asList("com.foo.app", PKGS[2], "com.bar.app"), mKeyStore));
-        verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[]{
-                new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1),
-                new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
+        verify(mNetd).networkRejectNonSecureVpn(eq(false), aryEq(new UidRangeParcel[]{
+                new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1),
+                new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.stop)
         }));
-        verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[]{
-                new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[2] - 1),
-                new UidRange(user.start + PKG_UIDS[2] + 1, user.stop)
+        verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(new UidRangeParcel[]{
+                new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[2] - 1),
+                new UidRangeParcel(user.start + PKG_UIDS[2] + 1, user.stop)
         }));
     }
 
@@ -467,86 +471,86 @@
                 restrictedProfileA.flags);
         tempProfile.restrictedProfileParentId = primaryUser.id;
 
-        final UidRange user = UidRange.createForUser(primaryUser.id);
+        final UidRange user = PRI_USER_RANGE;
         final UidRange profile = UidRange.createForUser(tempProfile.id);
 
         // Set lockdown.
         assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null, mKeyStore));
-        verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
-            new UidRange(user.start, user.start + PKG_UIDS[3] - 1),
-            new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
+        verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(new UidRangeParcel[] {
+                new UidRangeParcel(user.start, user.start + PKG_UIDS[3] - 1),
+                new UidRangeParcel(user.start + PKG_UIDS[3] + 1, user.stop)
         }));
-
         // Verify restricted user isn't affected at first.
         assertUnblocked(vpn, profile.start + PKG_UIDS[0]);
 
         // Add the restricted user.
         setMockedUsers(primaryUser, tempProfile);
         vpn.onUserAdded(tempProfile.id);
-        verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
-            new UidRange(profile.start, profile.start + PKG_UIDS[3] - 1),
-            new UidRange(profile.start + PKG_UIDS[3] + 1, profile.stop)
+        verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(new UidRangeParcel[] {
+                new UidRangeParcel(profile.start, profile.start + PKG_UIDS[3] - 1),
+                new UidRangeParcel(profile.start + PKG_UIDS[3] + 1, profile.stop)
         }));
 
         // Remove the restricted user.
         tempProfile.partial = true;
         vpn.onUserRemoved(tempProfile.id);
-        verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
-            new UidRange(profile.start, profile.start + PKG_UIDS[3] - 1),
-            new UidRange(profile.start + PKG_UIDS[3] + 1, profile.stop)
+        verify(mNetd).networkRejectNonSecureVpn(eq(false), aryEq(new UidRangeParcel[] {
+                new UidRangeParcel(profile.start, profile.start + PKG_UIDS[3] - 1),
+                new UidRangeParcel(profile.start + PKG_UIDS[3] + 1, profile.stop)
         }));
     }
 
     @Test
     public void testLockdownRuleRepeatability() throws Exception {
         final Vpn vpn = createVpn(primaryUser.id);
-
+        final UidRangeParcel[] primaryUserRangeParcel = new UidRangeParcel[] {
+                new UidRangeParcel(PRI_USER_RANGE.start, PRI_USER_RANGE.stop)};
         // Given legacy lockdown is already enabled,
         vpn.setLockdown(true);
-        verify(mNetService, times(1)).setAllowOnlyVpnForUids(
-                eq(true), aryEq(new UidRange[] {UidRange.createForUser(primaryUser.id)}));
+
+        verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(primaryUserRangeParcel));
 
         // Enabling legacy lockdown twice should do nothing.
         vpn.setLockdown(true);
-        verify(mNetService, times(1)).setAllowOnlyVpnForUids(anyBoolean(), any(UidRange[].class));
+        verify(mNetd, times(1))
+                .networkRejectNonSecureVpn(anyBoolean(), any(UidRangeParcel[].class));
 
         // And disabling should remove the rules exactly once.
         vpn.setLockdown(false);
-        verify(mNetService, times(1)).setAllowOnlyVpnForUids(
-                eq(false), aryEq(new UidRange[] {UidRange.createForUser(primaryUser.id)}));
+        verify(mNetd).networkRejectNonSecureVpn(eq(false), aryEq(primaryUserRangeParcel));
 
         // Removing the lockdown again should have no effect.
         vpn.setLockdown(false);
-        verify(mNetService, times(2)).setAllowOnlyVpnForUids(anyBoolean(), any(UidRange[].class));
+        verify(mNetd, times(2)).networkRejectNonSecureVpn(
+                anyBoolean(), any(UidRangeParcel[].class));
     }
 
     @Test
     public void testLockdownRuleReversibility() throws Exception {
         final Vpn vpn = createVpn(primaryUser.id);
-
-        final UidRange[] entireUser = {
-            UidRange.createForUser(primaryUser.id)
+        final UidRangeParcel[] entireUser = {
+            new UidRangeParcel(PRI_USER_RANGE.start, PRI_USER_RANGE.stop)
         };
-        final UidRange[] exceptPkg0 = {
-            new UidRange(entireUser[0].start, entireUser[0].start + PKG_UIDS[0] - 1),
-            new UidRange(entireUser[0].start + PKG_UIDS[0] + 1, entireUser[0].stop)
+        final UidRangeParcel[] exceptPkg0 = {
+            new UidRangeParcel(entireUser[0].start, entireUser[0].start + PKG_UIDS[0] - 1),
+            new UidRangeParcel(entireUser[0].start + PKG_UIDS[0] + 1, entireUser[0].stop)
         };
 
-        final InOrder order = inOrder(mNetService);
+        final InOrder order = inOrder(mNetd);
 
         // Given lockdown is enabled with no package (legacy VPN),
         vpn.setLockdown(true);
-        order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(entireUser));
+        order.verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(entireUser));
 
         // When a new VPN package is set the rules should change to cover that package.
         vpn.prepare(null, PKGS[0], VpnManager.TYPE_VPN_SERVICE);
-        order.verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(entireUser));
-        order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(exceptPkg0));
+        order.verify(mNetd).networkRejectNonSecureVpn(eq(false), aryEq(entireUser));
+        order.verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(exceptPkg0));
 
         // When that VPN package is unset, everything should be undone again in reverse.
         vpn.prepare(null, VpnConfig.LEGACY_VPN, VpnManager.TYPE_VPN_SERVICE);
-        order.verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(exceptPkg0));
-        order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(entireUser));
+        order.verify(mNetd).networkRejectNonSecureVpn(eq(false), aryEq(exceptPkg0));
+        order.verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(entireUser));
     }
 
     @Test
@@ -1186,7 +1190,7 @@
                 .thenReturn(asUserContext);
         final TestLooper testLooper = new TestLooper();
         final Vpn vpn = new Vpn(testLooper.getLooper(), mContext, new TestDeps(), mNetService,
-                userId, mKeyStore, mSystemServices, mIkev2SessionCreator);
+                mNetd, userId, mKeyStore, mSystemServices, mIkev2SessionCreator);
         verify(mConnectivityManager, times(1)).registerNetworkProvider(argThat(
                 provider -> provider.getName().contains("VpnNetworkProvider")
         ));