Merge "Update frameworks to use unbundled version of BouncyCastle."
diff --git a/core/java/android/net/NetworkState.java b/core/java/android/net/NetworkState.java
index 713b688..e1ef8b5 100644
--- a/core/java/android/net/NetworkState.java
+++ b/core/java/android/net/NetworkState.java
@@ -16,6 +16,7 @@
 
 package android.net;
 
+import android.annotation.NonNull;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.os.Parcel;
@@ -30,7 +31,8 @@
 public class NetworkState implements Parcelable {
     private static final boolean VALIDATE_ROAMING_STATE = false;
 
-    public static final NetworkState EMPTY = new NetworkState(null, null, null, null, null, null);
+    // TODO: remove and make members @NonNull.
+    public static final NetworkState EMPTY = new NetworkState();
 
     public final NetworkInfo networkInfo;
     public final LinkProperties linkProperties;
@@ -40,9 +42,18 @@
     public final String subscriberId;
     public final String networkId;
 
-    public NetworkState(NetworkInfo networkInfo, LinkProperties linkProperties,
-            NetworkCapabilities networkCapabilities, Network network, String subscriberId,
-            String networkId) {
+    private NetworkState() {
+        networkInfo = null;
+        linkProperties = null;
+        networkCapabilities = null;
+        network = null;
+        subscriberId = null;
+        networkId = null;
+    }
+
+    public NetworkState(@NonNull NetworkInfo networkInfo, @NonNull LinkProperties linkProperties,
+            @NonNull NetworkCapabilities networkCapabilities, @NonNull Network network,
+            String subscriberId, String networkId) {
         this.networkInfo = networkInfo;
         this.linkProperties = linkProperties;
         this.networkCapabilities = networkCapabilities;
diff --git a/core/java/android/net/CaptivePortal.java b/framework/src/android/net/CaptivePortal.java
similarity index 100%
rename from core/java/android/net/CaptivePortal.java
rename to framework/src/android/net/CaptivePortal.java
diff --git a/framework/src/android/net/CaptivePortalData.aidl b/framework/src/android/net/CaptivePortalData.aidl
new file mode 100644
index 0000000..1d57ee7
--- /dev/null
+++ b/framework/src/android/net/CaptivePortalData.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+@JavaOnlyStableParcelable parcelable CaptivePortalData;
diff --git a/core/java/android/net/CaptivePortalData.java b/framework/src/android/net/CaptivePortalData.java
similarity index 100%
rename from core/java/android/net/CaptivePortalData.java
rename to framework/src/android/net/CaptivePortalData.java
diff --git a/framework/src/android/net/ConnectionInfo.aidl b/framework/src/android/net/ConnectionInfo.aidl
new file mode 100644
index 0000000..07faf8b
--- /dev/null
+++ b/framework/src/android/net/ConnectionInfo.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** Copyright (C) 2018 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.net;
+
+parcelable ConnectionInfo;
diff --git a/core/java/android/net/ConnectionInfo.java b/framework/src/android/net/ConnectionInfo.java
similarity index 100%
rename from core/java/android/net/ConnectionInfo.java
rename to framework/src/android/net/ConnectionInfo.java
diff --git a/framework/src/android/net/ConnectivityDiagnosticsManager.aidl b/framework/src/android/net/ConnectivityDiagnosticsManager.aidl
new file mode 100644
index 0000000..82ba0ca
--- /dev/null
+++ b/framework/src/android/net/ConnectivityDiagnosticsManager.aidl
@@ -0,0 +1,21 @@
+/**
+ *
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+parcelable ConnectivityDiagnosticsManager.ConnectivityReport;
+parcelable ConnectivityDiagnosticsManager.DataStallReport;
\ No newline at end of file
diff --git a/core/java/android/net/ConnectivityDiagnosticsManager.java b/framework/src/android/net/ConnectivityDiagnosticsManager.java
similarity index 100%
rename from core/java/android/net/ConnectivityDiagnosticsManager.java
rename to framework/src/android/net/ConnectivityDiagnosticsManager.java
diff --git a/framework/src/android/net/ConnectivityFrameworkInitializer.java b/framework/src/android/net/ConnectivityFrameworkInitializer.java
new file mode 100644
index 0000000..9afa5d1
--- /dev/null
+++ b/framework/src/android/net/ConnectivityFrameworkInitializer.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.SystemApi;
+import android.app.SystemServiceRegistry;
+import android.content.Context;
+
+/**
+ * Class for performing registration for all core connectivity services.
+ *
+ * @hide
+ */
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+public final class ConnectivityFrameworkInitializer {
+    private ConnectivityFrameworkInitializer() {}
+
+    /**
+     * Called by {@link SystemServiceRegistry}'s static initializer and registers all core
+     * connectivity services to {@link Context}, so that {@link Context#getSystemService} can
+     * return them.
+     *
+     * @throws IllegalStateException if this is called anywhere besides
+     * {@link SystemServiceRegistry}.
+     */
+    public static void registerServiceWrappers() {
+        // registerContextAwareService will throw if this is called outside of SystemServiceRegistry
+        // initialization.
+        SystemServiceRegistry.registerContextAwareService(
+                Context.CONNECTIVITY_SERVICE,
+                ConnectivityManager.class,
+                (context, serviceBinder) -> {
+                    IConnectivityManager icm = IConnectivityManager.Stub.asInterface(serviceBinder);
+                    return new ConnectivityManager(context, icm);
+                }
+        );
+
+        // TODO: move outside of the connectivity JAR
+        SystemServiceRegistry.registerContextAwareService(
+                Context.VPN_MANAGEMENT_SERVICE,
+                VpnManager.class,
+                (context) -> {
+                    final ConnectivityManager cm = context.getSystemService(
+                            ConnectivityManager.class);
+                    return cm.createVpnManager();
+                }
+        );
+
+        SystemServiceRegistry.registerContextAwareService(
+                Context.CONNECTIVITY_DIAGNOSTICS_SERVICE,
+                ConnectivityDiagnosticsManager.class,
+                (context) -> {
+                    final ConnectivityManager cm = context.getSystemService(
+                            ConnectivityManager.class);
+                    return cm.createDiagnosticsManager();
+                }
+        );
+
+        SystemServiceRegistry.registerContextAwareService(
+                Context.TEST_NETWORK_SERVICE,
+                TestNetworkManager.class,
+                context -> {
+                    final ConnectivityManager cm = context.getSystemService(
+                            ConnectivityManager.class);
+                    return cm.startOrGetTestNetworkManager();
+                }
+        );
+    }
+}
diff --git a/core/java/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java
similarity index 96%
rename from core/java/android/net/ConnectivityManager.java
rename to framework/src/android/net/ConnectivityManager.java
index d107261..987dcc4 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/framework/src/android/net/ConnectivityManager.java
@@ -15,7 +15,9 @@
  */
 package android.net;
 
+import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
 import static android.net.IpSecManager.INVALID_RESOURCE_ID;
+import static android.net.NetworkRequest.Type.BACKGROUND_REQUEST;
 import static android.net.NetworkRequest.Type.LISTEN;
 import static android.net.NetworkRequest.Type.REQUEST;
 import static android.net.NetworkRequest.Type.TRACK_DEFAULT;
@@ -28,6 +30,7 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.app.PendingIntent;
@@ -4820,6 +4823,28 @@
         }
     }
 
+    /** @hide */
+    public TestNetworkManager startOrGetTestNetworkManager() {
+        final IBinder tnBinder;
+        try {
+            tnBinder = mService.startOrGetTestNetworkService();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+
+        return new TestNetworkManager(ITestNetworkManager.Stub.asInterface(tnBinder));
+    }
+
+    /** @hide */
+    public VpnManager createVpnManager() {
+        return new VpnManager(mContext, mService);
+    }
+
+    /** @hide */
+    public ConnectivityDiagnosticsManager createDiagnosticsManager() {
+        return new ConnectivityDiagnosticsManager(mContext, mService);
+    }
+
     /**
      * Simulates a Data Stall for the specified Network.
      *
@@ -4964,4 +4989,92 @@
         }
         return null;
     }
+
+    /**
+     * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}, but
+     * does not cause any networks to retain the NET_CAPABILITY_FOREGROUND capability. This can
+     * be used to request that the system provide a network without causing the network to be
+     * in the foreground.
+     *
+     * <p>This method will attempt to find the best network that matches the passed
+     * {@link NetworkRequest}, and to bring up one that does if none currently satisfies the
+     * criteria. The platform will evaluate which network is the best at its own discretion.
+     * Throughput, latency, cost per byte, policy, user preference and other considerations
+     * may be factored in the decision of what is considered the best network.
+     *
+     * <p>As long as this request is outstanding, the platform will try to maintain the best network
+     * matching this request, while always attempting to match the request to a better network if
+     * possible. If a better match is found, the platform will switch this request to the now-best
+     * network and inform the app of the newly best network by invoking
+     * {@link NetworkCallback#onAvailable(Network)} on the provided callback. Note that the platform
+     * will not try to maintain any other network than the best one currently matching the request:
+     * a network not matching any network request may be disconnected at any time.
+     *
+     * <p>For example, an application could use this method to obtain a connected cellular network
+     * even if the device currently has a data connection over Ethernet. This may cause the cellular
+     * radio to consume additional power. Or, an application could inform the system that it wants
+     * a network supporting sending MMSes and have the system let it know about the currently best
+     * MMS-supporting network through the provided {@link NetworkCallback}.
+     *
+     * <p>The status of the request can be followed by listening to the various callbacks described
+     * in {@link NetworkCallback}. The {@link Network} object passed to the callback methods can be
+     * used to direct traffic to the network (although accessing some networks may be subject to
+     * holding specific permissions). Callers will learn about the specific characteristics of the
+     * network through
+     * {@link NetworkCallback#onCapabilitiesChanged(Network, NetworkCapabilities)} and
+     * {@link NetworkCallback#onLinkPropertiesChanged(Network, LinkProperties)}. The methods of the
+     * provided {@link NetworkCallback} will only be invoked due to changes in the best network
+     * matching the request at any given time; therefore when a better network matching the request
+     * becomes available, the {@link NetworkCallback#onAvailable(Network)} method is called
+     * with the new network after which no further updates are given about the previously-best
+     * network, unless it becomes the best again at some later time. All callbacks are invoked
+     * in order on the same thread, which by default is a thread created by the framework running
+     * in the app.
+     *
+     * <p>This{@link NetworkRequest} will live until released via
+     * {@link #unregisterNetworkCallback(NetworkCallback)} or the calling application exits, at
+     * which point the system may let go of the network at any time.
+     *
+     * <p>It is presently unsupported to request a network with mutable
+     * {@link NetworkCapabilities} such as
+     * {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED} or
+     * {@link NetworkCapabilities#NET_CAPABILITY_CAPTIVE_PORTAL}
+     * as these {@code NetworkCapabilities} represent states that a particular
+     * network may never attain, and whether a network will attain these states
+     * is unknown prior to bringing up the network so the framework does not
+     * know how to go about satisfying a request with these capabilities.
+     *
+     * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
+     * number of outstanding requests to 100 per app (identified by their UID), shared with
+     * all variants of this method, of {@link #registerNetworkCallback} as well as
+     * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}.
+     * Requesting a network with this method will count toward this limit. If this limit is
+     * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources,
+     * make sure to unregister the callbacks with
+     * {@link #unregisterNetworkCallback(NetworkCallback)}.
+     *
+     * @param request {@link NetworkRequest} describing this request.
+     * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
+     *                If null, the callback is invoked on the default internal Handler.
+     * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
+     *                        the callback must not be shared - it uniquely specifies this request.
+     * @throws IllegalArgumentException if {@code request} contains invalid network capabilities.
+     * @throws SecurityException if missing the appropriate permissions.
+     * @throws RuntimeException if the app already has too many callbacks registered.
+     *
+     * @hide
+     */
+    @SystemApi(client = MODULE_LIBRARIES)
+    @SuppressLint("ExecutorRegistration")
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_SETTINGS,
+            android.Manifest.permission.NETWORK_STACK,
+            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
+    })
+    public void requestBackgroundNetwork(@NonNull NetworkRequest request,
+            @Nullable Handler handler, @NonNull NetworkCallback networkCallback) {
+        final NetworkCapabilities nc = request.networkCapabilities;
+        sendRequestForNetwork(nc, networkCallback, 0, BACKGROUND_REQUEST,
+                TYPE_NONE, handler == null ? getDefaultHandler() : new CallbackHandler(handler));
+    }
 }
diff --git a/framework/src/android/net/ConnectivityMetricsEvent.aidl b/framework/src/android/net/ConnectivityMetricsEvent.aidl
new file mode 100644
index 0000000..1c541dc
--- /dev/null
+++ b/framework/src/android/net/ConnectivityMetricsEvent.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+/** {@hide} */
+parcelable ConnectivityMetricsEvent;
diff --git a/core/java/android/net/ConnectivityThread.java b/framework/src/android/net/ConnectivityThread.java
similarity index 100%
rename from core/java/android/net/ConnectivityThread.java
rename to framework/src/android/net/ConnectivityThread.java
diff --git a/framework/src/android/net/DhcpInfo.aidl b/framework/src/android/net/DhcpInfo.aidl
new file mode 100644
index 0000000..29cd21f
--- /dev/null
+++ b/framework/src/android/net/DhcpInfo.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2008, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ *
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+
+package android.net;
+
+parcelable DhcpInfo;
diff --git a/core/java/android/net/DhcpInfo.java b/framework/src/android/net/DhcpInfo.java
similarity index 100%
rename from core/java/android/net/DhcpInfo.java
rename to framework/src/android/net/DhcpInfo.java
diff --git a/core/java/android/net/DnsResolver.java b/framework/src/android/net/DnsResolver.java
similarity index 100%
rename from core/java/android/net/DnsResolver.java
rename to framework/src/android/net/DnsResolver.java
diff --git a/framework/src/android/net/ICaptivePortal.aidl b/framework/src/android/net/ICaptivePortal.aidl
new file mode 100644
index 0000000..fe21905
--- /dev/null
+++ b/framework/src/android/net/ICaptivePortal.aidl
@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+/**
+ * Interface to inform NetworkMonitor of decisions of app handling captive portal.
+ * @hide
+ */
+oneway interface ICaptivePortal {
+    void appRequest(int request);
+    void appResponse(int response);
+    void logEvent(int eventId, String packageName);
+}
diff --git a/framework/src/android/net/IConnectivityDiagnosticsCallback.aidl b/framework/src/android/net/IConnectivityDiagnosticsCallback.aidl
new file mode 100644
index 0000000..82b64a9
--- /dev/null
+++ b/framework/src/android/net/IConnectivityDiagnosticsCallback.aidl
@@ -0,0 +1,28 @@
+/**
+ *
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.net.ConnectivityDiagnosticsManager;
+import android.net.Network;
+
+/** @hide */
+oneway interface IConnectivityDiagnosticsCallback {
+    void onConnectivityReportAvailable(in ConnectivityDiagnosticsManager.ConnectivityReport report);
+    void onDataStallSuspected(in ConnectivityDiagnosticsManager.DataStallReport report);
+    void onNetworkConnectivityReported(in Network n, boolean hasConnectivity);
+}
\ No newline at end of file
diff --git a/core/java/android/net/IConnectivityManager.aidl b/framework/src/android/net/IConnectivityManager.aidl
similarity index 99%
rename from core/java/android/net/IConnectivityManager.aidl
rename to framework/src/android/net/IConnectivityManager.aidl
index 7197831..1b4d2e4 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/framework/src/android/net/IConnectivityManager.aidl
@@ -31,7 +31,6 @@
 import android.net.NetworkState;
 import android.net.ProxyInfo;
 import android.net.UidRange;
-import android.net.VpnInfo;
 import android.net.QosSocketInfo;
 import android.os.Bundle;
 import android.os.IBinder;
diff --git a/framework/src/android/net/ISocketKeepaliveCallback.aidl b/framework/src/android/net/ISocketKeepaliveCallback.aidl
new file mode 100644
index 0000000..020fbca
--- /dev/null
+++ b/framework/src/android/net/ISocketKeepaliveCallback.aidl
@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+/**
+ * Callback to provide status changes of keepalive offload.
+ *
+ * @hide
+ */
+oneway interface ISocketKeepaliveCallback
+{
+    /** The keepalive was successfully started. */
+    void onStarted(int slot);
+    /** The keepalive was successfully stopped. */
+    void onStopped();
+    /** The keepalive was stopped because of an error. */
+    void onError(int error);
+    /** The keepalive on a TCP socket was stopped because the socket received data. */
+    void onDataReceived();
+}
diff --git a/framework/src/android/net/ITestNetworkManager.aidl b/framework/src/android/net/ITestNetworkManager.aidl
new file mode 100644
index 0000000..2a863ad
--- /dev/null
+++ b/framework/src/android/net/ITestNetworkManager.aidl
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.TestNetworkInterface;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+
+/**
+ * Interface that allows for creation and management of test-only networks.
+ *
+ * @hide
+ */
+interface ITestNetworkManager
+{
+    TestNetworkInterface createTunInterface(in LinkAddress[] linkAddrs);
+    TestNetworkInterface createTapInterface();
+
+    void setupTestNetwork(in String iface, in LinkProperties lp, in boolean isMetered,
+            in int[] administratorUids, in IBinder binder);
+
+    void teardownTestNetwork(int netId);
+}
diff --git a/core/java/android/net/InetAddresses.java b/framework/src/android/net/InetAddresses.java
similarity index 100%
rename from core/java/android/net/InetAddresses.java
rename to framework/src/android/net/InetAddresses.java
diff --git a/framework/src/android/net/InterfaceConfiguration.aidl b/framework/src/android/net/InterfaceConfiguration.aidl
new file mode 100644
index 0000000..8aa5e34
--- /dev/null
+++ b/framework/src/android/net/InterfaceConfiguration.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2008, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ *
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+
+package android.net;
+
+parcelable InterfaceConfiguration;
diff --git a/core/java/android/net/InvalidPacketException.java b/framework/src/android/net/InvalidPacketException.java
similarity index 100%
rename from core/java/android/net/InvalidPacketException.java
rename to framework/src/android/net/InvalidPacketException.java
diff --git a/framework/src/android/net/IpConfiguration.aidl b/framework/src/android/net/IpConfiguration.aidl
new file mode 100644
index 0000000..7a30f0e
--- /dev/null
+++ b/framework/src/android/net/IpConfiguration.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+parcelable IpConfiguration;
diff --git a/core/java/android/net/IpConfiguration.java b/framework/src/android/net/IpConfiguration.java
similarity index 100%
rename from core/java/android/net/IpConfiguration.java
rename to framework/src/android/net/IpConfiguration.java
diff --git a/framework/src/android/net/IpPrefix.aidl b/framework/src/android/net/IpPrefix.aidl
new file mode 100644
index 0000000..0d70f2a
--- /dev/null
+++ b/framework/src/android/net/IpPrefix.aidl
@@ -0,0 +1,22 @@
+/**
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+// @JavaOnlyStableParcelable only affects the parcelable when built as stable aidl (aidl_interface
+// build rule). IpPrefix is also used in cpp but only as non-stable aidl.
+@JavaOnlyStableParcelable parcelable IpPrefix cpp_header "binder/IpPrefix.h";
diff --git a/core/java/android/net/IpPrefix.java b/framework/src/android/net/IpPrefix.java
similarity index 100%
rename from core/java/android/net/IpPrefix.java
rename to framework/src/android/net/IpPrefix.java
diff --git a/framework/src/android/net/KeepalivePacketData.aidl b/framework/src/android/net/KeepalivePacketData.aidl
new file mode 100644
index 0000000..d456b53
--- /dev/null
+++ b/framework/src/android/net/KeepalivePacketData.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+parcelable KeepalivePacketData;
diff --git a/core/java/android/net/KeepalivePacketData.java b/framework/src/android/net/KeepalivePacketData.java
similarity index 100%
rename from core/java/android/net/KeepalivePacketData.java
rename to framework/src/android/net/KeepalivePacketData.java
diff --git a/framework/src/android/net/LinkAddress.aidl b/framework/src/android/net/LinkAddress.aidl
new file mode 100644
index 0000000..9c804db
--- /dev/null
+++ b/framework/src/android/net/LinkAddress.aidl
@@ -0,0 +1,21 @@
+/**
+ *
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+@JavaOnlyStableParcelable parcelable LinkAddress;
+
diff --git a/core/java/android/net/LinkAddress.java b/framework/src/android/net/LinkAddress.java
similarity index 100%
rename from core/java/android/net/LinkAddress.java
rename to framework/src/android/net/LinkAddress.java
diff --git a/framework/src/android/net/LinkProperties.aidl b/framework/src/android/net/LinkProperties.aidl
new file mode 100644
index 0000000..a8b3c7b
--- /dev/null
+++ b/framework/src/android/net/LinkProperties.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** Copyright (C) 2010 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.net;
+
+@JavaOnlyStableParcelable parcelable LinkProperties;
diff --git a/core/java/android/net/LinkProperties.java b/framework/src/android/net/LinkProperties.java
similarity index 100%
rename from core/java/android/net/LinkProperties.java
rename to framework/src/android/net/LinkProperties.java
diff --git a/framework/src/android/net/MacAddress.aidl b/framework/src/android/net/MacAddress.aidl
new file mode 100644
index 0000000..48a18a7
--- /dev/null
+++ b/framework/src/android/net/MacAddress.aidl
@@ -0,0 +1,20 @@
+/**
+ *
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+@JavaOnlyStableParcelable parcelable MacAddress;
diff --git a/core/java/android/net/MacAddress.java b/framework/src/android/net/MacAddress.java
similarity index 100%
rename from core/java/android/net/MacAddress.java
rename to framework/src/android/net/MacAddress.java
diff --git a/core/java/android/net/NattKeepalivePacketData.java b/framework/src/android/net/NattKeepalivePacketData.java
similarity index 100%
rename from core/java/android/net/NattKeepalivePacketData.java
rename to framework/src/android/net/NattKeepalivePacketData.java
diff --git a/core/java/android/net/NattSocketKeepalive.java b/framework/src/android/net/NattSocketKeepalive.java
similarity index 100%
rename from core/java/android/net/NattSocketKeepalive.java
rename to framework/src/android/net/NattSocketKeepalive.java
diff --git a/framework/src/android/net/Network.aidl b/framework/src/android/net/Network.aidl
new file mode 100644
index 0000000..0562202
--- /dev/null
+++ b/framework/src/android/net/Network.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** Copyright (C) 2014 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.net;
+
+@JavaOnlyStableParcelable parcelable Network;
diff --git a/core/java/android/net/Network.java b/framework/src/android/net/Network.java
similarity index 94%
rename from core/java/android/net/Network.java
rename to framework/src/android/net/Network.java
index fbca7f1..b07bd68 100644
--- a/core/java/android/net/Network.java
+++ b/framework/src/android/net/Network.java
@@ -21,6 +21,7 @@
 import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
 import android.system.ErrnoException;
 import android.system.Os;
@@ -380,7 +381,13 @@
         // Query a property of the underlying socket to ensure that the socket's file descriptor
         // exists, is available to bind to a network and is not closed.
         socket.getReuseAddress();
-        bindSocket(socket.getFileDescriptor$());
+        final ParcelFileDescriptor pfd = ParcelFileDescriptor.fromDatagramSocket(socket);
+        bindSocket(pfd.getFileDescriptor());
+        // ParcelFileDescriptor.fromSocket() creates a dup of the original fd. The original and the
+        // dup share the underlying socket in the kernel. The socket is never truly closed until the
+        // last fd pointing to the socket being closed. So close the dup one after binding the
+        // socket to control the lifetime of the dup fd.
+        pfd.close();
     }
 
     /**
@@ -392,7 +399,13 @@
         // Query a property of the underlying socket to ensure that the socket's file descriptor
         // exists, is available to bind to a network and is not closed.
         socket.getReuseAddress();
-        bindSocket(socket.getFileDescriptor$());
+        final ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket);
+        bindSocket(pfd.getFileDescriptor());
+        // ParcelFileDescriptor.fromSocket() creates a dup of the original fd. The original and the
+        // dup share the underlying socket in the kernel. The socket is never truly closed until the
+        // last fd pointing to the socket being closed. So close the dup one after binding the
+        // socket to control the lifetime of the dup fd.
+        pfd.close();
     }
 
     /**
diff --git a/core/java/android/net/NetworkAgent.java b/framework/src/android/net/NetworkAgent.java
similarity index 100%
rename from core/java/android/net/NetworkAgent.java
rename to framework/src/android/net/NetworkAgent.java
diff --git a/framework/src/android/net/NetworkAgentConfig.aidl b/framework/src/android/net/NetworkAgentConfig.aidl
new file mode 100644
index 0000000..cb70bdd
--- /dev/null
+++ b/framework/src/android/net/NetworkAgentConfig.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+parcelable NetworkAgentConfig;
diff --git a/core/java/android/net/NetworkAgentConfig.java b/framework/src/android/net/NetworkAgentConfig.java
similarity index 98%
rename from core/java/android/net/NetworkAgentConfig.java
rename to framework/src/android/net/NetworkAgentConfig.java
index fe1268d..664c265 100644
--- a/core/java/android/net/NetworkAgentConfig.java
+++ b/framework/src/android/net/NetworkAgentConfig.java
@@ -16,6 +16,8 @@
 
 package android.net;
 
+import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
@@ -125,6 +127,7 @@
      * @return the subscriber ID, or null if none.
      * @hide
      */
+    @SystemApi(client = MODULE_LIBRARIES)
     @Nullable
     public String getSubscriberId() {
         return subscriberId;
@@ -275,6 +278,7 @@
          * @hide
          */
         @NonNull
+        @SystemApi(client = MODULE_LIBRARIES)
         public Builder setSubscriberId(@Nullable String subscriberId) {
             mConfig.subscriberId = subscriberId;
             return this;
diff --git a/framework/src/android/net/NetworkCapabilities.aidl b/framework/src/android/net/NetworkCapabilities.aidl
new file mode 100644
index 0000000..01d3286
--- /dev/null
+++ b/framework/src/android/net/NetworkCapabilities.aidl
@@ -0,0 +1,21 @@
+/*
+**
+** Copyright (C) 2014 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.net;
+
+@JavaOnlyStableParcelable parcelable NetworkCapabilities;
+
diff --git a/core/java/android/net/NetworkCapabilities.java b/framework/src/android/net/NetworkCapabilities.java
similarity index 97%
rename from core/java/android/net/NetworkCapabilities.java
rename to framework/src/android/net/NetworkCapabilities.java
index 0a895b9..8bfa77a 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/framework/src/android/net/NetworkCapabilities.java
@@ -34,9 +34,9 @@
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.BitUtils;
 import com.android.internal.util.Preconditions;
+import com.android.net.module.util.CollectionUtils;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -204,6 +204,7 @@
             NET_CAPABILITY_TEMPORARILY_NOT_METERED,
             NET_CAPABILITY_OEM_PRIVATE,
             NET_CAPABILITY_VEHICLE_INTERNAL,
+            NET_CAPABILITY_NOT_VCN_MANAGED,
     })
     public @interface NetCapability { }
 
@@ -399,8 +400,23 @@
     @SystemApi
     public static final int NET_CAPABILITY_VEHICLE_INTERNAL = 27;
 
+    /**
+     * Indicates that this network is not subsumed by a Virtual Carrier Network (VCN).
+     * <p>
+     * To provide an experience on a VCN similar to a single traditional carrier network, in
+     * some cases the system sets this bit is set by default in application's network requests,
+     * and may choose to remove it at its own discretion when matching the request to a network.
+     * <p>
+     * Applications that want to know about a Virtual Carrier Network's underlying networks,
+     * for example to use them for multipath purposes, should remove this bit from their network
+     * requests ; the system will not add it back once removed.
+     * @hide
+     */
+    @SystemApi
+    public static final int NET_CAPABILITY_NOT_VCN_MANAGED = 28;
+
     private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS;
-    private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_VEHICLE_INTERNAL;
+    private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_NOT_VCN_MANAGED;
 
     /**
      * Network capabilities that are expected to be mutable, i.e., can change while a particular
@@ -417,7 +433,8 @@
             | (1 << NET_CAPABILITY_NOT_CONGESTED)
             | (1 << NET_CAPABILITY_NOT_SUSPENDED)
             | (1 << NET_CAPABILITY_PARTIAL_CONNECTIVITY)
-            | (1 << NET_CAPABILITY_TEMPORARILY_NOT_METERED);
+            | (1 << NET_CAPABILITY_TEMPORARILY_NOT_METERED)
+            | (1 << NET_CAPABILITY_NOT_VCN_MANAGED);
 
     /**
      * Network capabilities that are not allowed in NetworkRequests. This exists because the
@@ -426,16 +443,21 @@
      * can get into a cycle where the NetworkFactory endlessly churns out NetworkAgents that then
      * get immediately torn down because they do not have the requested capability.
      */
+    // Note that as a historical exception, the TRUSTED and NOT_VCN_MANAGED capabilities
+    // are mutable but requestable. Factories are responsible for not getting
+    // in an infinite loop about these.
     private static final long NON_REQUESTABLE_CAPABILITIES =
-            MUTABLE_CAPABILITIES & ~(1 << NET_CAPABILITY_TRUSTED);
+            MUTABLE_CAPABILITIES
+            & ~(1 << NET_CAPABILITY_TRUSTED)
+            & ~(1 << NET_CAPABILITY_NOT_VCN_MANAGED);
 
     /**
      * Capabilities that are set by default when the object is constructed.
      */
     private static final long DEFAULT_CAPABILITIES =
-            (1 << NET_CAPABILITY_NOT_RESTRICTED) |
-            (1 << NET_CAPABILITY_TRUSTED) |
-            (1 << NET_CAPABILITY_NOT_VPN);
+            (1 << NET_CAPABILITY_NOT_RESTRICTED)
+            | (1 << NET_CAPABILITY_TRUSTED)
+            | (1 << NET_CAPABILITY_NOT_VPN);
 
     /**
      * Capabilities that suggest that a network is restricted.
@@ -495,7 +517,8 @@
             | (1 << NET_CAPABILITY_NOT_VPN)
             | (1 << NET_CAPABILITY_NOT_ROAMING)
             | (1 << NET_CAPABILITY_NOT_CONGESTED)
-            | (1 << NET_CAPABILITY_NOT_SUSPENDED);
+            | (1 << NET_CAPABILITY_NOT_SUSPENDED)
+            | (1 << NET_CAPABILITY_NOT_VCN_MANAGED);
 
     /**
      * Adds the given capability to this {@code NetworkCapability} instance.
@@ -751,7 +774,7 @@
         if (originalOwnerUid == creatorUid) {
             setOwnerUid(creatorUid);
         }
-        if (ArrayUtils.contains(originalAdministratorUids, creatorUid)) {
+        if (CollectionUtils.contains(originalAdministratorUids, creatorUid)) {
             setAdministratorUids(new int[] {creatorUid});
         }
         // There is no need to clear the UIDs, they have already been cleared by clearAll() above.
@@ -1857,7 +1880,7 @@
             sb.append(" OwnerUid: ").append(mOwnerUid);
         }
 
-        if (!ArrayUtils.isEmpty(mAdministratorUids)) {
+        if (mAdministratorUids != null && mAdministratorUids.length != 0) {
             sb.append(" AdminUids: ").append(Arrays.toString(mAdministratorUids));
         }
 
@@ -1982,6 +2005,7 @@
             case NET_CAPABILITY_TEMPORARILY_NOT_METERED:    return "TEMPORARILY_NOT_METERED";
             case NET_CAPABILITY_OEM_PRIVATE:          return "OEM_PRIVATE";
             case NET_CAPABILITY_VEHICLE_INTERNAL:     return "NET_CAPABILITY_VEHICLE_INTERNAL";
+            case NET_CAPABILITY_NOT_VCN_MANAGED:      return "NOT_VCN_MANAGED";
             default:                                  return Integer.toString(capability);
         }
     }
@@ -2489,7 +2513,7 @@
         @NonNull
         public NetworkCapabilities build() {
             if (mCaps.getOwnerUid() != Process.INVALID_UID) {
-                if (!ArrayUtils.contains(mCaps.getAdministratorUids(), mCaps.getOwnerUid())) {
+                if (!CollectionUtils.contains(mCaps.getAdministratorUids(), mCaps.getOwnerUid())) {
                     throw new IllegalStateException("The owner UID must be included in "
                             + " administrator UIDs.");
                 }
diff --git a/core/java/android/net/NetworkConfig.java b/framework/src/android/net/NetworkConfig.java
similarity index 100%
rename from core/java/android/net/NetworkConfig.java
rename to framework/src/android/net/NetworkConfig.java
diff --git a/framework/src/android/net/NetworkInfo.aidl b/framework/src/android/net/NetworkInfo.aidl
new file mode 100644
index 0000000..f501873
--- /dev/null
+++ b/framework/src/android/net/NetworkInfo.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ *
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+
+package android.net;
+
+parcelable NetworkInfo;
diff --git a/core/java/android/net/NetworkInfo.java b/framework/src/android/net/NetworkInfo.java
similarity index 100%
rename from core/java/android/net/NetworkInfo.java
rename to framework/src/android/net/NetworkInfo.java
diff --git a/core/java/android/net/NetworkProvider.java b/framework/src/android/net/NetworkProvider.java
similarity index 100%
rename from core/java/android/net/NetworkProvider.java
rename to framework/src/android/net/NetworkProvider.java
diff --git a/framework/src/android/net/NetworkRequest.aidl b/framework/src/android/net/NetworkRequest.aidl
new file mode 100644
index 0000000..508defc
--- /dev/null
+++ b/framework/src/android/net/NetworkRequest.aidl
@@ -0,0 +1,20 @@
+/**
+ * Copyright (c) 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+parcelable NetworkRequest;
+
diff --git a/core/java/android/net/NetworkRequest.java b/framework/src/android/net/NetworkRequest.java
similarity index 98%
rename from core/java/android/net/NetworkRequest.java
rename to framework/src/android/net/NetworkRequest.java
index f0c637c..04011fc 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/framework/src/android/net/NetworkRequest.java
@@ -353,7 +353,9 @@
          *                         NetworkSpecifier.
          */
         public Builder setNetworkSpecifier(NetworkSpecifier networkSpecifier) {
-            MatchAllNetworkSpecifier.checkNotMatchAllNetworkSpecifier(networkSpecifier);
+            if (networkSpecifier instanceof MatchAllNetworkSpecifier) {
+                throw new IllegalArgumentException("A MatchAllNetworkSpecifier is not permitted");
+            }
             mNetworkCapabilities.setNetworkSpecifier(networkSpecifier);
             return this;
         }
diff --git a/core/java/android/net/NetworkUtils.java b/framework/src/android/net/NetworkUtils.java
similarity index 100%
rename from core/java/android/net/NetworkUtils.java
rename to framework/src/android/net/NetworkUtils.java
diff --git a/framework/src/android/net/PacProxySelector.java b/framework/src/android/net/PacProxySelector.java
new file mode 100644
index 0000000..326943a
--- /dev/null
+++ b/framework/src/android/net/PacProxySelector.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.os.ServiceManager;
+import android.util.Log;
+
+import com.android.net.IProxyService;
+
+import com.google.android.collect.Lists;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.MalformedURLException;
+import java.net.Proxy;
+import java.net.Proxy.Type;
+import java.net.ProxySelector;
+import java.net.SocketAddress;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.List;
+
+/**
+ * @hide
+ */
+public class PacProxySelector extends ProxySelector {
+    private static final String TAG = "PacProxySelector";
+    public static final String PROXY_SERVICE = "com.android.net.IProxyService";
+    private static final String SOCKS = "SOCKS ";
+    private static final String PROXY = "PROXY ";
+
+    private IProxyService mProxyService;
+    private final List<Proxy> mDefaultList;
+
+    public PacProxySelector() {
+        mProxyService = IProxyService.Stub.asInterface(
+                ServiceManager.getService(PROXY_SERVICE));
+        if (mProxyService == null) {
+            // Added because of b10267814 where mako is restarting.
+            Log.e(TAG, "PacProxyInstaller: no proxy service");
+        }
+        mDefaultList = Lists.newArrayList(java.net.Proxy.NO_PROXY);
+    }
+
+    @Override
+    public List<Proxy> select(URI uri) {
+        if (mProxyService == null) {
+            mProxyService = IProxyService.Stub.asInterface(
+                    ServiceManager.getService(PROXY_SERVICE));
+        }
+        if (mProxyService == null) {
+            Log.e(TAG, "select: no proxy service return NO_PROXY");
+            return Lists.newArrayList(java.net.Proxy.NO_PROXY);
+        }
+        String response = null;
+        String urlString;
+        try {
+            // Strip path and username/password from URI so it's not visible to PAC script. The
+            // path often contains credentials the app does not want exposed to a potentially
+            // malicious PAC script.
+            if (!"http".equalsIgnoreCase(uri.getScheme())) {
+                uri = new URI(uri.getScheme(), null, uri.getHost(), uri.getPort(), "/", null, null);
+            }
+            urlString = uri.toURL().toString();
+        } catch (URISyntaxException e) {
+            urlString = uri.getHost();
+        } catch (MalformedURLException e) {
+            urlString = uri.getHost();
+        }
+        try {
+            response = mProxyService.resolvePacFile(uri.getHost(), urlString);
+        } catch (Exception e) {
+            Log.e(TAG, "Error resolving PAC File", e);
+        }
+        if (response == null) {
+            return mDefaultList;
+        }
+
+        return parseResponse(response);
+    }
+
+    private static List<Proxy> parseResponse(String response) {
+        String[] split = response.split(";");
+        List<Proxy> ret = Lists.newArrayList();
+        for (String s : split) {
+            String trimmed = s.trim();
+            if (trimmed.equals("DIRECT")) {
+                ret.add(java.net.Proxy.NO_PROXY);
+            } else if (trimmed.startsWith(PROXY)) {
+                Proxy proxy = proxyFromHostPort(Type.HTTP, trimmed.substring(PROXY.length()));
+                if (proxy != null) {
+                    ret.add(proxy);
+                }
+            } else if (trimmed.startsWith(SOCKS)) {
+                Proxy proxy = proxyFromHostPort(Type.SOCKS, trimmed.substring(SOCKS.length()));
+                if (proxy != null) {
+                    ret.add(proxy);
+                }
+            }
+        }
+        if (ret.size() == 0) {
+            ret.add(java.net.Proxy.NO_PROXY);
+        }
+        return ret;
+    }
+
+    private static Proxy proxyFromHostPort(Proxy.Type type, String hostPortString) {
+        try {
+            String[] hostPort = hostPortString.split(":");
+            String host = hostPort[0];
+            int port = Integer.parseInt(hostPort[1]);
+            return new Proxy(type, InetSocketAddress.createUnresolved(host, port));
+        } catch (NumberFormatException|ArrayIndexOutOfBoundsException e) {
+            Log.d(TAG, "Unable to parse proxy " + hostPortString + " " + e);
+            return null;
+        }
+    }
+
+    @Override
+    public void connectFailed(URI uri, SocketAddress address, IOException failure) {
+
+    }
+
+}
diff --git a/framework/src/android/net/Proxy.java b/framework/src/android/net/Proxy.java
new file mode 100644
index 0000000..03b07e0
--- /dev/null
+++ b/framework/src/android/net/Proxy.java
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.compat.annotation.UnsupportedAppUsage;
+import android.content.Context;
+import android.os.Build;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.net.module.util.ProxyUtils;
+
+import java.net.InetSocketAddress;
+import java.net.ProxySelector;
+import java.net.URI;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * A convenience class for accessing the user and default proxy
+ * settings.
+ */
+public final class Proxy {
+
+    private static final String TAG = "Proxy";
+
+    private static final ProxySelector sDefaultProxySelector;
+
+    /**
+     * Used to notify an app that's caching the proxy that either the default
+     * connection has changed or any connection's proxy has changed. The new
+     * proxy should be queried using {@link ConnectivityManager#getDefaultProxy()}.
+     *
+     * <p class="note">This is a protected intent that can only be sent by the system
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String PROXY_CHANGE_ACTION = "android.intent.action.PROXY_CHANGE";
+    /**
+     * Intent extra included with {@link #PROXY_CHANGE_ACTION} intents.
+     * It describes the new proxy being used (as a {@link ProxyInfo} object).
+     * @deprecated Because {@code PROXY_CHANGE_ACTION} is sent whenever the proxy
+     * for any network on the system changes, applications should always use
+     * {@link ConnectivityManager#getDefaultProxy()} or
+     * {@link ConnectivityManager#getLinkProperties(Network)}.{@link LinkProperties#getHttpProxy()}
+     * to get the proxy for the Network(s) they are using.
+     */
+    @Deprecated
+    public static final String EXTRA_PROXY_INFO = "android.intent.extra.PROXY_INFO";
+
+    /** @hide */
+    public static final int PROXY_VALID             = 0;
+    /** @hide */
+    public static final int PROXY_HOSTNAME_EMPTY    = 1;
+    /** @hide */
+    public static final int PROXY_HOSTNAME_INVALID  = 2;
+    /** @hide */
+    public static final int PROXY_PORT_EMPTY        = 3;
+    /** @hide */
+    public static final int PROXY_PORT_INVALID      = 4;
+    /** @hide */
+    public static final int PROXY_EXCLLIST_INVALID  = 5;
+
+    private static ConnectivityManager sConnectivityManager = null;
+
+    // Hostname / IP REGEX validation
+    // Matches blank input, ips, and domain names
+    private static final String NAME_IP_REGEX =
+        "[a-zA-Z0-9]+(\\-[a-zA-Z0-9]+)*(\\.[a-zA-Z0-9]+(\\-[a-zA-Z0-9]+)*)*";
+
+    private static final String HOSTNAME_REGEXP = "^$|^" + NAME_IP_REGEX + "$";
+
+    private static final Pattern HOSTNAME_PATTERN;
+
+    private static final String EXCL_REGEX =
+        "[a-zA-Z0-9*]+(\\-[a-zA-Z0-9*]+)*(\\.[a-zA-Z0-9*]+(\\-[a-zA-Z0-9*]+)*)*";
+
+    private static final String EXCLLIST_REGEXP = "^$|^" + EXCL_REGEX + "(," + EXCL_REGEX + ")*$";
+
+    private static final Pattern EXCLLIST_PATTERN;
+
+    static {
+        HOSTNAME_PATTERN = Pattern.compile(HOSTNAME_REGEXP);
+        EXCLLIST_PATTERN = Pattern.compile(EXCLLIST_REGEXP);
+        sDefaultProxySelector = ProxySelector.getDefault();
+    }
+
+    /**
+     * Return the proxy object to be used for the URL given as parameter.
+     * @param ctx A Context used to get the settings for the proxy host.
+     * @param url A URL to be accessed. Used to evaluate exclusion list.
+     * @return Proxy (java.net) object containing the host name. If the
+     *         user did not set a hostname it returns the default host.
+     *         A null value means that no host is to be used.
+     * {@hide}
+     */
+    @UnsupportedAppUsage
+    public static final java.net.Proxy getProxy(Context ctx, String url) {
+        String host = "";
+        if ((url != null) && !isLocalHost(host)) {
+            URI uri = URI.create(url);
+            ProxySelector proxySelector = ProxySelector.getDefault();
+
+            List<java.net.Proxy> proxyList = proxySelector.select(uri);
+
+            if (proxyList.size() > 0) {
+                return proxyList.get(0);
+            }
+        }
+        return java.net.Proxy.NO_PROXY;
+    }
+
+
+    /**
+     * Return the proxy host set by the user.
+     * @param ctx A Context used to get the settings for the proxy host.
+     * @return String containing the host name. If the user did not set a host
+     *         name it returns the default host. A null value means that no
+     *         host is to be used.
+     * @deprecated Use standard java vm proxy values to find the host, port
+     *         and exclusion list.  This call ignores the exclusion list.
+     */
+    @Deprecated
+    public static final String getHost(Context ctx) {
+        java.net.Proxy proxy = getProxy(ctx, null);
+        if (proxy == java.net.Proxy.NO_PROXY) return null;
+        try {
+            return ((InetSocketAddress)(proxy.address())).getHostName();
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    /**
+     * Return the proxy port set by the user.
+     * @param ctx A Context used to get the settings for the proxy port.
+     * @return The port number to use or -1 if no proxy is to be used.
+     * @deprecated Use standard java vm proxy values to find the host, port
+     *         and exclusion list.  This call ignores the exclusion list.
+     */
+    @Deprecated
+    public static final int getPort(Context ctx) {
+        java.net.Proxy proxy = getProxy(ctx, null);
+        if (proxy == java.net.Proxy.NO_PROXY) return -1;
+        try {
+            return ((InetSocketAddress)(proxy.address())).getPort();
+        } catch (Exception e) {
+            return -1;
+        }
+    }
+
+    /**
+     * Return the default proxy host specified by the carrier.
+     * @return String containing the host name or null if there is no proxy for
+     * this carrier.
+     * @deprecated Use standard java vm proxy values to find the host, port and
+     *         exclusion list.  This call ignores the exclusion list and no
+     *         longer reports only mobile-data apn-based proxy values.
+     */
+    @Deprecated
+    public static final String getDefaultHost() {
+        String host = System.getProperty("http.proxyHost");
+        if (TextUtils.isEmpty(host)) return null;
+        return host;
+    }
+
+    /**
+     * Return the default proxy port specified by the carrier.
+     * @return The port number to be used with the proxy host or -1 if there is
+     * no proxy for this carrier.
+     * @deprecated Use standard java vm proxy values to find the host, port and
+     *         exclusion list.  This call ignores the exclusion list and no
+     *         longer reports only mobile-data apn-based proxy values.
+     */
+    @Deprecated
+    public static final int getDefaultPort() {
+        if (getDefaultHost() == null) return -1;
+        try {
+            return Integer.parseInt(System.getProperty("http.proxyPort"));
+        } catch (NumberFormatException e) {
+            return -1;
+        }
+    }
+
+    private static final boolean isLocalHost(String host) {
+        if (host == null) {
+            return false;
+        }
+        try {
+            if (host != null) {
+                if (host.equalsIgnoreCase("localhost")) {
+                    return true;
+                }
+                if (InetAddresses.parseNumericAddress(host).isLoopbackAddress()) {
+                    return true;
+                }
+            }
+        } catch (IllegalArgumentException iex) {
+        }
+        return false;
+    }
+
+    /**
+     * Validate syntax of hostname, port and exclusion list entries
+     * {@hide}
+     */
+    public static int validate(String hostname, String port, String exclList) {
+        Matcher match = HOSTNAME_PATTERN.matcher(hostname);
+        Matcher listMatch = EXCLLIST_PATTERN.matcher(exclList);
+
+        if (!match.matches()) return PROXY_HOSTNAME_INVALID;
+
+        if (!listMatch.matches()) return PROXY_EXCLLIST_INVALID;
+
+        if (hostname.length() > 0 && port.length() == 0) return PROXY_PORT_EMPTY;
+
+        if (port.length() > 0) {
+            if (hostname.length() == 0) return PROXY_HOSTNAME_EMPTY;
+            int portVal = -1;
+            try {
+                portVal = Integer.parseInt(port);
+            } catch (NumberFormatException ex) {
+                return PROXY_PORT_INVALID;
+            }
+            if (portVal <= 0 || portVal > 0xFFFF) return PROXY_PORT_INVALID;
+        }
+        return PROXY_VALID;
+    }
+
+    /** @hide */
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+    public static final void setHttpProxySystemProperty(ProxyInfo p) {
+        String host = null;
+        String port = null;
+        String exclList = null;
+        Uri pacFileUrl = Uri.EMPTY;
+        if (p != null) {
+            host = p.getHost();
+            port = Integer.toString(p.getPort());
+            exclList = ProxyUtils.exclusionListAsString(p.getExclusionList());
+            pacFileUrl = p.getPacFileUrl();
+        }
+        setHttpProxySystemProperty(host, port, exclList, pacFileUrl);
+    }
+
+    /** @hide */
+    public static final void setHttpProxySystemProperty(String host, String port, String exclList,
+            Uri pacFileUrl) {
+        if (exclList != null) exclList = exclList.replace(",", "|");
+        if (false) Log.d(TAG, "setHttpProxySystemProperty :"+host+":"+port+" - "+exclList);
+        if (host != null) {
+            System.setProperty("http.proxyHost", host);
+            System.setProperty("https.proxyHost", host);
+        } else {
+            System.clearProperty("http.proxyHost");
+            System.clearProperty("https.proxyHost");
+        }
+        if (port != null) {
+            System.setProperty("http.proxyPort", port);
+            System.setProperty("https.proxyPort", port);
+        } else {
+            System.clearProperty("http.proxyPort");
+            System.clearProperty("https.proxyPort");
+        }
+        if (exclList != null) {
+            System.setProperty("http.nonProxyHosts", exclList);
+            System.setProperty("https.nonProxyHosts", exclList);
+        } else {
+            System.clearProperty("http.nonProxyHosts");
+            System.clearProperty("https.nonProxyHosts");
+        }
+        if (!Uri.EMPTY.equals(pacFileUrl)) {
+            ProxySelector.setDefault(new PacProxySelector());
+        } else {
+            ProxySelector.setDefault(sDefaultProxySelector);
+        }
+    }
+}
diff --git a/framework/src/android/net/ProxyInfo.aidl b/framework/src/android/net/ProxyInfo.aidl
new file mode 100644
index 0000000..a5d0c12
--- /dev/null
+++ b/framework/src/android/net/ProxyInfo.aidl
@@ -0,0 +1,21 @@
+/*
+**
+** Copyright (C) 2010 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.net;
+
+@JavaOnlyStableParcelable parcelable ProxyInfo;
+
diff --git a/core/java/android/net/ProxyInfo.java b/framework/src/android/net/ProxyInfo.java
similarity index 99%
rename from core/java/android/net/ProxyInfo.java
rename to framework/src/android/net/ProxyInfo.java
index a202d77..c9bca28 100644
--- a/core/java/android/net/ProxyInfo.java
+++ b/framework/src/android/net/ProxyInfo.java
@@ -355,7 +355,7 @@
                     port = in.readInt();
                 }
                 String exclList = in.readString();
-                String[] parsedExclList = in.readStringArray();
+                String[] parsedExclList = in.createStringArray();
                 ProxyInfo proxyProperties = new ProxyInfo(host, port, exclList, parsedExclList);
                 return proxyProperties;
             }
diff --git a/framework/src/android/net/RouteInfo.aidl b/framework/src/android/net/RouteInfo.aidl
new file mode 100644
index 0000000..7af9fda
--- /dev/null
+++ b/framework/src/android/net/RouteInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+@JavaOnlyStableParcelable parcelable RouteInfo;
diff --git a/core/java/android/net/RouteInfo.java b/framework/src/android/net/RouteInfo.java
similarity index 100%
rename from core/java/android/net/RouteInfo.java
rename to framework/src/android/net/RouteInfo.java
diff --git a/core/java/android/net/SocketKeepalive.java b/framework/src/android/net/SocketKeepalive.java
similarity index 100%
rename from core/java/android/net/SocketKeepalive.java
rename to framework/src/android/net/SocketKeepalive.java
diff --git a/framework/src/android/net/StaticIpConfiguration.aidl b/framework/src/android/net/StaticIpConfiguration.aidl
new file mode 100644
index 0000000..8aac701
--- /dev/null
+++ b/framework/src/android/net/StaticIpConfiguration.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** Copyright (C) 2019 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.net;
+
+@JavaOnlyStableParcelable parcelable StaticIpConfiguration;
\ No newline at end of file
diff --git a/core/java/android/net/StaticIpConfiguration.java b/framework/src/android/net/StaticIpConfiguration.java
similarity index 100%
rename from core/java/android/net/StaticIpConfiguration.java
rename to framework/src/android/net/StaticIpConfiguration.java
diff --git a/core/java/android/net/TcpKeepalivePacketData.java b/framework/src/android/net/TcpKeepalivePacketData.java
similarity index 100%
rename from core/java/android/net/TcpKeepalivePacketData.java
rename to framework/src/android/net/TcpKeepalivePacketData.java
diff --git a/core/java/android/net/TcpRepairWindow.java b/framework/src/android/net/TcpRepairWindow.java
similarity index 100%
rename from core/java/android/net/TcpRepairWindow.java
rename to framework/src/android/net/TcpRepairWindow.java
diff --git a/core/java/android/net/TcpSocketKeepalive.java b/framework/src/android/net/TcpSocketKeepalive.java
similarity index 100%
rename from core/java/android/net/TcpSocketKeepalive.java
rename to framework/src/android/net/TcpSocketKeepalive.java
diff --git a/framework/src/android/net/TestNetworkInterface.aidl b/framework/src/android/net/TestNetworkInterface.aidl
new file mode 100644
index 0000000..e1f4f9f
--- /dev/null
+++ b/framework/src/android/net/TestNetworkInterface.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+/** @hide */
+parcelable TestNetworkInterface;
diff --git a/core/java/android/net/TestNetworkInterface.java b/framework/src/android/net/TestNetworkInterface.java
similarity index 100%
rename from core/java/android/net/TestNetworkInterface.java
rename to framework/src/android/net/TestNetworkInterface.java
diff --git a/core/java/android/net/TestNetworkManager.java b/framework/src/android/net/TestNetworkManager.java
similarity index 100%
rename from core/java/android/net/TestNetworkManager.java
rename to framework/src/android/net/TestNetworkManager.java
diff --git a/core/java/android/net/TransportInfo.java b/framework/src/android/net/TransportInfo.java
similarity index 100%
rename from core/java/android/net/TransportInfo.java
rename to framework/src/android/net/TransportInfo.java
diff --git a/framework/src/android/net/UidRange.aidl b/framework/src/android/net/UidRange.aidl
new file mode 100644
index 0000000..f70fc8e
--- /dev/null
+++ b/framework/src/android/net/UidRange.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+/**
+ * An inclusive range of UIDs.
+ *
+ * {@hide}
+ */
+parcelable UidRange;
\ No newline at end of file
diff --git a/framework/src/android/net/VpnManager.java b/framework/src/android/net/VpnManager.java
new file mode 100644
index 0000000..c87b827
--- /dev/null
+++ b/framework/src/android/net/VpnManager.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.os.RemoteException;
+
+import com.android.internal.net.VpnProfile;
+
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.security.GeneralSecurityException;
+
+/**
+ * This class provides an interface for apps to manage platform VPN profiles
+ *
+ * <p>Apps can use this API to provide profiles with which the platform can set up a VPN without
+ * further app intermediation. When a VPN profile is present and the app is selected as an always-on
+ * VPN, the platform will directly trigger the negotiation of the VPN without starting or waking the
+ * app (unlike VpnService).
+ *
+ * <p>VPN apps using supported protocols should preferentially use this API over the {@link
+ * VpnService} API for ease-of-development and reduced maintainance burden. This also give the user
+ * the guarantee that VPN network traffic is not subjected to on-device packet interception.
+ *
+ * @see Ikev2VpnProfile
+ */
+public class VpnManager {
+    /** Type representing a lack of VPN @hide */
+    public static final int TYPE_VPN_NONE = -1;
+    /** VPN service type code @hide */
+    public static final int TYPE_VPN_SERVICE = 1;
+    /** Platform VPN type code @hide */
+    public static final int TYPE_VPN_PLATFORM = 2;
+
+    /** @hide */
+    @IntDef(value = {TYPE_VPN_NONE, TYPE_VPN_SERVICE, TYPE_VPN_PLATFORM})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface VpnType {}
+
+    @NonNull private final Context mContext;
+    @NonNull private final IConnectivityManager mService;
+
+    private static Intent getIntentForConfirmation() {
+        final Intent intent = new Intent();
+        final ComponentName componentName = ComponentName.unflattenFromString(
+                Resources.getSystem().getString(
+                        com.android.internal.R.string.config_platformVpnConfirmDialogComponent));
+        intent.setComponent(componentName);
+        return intent;
+    }
+
+    /**
+     * Create an instance of the VpnManager with the given context.
+     *
+     * <p>Internal only. Applications are expected to obtain an instance of the VpnManager via the
+     * {@link Context.getSystemService()} method call.
+     *
+     * @hide
+     */
+    public VpnManager(@NonNull Context ctx, @NonNull IConnectivityManager service) {
+        mContext = checkNotNull(ctx, "missing Context");
+        mService = checkNotNull(service, "missing IConnectivityManager");
+    }
+
+    /**
+     * Install a VpnProfile configuration keyed on the calling app's package name.
+     *
+     * <p>This method returns {@code null} if user consent has already been granted, or an {@link
+     * Intent} to a system activity. If an intent is returned, the application should launch the
+     * activity using {@link Activity#startActivityForResult} to request user consent. The activity
+     * may pop up a dialog to require user action, and the result will come back via its {@link
+     * Activity#onActivityResult}. If the result is {@link Activity#RESULT_OK}, the user has
+     * consented, and the VPN profile can be started.
+     *
+     * @param profile the VpnProfile provided by this package. Will override any previous VpnProfile
+     *     stored for this package.
+     * @return an Intent requesting user consent to start the VPN, or null if consent is not
+     *     required based on privileges or previous user consent.
+     */
+    @Nullable
+    public Intent provisionVpnProfile(@NonNull PlatformVpnProfile profile) {
+        final VpnProfile internalProfile;
+
+        try {
+            internalProfile = profile.toVpnProfile();
+        } catch (GeneralSecurityException | IOException e) {
+            // Conversion to VpnProfile failed; this is an invalid profile. Both of these exceptions
+            // indicate a failure to convert a PrivateKey or X509Certificate to a Base64 encoded
+            // string as required by the VpnProfile.
+            throw new IllegalArgumentException("Failed to serialize PlatformVpnProfile", e);
+        }
+
+        try {
+            // Profile can never be null; it either gets set, or an exception is thrown.
+            if (mService.provisionVpnProfile(internalProfile, mContext.getOpPackageName())) {
+                return null;
+            }
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+        return getIntentForConfirmation();
+    }
+
+    /**
+     * Delete the VPN profile configuration that was provisioned by the calling app
+     *
+     * @throws SecurityException if this would violate user settings
+     */
+    public void deleteProvisionedVpnProfile() {
+        try {
+            mService.deleteVpnProfile(mContext.getOpPackageName());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Request the startup of a previously provisioned VPN.
+     *
+     * @throws SecurityException exception if user or device settings prevent this VPN from being
+     *     setup, or if user consent has not been granted
+     */
+    public void startProvisionedVpnProfile() {
+        try {
+            mService.startVpnProfile(mContext.getOpPackageName());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /** Tear down the VPN provided by the calling app (if any) */
+    public void stopProvisionedVpnProfile() {
+        try {
+            mService.stopVpnProfile(mContext.getOpPackageName());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+}
diff --git a/framework/src/android/net/VpnService.java b/framework/src/android/net/VpnService.java
new file mode 100644
index 0000000..8e90a11
--- /dev/null
+++ b/framework/src/android/net/VpnService.java
@@ -0,0 +1,903 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_INET6;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.app.admin.DevicePolicyManager;
+import android.compat.annotation.UnsupportedAppUsage;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+
+import com.android.internal.net.VpnConfig;
+
+import java.net.DatagramSocket;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * VpnService is a base class for applications to extend and build their
+ * own VPN solutions. In general, it creates a virtual network interface,
+ * configures addresses and routing rules, and returns a file descriptor
+ * to the application. Each read from the descriptor retrieves an outgoing
+ * packet which was routed to the interface. Each write to the descriptor
+ * injects an incoming packet just like it was received from the interface.
+ * The interface is running on Internet Protocol (IP), so packets are
+ * always started with IP headers. The application then completes a VPN
+ * connection by processing and exchanging packets with the remote server
+ * over a tunnel.
+ *
+ * <p>Letting applications intercept packets raises huge security concerns.
+ * A VPN application can easily break the network. Besides, two of them may
+ * conflict with each other. The system takes several actions to address
+ * these issues. Here are some key points:
+ * <ul>
+ *   <li>User action is required the first time an application creates a VPN
+ *       connection.</li>
+ *   <li>There can be only one VPN connection running at the same time. The
+ *       existing interface is deactivated when a new one is created.</li>
+ *   <li>A system-managed notification is shown during the lifetime of a
+ *       VPN connection.</li>
+ *   <li>A system-managed dialog gives the information of the current VPN
+ *       connection. It also provides a button to disconnect.</li>
+ *   <li>The network is restored automatically when the file descriptor is
+ *       closed. It also covers the cases when a VPN application is crashed
+ *       or killed by the system.</li>
+ * </ul>
+ *
+ * <p>There are two primary methods in this class: {@link #prepare} and
+ * {@link Builder#establish}. The former deals with user action and stops
+ * the VPN connection created by another application. The latter creates
+ * a VPN interface using the parameters supplied to the {@link Builder}.
+ * An application must call {@link #prepare} to grant the right to use
+ * other methods in this class, and the right can be revoked at any time.
+ * Here are the general steps to create a VPN connection:
+ * <ol>
+ *   <li>When the user presses the button to connect, call {@link #prepare}
+ *       and launch the returned intent, if non-null.</li>
+ *   <li>When the application becomes prepared, start the service.</li>
+ *   <li>Create a tunnel to the remote server and negotiate the network
+ *       parameters for the VPN connection.</li>
+ *   <li>Supply those parameters to a {@link Builder} and create a VPN
+ *       interface by calling {@link Builder#establish}.</li>
+ *   <li>Process and exchange packets between the tunnel and the returned
+ *       file descriptor.</li>
+ *   <li>When {@link #onRevoke} is invoked, close the file descriptor and
+ *       shut down the tunnel gracefully.</li>
+ * </ol>
+ *
+ * <p>Services extending this class need to be declared with an appropriate
+ * permission and intent filter. Their access must be secured by
+ * {@link android.Manifest.permission#BIND_VPN_SERVICE} permission, and
+ * their intent filter must match {@link #SERVICE_INTERFACE} action. Here
+ * is an example of declaring a VPN service in {@code AndroidManifest.xml}:
+ * <pre>
+ * &lt;service android:name=".ExampleVpnService"
+ *         android:permission="android.permission.BIND_VPN_SERVICE"&gt;
+ *     &lt;intent-filter&gt;
+ *         &lt;action android:name="android.net.VpnService"/&gt;
+ *     &lt;/intent-filter&gt;
+ * &lt;/service&gt;</pre>
+ *
+ * <p> The Android system starts a VPN in the background by calling
+ * {@link android.content.Context#startService startService()}. In Android 8.0
+ * (API level 26) and higher, the system places VPN apps on the temporary
+ * allowlist for a short period so the app can start in the background. The VPN
+ * app must promote itself to the foreground after it's launched or the system
+ * will shut down the app.
+ *
+ * <h3>Developer's guide</h3>
+ *
+ * <p>To learn more about developing VPN apps, read the
+ * <a href="{@docRoot}guide/topics/connectivity/vpn">VPN developer's guide</a>.
+ *
+ * @see Builder
+ */
+public class VpnService extends Service {
+
+    /**
+     * The action must be matched by the intent filter of this service. It also
+     * needs to require {@link android.Manifest.permission#BIND_VPN_SERVICE}
+     * permission so that other applications cannot abuse it.
+     */
+    public static final String SERVICE_INTERFACE = VpnConfig.SERVICE_INTERFACE;
+
+    /**
+     * Key for boolean meta-data field indicating whether this VpnService supports always-on mode.
+     *
+     * <p>For a VPN app targeting {@link android.os.Build.VERSION_CODES#N API 24} or above, Android
+     * provides users with the ability to set it as always-on, so that VPN connection is
+     * persisted after device reboot and app upgrade. Always-on VPN can also be enabled by device
+     * owner and profile owner apps through
+     * {@link DevicePolicyManager#setAlwaysOnVpnPackage}.
+     *
+     * <p>VPN apps not supporting this feature should opt out by adding this meta-data field to the
+     * {@code VpnService} component of {@code AndroidManifest.xml}. In case there is more than one
+     * {@code VpnService} component defined in {@code AndroidManifest.xml}, opting out any one of
+     * them will opt out the entire app. For example,
+     * <pre> {@code
+     * <service android:name=".ExampleVpnService"
+     *         android:permission="android.permission.BIND_VPN_SERVICE">
+     *     <intent-filter>
+     *         <action android:name="android.net.VpnService"/>
+     *     </intent-filter>
+     *     <meta-data android:name="android.net.VpnService.SUPPORTS_ALWAYS_ON"
+     *             android:value=false/>
+     * </service>
+     * } </pre>
+     *
+     * <p>This meta-data field defaults to {@code true} if absent. It will only have effect on
+     * {@link android.os.Build.VERSION_CODES#O_MR1} or higher.
+     */
+    public static final String SERVICE_META_DATA_SUPPORTS_ALWAYS_ON =
+            "android.net.VpnService.SUPPORTS_ALWAYS_ON";
+
+    /**
+     * Use IConnectivityManager since those methods are hidden and not
+     * available in ConnectivityManager.
+     */
+    private static IConnectivityManager getService() {
+        return IConnectivityManager.Stub.asInterface(
+                ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
+    }
+
+    /**
+     * Prepare to establish a VPN connection. This method returns {@code null}
+     * if the VPN application is already prepared or if the user has previously
+     * consented to the VPN application. Otherwise, it returns an
+     * {@link Intent} to a system activity. The application should launch the
+     * activity using {@link Activity#startActivityForResult} to get itself
+     * prepared. The activity may pop up a dialog to require user action, and
+     * the result will come back via its {@link Activity#onActivityResult}.
+     * If the result is {@link Activity#RESULT_OK}, the application becomes
+     * prepared and is granted to use other methods in this class.
+     *
+     * <p>Only one application can be granted at the same time. The right
+     * is revoked when another application is granted. The application
+     * losing the right will be notified via its {@link #onRevoke}. Unless
+     * it becomes prepared again, subsequent calls to other methods in this
+     * class will fail.
+     *
+     * <p>The user may disable the VPN at any time while it is activated, in
+     * which case this method will return an intent the next time it is
+     * executed to obtain the user's consent again.
+     *
+     * @see #onRevoke
+     */
+    public static Intent prepare(Context context) {
+        try {
+            if (getService().prepareVpn(context.getPackageName(), null, context.getUserId())) {
+                return null;
+            }
+        } catch (RemoteException e) {
+            // ignore
+        }
+        return VpnConfig.getIntentForConfirmation();
+    }
+
+    /**
+     * Version of {@link #prepare(Context)} which does not require user consent.
+     *
+     * <p>Requires {@link android.Manifest.permission#CONTROL_VPN} and should generally not be
+     * used. Only acceptable in situations where user consent has been obtained through other means.
+     *
+     * <p>Once this is run, future preparations may be done with the standard prepare method as this
+     * will authorize the package to prepare the VPN without consent in the future.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.CONTROL_VPN)
+    public static void prepareAndAuthorize(Context context) {
+        IConnectivityManager cm = getService();
+        String packageName = context.getPackageName();
+        try {
+            // Only prepare if we're not already prepared.
+            int userId = context.getUserId();
+            if (!cm.prepareVpn(packageName, null, userId)) {
+                cm.prepareVpn(null, packageName, userId);
+            }
+            cm.setVpnPackageAuthorization(packageName, userId, VpnManager.TYPE_VPN_SERVICE);
+        } catch (RemoteException e) {
+            // ignore
+        }
+    }
+
+    /**
+     * Protect a socket from VPN connections. After protecting, data sent
+     * through this socket will go directly to the underlying network,
+     * so its traffic will not be forwarded through the VPN.
+     * This method is useful if some connections need to be kept
+     * outside of VPN. For example, a VPN tunnel should protect itself if its
+     * destination is covered by VPN routes. Otherwise its outgoing packets
+     * will be sent back to the VPN interface and cause an infinite loop. This
+     * method will fail if the application is not prepared or is revoked.
+     *
+     * <p class="note">The socket is NOT closed by this method.
+     *
+     * @return {@code true} on success.
+     */
+    public boolean protect(int socket) {
+        return NetworkUtils.protectFromVpn(socket);
+    }
+
+    /**
+     * Convenience method to protect a {@link Socket} from VPN connections.
+     *
+     * @return {@code true} on success.
+     * @see #protect(int)
+     */
+    public boolean protect(Socket socket) {
+        return protect(socket.getFileDescriptor$().getInt$());
+    }
+
+    /**
+     * Convenience method to protect a {@link DatagramSocket} from VPN
+     * connections.
+     *
+     * @return {@code true} on success.
+     * @see #protect(int)
+     */
+    public boolean protect(DatagramSocket socket) {
+        return protect(socket.getFileDescriptor$().getInt$());
+    }
+
+    /**
+     * Adds a network address to the VPN interface.
+     *
+     * Both IPv4 and IPv6 addresses are supported. The VPN must already be established. Fails if the
+     * address is already in use or cannot be assigned to the interface for any other reason.
+     *
+     * Adding an address implicitly allows traffic from that address family (i.e., IPv4 or IPv6) to
+     * be routed over the VPN. @see Builder#allowFamily
+     *
+     * @throws IllegalArgumentException if the address is invalid.
+     *
+     * @param address The IP address (IPv4 or IPv6) to assign to the VPN interface.
+     * @param prefixLength The prefix length of the address.
+     *
+     * @return {@code true} on success.
+     * @see Builder#addAddress
+     *
+     * @hide
+     */
+    public boolean addAddress(InetAddress address, int prefixLength) {
+        check(address, prefixLength);
+        try {
+            return getService().addVpnAddress(address.getHostAddress(), prefixLength);
+        } catch (RemoteException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+    /**
+     * Removes a network address from the VPN interface.
+     *
+     * Both IPv4 and IPv6 addresses are supported. The VPN must already be established. Fails if the
+     * address is not assigned to the VPN interface, or if it is the only address assigned (thus
+     * cannot be removed), or if the address cannot be removed for any other reason.
+     *
+     * After removing an address, if there are no addresses, routes or DNS servers of a particular
+     * address family (i.e., IPv4 or IPv6) configured on the VPN, that <b>DOES NOT</b> block that
+     * family from being routed. In other words, once an address family has been allowed, it stays
+     * allowed for the rest of the VPN's session. @see Builder#allowFamily
+     *
+     * @throws IllegalArgumentException if the address is invalid.
+     *
+     * @param address The IP address (IPv4 or IPv6) to assign to the VPN interface.
+     * @param prefixLength The prefix length of the address.
+     *
+     * @return {@code true} on success.
+     *
+     * @hide
+     */
+    public boolean removeAddress(InetAddress address, int prefixLength) {
+        check(address, prefixLength);
+        try {
+            return getService().removeVpnAddress(address.getHostAddress(), prefixLength);
+        } catch (RemoteException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+    /**
+     * Sets the underlying networks used by the VPN for its upstream connections.
+     *
+     * <p>Used by the system to know the actual networks that carry traffic for apps affected by
+     * this VPN in order to present this information to the user (e.g., via status bar icons).
+     *
+     * <p>This method only needs to be called if the VPN has explicitly bound its underlying
+     * communications channels &mdash; such as the socket(s) passed to {@link #protect(int)} &mdash;
+     * to a {@code Network} using APIs such as {@link Network#bindSocket(Socket)} or
+     * {@link Network#bindSocket(DatagramSocket)}. The VPN should call this method every time
+     * the set of {@code Network}s it is using changes.
+     *
+     * <p>{@code networks} is one of the following:
+     * <ul>
+     * <li><strong>a non-empty array</strong>: an array of one or more {@link Network}s, in
+     * decreasing preference order. For example, if this VPN uses both wifi and mobile (cellular)
+     * networks to carry app traffic, but prefers or uses wifi more than mobile, wifi should appear
+     * first in the array.</li>
+     * <li><strong>an empty array</strong>: a zero-element array, meaning that the VPN has no
+     * underlying network connection, and thus, app traffic will not be sent or received.</li>
+     * <li><strong>null</strong>: (default) signifies that the VPN uses whatever is the system's
+     * default network. I.e., it doesn't use the {@code bindSocket} or {@code bindDatagramSocket}
+     * APIs mentioned above to send traffic over specific channels.</li>
+     * </ul>
+     *
+     * <p>This call will succeed only if the VPN is currently established. For setting this value
+     * when the VPN has not yet been established, see {@link Builder#setUnderlyingNetworks}.
+     *
+     * @param networks An array of networks the VPN uses to tunnel traffic to/from its servers.
+     *
+     * @return {@code true} on success.
+     */
+    public boolean setUnderlyingNetworks(Network[] networks) {
+        try {
+            return getService().setUnderlyingNetworksForVpn(networks);
+        } catch (RemoteException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+    /**
+     * Returns whether the service is running in always-on VPN mode. In this mode the system ensures
+     * that the service is always running by restarting it when necessary, e.g. after reboot.
+     *
+     * @see DevicePolicyManager#setAlwaysOnVpnPackage(ComponentName, String, boolean, Set)
+     */
+    public final boolean isAlwaysOn() {
+        try {
+            return getService().isCallerCurrentAlwaysOnVpnApp();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Returns whether the service is running in always-on VPN lockdown mode. In this mode the
+     * system ensures that the service is always running and that the apps aren't allowed to bypass
+     * the VPN.
+     *
+     * @see DevicePolicyManager#setAlwaysOnVpnPackage(ComponentName, String, boolean, Set)
+     */
+    public final boolean isLockdownEnabled() {
+        try {
+            return getService().isCallerCurrentAlwaysOnVpnLockdownApp();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Return the communication interface to the service. This method returns
+     * {@code null} on {@link Intent}s other than {@link #SERVICE_INTERFACE}
+     * action. Applications overriding this method must identify the intent
+     * and return the corresponding interface accordingly.
+     *
+     * @see Service#onBind
+     */
+    @Override
+    public IBinder onBind(Intent intent) {
+        if (intent != null && SERVICE_INTERFACE.equals(intent.getAction())) {
+            return new Callback();
+        }
+        return null;
+    }
+
+    /**
+     * Invoked when the application is revoked. At this moment, the VPN
+     * interface is already deactivated by the system. The application should
+     * close the file descriptor and shut down gracefully. The default
+     * implementation of this method is calling {@link Service#stopSelf()}.
+     *
+     * <p class="note">Calls to this method may not happen on the main thread
+     * of the process.
+     *
+     * @see #prepare
+     */
+    public void onRevoke() {
+        stopSelf();
+    }
+
+    /**
+     * Use raw Binder instead of AIDL since now there is only one usage.
+     */
+    private class Callback extends Binder {
+        @Override
+        protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) {
+            if (code == IBinder.LAST_CALL_TRANSACTION) {
+                onRevoke();
+                return true;
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Private method to validate address and prefixLength.
+     */
+    private static void check(InetAddress address, int prefixLength) {
+        if (address.isLoopbackAddress()) {
+            throw new IllegalArgumentException("Bad address");
+        }
+        if (address instanceof Inet4Address) {
+            if (prefixLength < 0 || prefixLength > 32) {
+                throw new IllegalArgumentException("Bad prefixLength");
+            }
+        } else if (address instanceof Inet6Address) {
+            if (prefixLength < 0 || prefixLength > 128) {
+                throw new IllegalArgumentException("Bad prefixLength");
+            }
+        } else {
+            throw new IllegalArgumentException("Unsupported family");
+        }
+    }
+
+    /**
+     * Helper class to create a VPN interface. This class should be always
+     * used within the scope of the outer {@link VpnService}.
+     *
+     * @see VpnService
+     */
+    public class Builder {
+
+        private final VpnConfig mConfig = new VpnConfig();
+        @UnsupportedAppUsage
+        private final List<LinkAddress> mAddresses = new ArrayList<LinkAddress>();
+        @UnsupportedAppUsage
+        private final List<RouteInfo> mRoutes = new ArrayList<RouteInfo>();
+
+        public Builder() {
+            mConfig.user = VpnService.this.getClass().getName();
+        }
+
+        /**
+         * Set the name of this session. It will be displayed in
+         * system-managed dialogs and notifications. This is recommended
+         * not required.
+         */
+        @NonNull
+        public Builder setSession(@NonNull String session) {
+            mConfig.session = session;
+            return this;
+        }
+
+        /**
+         * Set the {@link PendingIntent} to an activity for users to
+         * configure the VPN connection. If it is not set, the button
+         * to configure will not be shown in system-managed dialogs.
+         */
+        @NonNull
+        public Builder setConfigureIntent(@NonNull PendingIntent intent) {
+            mConfig.configureIntent = intent;
+            return this;
+        }
+
+        /**
+         * Set the maximum transmission unit (MTU) of the VPN interface. If
+         * it is not set, the default value in the operating system will be
+         * used.
+         *
+         * @throws IllegalArgumentException if the value is not positive.
+         */
+        @NonNull
+        public Builder setMtu(int mtu) {
+            if (mtu <= 0) {
+                throw new IllegalArgumentException("Bad mtu");
+            }
+            mConfig.mtu = mtu;
+            return this;
+        }
+
+        /**
+         * Sets an HTTP proxy for the VPN network. This proxy is only a recommendation
+         * and it is possible that some apps will ignore it.
+         */
+        @NonNull
+        public Builder setHttpProxy(@NonNull ProxyInfo proxyInfo) {
+            mConfig.proxyInfo = proxyInfo;
+            return this;
+        }
+
+        /**
+         * Add a network address to the VPN interface. Both IPv4 and IPv6
+         * addresses are supported. At least one address must be set before
+         * calling {@link #establish}.
+         *
+         * Adding an address implicitly allows traffic from that address family
+         * (i.e., IPv4 or IPv6) to be routed over the VPN. @see #allowFamily
+         *
+         * @throws IllegalArgumentException if the address is invalid.
+         */
+        @NonNull
+        public Builder addAddress(@NonNull InetAddress address, int prefixLength) {
+            check(address, prefixLength);
+
+            if (address.isAnyLocalAddress()) {
+                throw new IllegalArgumentException("Bad address");
+            }
+            mAddresses.add(new LinkAddress(address, prefixLength));
+            mConfig.updateAllowedFamilies(address);
+            return this;
+        }
+
+        /**
+         * Convenience method to add a network address to the VPN interface
+         * using a numeric address string. See {@link InetAddress} for the
+         * definitions of numeric address formats.
+         *
+         * Adding an address implicitly allows traffic from that address family
+         * (i.e., IPv4 or IPv6) to be routed over the VPN. @see #allowFamily
+         *
+         * @throws IllegalArgumentException if the address is invalid.
+         * @see #addAddress(InetAddress, int)
+         */
+        @NonNull
+        public Builder addAddress(@NonNull String address, int prefixLength) {
+            return addAddress(InetAddress.parseNumericAddress(address), prefixLength);
+        }
+
+        /**
+         * Add a network route to the VPN interface. Both IPv4 and IPv6
+         * routes are supported.
+         *
+         * Adding a route implicitly allows traffic from that address family
+         * (i.e., IPv4 or IPv6) to be routed over the VPN. @see #allowFamily
+         *
+         * @throws IllegalArgumentException if the route is invalid.
+         */
+        @NonNull
+        public Builder addRoute(@NonNull InetAddress address, int prefixLength) {
+            check(address, prefixLength);
+
+            int offset = prefixLength / 8;
+            byte[] bytes = address.getAddress();
+            if (offset < bytes.length) {
+                for (bytes[offset] <<= prefixLength % 8; offset < bytes.length; ++offset) {
+                    if (bytes[offset] != 0) {
+                        throw new IllegalArgumentException("Bad address");
+                    }
+                }
+            }
+            mRoutes.add(new RouteInfo(new IpPrefix(address, prefixLength), null));
+            mConfig.updateAllowedFamilies(address);
+            return this;
+        }
+
+        /**
+         * Convenience method to add a network route to the VPN interface
+         * using a numeric address string. See {@link InetAddress} for the
+         * definitions of numeric address formats.
+         *
+         * Adding a route implicitly allows traffic from that address family
+         * (i.e., IPv4 or IPv6) to be routed over the VPN. @see #allowFamily
+         *
+         * @throws IllegalArgumentException if the route is invalid.
+         * @see #addRoute(InetAddress, int)
+         */
+        @NonNull
+        public Builder addRoute(@NonNull String address, int prefixLength) {
+            return addRoute(InetAddress.parseNumericAddress(address), prefixLength);
+        }
+
+        /**
+         * Add a DNS server to the VPN connection. Both IPv4 and IPv6
+         * addresses are supported. If none is set, the DNS servers of
+         * the default network will be used.
+         *
+         * Adding a server implicitly allows traffic from that address family
+         * (i.e., IPv4 or IPv6) to be routed over the VPN. @see #allowFamily
+         *
+         * @throws IllegalArgumentException if the address is invalid.
+         */
+        @NonNull
+        public Builder addDnsServer(@NonNull InetAddress address) {
+            if (address.isLoopbackAddress() || address.isAnyLocalAddress()) {
+                throw new IllegalArgumentException("Bad address");
+            }
+            if (mConfig.dnsServers == null) {
+                mConfig.dnsServers = new ArrayList<String>();
+            }
+            mConfig.dnsServers.add(address.getHostAddress());
+            return this;
+        }
+
+        /**
+         * Convenience method to add a DNS server to the VPN connection
+         * using a numeric address string. See {@link InetAddress} for the
+         * definitions of numeric address formats.
+         *
+         * Adding a server implicitly allows traffic from that address family
+         * (i.e., IPv4 or IPv6) to be routed over the VPN. @see #allowFamily
+         *
+         * @throws IllegalArgumentException if the address is invalid.
+         * @see #addDnsServer(InetAddress)
+         */
+        @NonNull
+        public Builder addDnsServer(@NonNull String address) {
+            return addDnsServer(InetAddress.parseNumericAddress(address));
+        }
+
+        /**
+         * Add a search domain to the DNS resolver.
+         */
+        @NonNull
+        public Builder addSearchDomain(@NonNull String domain) {
+            if (mConfig.searchDomains == null) {
+                mConfig.searchDomains = new ArrayList<String>();
+            }
+            mConfig.searchDomains.add(domain);
+            return this;
+        }
+
+        /**
+         * Allows traffic from the specified address family.
+         *
+         * By default, if no address, route or DNS server of a specific family (IPv4 or IPv6) is
+         * added to this VPN, then all outgoing traffic of that family is blocked. If any address,
+         * route or DNS server is added, that family is allowed.
+         *
+         * This method allows an address family to be unblocked even without adding an address,
+         * route or DNS server of that family. Traffic of that family will then typically
+         * fall-through to the underlying network if it's supported.
+         *
+         * {@code family} must be either {@code AF_INET} (for IPv4) or {@code AF_INET6} (for IPv6).
+         * {@link IllegalArgumentException} is thrown if it's neither.
+         *
+         * @param family The address family ({@code AF_INET} or {@code AF_INET6}) to allow.
+         *
+         * @return this {@link Builder} object to facilitate chaining of method calls.
+         */
+        @NonNull
+        public Builder allowFamily(int family) {
+            if (family == AF_INET) {
+                mConfig.allowIPv4 = true;
+            } else if (family == AF_INET6) {
+                mConfig.allowIPv6 = true;
+            } else {
+                throw new IllegalArgumentException(family + " is neither " + AF_INET + " nor " +
+                        AF_INET6);
+            }
+            return this;
+        }
+
+        private void verifyApp(String packageName) throws PackageManager.NameNotFoundException {
+            IPackageManager pm = IPackageManager.Stub.asInterface(
+                    ServiceManager.getService("package"));
+            try {
+                pm.getApplicationInfo(packageName, 0, UserHandle.getCallingUserId());
+            } catch (RemoteException e) {
+                throw new IllegalStateException(e);
+            }
+        }
+
+        /**
+         * Adds an application that's allowed to access the VPN connection.
+         *
+         * If this method is called at least once, only applications added through this method (and
+         * no others) are allowed access. Else (if this method is never called), all applications
+         * are allowed by default.  If some applications are added, other, un-added applications
+         * will use networking as if the VPN wasn't running.
+         *
+         * A {@link Builder} may have only a set of allowed applications OR a set of disallowed
+         * ones, but not both. Calling this method after {@link #addDisallowedApplication} has
+         * already been called, or vice versa, will throw an {@link UnsupportedOperationException}.
+         *
+         * {@code packageName} must be the canonical name of a currently installed application.
+         * {@link PackageManager.NameNotFoundException} is thrown if there's no such application.
+         *
+         * @throws PackageManager.NameNotFoundException If the application isn't installed.
+         *
+         * @param packageName The full name (e.g.: "com.google.apps.contacts") of an application.
+         *
+         * @return this {@link Builder} object to facilitate chaining method calls.
+         */
+        @NonNull
+        public Builder addAllowedApplication(@NonNull String packageName)
+                throws PackageManager.NameNotFoundException {
+            if (mConfig.disallowedApplications != null) {
+                throw new UnsupportedOperationException("addDisallowedApplication already called");
+            }
+            verifyApp(packageName);
+            if (mConfig.allowedApplications == null) {
+                mConfig.allowedApplications = new ArrayList<String>();
+            }
+            mConfig.allowedApplications.add(packageName);
+            return this;
+        }
+
+        /**
+         * Adds an application that's denied access to the VPN connection.
+         *
+         * By default, all applications are allowed access, except for those denied through this
+         * method.  Denied applications will use networking as if the VPN wasn't running.
+         *
+         * A {@link Builder} may have only a set of allowed applications OR a set of disallowed
+         * ones, but not both. Calling this method after {@link #addAllowedApplication} has already
+         * been called, or vice versa, will throw an {@link UnsupportedOperationException}.
+         *
+         * {@code packageName} must be the canonical name of a currently installed application.
+         * {@link PackageManager.NameNotFoundException} is thrown if there's no such application.
+         *
+         * @throws PackageManager.NameNotFoundException If the application isn't installed.
+         *
+         * @param packageName The full name (e.g.: "com.google.apps.contacts") of an application.
+         *
+         * @return this {@link Builder} object to facilitate chaining method calls.
+         */
+        @NonNull
+        public Builder addDisallowedApplication(@NonNull String packageName)
+                throws PackageManager.NameNotFoundException {
+            if (mConfig.allowedApplications != null) {
+                throw new UnsupportedOperationException("addAllowedApplication already called");
+            }
+            verifyApp(packageName);
+            if (mConfig.disallowedApplications == null) {
+                mConfig.disallowedApplications = new ArrayList<String>();
+            }
+            mConfig.disallowedApplications.add(packageName);
+            return this;
+        }
+
+        /**
+         * Allows all apps to bypass this VPN connection.
+         *
+         * By default, all traffic from apps is forwarded through the VPN interface and it is not
+         * possible for apps to side-step the VPN. If this method is called, apps may use methods
+         * such as {@link ConnectivityManager#bindProcessToNetwork} to instead send/receive
+         * directly over the underlying network or any other network they have permissions for.
+         *
+         * @return this {@link Builder} object to facilitate chaining of method calls.
+         */
+        @NonNull
+        public Builder allowBypass() {
+            mConfig.allowBypass = true;
+            return this;
+        }
+
+        /**
+         * Sets the VPN interface's file descriptor to be in blocking/non-blocking mode.
+         *
+         * By default, the file descriptor returned by {@link #establish} is non-blocking.
+         *
+         * @param blocking True to put the descriptor into blocking mode; false for non-blocking.
+         *
+         * @return this {@link Builder} object to facilitate chaining method calls.
+         */
+        @NonNull
+        public Builder setBlocking(boolean blocking) {
+            mConfig.blocking = blocking;
+            return this;
+        }
+
+        /**
+         * Sets the underlying networks used by the VPN for its upstream connections.
+         *
+         * @see VpnService#setUnderlyingNetworks
+         *
+         * @param networks An array of networks the VPN uses to tunnel traffic to/from its servers.
+         *
+         * @return this {@link Builder} object to facilitate chaining method calls.
+         */
+        @NonNull
+        public Builder setUnderlyingNetworks(@Nullable Network[] networks) {
+            mConfig.underlyingNetworks = networks != null ? networks.clone() : null;
+            return this;
+        }
+
+        /**
+         * Marks the VPN network as metered. A VPN network is classified as metered when the user is
+         * sensitive to heavy data usage due to monetary costs and/or data limitations. In such
+         * cases, you should set this to {@code true} so that apps on the system can avoid doing
+         * large data transfers. Otherwise, set this to {@code false}. Doing so would cause VPN
+         * network to inherit its meteredness from its underlying networks.
+         *
+         * <p>VPN apps targeting {@link android.os.Build.VERSION_CODES#Q} or above will be
+         * considered metered by default.
+         *
+         * @param isMetered {@code true} if VPN network should be treated as metered regardless of
+         *     underlying network meteredness
+         * @return this {@link Builder} object to facilitate chaining method calls
+         * @see #setUnderlyingNetworks(Network[])
+         * @see ConnectivityManager#isActiveNetworkMetered()
+         */
+        @NonNull
+        public Builder setMetered(boolean isMetered) {
+            mConfig.isMetered = isMetered;
+            return this;
+        }
+
+        /**
+         * Create a VPN interface using the parameters supplied to this
+         * builder. The interface works on IP packets, and a file descriptor
+         * is returned for the application to access them. Each read
+         * retrieves an outgoing packet which was routed to the interface.
+         * Each write injects an incoming packet just like it was received
+         * from the interface. The file descriptor is put into non-blocking
+         * mode by default to avoid blocking Java threads. To use the file
+         * descriptor completely in native space, see
+         * {@link ParcelFileDescriptor#detachFd()}. The application MUST
+         * close the file descriptor when the VPN connection is terminated.
+         * The VPN interface will be removed and the network will be
+         * restored by the system automatically.
+         *
+         * <p>To avoid conflicts, there can be only one active VPN interface
+         * at the same time. Usually network parameters are never changed
+         * during the lifetime of a VPN connection. It is also common for an
+         * application to create a new file descriptor after closing the
+         * previous one. However, it is rare but not impossible to have two
+         * interfaces while performing a seamless handover. In this case, the
+         * old interface will be deactivated when the new one is created
+         * successfully. Both file descriptors are valid but now outgoing
+         * packets will be routed to the new interface. Therefore, after
+         * draining the old file descriptor, the application MUST close it
+         * and start using the new file descriptor. If the new interface
+         * cannot be created, the existing interface and its file descriptor
+         * remain untouched.
+         *
+         * <p>An exception will be thrown if the interface cannot be created
+         * for any reason. However, this method returns {@code null} if the
+         * application is not prepared or is revoked. This helps solve
+         * possible race conditions between other VPN applications.
+         *
+         * @return {@link ParcelFileDescriptor} of the VPN interface, or
+         *         {@code null} if the application is not prepared.
+         * @throws IllegalArgumentException if a parameter is not accepted
+         *         by the operating system.
+         * @throws IllegalStateException if a parameter cannot be applied
+         *         by the operating system.
+         * @throws SecurityException if the service is not properly declared
+         *         in {@code AndroidManifest.xml}.
+         * @see VpnService
+         */
+        @Nullable
+        public ParcelFileDescriptor establish() {
+            mConfig.addresses = mAddresses;
+            mConfig.routes = mRoutes;
+
+            try {
+                return getService().establishVpn(mConfig);
+            } catch (RemoteException e) {
+                throw new IllegalStateException(e);
+            }
+        }
+    }
+}
diff --git a/framework/src/android/net/apf/ApfCapabilities.aidl b/framework/src/android/net/apf/ApfCapabilities.aidl
new file mode 100644
index 0000000..7c4d4c2
--- /dev/null
+++ b/framework/src/android/net/apf/ApfCapabilities.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** Copyright (C) 2019 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.net.apf;
+
+@JavaOnlyStableParcelable parcelable ApfCapabilities;
\ No newline at end of file
diff --git a/core/java/android/net/apf/ApfCapabilities.java b/framework/src/android/net/apf/ApfCapabilities.java
similarity index 100%
rename from core/java/android/net/apf/ApfCapabilities.java
rename to framework/src/android/net/apf/ApfCapabilities.java
diff --git a/core/java/android/net/util/DnsUtils.java b/framework/src/android/net/util/DnsUtils.java
similarity index 100%
rename from core/java/android/net/util/DnsUtils.java
rename to framework/src/android/net/util/DnsUtils.java
diff --git a/core/java/android/net/util/KeepaliveUtils.java b/framework/src/android/net/util/KeepaliveUtils.java
similarity index 100%
rename from core/java/android/net/util/KeepaliveUtils.java
rename to framework/src/android/net/util/KeepaliveUtils.java
diff --git a/core/java/android/net/util/MultinetworkPolicyTracker.java b/framework/src/android/net/util/MultinetworkPolicyTracker.java
similarity index 100%
rename from core/java/android/net/util/MultinetworkPolicyTracker.java
rename to framework/src/android/net/util/MultinetworkPolicyTracker.java
diff --git a/framework/src/android/net/util/SocketUtils.java b/framework/src/android/net/util/SocketUtils.java
new file mode 100644
index 0000000..e64060f
--- /dev/null
+++ b/framework/src/android/net/util/SocketUtils.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.util;
+
+import static android.system.OsConstants.SOL_SOCKET;
+import static android.system.OsConstants.SO_BINDTODEVICE;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.net.NetworkUtils;
+import android.system.ErrnoException;
+import android.system.NetlinkSocketAddress;
+import android.system.Os;
+import android.system.PacketSocketAddress;
+
+import libcore.io.IoBridge;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.net.SocketAddress;
+
+/**
+ * Collection of utilities to interact with raw sockets.
+ * @hide
+ */
+@SystemApi
+public final class SocketUtils {
+    /**
+     * Create a raw datagram socket that is bound to an interface.
+     *
+     * <p>Data sent through the socket will go directly to the underlying network, ignoring VPNs.
+     */
+    public static void bindSocketToInterface(@NonNull FileDescriptor socket, @NonNull String iface)
+            throws ErrnoException {
+        // SO_BINDTODEVICE actually takes a string. This works because the first member
+        // of struct ifreq is a NULL-terminated interface name.
+        // TODO: add a setsockoptString()
+        Os.setsockoptIfreq(socket, SOL_SOCKET, SO_BINDTODEVICE, iface);
+        NetworkUtils.protectFromVpn(socket);
+    }
+
+    /**
+     * Make a socket address to communicate with netlink.
+     */
+    @NonNull
+    public static SocketAddress makeNetlinkSocketAddress(int portId, int groupsMask) {
+        return new NetlinkSocketAddress(portId, groupsMask);
+    }
+
+    /**
+     * Make socket address that packet sockets can bind to.
+     *
+     * @param protocol the layer 2 protocol of the packets to receive. One of the {@code ETH_P_*}
+     *                 constants in {@link android.system.OsConstants}.
+     * @param ifIndex the interface index on which packets will be received.
+     */
+    @NonNull
+    public static SocketAddress makePacketSocketAddress(int protocol, int ifIndex) {
+        return new PacketSocketAddress(
+                protocol /* sll_protocol */,
+                ifIndex /* sll_ifindex */,
+                null /* sll_addr */);
+    }
+
+    /**
+     * Make a socket address that packet socket can send packets to.
+     * @deprecated Use {@link #makePacketSocketAddress(int, int, byte[])} instead.
+     *
+     * @param ifIndex the interface index on which packets will be sent.
+     * @param hwAddr the hardware address to which packets will be sent.
+     */
+    @Deprecated
+    @NonNull
+    public static SocketAddress makePacketSocketAddress(int ifIndex, @NonNull byte[] hwAddr) {
+        return new PacketSocketAddress(
+                0 /* sll_protocol */,
+                ifIndex /* sll_ifindex */,
+                hwAddr /* sll_addr */);
+    }
+
+    /**
+     * Make a socket address that a packet socket can send packets to.
+     *
+     * @param protocol the layer 2 protocol of the packets to send. One of the {@code ETH_P_*}
+     *                 constants in {@link android.system.OsConstants}.
+     * @param ifIndex the interface index on which packets will be sent.
+     * @param hwAddr the hardware address to which packets will be sent.
+     */
+    @NonNull
+    public static SocketAddress makePacketSocketAddress(int protocol, int ifIndex,
+            @NonNull byte[] hwAddr) {
+        return new PacketSocketAddress(
+                protocol /* sll_protocol */,
+                ifIndex /* sll_ifindex */,
+                hwAddr /* sll_addr */);
+    }
+
+    /**
+     * @see IoBridge#closeAndSignalBlockedThreads(FileDescriptor)
+     */
+    public static void closeSocket(@Nullable FileDescriptor fd) throws IOException {
+        IoBridge.closeAndSignalBlockedThreads(fd);
+    }
+
+    private SocketUtils() {}
+}
diff --git a/service/Android.bp b/service/Android.bp
index c8f3bd3..8fc3181 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -57,6 +57,7 @@
     static_libs: [
         "net-utils-device-common",
         "net-utils-framework-common",
+        "netd-client",
     ],
     apex_available: [
         "//apex_available:platform",
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 74a6e07..c091dfa 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -132,8 +132,8 @@
 import android.net.TetheringManager;
 import android.net.UidRange;
 import android.net.UidRangeParcel;
+import android.net.UnderlyingNetworkInfo;
 import android.net.Uri;
-import android.net.VpnInfo;
 import android.net.VpnManager;
 import android.net.VpnService;
 import android.net.metrics.INetdEventListener;
@@ -216,8 +216,6 @@
 import com.android.server.net.NetworkPolicyManagerInternal;
 import com.android.server.utils.PriorityDump;
 
-import com.google.android.collect.Lists;
-
 import libcore.io.IoUtils;
 
 import java.io.FileDescriptor;
@@ -1329,31 +1327,6 @@
         return mNextNetworkRequestId++;
     }
 
-    private NetworkState getFilteredNetworkState(int networkType, int uid) {
-        if (mLegacyTypeTracker.isTypeSupported(networkType)) {
-            final NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType);
-            final NetworkState state;
-            if (nai != null) {
-                state = nai.getNetworkState();
-                state.networkInfo.setType(networkType);
-            } else {
-                final NetworkInfo info = new NetworkInfo(networkType, 0,
-                        getNetworkTypeName(networkType), "");
-                info.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null);
-                info.setIsAvailable(true);
-                final NetworkCapabilities capabilities = new NetworkCapabilities();
-                capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING,
-                        !info.isRoaming());
-                state = new NetworkState(info, new LinkProperties(), capabilities,
-                        null, null, null);
-            }
-            filterNetworkStateForUid(state, uid, false);
-            return state;
-        } else {
-            return NetworkState.EMPTY;
-        }
-    }
-
     @VisibleForTesting
     protected NetworkAgentInfo getNetworkAgentInfoForNetwork(Network network) {
         if (network == null) {
@@ -1464,6 +1437,18 @@
                 "%s %d(%d) on netId %d", action, nri.mUid, requestId, net.getNetId()));
     }
 
+    private void filterNetworkInfo(@NonNull NetworkInfo networkInfo,
+            @NonNull NetworkCapabilities nc, int uid, boolean ignoreBlocked) {
+        if (isNetworkWithCapabilitiesBlocked(nc, uid, ignoreBlocked)) {
+            networkInfo.setDetailedState(DetailedState.BLOCKED, null, null);
+        }
+        synchronized (mVpns) {
+            if (mLockdownTracker != null) {
+                mLockdownTracker.augmentNetworkInfo(networkInfo);
+            }
+        }
+    }
+
     /**
      * Apply any relevant filters to {@link NetworkState} for the given UID. For
      * example, this may mark the network as {@link DetailedState#BLOCKED} based
@@ -1471,16 +1456,7 @@
      */
     private void filterNetworkStateForUid(NetworkState state, int uid, boolean ignoreBlocked) {
         if (state == null || state.networkInfo == null || state.linkProperties == null) return;
-
-        if (isNetworkWithCapabilitiesBlocked(state.networkCapabilities, uid,
-                ignoreBlocked)) {
-            state.networkInfo.setDetailedState(DetailedState.BLOCKED, null, null);
-        }
-        synchronized (mVpns) {
-            if (mLockdownTracker != null) {
-                mLockdownTracker.augmentNetworkInfo(state.networkInfo);
-            }
-        }
+        filterNetworkInfo(state.networkInfo, state.networkCapabilities, uid, ignoreBlocked);
     }
 
     /**
@@ -1545,6 +1521,27 @@
         return state.networkInfo;
     }
 
+    private NetworkInfo getFilteredNetworkInfo(int networkType, int uid) {
+        if (!mLegacyTypeTracker.isTypeSupported(networkType)) {
+            return null;
+        }
+        final NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType);
+        final NetworkInfo info;
+        final NetworkCapabilities nc;
+        if (nai != null) {
+            info = new NetworkInfo(nai.networkInfo);
+            info.setType(networkType);
+            nc = nai.networkCapabilities;
+        } else {
+            info = new NetworkInfo(networkType, 0, getNetworkTypeName(networkType), "");
+            info.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null);
+            info.setIsAvailable(true);
+            nc = new NetworkCapabilities();
+        }
+        filterNetworkInfo(info, nc, uid, false);
+        return info;
+    }
+
     @Override
     public NetworkInfo getNetworkInfo(int networkType) {
         enforceAccessPermission();
@@ -1559,8 +1556,7 @@
                 return state.networkInfo;
             }
         }
-        final NetworkState state = getFilteredNetworkState(networkType, uid);
-        return state.networkInfo;
+        return getFilteredNetworkInfo(networkType, uid);
     }
 
     @Override
@@ -1579,7 +1575,7 @@
     @Override
     public NetworkInfo[] getAllNetworkInfo() {
         enforceAccessPermission();
-        final ArrayList<NetworkInfo> result = Lists.newArrayList();
+        final ArrayList<NetworkInfo> result = new ArrayList<>();
         for (int networkType = 0; networkType <= ConnectivityManager.MAX_NETWORK_TYPE;
                 networkType++) {
             NetworkInfo info = getNetworkInfo(networkType);
@@ -1593,10 +1589,16 @@
     @Override
     public Network getNetworkForType(int networkType) {
         enforceAccessPermission();
+        if (!mLegacyTypeTracker.isTypeSupported(networkType)) {
+            return null;
+        }
+        final NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType);
+        if (nai == null) {
+            return null;
+        }
         final int uid = mDeps.getCallingUid();
-        NetworkState state = getFilteredNetworkState(networkType, uid);
-        if (!isNetworkWithCapabilitiesBlocked(state.networkCapabilities, uid, false)) {
-            return state.network;
+        if (!isNetworkWithCapabilitiesBlocked(nai.networkCapabilities, uid, false)) {
+            return nai.network;
         }
         return null;
     }
@@ -1847,7 +1849,7 @@
         // This contains IMSI details, so make sure the caller is privileged.
         NetworkStack.checkNetworkStackPermission(mContext);
 
-        final ArrayList<NetworkState> result = Lists.newArrayList();
+        final ArrayList<NetworkState> result = new ArrayList<>();
         for (Network network : getAllNetworks()) {
             final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
             if (nai != null) {
@@ -4854,28 +4856,28 @@
      *
      * <p>Must be called on the handler thread.
      */
-    private VpnInfo[] getAllVpnInfo() {
+    private UnderlyingNetworkInfo[] getAllVpnInfo() {
         ensureRunningOnConnectivityServiceThread();
         synchronized (mVpns) {
             if (mLockdownEnabled) {
-                return new VpnInfo[0];
+                return new UnderlyingNetworkInfo[0];
             }
         }
-        List<VpnInfo> infoList = new ArrayList<>();
+        List<UnderlyingNetworkInfo> infoList = new ArrayList<>();
         for (NetworkAgentInfo nai : mNetworkAgentInfos) {
-            VpnInfo info = createVpnInfo(nai);
+            UnderlyingNetworkInfo info = createVpnInfo(nai);
             if (info != null) {
                 infoList.add(info);
             }
         }
-        return infoList.toArray(new VpnInfo[infoList.size()]);
+        return infoList.toArray(new UnderlyingNetworkInfo[infoList.size()]);
     }
 
     /**
      * @return VPN information for accounting, or null if we can't retrieve all required
      *         information, e.g underlying ifaces.
      */
-    private VpnInfo createVpnInfo(NetworkAgentInfo nai) {
+    private UnderlyingNetworkInfo createVpnInfo(NetworkAgentInfo nai) {
         if (!nai.isVPN()) return null;
 
         Network[] underlyingNetworks = nai.declaredUnderlyingNetworks;
@@ -4907,11 +4909,11 @@
         // Must be non-null or NetworkStatsService will crash.
         // Cannot happen in production code because Vpn only registers the NetworkAgent after the
         // tun or ipsec interface is created.
+        // TODO: Remove this check.
         if (nai.linkProperties.getInterfaceName() == null) return null;
 
-        return new VpnInfo(nai.networkCapabilities.getOwnerUid(),
-                nai.linkProperties.getInterfaceName(),
-                interfaces.toArray(new String[0]));
+        return new UnderlyingNetworkInfo(nai.networkCapabilities.getOwnerUid(),
+                nai.linkProperties.getInterfaceName(), interfaces);
     }
 
     /**
@@ -5658,7 +5660,9 @@
         if (ns == null) {
             return;
         }
-        MatchAllNetworkSpecifier.checkNotMatchAllNetworkSpecifier(ns);
+        if (ns instanceof MatchAllNetworkSpecifier) {
+            throw new IllegalArgumentException("A MatchAllNetworkSpecifier is not permitted");
+        }
     }
 
     private void ensureValid(NetworkCapabilities nc) {
@@ -5705,6 +5709,9 @@
                 networkCapabilities = createDefaultNetworkCapabilitiesForUid(callingUid);
                 enforceAccessPermission();
                 break;
+            case BACKGROUND_REQUEST:
+                enforceNetworkStackOrSettingsPermission();
+                // Fall-through since other checks are the same with normal requests.
             case REQUEST:
                 networkCapabilities = new NetworkCapabilities(networkCapabilities);
                 enforceNetworkRequestPermissions(networkCapabilities, callingPackageName,
@@ -6194,7 +6201,7 @@
         nai.networkAgentPortalData = lp.getCaptivePortalData();
     }
 
-    private void updateLinkProperties(NetworkAgentInfo networkAgent, LinkProperties newLp,
+    private void updateLinkProperties(NetworkAgentInfo networkAgent, @NonNull LinkProperties newLp,
             @NonNull LinkProperties oldLp) {
         int netId = networkAgent.network.getNetId();
 
@@ -6203,8 +6210,7 @@
         // the LinkProperties for the network are accurate.
         networkAgent.clatd.fixupLinkProperties(oldLp, newLp);
 
-        updateInterfaces(newLp, oldLp, netId, networkAgent.networkCapabilities,
-                networkAgent.networkInfo.getType());
+        updateInterfaces(newLp, oldLp, netId, networkAgent.networkCapabilities);
 
         // update filtering rules, need to happen after the interface update so netd knows about the
         // new interface (the interface name -> index map becomes initialized)
@@ -6343,7 +6349,7 @@
 
     private void updateInterfaces(final @Nullable LinkProperties newLp,
             final @Nullable LinkProperties oldLp, final int netId,
-            final @Nullable NetworkCapabilities caps, final int legacyType) {
+            final @NonNull NetworkCapabilities caps) {
         final CompareResult<String> interfaceDiff = new CompareResult<>(
                 oldLp != null ? oldLp.getAllInterfaceNames() : null,
                 newLp != null ? newLp.getAllInterfaceNames() : null);
@@ -6354,7 +6360,7 @@
                     if (DBG) log("Adding iface " + iface + " to network " + netId);
                     mNetd.networkAddInterface(netId, iface);
                     wakeupModifyInterface(iface, caps, true);
-                    bs.noteNetworkInterfaceType(iface, legacyType);
+                    bs.noteNetworkInterfaceForTransports(iface, caps.getTransportTypes());
                 } catch (Exception e) {
                     loge("Exception adding interface: " + e);
                 }
@@ -6626,6 +6632,7 @@
      * maintained here that the NetworkAgent is not aware of (e.g., validated, captive portal,
      * and foreground status).
      */
+    @NonNull
     private NetworkCapabilities mixInCapabilities(NetworkAgentInfo nai, NetworkCapabilities nc) {
         // Once a NetworkAgent is connected, complain if some immutable capabilities are removed.
          // Don't complain for VPNs since they're not driven by requests and there is no risk of
@@ -6682,6 +6689,25 @@
         return newNc;
     }
 
+    private void updateNetworkInfoForRoamingAndSuspended(NetworkAgentInfo nai,
+            NetworkCapabilities prevNc, NetworkCapabilities newNc) {
+        final boolean prevSuspended = !prevNc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED);
+        final boolean suspended = !newNc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED);
+        final boolean prevRoaming = !prevNc.hasCapability(NET_CAPABILITY_NOT_ROAMING);
+        final boolean roaming = !newNc.hasCapability(NET_CAPABILITY_NOT_ROAMING);
+        if (prevSuspended != suspended) {
+            // TODO (b/73132094) : remove this call once the few users of onSuspended and
+            // onResumed have been removed.
+            notifyNetworkCallbacks(nai, suspended ? ConnectivityManager.CALLBACK_SUSPENDED
+                    : ConnectivityManager.CALLBACK_RESUMED);
+        }
+        if (prevSuspended != suspended || prevRoaming != roaming) {
+            // updateNetworkInfo will mix in the suspended info from the capabilities and
+            // take appropriate action for the network having possibly changed state.
+            updateNetworkInfo(nai, nai.networkInfo);
+        }
+    }
+
     /**
      * Update the NetworkCapabilities for {@code nai} to {@code nc}. Specifically:
      *
@@ -6713,25 +6739,13 @@
             // on this network. We might have been called by rematchNetworkAndRequests when a
             // network changed foreground state.
             processListenRequests(nai);
-            final boolean prevSuspended = !prevNc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED);
-            final boolean suspended = !newNc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED);
-            final boolean prevRoaming = !prevNc.hasCapability(NET_CAPABILITY_NOT_ROAMING);
-            final boolean roaming = !newNc.hasCapability(NET_CAPABILITY_NOT_ROAMING);
-            if (prevSuspended != suspended || prevRoaming != roaming) {
-                // TODO (b/73132094) : remove this call once the few users of onSuspended and
-                // onResumed have been removed.
-                notifyNetworkCallbacks(nai, suspended ? ConnectivityManager.CALLBACK_SUSPENDED
-                        : ConnectivityManager.CALLBACK_RESUMED);
-                // updateNetworkInfo will mix in the suspended info from the capabilities and
-                // take appropriate action for the network having possibly changed state.
-                updateNetworkInfo(nai, nai.networkInfo);
-            }
         } else {
             // If the requestable capabilities have changed or the score changed, we can't have been
             // called by rematchNetworkAndRequests, so it's safe to start a rematch.
             rematchAllNetworksAndRequests();
             notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
         }
+        updateNetworkInfoForRoamingAndSuspended(nai, prevNc, newNc);
 
         final boolean oldMetered = prevNc.isMetered();
         final boolean newMetered = newNc.isMetered();
@@ -7989,10 +8003,10 @@
             activeIface = activeLinkProperties.getInterfaceName();
         }
 
-        final VpnInfo[] vpnInfos = getAllVpnInfo();
+        final UnderlyingNetworkInfo[] underlyingNetworkInfos = getAllVpnInfo();
         try {
-            mStatsService.forceUpdateIfaces(
-                    getDefaultNetworks(), getAllNetworkState(), activeIface, vpnInfos);
+            mStatsService.forceUpdateIfaces(getDefaultNetworks(), getAllNetworkState(), activeIface,
+                    underlyingNetworkInfos);
         } catch (Exception ignored) {
         }
     }
@@ -8252,6 +8266,7 @@
         return getVpnIfOwner(mDeps.getCallingUid());
     }
 
+    // TODO: stop calling into Vpn.java and get this information from data in this class.
     @GuardedBy("mVpns")
     private Vpn getVpnIfOwner(int uid) {
         final int user = UserHandle.getUserId(uid);
@@ -8260,7 +8275,7 @@
         if (vpn == null) {
             return null;
         } else {
-            final VpnInfo info = vpn.getVpnInfo();
+            final UnderlyingNetworkInfo info = vpn.getUnderlyingNetworkInfo();
             return (info == null || info.ownerUid != uid) ? null : vpn;
         }
     }
diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java
index e8687e5..e96fd39 100644
--- a/services/core/java/com/android/server/TestNetworkService.java
+++ b/services/core/java/com/android/server/TestNetworkService.java
@@ -32,6 +32,7 @@
 import android.net.NetworkAgentConfig;
 import android.net.NetworkCapabilities;
 import android.net.NetworkProvider;
+import android.net.NetworkStack;
 import android.net.RouteInfo;
 import android.net.StringNetworkSpecifier;
 import android.net.TestNetworkInterface;
@@ -48,6 +49,7 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.net.module.util.NetdUtils;
 
 import java.io.UncheckedIOException;
 import java.net.Inet4Address;
@@ -242,6 +244,7 @@
         nc.addTransportType(NetworkCapabilities.TRANSPORT_TEST);
         nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED);
         nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+        nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
         nc.setNetworkSpecifier(new StringNetworkSpecifier(iface));
         nc.setAdministratorUids(administratorUids);
         if (!isMetered) {
@@ -316,10 +319,10 @@
         }
 
         try {
-            // This requires NETWORK_STACK privileges.
             final long token = Binder.clearCallingIdentity();
             try {
-                mNMS.setInterfaceUp(iface);
+                NetworkStack.checkNetworkStackPermission(mContext);
+                NetdUtils.setInterfaceUp(mNetd, iface);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index ab0360b..1a4f20c 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -57,6 +57,7 @@
 import com.android.server.ConnectivityService;
 
 import java.io.PrintWriter;
+import java.util.Arrays;
 import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.Objects;
@@ -329,7 +330,7 @@
     private final QosCallbackTracker mQosCallbackTracker;
 
     public NetworkAgentInfo(INetworkAgent na, Network net, NetworkInfo info,
-            LinkProperties lp, NetworkCapabilities nc, int score, Context context,
+            @NonNull LinkProperties lp, @NonNull NetworkCapabilities nc, int score, Context context,
             Handler handler, NetworkAgentConfig config, ConnectivityService connService, INetd netd,
             IDnsResolver dnsResolver, INetworkManagementService nms, int factorySerialNumber,
             int creatorUid, QosCallbackTracker qosCallbackTracker) {
@@ -1025,6 +1026,8 @@
                 + (networkAgentConfig.acceptUnvalidated ? " acceptUnvalidated" : "")
                 + (networkAgentConfig.acceptPartialConnectivity ? " acceptPartialConnectivity" : "")
                 + (clatd.isStarted() ? " clat{" + clatd + "} " : "")
+                + (declaredUnderlyingNetworks != null
+                        ? " underlying{" + Arrays.toString(declaredUnderlyingNetworks) + "}" : "")
                 + "  lp{" + linkProperties + "}"
                 + "  nc{" + networkCapabilities + "}"
                 + "}";
diff --git a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
index a7be657..5e6b9f3 100644
--- a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
+++ b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
@@ -686,7 +686,7 @@
 
             mHostname = hostname;
             mMeasurement.description = "DNS TLS dst{" + mTarget.getHostAddress() + "} hostname{"
-                    + TextUtils.emptyIfNull(mHostname) + "}";
+                    + (mHostname == null ? "" : mHostname) + "}";
         }
 
         private SSLSocket setupSSLSocket() throws IOException {
diff --git a/tests/net/common/java/android/net/UnderlyingNetworkInfoTest.kt b/tests/net/common/java/android/net/UnderlyingNetworkInfoTest.kt
new file mode 100644
index 0000000..87cfb34
--- /dev/null
+++ b/tests/net/common/java/android/net/UnderlyingNetworkInfoTest.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net
+
+import android.os.Build
+import androidx.test.filters.SmallTest
+import com.android.testutils.DevSdkIgnoreRule
+import com.android.testutils.DevSdkIgnoreRunner
+import com.android.testutils.assertParcelSane
+import org.junit.Test
+import org.junit.runner.RunWith
+import kotlin.test.assertEquals
+
+private const val TEST_OWNER_UID = 123
+private const val TEST_IFACE = "test_tun0"
+private val TEST_IFACE_LIST = listOf("wlan0", "rmnet_data0", "eth0")
+
+@SmallTest
+@RunWith(DevSdkIgnoreRunner::class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
+class UnderlyingNetworkInfoTest {
+    @Test
+    fun testParcelUnparcel() {
+        val testInfo = UnderlyingNetworkInfo(TEST_OWNER_UID, TEST_IFACE, TEST_IFACE_LIST)
+        assertEquals(TEST_OWNER_UID, testInfo.ownerUid)
+        assertEquals(TEST_IFACE, testInfo.iface)
+        assertEquals(TEST_IFACE_LIST, testInfo.underlyingIfaces)
+        assertParcelSane(testInfo, 3)
+
+        val emptyInfo = UnderlyingNetworkInfo(0, String(), listOf())
+        assertEquals(0, emptyInfo.ownerUid)
+        assertEquals(String(), emptyInfo.iface)
+        assertEquals(listOf(), emptyInfo.underlyingIfaces)
+        assertParcelSane(emptyInfo, 3)
+    }
+}
\ No newline at end of file
diff --git a/tests/net/java/android/net/ConnectivityManagerTest.java b/tests/net/java/android/net/ConnectivityManagerTest.java
index f2dd27e..c2fddf3 100644
--- a/tests/net/java/android/net/ConnectivityManagerTest.java
+++ b/tests/net/java/android/net/ConnectivityManagerTest.java
@@ -32,6 +32,7 @@
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.NetworkRequest.Type.BACKGROUND_REQUEST;
 import static android.net.NetworkRequest.Type.REQUEST;
 import static android.net.NetworkRequest.Type.TRACK_DEFAULT;
 
@@ -368,6 +369,12 @@
                 eq(TRACK_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE),
                 eq(testPkgName), eq(null));
         reset(mService);
+
+        manager.requestBackgroundNetwork(request, null, callback);
+        verify(mService).requestNetwork(eq(request.networkCapabilities),
+                eq(BACKGROUND_REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE),
+                eq(testPkgName), eq(null));
+        reset(mService);
     }
 
     static Message makeMessage(NetworkRequest req, int messageType) {
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index ca73689..4c658e1 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -64,6 +64,7 @@
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_RCS;
@@ -200,8 +201,8 @@
 import android.net.SocketKeepalive;
 import android.net.UidRange;
 import android.net.UidRangeParcel;
+import android.net.UnderlyingNetworkInfo;
 import android.net.Uri;
-import android.net.VpnInfo;
 import android.net.VpnManager;
 import android.net.metrics.IpConnectivityLog;
 import android.net.shared.NetworkMonitorUtils;
@@ -379,6 +380,10 @@
     private QosCallbackMockHelper mQosCallbackMockHelper;
     private QosCallbackTracker mQosCallbackTracker;
 
+    // State variables required to emulate NetworkPolicyManagerService behaviour.
+    private int mUidRules = RULE_NONE;
+    private boolean mRestrictBackground = false;
+
     @Mock DeviceIdleInternal mDeviceIdleInternal;
     @Mock INetworkManagementService mNetworkManagementService;
     @Mock INetworkStatsService mStatsService;
@@ -1075,7 +1080,7 @@
         private boolean mAgentRegistered = false;
 
         private int mVpnType = VpnManager.TYPE_VPN_SERVICE;
-        private VpnInfo mVpnInfo;
+        private UnderlyingNetworkInfo mUnderlyingNetworkInfo;
 
         // These ConditionVariables allow tests to wait for LegacyVpnRunner to be stopped/started.
         // TODO: this scheme is ad-hoc and error-prone because it does not fail if, for example, the
@@ -1249,14 +1254,15 @@
         }
 
         @Override
-        public synchronized VpnInfo getVpnInfo() {
-            if (mVpnInfo != null) return mVpnInfo;
+        public synchronized UnderlyingNetworkInfo getUnderlyingNetworkInfo() {
+            if (mUnderlyingNetworkInfo != null) return mUnderlyingNetworkInfo;
 
-            return super.getVpnInfo();
+            return super.getUnderlyingNetworkInfo();
         }
 
-        private synchronized void setVpnInfo(VpnInfo vpnInfo) {
-            mVpnInfo = vpnInfo;
+        private synchronized void setUnderlyingNetworkInfo(
+                UnderlyingNetworkInfo underlyingNetworkInfo) {
+            mUnderlyingNetworkInfo = underlyingNetworkInfo;
         }
     }
 
@@ -1276,12 +1282,23 @@
         }
     }
 
+    private void updateUidNetworkingBlocked() {
+        doAnswer(i -> NetworkPolicyManagerInternal.isUidNetworkingBlocked(
+                i.getArgument(0) /* uid */, mUidRules, i.getArgument(1) /* metered */,
+                mRestrictBackground)
+        ).when(mNetworkPolicyManager).isUidNetworkingBlocked(anyInt(), anyBoolean());
+    }
+
     private void setUidRulesChanged(int uidRules) throws RemoteException {
-        mPolicyListener.onUidRulesChanged(Process.myUid(), uidRules);
+        mUidRules = uidRules;
+        updateUidNetworkingBlocked();
+        mPolicyListener.onUidRulesChanged(Process.myUid(), mUidRules);
     }
 
     private void setRestrictBackgroundChanged(boolean restrictBackground) throws RemoteException {
-        mPolicyListener.onRestrictBackgroundChanged(restrictBackground);
+        mRestrictBackground = restrictBackground;
+        updateUidNetworkingBlocked();
+        mPolicyListener.onRestrictBackgroundChanged(mRestrictBackground);
     }
 
     private Nat464Xlat getNat464Xlat(NetworkAgentWrapper mna) {
@@ -3692,10 +3709,13 @@
 
     @Test
     public void testBackgroundNetworks() throws Exception {
-        // Create a background request. We can't do this ourselves because ConnectivityService
-        // doesn't have an API for it. So just turn on mobile data always on.
-        setAlwaysOnNetworks(true);
+        // Create a cellular background request.
         grantUsingBackgroundNetworksPermissionForUid(Binder.getCallingUid());
+        final TestNetworkCallback cellBgCallback = new TestNetworkCallback();
+        mCm.requestBackgroundNetwork(new NetworkRequest.Builder()
+                .addTransportType(TRANSPORT_CELLULAR).build(), null, cellBgCallback);
+
+        // Make callbacks for monitoring.
         final NetworkRequest request = new NetworkRequest.Builder().build();
         final NetworkRequest fgRequest = new NetworkRequest.Builder()
                 .addCapability(NET_CAPABILITY_FOREGROUND).build();
@@ -3764,6 +3784,7 @@
 
         mCm.unregisterNetworkCallback(callback);
         mCm.unregisterNetworkCallback(fgCallback);
+        mCm.unregisterNetworkCallback(cellBgCallback);
     }
 
     @Ignore // This test has instrinsic chances of spurious failures: ignore for continuous testing.
@@ -5194,20 +5215,22 @@
     private void expectForceUpdateIfaces(Network[] networks, String defaultIface,
             Integer vpnUid, String vpnIfname, String[] underlyingIfaces) throws Exception {
         ArgumentCaptor<Network[]> networksCaptor = ArgumentCaptor.forClass(Network[].class);
-        ArgumentCaptor<VpnInfo[]> vpnInfosCaptor = ArgumentCaptor.forClass(VpnInfo[].class);
+        ArgumentCaptor<UnderlyingNetworkInfo[]> vpnInfosCaptor = ArgumentCaptor.forClass(
+                UnderlyingNetworkInfo[].class);
 
         verify(mStatsService, atLeastOnce()).forceUpdateIfaces(networksCaptor.capture(),
                 any(NetworkState[].class), eq(defaultIface), vpnInfosCaptor.capture());
 
         assertSameElementsNoDuplicates(networksCaptor.getValue(), networks);
 
-        VpnInfo[] infos = vpnInfosCaptor.getValue();
+        UnderlyingNetworkInfo[] infos = vpnInfosCaptor.getValue();
         if (vpnUid != null) {
             assertEquals("Should have exactly one VPN:", 1, infos.length);
-            VpnInfo info = infos[0];
+            UnderlyingNetworkInfo info = infos[0];
             assertEquals("Unexpected VPN owner:", (int) vpnUid, info.ownerUid);
-            assertEquals("Unexpected VPN interface:", vpnIfname, info.vpnIface);
-            assertSameElementsNoDuplicates(underlyingIfaces, info.underlyingIfaces);
+            assertEquals("Unexpected VPN interface:", vpnIfname, info.iface);
+            assertSameElementsNoDuplicates(underlyingIfaces,
+                    info.underlyingIfaces.toArray(new String[0]));
         } else {
             assertEquals(0, infos.length);
             return;
@@ -5268,7 +5291,7 @@
         waitForIdle();
         verify(mStatsService, never())
                 .forceUpdateIfaces(eq(onlyCell), any(NetworkState[].class), eq(MOBILE_IFNAME),
-                        eq(new VpnInfo[0]));
+                        eq(new UnderlyingNetworkInfo[0]));
         reset(mStatsService);
 
         // Roaming change should update ifaces
@@ -5351,8 +5374,8 @@
         // network for the VPN...
         verify(mStatsService, never()).forceUpdateIfaces(any(Network[].class),
                 any(NetworkState[].class), any() /* anyString() doesn't match null */,
-                argThat(infos -> infos[0].underlyingIfaces.length == 1
-                        && WIFI_IFNAME.equals(infos[0].underlyingIfaces[0])));
+                argThat(infos -> infos[0].underlyingIfaces.size() == 1
+                        && WIFI_IFNAME.equals(infos[0].underlyingIfaces.get(0))));
         verifyNoMoreInteractions(mStatsService);
         reset(mStatsService);
 
@@ -5365,8 +5388,8 @@
         waitForIdle();
         verify(mStatsService).forceUpdateIfaces(any(Network[].class),
                 any(NetworkState[].class), any() /* anyString() doesn't match null */,
-                argThat(vpnInfos -> vpnInfos[0].underlyingIfaces.length == 1
-                        && WIFI_IFNAME.equals(vpnInfos[0].underlyingIfaces[0])));
+                argThat(vpnInfos -> vpnInfos[0].underlyingIfaces.size() == 1
+                        && WIFI_IFNAME.equals(vpnInfos[0].underlyingIfaces.get(0))));
         mEthernetNetworkAgent.disconnect();
         waitForIdle();
         reset(mStatsService);
@@ -5963,23 +5986,18 @@
         callback.expectCapabilitiesThat(mMockVpn,
                 nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
                         && nc.hasTransport(TRANSPORT_WIFI));
-
-        // BUG: the VPN is no longer suspended, so a RESUMED callback should have been sent.
-        // callback.expectCallback(CallbackEntry.RESUMED, mMockVpn);
+        callback.expectCallback(CallbackEntry.RESUMED, mMockVpn);
         callback.assertNoCallback();
 
         assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
                 .hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
         assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
         assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
-        assertNetworkInfo(TYPE_VPN, DetailedState.SUSPENDED);  // BUG: VPN caps have NOT_SUSPENDED.
+        assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
         assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
-        // BUG: the device has connectivity, so this should return true.
-        assertGetNetworkInfoOfGetActiveNetworkIsConnected(false);
+        assertGetNetworkInfoOfGetActiveNetworkIsConnected(true);
 
-        // Unsuspend cellular and then switch back to it.
-        // The same bug happens in the opposite direction: the VPN's capabilities correctly have
-        // NOT_SUSPENDED, but the VPN's NetworkInfo is in state SUSPENDED.
+        // Unsuspend cellular and then switch back to it. The VPN remains not suspended.
         mCellNetworkAgent.resume();
         callback.assertNoCallback();
         mWiFiNetworkAgent.disconnect();
@@ -5996,12 +6014,11 @@
                 .hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
         assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
         assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED);
-        assertNetworkInfo(TYPE_VPN, DetailedState.SUSPENDED);  // BUG: VPN caps have NOT_SUSPENDED.
+        assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
         assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
-        // BUG: the device has connectivity, so this should return true.
-        assertGetNetworkInfoOfGetActiveNetworkIsConnected(false);
+        assertGetNetworkInfoOfGetActiveNetworkIsConnected(true);
 
-        // Re-suspending the current network fixes the problem.
+        // Suspend cellular and expect no connectivity.
         mCellNetworkAgent.suspend();
         callback.expectCapabilitiesThat(mMockVpn,
                 nc -> !nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
@@ -6017,6 +6034,7 @@
         assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.SUSPENDED);
         assertGetNetworkInfoOfGetActiveNetworkIsConnected(false);
 
+        // Resume cellular and expect that connectivity comes back.
         mCellNetworkAgent.resume();
         callback.expectCapabilitiesThat(mMockVpn,
                 nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
@@ -6407,10 +6425,7 @@
                 && caps.hasTransport(TRANSPORT_CELLULAR)
                 && !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
                 && !caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
-        // While the SUSPENDED callback should in theory be sent here, it is not. This is
-        // a bug in ConnectivityService, but as the SUSPENDED and RESUMED callbacks have never
-        // been public and are deprecated and slated for removal, there is no sense in spending
-        // resources fixing this bug now.
+        vpnNetworkCallback.expectCallback(CallbackEntry.SUSPENDED, mMockVpn);
         assertDefaultNetworkCapabilities(userId, mCellNetworkAgent, mWiFiNetworkAgent);
 
         // Use both again.
@@ -6422,8 +6437,7 @@
                 && caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
                 && !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
                 && caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
-        // As above, the RESUMED callback not being sent here is a bug, but not a bug that's
-        // worth anybody's time to fix.
+        vpnNetworkCallback.expectCallback(CallbackEntry.RESUMED, mMockVpn);
         assertDefaultNetworkCapabilities(userId, mCellNetworkAgent, mWiFiNetworkAgent);
 
         // Disconnect cell. Receive update without even removing the dead network from the
@@ -6843,9 +6857,15 @@
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
         cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+        assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+        assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
 
         setUidRulesChanged(RULE_REJECT_ALL);
         cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
+        assertNull(mCm.getActiveNetwork());
+        assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
 
         // ConnectivityService should cache it not to invoke the callback again.
         setUidRulesChanged(RULE_REJECT_METERED);
@@ -6853,32 +6873,60 @@
 
         setUidRulesChanged(RULE_NONE);
         cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
+        assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+        assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
 
         setUidRulesChanged(RULE_REJECT_METERED);
         cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
+        assertNull(mCm.getActiveNetwork());
+        assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
 
         // Restrict the network based on UID rule and NOT_METERED capability change.
         mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
         cellNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_METERED, mCellNetworkAgent);
         cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
+        assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+        assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+
         mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
         cellNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED,
                 mCellNetworkAgent);
         cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
+        assertNull(mCm.getActiveNetwork());
+        assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
+
         setUidRulesChanged(RULE_ALLOW_METERED);
         cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
+        assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+        assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
 
         setUidRulesChanged(RULE_NONE);
         cellNetworkCallback.assertNoCallback();
 
-        // Restrict the network based on BackgroundRestricted.
+        // Restrict background data. Networking is not blocked because the network is unmetered.
         setRestrictBackgroundChanged(true);
         cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
+        assertNull(mCm.getActiveNetwork());
+        assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
         setRestrictBackgroundChanged(true);
         cellNetworkCallback.assertNoCallback();
-        setRestrictBackgroundChanged(false);
+
+        setUidRulesChanged(RULE_ALLOW_METERED);
         cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
+        assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+
+        setRestrictBackgroundChanged(false);
         cellNetworkCallback.assertNoCallback();
+        assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+        assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
 
         mCm.unregisterNetworkCallback(cellNetworkCallback);
     }
@@ -7335,39 +7383,68 @@
         b2.expectBroadcast();
     }
 
+    /**
+     * Test mutable and requestable network capabilities such as
+     * {@link NetworkCapabilities#NET_CAPABILITY_TRUSTED} and
+     * {@link NetworkCapabilities#NET_CAPABILITY_NOT_VCN_MANAGED}. Verify that the
+     * {@code ConnectivityService} re-assign the networks accordingly.
+     */
     @Test
-    public final void testLoseTrusted() throws Exception {
-        final NetworkRequest trustedRequest = new NetworkRequest.Builder()
-                .addCapability(NET_CAPABILITY_TRUSTED)
-                .build();
-        final TestNetworkCallback trustedCallback = new TestNetworkCallback();
-        mCm.requestNetwork(trustedRequest, trustedCallback);
+    public final void testLoseMutableAndRequestableCaps() throws Exception {
+        final int[] testCaps = new int [] {
+                NET_CAPABILITY_TRUSTED,
+                NET_CAPABILITY_NOT_VCN_MANAGED
+        };
+        for (final int testCap : testCaps) {
+            // Create requests with and without the testing capability.
+            final TestNetworkCallback callbackWithCap = new TestNetworkCallback();
+            final TestNetworkCallback callbackWithoutCap = new TestNetworkCallback();
+            mCm.requestNetwork(new NetworkRequest.Builder().addCapability(testCap).build(),
+                    callbackWithCap);
+            mCm.requestNetwork(new NetworkRequest.Builder().removeCapability(testCap).build(),
+                    callbackWithoutCap);
 
-        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
-        mCellNetworkAgent.connect(true);
-        trustedCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
-        verify(mMockNetd).networkSetDefault(eq(mCellNetworkAgent.getNetwork().netId));
-        reset(mMockNetd);
+            // Setup networks with testing capability and verify the default network changes.
+            mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+            mCellNetworkAgent.addCapability(testCap);
+            mCellNetworkAgent.connect(true);
+            callbackWithCap.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+            callbackWithoutCap.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+            verify(mMockNetd).networkSetDefault(eq(mCellNetworkAgent.getNetwork().netId));
+            reset(mMockNetd);
 
-        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
-        mWiFiNetworkAgent.connect(true);
-        trustedCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
-        verify(mMockNetd).networkSetDefault(eq(mWiFiNetworkAgent.getNetwork().netId));
-        reset(mMockNetd);
+            mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+            mWiFiNetworkAgent.addCapability(testCap);
+            mWiFiNetworkAgent.connect(true);
+            callbackWithCap.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
+            callbackWithoutCap.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
+            verify(mMockNetd).networkSetDefault(eq(mWiFiNetworkAgent.getNetwork().netId));
+            reset(mMockNetd);
 
-        mWiFiNetworkAgent.removeCapability(NET_CAPABILITY_TRUSTED);
-        trustedCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
-        verify(mMockNetd).networkSetDefault(eq(mCellNetworkAgent.getNetwork().netId));
-        reset(mMockNetd);
+            // Remove the testing capability on wifi, verify the callback and default network
+            // changes back to cellular.
+            mWiFiNetworkAgent.removeCapability(testCap);
+            callbackWithCap.expectAvailableCallbacksValidated(mCellNetworkAgent);
+            callbackWithoutCap.expectCapabilitiesWithout(testCap, mWiFiNetworkAgent);
+            // TODO: Test default network changes for NOT_VCN_MANAGED once the default request has
+            //  it.
+            if (testCap == NET_CAPABILITY_TRUSTED) {
+                verify(mMockNetd).networkSetDefault(eq(mCellNetworkAgent.getNetwork().netId));
+                reset(mMockNetd);
+            }
 
-        mCellNetworkAgent.removeCapability(NET_CAPABILITY_TRUSTED);
-        trustedCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
-        verify(mMockNetd).networkClearDefault();
+            mCellNetworkAgent.removeCapability(testCap);
+            callbackWithCap.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+            callbackWithoutCap.assertNoCallback();
+            if (testCap == NET_CAPABILITY_TRUSTED) {
+                verify(mMockNetd).networkClearDefault();
+            }
 
-        mCm.unregisterNetworkCallback(trustedCallback);
+            mCm.unregisterNetworkCallback(callbackWithCap);
+            mCm.unregisterNetworkCallback(callbackWithoutCap);
+        }
     }
 
-    @Ignore // 40%+ flakiness : figure out why and re-enable.
     @Test
     public final void testBatteryStatsNetworkType() throws Exception {
         final LinkProperties cellLp = new LinkProperties();
@@ -7375,8 +7452,8 @@
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
         mCellNetworkAgent.connect(true);
         waitForIdle();
-        verify(mBatteryStatsService).noteNetworkInterfaceType(cellLp.getInterfaceName(),
-                TYPE_MOBILE);
+        verify(mBatteryStatsService).noteNetworkInterfaceForTransports(cellLp.getInterfaceName(),
+                new int[] { TRANSPORT_CELLULAR });
         reset(mBatteryStatsService);
 
         final LinkProperties wifiLp = new LinkProperties();
@@ -7384,18 +7461,20 @@
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp);
         mWiFiNetworkAgent.connect(true);
         waitForIdle();
-        verify(mBatteryStatsService).noteNetworkInterfaceType(wifiLp.getInterfaceName(),
-                TYPE_WIFI);
+        verify(mBatteryStatsService).noteNetworkInterfaceForTransports(wifiLp.getInterfaceName(),
+                new int[] { TRANSPORT_WIFI });
         reset(mBatteryStatsService);
 
         mCellNetworkAgent.disconnect();
+        mWiFiNetworkAgent.disconnect();
 
         cellLp.setInterfaceName("wifi0");
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
         mCellNetworkAgent.connect(true);
         waitForIdle();
-        verify(mBatteryStatsService).noteNetworkInterfaceType(cellLp.getInterfaceName(),
-                TYPE_MOBILE);
+        verify(mBatteryStatsService).noteNetworkInterfaceForTransports(cellLp.getInterfaceName(),
+                new int[] { TRANSPORT_CELLULAR });
+        mCellNetworkAgent.disconnect();
     }
 
     /**
@@ -7468,8 +7547,8 @@
         assertRoutesAdded(cellNetId, ipv6Subnet, defaultRoute);
         verify(mMockDnsResolver, times(1)).createNetworkCache(eq(cellNetId));
         verify(mMockNetd, times(1)).networkAddInterface(cellNetId, MOBILE_IFNAME);
-        verify(mBatteryStatsService).noteNetworkInterfaceType(cellLp.getInterfaceName(),
-                TYPE_MOBILE);
+        verify(mBatteryStatsService).noteNetworkInterfaceForTransports(cellLp.getInterfaceName(),
+                new int[] { TRANSPORT_CELLULAR });
 
         networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
@@ -7489,7 +7568,8 @@
         // Make sure BatteryStats was not told about any v4- interfaces, as none should have
         // come online yet.
         waitForIdle();
-        verify(mBatteryStatsService, never()).noteNetworkInterfaceType(startsWith("v4-"), anyInt());
+        verify(mBatteryStatsService, never()).noteNetworkInterfaceForTransports(startsWith("v4-"),
+                any());
 
         verifyNoMoreInteractions(mMockNetd);
         verifyNoMoreInteractions(mMockDnsResolver);
@@ -7542,8 +7622,8 @@
         assertTrue(ArrayUtils.contains(resolvrParams.servers, "8.8.8.8"));
 
         for (final LinkProperties stackedLp : stackedLpsAfterChange) {
-            verify(mBatteryStatsService).noteNetworkInterfaceType(stackedLp.getInterfaceName(),
-                    TYPE_MOBILE);
+            verify(mBatteryStatsService).noteNetworkInterfaceForTransports(
+                    stackedLp.getInterfaceName(), new int[] { TRANSPORT_CELLULAR });
         }
         reset(mMockNetd);
         when(mMockNetd.interfaceGetCfg(CLAT_PREFIX + MOBILE_IFNAME))
@@ -8323,8 +8403,9 @@
         assertVpnUidRangesUpdated(true, vpnRange, vpnOwnerUid);
         mMockVpn.setVpnType(vpnType);
 
-        final VpnInfo vpnInfo = new VpnInfo(vpnOwnerUid, null, null);
-        mMockVpn.setVpnInfo(vpnInfo);
+        final UnderlyingNetworkInfo underlyingNetworkInfo =
+                new UnderlyingNetworkInfo(vpnOwnerUid, VPN_IFNAME, new ArrayList<String>());
+        mMockVpn.setUnderlyingNetworkInfo(underlyingNetworkInfo);
     }
 
     private void setupConnectionOwnerUidAsVpnApp(int vpnOwnerUid, @VpnManager.VpnType int vpnType)
diff --git a/tests/net/java/com/android/server/net/NetworkStatsBaseTest.java b/tests/net/java/com/android/server/net/NetworkStatsBaseTest.java
index 1b33930..a058a46 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsBaseTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsBaseTest.java
@@ -33,7 +33,9 @@
 import static org.junit.Assert.assertEquals;
 
 import android.net.NetworkStats;
-import android.net.VpnInfo;
+import android.net.UnderlyingNetworkInfo;
+
+import java.util.Arrays;
 
 /** Superclass with utilities for NetworkStats(Service|Factory)Test */
 abstract class NetworkStatsBaseTest {
@@ -107,11 +109,11 @@
         assertEquals("unexpected operations", operations, entry.operations);
     }
 
-    static VpnInfo createVpnInfo(String[] underlyingIfaces) {
+    static UnderlyingNetworkInfo createVpnInfo(String[] underlyingIfaces) {
         return createVpnInfo(TUN_IFACE, underlyingIfaces);
     }
 
-    static VpnInfo createVpnInfo(String vpnIface, String[] underlyingIfaces) {
-        return new VpnInfo(UID_VPN, vpnIface, underlyingIfaces);
+    static UnderlyingNetworkInfo createVpnInfo(String vpnIface, String[] underlyingIfaces) {
+        return new UnderlyingNetworkInfo(UID_VPN, vpnIface, Arrays.asList(underlyingIfaces));
     }
 }
diff --git a/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java b/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java
index 76647a6..f3ae9b0 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java
@@ -36,7 +36,7 @@
 import android.content.res.Resources;
 import android.net.NetworkStats;
 import android.net.TrafficStats;
-import android.net.VpnInfo;
+import android.net.UnderlyingNetworkInfo;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
@@ -79,7 +79,7 @@
         // related to networkStatsFactory is compiled to a minimal native library and loaded here.
         System.loadLibrary("networkstatsfactorytestjni");
         mFactory = new NetworkStatsFactory(mTestProc, false);
-        mFactory.updateVpnInfos(new VpnInfo[0]);
+        mFactory.updateUnderlyingNetworkInfos(new UnderlyingNetworkInfo[0]);
     }
 
     @After
@@ -105,8 +105,9 @@
 
     @Test
     public void testVpnRewriteTrafficThroughItself() throws Exception {
-        VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
-        mFactory.updateVpnInfos(vpnInfos);
+        UnderlyingNetworkInfo[] underlyingNetworkInfos =
+                new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
+        mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
 
         // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
         // overhead per packet):
@@ -134,8 +135,9 @@
 
     @Test
     public void testVpnWithClat() throws Exception {
-        VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {CLAT_PREFIX + TEST_IFACE})};
-        mFactory.updateVpnInfos(vpnInfos);
+        final UnderlyingNetworkInfo[] underlyingNetworkInfos = new UnderlyingNetworkInfo[] {
+                createVpnInfo(new String[] {CLAT_PREFIX + TEST_IFACE})};
+        mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
         mFactory.noteStackedIface(CLAT_PREFIX + TEST_IFACE, TEST_IFACE);
 
         // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
@@ -167,8 +169,9 @@
 
     @Test
     public void testVpnWithOneUnderlyingIface() throws Exception {
-        VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
-        mFactory.updateVpnInfos(vpnInfos);
+        final UnderlyingNetworkInfo[] underlyingNetworkInfos =
+                new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
+        mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
 
         // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
         // overhead per packet):
@@ -191,8 +194,9 @@
     @Test
     public void testVpnWithOneUnderlyingIfaceAndOwnTraffic() throws Exception {
         // WiFi network is connected and VPN is using WiFi (which has TEST_IFACE).
-        VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
-        mFactory.updateVpnInfos(vpnInfos);
+        final UnderlyingNetworkInfo[] underlyingNetworkInfos =
+                new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
+        mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
 
         // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
         // overhead per packet):
@@ -219,8 +223,9 @@
     @Test
     public void testVpnWithOneUnderlyingIface_withCompression() throws Exception {
         // WiFi network is connected and VPN is using WiFi (which has TEST_IFACE).
-        VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
-        mFactory.updateVpnInfos(vpnInfos);
+        final UnderlyingNetworkInfo[] underlyingNetworkInfos =
+                new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
+        mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
 
         // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
         // overhead per packet):
@@ -242,8 +247,9 @@
         // WiFi and Cell networks are connected and VPN is using WiFi (which has TEST_IFACE) and
         // Cell (which has TEST_IFACE2) and has declared both of them in its underlying network set.
         // Additionally, VPN is duplicating traffic across both WiFi and Cell.
-        VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
-        mFactory.updateVpnInfos(vpnInfos);
+        final UnderlyingNetworkInfo[] underlyingNetworkInfos =
+                new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
+        mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
 
         // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
         // overhead per packet):
@@ -267,10 +273,10 @@
     public void testConcurrentVpns() throws Exception {
         // Assume two VPNs are connected on two different network interfaces. VPN1 is using
         // TEST_IFACE and VPN2 is using TEST_IFACE2.
-        final VpnInfo[] vpnInfos = new VpnInfo[] {
+        final UnderlyingNetworkInfo[] underlyingNetworkInfos = new UnderlyingNetworkInfo[] {
                 createVpnInfo(TUN_IFACE, new String[] {TEST_IFACE}),
                 createVpnInfo(TUN_IFACE2, new String[] {TEST_IFACE2})};
-        mFactory.updateVpnInfos(vpnInfos);
+        mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
 
         // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
         // overhead per packet):
@@ -308,8 +314,9 @@
         // WiFi and Cell networks are connected and VPN is using WiFi (which has TEST_IFACE) and
         // Cell (which has TEST_IFACE2) and has declared both of them in its underlying network set.
         // Additionally, VPN is arbitrarily splitting traffic across WiFi and Cell.
-        VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
-        mFactory.updateVpnInfos(vpnInfos);
+        final UnderlyingNetworkInfo[] underlyingNetworkInfos =
+                new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
+        mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
 
         // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
         // overhead per packet):
@@ -335,8 +342,9 @@
         // WiFi and Cell networks are connected and VPN is using WiFi (which has TEST_IFACE) and
         // Cell (which has TEST_IFACE2) and has declared both of them in its underlying network set.
         // Additionally, VPN is arbitrarily splitting compressed traffic across WiFi and Cell.
-        VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
-        mFactory.updateVpnInfos(vpnInfos);
+        final UnderlyingNetworkInfo[] underlyingNetworkInfos =
+                new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
+        mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
 
         // create some traffic (assume 10 bytes of MTU for VPN interface:
         // 1000 bytes (100 packets) were sent/received by UID_RED over VPN.
@@ -357,8 +365,9 @@
     public void testVpnWithIncorrectUnderlyingIface() throws Exception {
         // WiFi and Cell networks are connected and VPN is using Cell (which has TEST_IFACE2),
         // but has declared only WiFi (TEST_IFACE) in its underlying network set.
-        VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
-        mFactory.updateVpnInfos(vpnInfos);
+        final UnderlyingNetworkInfo[] underlyingNetworkInfos =
+                new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
+        mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
 
         // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
         // overhead per packet):
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index b4e37de..dde78aa 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -86,7 +86,7 @@
 import android.net.NetworkStats;
 import android.net.NetworkStatsHistory;
 import android.net.NetworkTemplate;
-import android.net.VpnInfo;
+import android.net.UnderlyingNetworkInfo;
 import android.net.netstats.provider.INetworkStatsProviderCallback;
 import android.os.ConditionVariable;
 import android.os.Handler;
@@ -286,7 +286,8 @@
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
-        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+                new UnderlyingNetworkInfo[0]);
 
         // verify service has empty history for wifi
         assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
@@ -328,7 +329,8 @@
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
-        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+                new UnderlyingNetworkInfo[0]);
 
         // verify service has empty history for wifi
         assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
@@ -401,7 +403,8 @@
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
-        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+                new UnderlyingNetworkInfo[0]);
 
         // modify some number on wifi, and trigger poll event
         incrementCurrentTime(2 * HOUR_IN_MILLIS);
@@ -441,7 +444,8 @@
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
-        mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]);
+        mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+                new UnderlyingNetworkInfo[0]);
 
         // create some traffic on first network
         incrementCurrentTime(HOUR_IN_MILLIS);
@@ -475,7 +479,8 @@
                 .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
                 .insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L));
 
-        mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]);
+        mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+                new UnderlyingNetworkInfo[0]);
         forcePollAndWaitForIdle();
 
 
@@ -514,7 +519,8 @@
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
-        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+                new UnderlyingNetworkInfo[0]);
 
         // create some traffic
         incrementCurrentTime(HOUR_IN_MILLIS);
@@ -581,7 +587,7 @@
 
         setMobileRatTypeAndWaitForIdle(TelephonyManager.NETWORK_TYPE_UMTS);
         mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
-                new VpnInfo[0]);
+                new UnderlyingNetworkInfo[0]);
 
         // Create some traffic.
         incrementCurrentTime(MINUTE_IN_MILLIS);
@@ -655,7 +661,8 @@
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
-        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+                new UnderlyingNetworkInfo[0]);
 
         // create some traffic for two apps
         incrementCurrentTime(HOUR_IN_MILLIS);
@@ -713,7 +720,8 @@
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
-        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+                new UnderlyingNetworkInfo[0]);
 
         NetworkStats.Entry entry1 = new NetworkStats.Entry(
                 TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L);
@@ -756,7 +764,8 @@
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
-        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+                new UnderlyingNetworkInfo[0]);
 
         NetworkStats.Entry uidStats = new NetworkStats.Entry(
                 TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xF00D, 1024L, 8L, 512L, 4L, 0L);
@@ -810,7 +819,8 @@
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
-        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+                new UnderlyingNetworkInfo[0]);
 
         // create some initial traffic
         incrementCurrentTime(HOUR_IN_MILLIS);
@@ -867,7 +877,8 @@
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
-        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+                new UnderlyingNetworkInfo[0]);
 
         // create some initial traffic
         incrementCurrentTime(HOUR_IN_MILLIS);
@@ -906,7 +917,8 @@
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
-        mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]);
+        mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+                new UnderlyingNetworkInfo[0]);
 
         // Create some traffic
         incrementCurrentTime(HOUR_IN_MILLIS);
@@ -943,7 +955,8 @@
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
-        mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]);
+        mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+                new UnderlyingNetworkInfo[0]);
 
         // create some tethering traffic
         incrementCurrentTime(HOUR_IN_MILLIS);
@@ -999,7 +1012,8 @@
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
-        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+                new UnderlyingNetworkInfo[0]);
 
         // verify service has empty history for wifi
         assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
@@ -1104,7 +1118,8 @@
                 mService.registerNetworkStatsProvider("TEST", provider);
         assertNotNull(cb);
 
-        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+                new UnderlyingNetworkInfo[0]);
 
         // Verifies that one requestStatsUpdate will be called during iface update.
         provider.expectOnRequestStatsUpdate(0 /* unused */);
@@ -1155,7 +1170,8 @@
         expectDefaultSettings();
         NetworkState[] states =
                 new NetworkState[]{buildWifiState(true /* isMetered */, TEST_IFACE)};
-        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+                new UnderlyingNetworkInfo[0]);
 
         // Register custom provider and retrieve callback.
         final TestableNetworkStatsProviderBinder provider =
@@ -1204,7 +1220,7 @@
         // 3G network comes online.
         setMobileRatTypeAndWaitForIdle(TelephonyManager.NETWORK_TYPE_UMTS);
         mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
-                new VpnInfo[0]);
+                new UnderlyingNetworkInfo[0]);
 
         // Create some traffic.
         incrementCurrentTime(MINUTE_IN_MILLIS);
@@ -1274,7 +1290,8 @@
         NetworkState[] states = new NetworkState[]{
                 buildWifiState(true /*isMetered*/, TEST_IFACE2), buildMobile3gState(IMSI_1)};
         expectNetworkStatsUidDetail(buildEmptyStats());
-        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+                new UnderlyingNetworkInfo[0]);
 
         // Create some traffic on mobile network.
         incrementCurrentTime(HOUR_IN_MILLIS);