Merge changes Idfb5e149,Ia52b24c5

* changes:
  Stop using NetworkState internally in ConnectivityService.
  Isolate an ad-hoc legacy API codepath.
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetworkUtils.cpp
similarity index 94%
rename from core/jni/android_net_NetUtils.cpp
rename to core/jni/android_net_NetworkUtils.cpp
index e2af87e..7508108 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetworkUtils.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "NetUtils"
+#define LOG_TAG "NetworkUtils"
 
 #include <vector>
 
@@ -123,15 +123,6 @@
     return setNetworkForSocket(netId, AFileDescriptor_getFD(env, javaFd));
 }
 
-static jboolean android_net_utils_protectFromVpn(JNIEnv *env, jobject thiz, jint socket)
-{
-    return (jboolean) !protectFromVpn(socket);
-}
-
-static jboolean android_net_utils_protectFromVpnWithFd(JNIEnv *env, jobject thiz, jobject javaFd) {
-    return android_net_utils_protectFromVpn(env, thiz, AFileDescriptor_getFD(env, javaFd));
-}
-
 static jboolean android_net_utils_queryUserAccess(JNIEnv *env, jobject thiz, jint uid, jint netId)
 {
     return (jboolean) !queryUserAccess(uid, netId);
@@ -276,8 +267,6 @@
     { "getBoundNetworkForProcess", "()I", (void*) android_net_utils_getBoundNetworkForProcess },
     { "bindProcessToNetworkForHostResolution", "(I)Z", (void*) android_net_utils_bindProcessToNetworkForHostResolution },
     { "bindSocketToNetwork", "(Ljava/io/FileDescriptor;I)I", (void*) android_net_utils_bindSocketToNetwork },
-    { "protectFromVpn", "(I)Z", (void*) android_net_utils_protectFromVpn },
-    { "protectFromVpn", "(Ljava/io/FileDescriptor;)Z", (void*) android_net_utils_protectFromVpnWithFd },
     { "queryUserAccess", "(II)Z", (void*)android_net_utils_queryUserAccess },
     { "attachDropAllBPFFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_attachDropAllBPFFilter },
     { "detachBPFFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_detachBPFFilter },
diff --git a/framework/aidl-export/android/net/QosFilterParcelable.aidl b/framework/aidl-export/android/net/QosFilterParcelable.aidl
new file mode 100644
index 0000000..312d635
--- /dev/null
+++ b/framework/aidl-export/android/net/QosFilterParcelable.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 QosFilterParcelable;
+
diff --git a/framework/aidl-export/android/net/QosSession.aidl b/framework/aidl-export/android/net/QosSession.aidl
new file mode 100644
index 0000000..c2cf366
--- /dev/null
+++ b/framework/aidl-export/android/net/QosSession.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 QosSession;
+
diff --git a/framework/aidl-export/android/net/QosSocketInfo.aidl b/framework/aidl-export/android/net/QosSocketInfo.aidl
new file mode 100644
index 0000000..476c090
--- /dev/null
+++ b/framework/aidl-export/android/net/QosSocketInfo.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 QosSocketInfo;
+
diff --git a/framework/api/current.txt b/framework/api/current.txt
index d4262a8..4bfcda3 100644
--- a/framework/api/current.txt
+++ b/framework/api/current.txt
@@ -400,16 +400,6 @@
     method public android.net.NetworkRequest.Builder setNetworkSpecifier(android.net.NetworkSpecifier);
   }
 
-  public final class Proxy {
-    ctor public Proxy();
-    method @Deprecated public static String getDefaultHost();
-    method @Deprecated public static int getDefaultPort();
-    method @Deprecated public static String getHost(android.content.Context);
-    method @Deprecated public static int getPort(android.content.Context);
-    field @Deprecated public static final String EXTRA_PROXY_INFO = "android.intent.extra.PROXY_INFO";
-    field public static final String PROXY_CHANGE_ACTION = "android.intent.action.PROXY_CHANGE";
-  }
-
   public class ProxyInfo implements android.os.Parcelable {
     ctor public ProxyInfo(@Nullable android.net.ProxyInfo);
     method public static android.net.ProxyInfo buildDirectProxy(String, int);
diff --git a/framework/api/module-lib-current.txt b/framework/api/module-lib-current.txt
index 3af855e..a9fd6f2 100644
--- a/framework/api/module-lib-current.txt
+++ b/framework/api/module-lib-current.txt
@@ -23,10 +23,6 @@
     field public static final int TRANSPORT_TEST = 7; // 0x7
   }
 
-  public final class Proxy {
-    method public static void setHttpProxyConfiguration(@Nullable android.net.ProxyInfo);
-  }
-
   public final class TcpRepairWindow {
     ctor public TcpRepairWindow(int, int, int, int, int, int);
     field public final int maxWindow;
diff --git a/framework/api/system-current.txt b/framework/api/system-current.txt
index 41ebc57..373fa3c 100644
--- a/framework/api/system-current.txt
+++ b/framework/api/system-current.txt
@@ -308,6 +308,9 @@
     field public static final int ID_NONE = -1; // 0xffffffff
   }
 
+  public class NetworkReleasedException extends java.lang.Exception {
+  }
+
   public class NetworkRequest implements android.os.Parcelable {
     method @Nullable public String getRequestorPackageName();
     method public int getRequestorUid();
@@ -317,6 +320,47 @@
     method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkRequest.Builder setSignalStrength(int);
   }
 
+  public abstract class QosCallback {
+    ctor public QosCallback();
+    method public void onError(@NonNull android.net.QosCallbackException);
+    method public void onQosSessionAvailable(@NonNull android.net.QosSession, @NonNull android.net.QosSessionAttributes);
+    method public void onQosSessionLost(@NonNull android.net.QosSession);
+  }
+
+  public static class QosCallback.QosCallbackRegistrationException extends java.lang.RuntimeException {
+  }
+
+  public final class QosCallbackException extends java.lang.Exception {
+  }
+
+  public abstract class QosFilter {
+    method @NonNull public abstract android.net.Network getNetwork();
+    method public abstract boolean matchesLocalAddress(@NonNull java.net.InetAddress, int, int);
+  }
+
+  public final class QosSession implements android.os.Parcelable {
+    ctor public QosSession(int, int);
+    method public int describeContents();
+    method public int getSessionId();
+    method public int getSessionType();
+    method public long getUniqueId();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.QosSession> CREATOR;
+    field public static final int TYPE_EPS_BEARER = 1; // 0x1
+  }
+
+  public interface QosSessionAttributes {
+  }
+
+  public final class QosSocketInfo implements android.os.Parcelable {
+    ctor public QosSocketInfo(@NonNull android.net.Network, @NonNull java.net.Socket) throws java.io.IOException;
+    method public int describeContents();
+    method @NonNull public java.net.InetSocketAddress getLocalSocketAddress();
+    method @NonNull public android.net.Network getNetwork();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.QosSocketInfo> CREATOR;
+  }
+
   public final class RouteInfo implements android.os.Parcelable {
     ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int);
     ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int, int);
@@ -331,6 +375,12 @@
     field public static final int SUCCESS = 0; // 0x0
   }
 
+  public class SocketLocalAddressChangedException extends java.lang.Exception {
+  }
+
+  public class SocketNotBoundException extends java.lang.Exception {
+  }
+
   public final class StaticIpConfiguration implements android.os.Parcelable {
     ctor public StaticIpConfiguration();
     ctor public StaticIpConfiguration(@Nullable android.net.StaticIpConfiguration);
@@ -392,16 +442,3 @@
 
 }
 
-package android.net.util {
-
-  public final class SocketUtils {
-    method public static void bindSocketToInterface(@NonNull java.io.FileDescriptor, @NonNull String) throws android.system.ErrnoException;
-    method public static void closeSocket(@Nullable java.io.FileDescriptor) throws java.io.IOException;
-    method @NonNull public static java.net.SocketAddress makeNetlinkSocketAddress(int, int);
-    method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, int);
-    method @Deprecated @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, @NonNull byte[]);
-    method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, int, @NonNull byte[]);
-  }
-
-}
-
diff --git a/framework/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java
index 6273f4b..66e7da4 100644
--- a/framework/src/android/net/ConnectivityManager.java
+++ b/framework/src/android/net/ConnectivityManager.java
@@ -2245,31 +2245,6 @@
         }
     }
 
-    /* TODO: These permissions checks don't belong in client-side code. Move them to
-     * services.jar, possibly in com.android.server.net. */
-
-    /** {@hide} */
-    public static final void enforceChangePermission(Context context,
-            String callingPkg, String callingAttributionTag) {
-        int uid = Binder.getCallingUid();
-        checkAndNoteChangeNetworkStateOperation(context, uid, callingPkg,
-                callingAttributionTag, true /* throwException */);
-    }
-
-    /**
-     * Check if the package is a allowed to change the network state. This also accounts that such
-     * an access happened.
-     *
-     * @return {@code true} iff the package is allowed to change the network state.
-     */
-    // TODO: Remove method and replace with direct call once R code is pushed to AOSP
-    private static boolean checkAndNoteChangeNetworkStateOperation(@NonNull Context context,
-            int uid, @NonNull String callingPackage, @Nullable String callingAttributionTag,
-            boolean throwException) {
-        return Settings.checkAndNoteChangeNetworkStateOperation(context, uid, callingPackage,
-                throwException);
-    }
-
     /**
      * Check if the package is a allowed to write settings. This also accounts that such an access
      * happened.
diff --git a/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl b/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl
new file mode 100644
index 0000000..7979afc
--- /dev/null
+++ b/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl
@@ -0,0 +1,23 @@
+/**
+ *
+ * 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;
+
+/** @hide */
+oneway interface IOnSetOemNetworkPreferenceListener {
+    void onComplete();
+}
diff --git a/framework/src/android/net/IQosCallback.aidl b/framework/src/android/net/IQosCallback.aidl
new file mode 100644
index 0000000..91c7575
--- /dev/null
+++ b/framework/src/android/net/IQosCallback.aidl
@@ -0,0 +1,34 @@
+/*
+ * 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;
+
+import android.os.Bundle;
+import android.net.QosSession;
+import android.telephony.data.EpsBearerQosSessionAttributes;
+
+/**
+ * AIDL interface for QosCallback
+ *
+ * @hide
+ */
+oneway interface IQosCallback
+{
+     void onQosEpsBearerSessionAvailable(in QosSession session,
+        in EpsBearerQosSessionAttributes attributes);
+     void onQosSessionLost(in QosSession session);
+     void onError(in int type);
+}
diff --git a/framework/src/android/net/NetworkReleasedException.java b/framework/src/android/net/NetworkReleasedException.java
new file mode 100644
index 0000000..0629b75
--- /dev/null
+++ b/framework/src/android/net/NetworkReleasedException.java
@@ -0,0 +1,32 @@
+/*
+ * 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;
+
+/**
+ * Indicates that the {@link Network} was released and is no longer available.
+ *
+ * @hide
+ */
+@SystemApi
+public class NetworkReleasedException extends Exception {
+    /** @hide */
+    public NetworkReleasedException() {
+        super("The network was released and is no longer available");
+    }
+}
diff --git a/framework/src/android/net/NetworkUtils.java b/framework/src/android/net/NetworkUtils.java
index b5e8a61..9e42bbe 100644
--- a/framework/src/android/net/NetworkUtils.java
+++ b/framework/src/android/net/NetworkUtils.java
@@ -87,22 +87,6 @@
     public static native int bindSocketToNetwork(FileDescriptor fd, int netId);
 
     /**
-     * Protect {@code fd} 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.
-     */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553,
-            publicAlternatives = "Use {@link android.net.VpnService#protect} instead.")
-    public static native boolean protectFromVpn(FileDescriptor fd);
-
-    /**
-     * Protect {@code socketfd} 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.
-     */
-    public native static boolean protectFromVpn(int socketfd);
-
-    /**
      * Determine if {@code uid} can access network designated by {@code netId}.
      * @return {@code true} if {@code uid} can access network, {@code false} otherwise.
      */
diff --git a/framework/src/android/net/PacProxySelector.java b/framework/src/android/net/PacProxySelector.java
deleted file mode 100644
index 326943a..0000000
--- a/framework/src/android/net/PacProxySelector.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 77c8a4f..0000000
--- a/framework/src/android/net/Proxy.java
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * 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.Nullable;
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-import android.annotation.SystemApi;
-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;
-
-/**
- * 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";
-
-    private static ConnectivityManager sConnectivityManager = null;
-
-    static {
-        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;
-    }
-
-    /** @hide */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    @Deprecated
-    public static void setHttpProxySystemProperty(ProxyInfo p) {
-        setHttpProxyConfiguration(p);
-    }
-
-    /**
-     * Set HTTP proxy configuration for the process to match the provided ProxyInfo.
-     *
-     * If the provided ProxyInfo is null, the proxy configuration will be cleared.
-     * @hide
-     */
-    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
-    public static void setHttpProxyConfiguration(@Nullable 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();
-        }
-        setHttpProxyConfiguration(host, port, exclList, pacFileUrl);
-    }
-
-    /** @hide */
-    public static void setHttpProxyConfiguration(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/core/java/android/net/QosCallback.java b/framework/src/android/net/QosCallback.java
similarity index 100%
rename from core/java/android/net/QosCallback.java
rename to framework/src/android/net/QosCallback.java
diff --git a/core/java/android/net/QosCallbackConnection.java b/framework/src/android/net/QosCallbackConnection.java
similarity index 100%
rename from core/java/android/net/QosCallbackConnection.java
rename to framework/src/android/net/QosCallbackConnection.java
diff --git a/core/java/android/net/QosCallbackException.java b/framework/src/android/net/QosCallbackException.java
similarity index 100%
rename from core/java/android/net/QosCallbackException.java
rename to framework/src/android/net/QosCallbackException.java
diff --git a/core/java/android/net/QosFilter.java b/framework/src/android/net/QosFilter.java
similarity index 100%
rename from core/java/android/net/QosFilter.java
rename to framework/src/android/net/QosFilter.java
diff --git a/core/java/android/net/QosFilterParcelable.java b/framework/src/android/net/QosFilterParcelable.java
similarity index 100%
rename from core/java/android/net/QosFilterParcelable.java
rename to framework/src/android/net/QosFilterParcelable.java
diff --git a/core/java/android/net/QosSession.java b/framework/src/android/net/QosSession.java
similarity index 100%
rename from core/java/android/net/QosSession.java
rename to framework/src/android/net/QosSession.java
diff --git a/framework/src/android/net/QosSessionAttributes.java b/framework/src/android/net/QosSessionAttributes.java
new file mode 100644
index 0000000..7a88594
--- /dev/null
+++ b/framework/src/android/net/QosSessionAttributes.java
@@ -0,0 +1,30 @@
+/*
+ * 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;
+
+import android.annotation.SystemApi;
+
+/**
+ * Implemented by classes that encapsulate Qos related attributes that describe a Qos Session.
+ *
+ * Use the instanceof keyword to determine the underlying type.
+ *
+ * @hide
+ */
+@SystemApi
+public interface QosSessionAttributes {
+}
diff --git a/core/java/android/net/QosSocketFilter.java b/framework/src/android/net/QosSocketFilter.java
similarity index 100%
rename from core/java/android/net/QosSocketFilter.java
rename to framework/src/android/net/QosSocketFilter.java
diff --git a/core/java/android/net/QosSocketInfo.java b/framework/src/android/net/QosSocketInfo.java
similarity index 100%
rename from core/java/android/net/QosSocketInfo.java
rename to framework/src/android/net/QosSocketInfo.java
diff --git a/framework/src/android/net/SocketLocalAddressChangedException.java b/framework/src/android/net/SocketLocalAddressChangedException.java
new file mode 100644
index 0000000..9daad83
--- /dev/null
+++ b/framework/src/android/net/SocketLocalAddressChangedException.java
@@ -0,0 +1,32 @@
+/*
+ * 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;
+
+/**
+ * Thrown when the local address of the socket has changed.
+ *
+ * @hide
+ */
+@SystemApi
+public class SocketLocalAddressChangedException extends Exception {
+    /** @hide */
+    public SocketLocalAddressChangedException() {
+        super("The local address of the socket changed");
+    }
+}
diff --git a/framework/src/android/net/SocketNotBoundException.java b/framework/src/android/net/SocketNotBoundException.java
new file mode 100644
index 0000000..b1d7026
--- /dev/null
+++ b/framework/src/android/net/SocketNotBoundException.java
@@ -0,0 +1,32 @@
+/*
+ * 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;
+
+/**
+ * Thrown when a previously bound socket becomes unbound.
+ *
+ * @hide
+ */
+@SystemApi
+public class SocketNotBoundException extends Exception {
+    /** @hide */
+    public SocketNotBoundException() {
+        super("The socket is unbound");
+    }
+}
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/core/java/android/net/UidRange.java b/framework/src/android/net/UidRange.java
similarity index 86%
rename from core/java/android/net/UidRange.java
rename to framework/src/android/net/UidRange.java
index f0e7da7..26518d3 100644
--- a/core/java/android/net/UidRange.java
+++ b/framework/src/android/net/UidRange.java
@@ -16,8 +16,6 @@
 
 package android.net;
 
-import static android.os.UserHandle.PER_USER_RANGE;
-
 import android.annotation.Nullable;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -52,14 +50,15 @@
 
     /** Returns the smallest user Id which is contained in this UidRange */
     public int getStartUser() {
-        return start / PER_USER_RANGE;
+        return UserHandle.getUserHandleForUid(start).getIdentifier();
     }
 
     /** Returns the largest user Id which is contained in this UidRange */
     public int getEndUser() {
-        return stop / PER_USER_RANGE;
+        return UserHandle.getUserHandleForUid(stop).getIdentifier();
     }
 
+    /** Returns whether the UidRange contains the specified UID. */
     public boolean contains(int uid) {
         return start <= uid && uid <= stop;
     }
@@ -72,7 +71,7 @@
     }
 
     /**
-     * @return {@code true} if this range contains every UID contained by the {@param other} range.
+     * @return {@code true} if this range contains every UID contained by the {@code other} range.
      */
     public boolean containsRange(UidRange other) {
         return start <= other.start && other.stop <= stop;
@@ -118,18 +117,18 @@
     }
 
     public static final @android.annotation.NonNull Creator<UidRange> CREATOR =
-        new Creator<UidRange>() {
-            @Override
-            public UidRange createFromParcel(Parcel in) {
-                int start = in.readInt();
-                int stop = in.readInt();
+            new Creator<UidRange>() {
+        @Override
+        public UidRange createFromParcel(Parcel in) {
+            int start = in.readInt();
+            int stop = in.readInt();
 
-                return new UidRange(start, stop);
-            }
-            @Override
-            public UidRange[] newArray(int size) {
-                return new UidRange[size];
-            }
+            return new UidRange(start, stop);
+        }
+        @Override
+        public UidRange[] newArray(int size) {
+            return new UidRange[size];
+        }
     };
 
     /**
diff --git a/framework/src/android/net/util/SocketUtils.java b/framework/src/android/net/util/SocketUtils.java
deleted file mode 100644
index e64060f..0000000
--- a/framework/src/android/net/util/SocketUtils.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * 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 f20b89f..e65b7b4 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -63,6 +63,7 @@
         "unsupportedappusage",
     ],
     static_libs: [
+        "modules-utils-os",
         "net-utils-device-common",
         "net-utils-framework-common",
         "netd-client",
diff --git a/service/jarjar-rules.txt b/service/jarjar-rules.txt
index ef53ebb..d8205bf 100644
--- a/service/jarjar-rules.txt
+++ b/service/jarjar-rules.txt
@@ -1 +1,2 @@
-rule com.android.net.module.util.** com.android.connectivity.util.@1
\ No newline at end of file
+rule com.android.net.module.util.** com.android.connectivity.net-utils.@1
+rule com.android.modules.utils.** com.android.connectivity.modules-utils.@1
\ No newline at end of file
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 93fab6e..986e2ac 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -120,6 +120,7 @@
 import android.net.NetworkStack;
 import android.net.NetworkStackClient;
 import android.net.NetworkState;
+import android.net.NetworkStateSnapshot;
 import android.net.NetworkTestResultParcelable;
 import android.net.NetworkUtils;
 import android.net.NetworkWatchlistManager;
@@ -141,10 +142,13 @@
 import android.net.Uri;
 import android.net.VpnManager;
 import android.net.VpnTransportInfo;
-import android.net.metrics.INetdEventListener;
 import android.net.metrics.IpConnectivityLog;
 import android.net.metrics.NetworkEvent;
 import android.net.netlink.InetDiagMessage;
+import android.net.resolv.aidl.DnsHealthEventParcel;
+import android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener;
+import android.net.resolv.aidl.Nat64PrefixEventParcel;
+import android.net.resolv.aidl.PrivateDnsValidationEventParcel;
 import android.net.shared.PrivateDnsConfig;
 import android.net.util.MultinetworkPolicyTracker;
 import android.net.util.NetdService;
@@ -155,7 +159,6 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
-import android.os.INetworkManagementService;
 import android.os.Looper;
 import android.os.Message;
 import android.os.Messenger;
@@ -324,7 +327,6 @@
     // 0 is full bad, 100 is full good
     private int mDefaultInetConditionPublished = 0;
 
-    private INetworkManagementService mNMS;
     @VisibleForTesting
     protected IDnsResolver mDnsResolver;
     @VisibleForTesting
@@ -1040,15 +1042,14 @@
         }
     }
 
-    public ConnectivityService(Context context, INetworkManagementService netManager,
-            INetworkStatsService statsService) {
-        this(context, netManager, statsService, getDnsResolver(context), new IpConnectivityLog(),
+    public ConnectivityService(Context context, INetworkStatsService statsService) {
+        this(context, statsService, getDnsResolver(context), new IpConnectivityLog(),
                 NetdService.getInstance(), new Dependencies());
     }
 
     @VisibleForTesting
-    protected ConnectivityService(Context context, INetworkManagementService netManager,
-            INetworkStatsService statsService, IDnsResolver dnsresolver, IpConnectivityLog logger,
+    protected ConnectivityService(Context context, INetworkStatsService statsService,
+            IDnsResolver dnsresolver, IpConnectivityLog logger,
             INetd netd, Dependencies deps) {
         if (DBG) log("ConnectivityService starting up");
 
@@ -1095,7 +1096,6 @@
         // TODO: Consider making the timer customizable.
         mNascentDelayMs = DEFAULT_NASCENT_DELAY_MS;
 
-        mNMS = Objects.requireNonNull(netManager, "missing INetworkManagementService");
         mStatsService = Objects.requireNonNull(statsService, "missing INetworkStatsService");
         mPolicyManager = mContext.getSystemService(NetworkPolicyManager.class);
         mPolicyManagerInternal = Objects.requireNonNull(
@@ -1203,7 +1203,7 @@
         mUserAllContext.registerReceiver(mIntentReceiver, intentFilter,
                 null /* broadcastPermission */, mHandler);
 
-        mNetworkActivityTracker = new LegacyNetworkActivityTracker(mContext, mHandler, mNMS, mNetd);
+        mNetworkActivityTracker = new LegacyNetworkActivityTracker(mContext, mHandler, mNetd);
 
         mNetdCallback = new NetdCallback();
         try {
@@ -1237,12 +1237,12 @@
         mDnsManager = new DnsManager(mContext, mDnsResolver);
         registerPrivateDnsSettingsCallbacks();
 
-        mNoServiceNetwork =  new NetworkAgentInfo(null,
+        mNoServiceNetwork = new NetworkAgentInfo(null,
                 new Network(NO_SERVICE_NET_ID),
                 new NetworkInfo(TYPE_NONE, 0, "", ""),
                 new LinkProperties(), new NetworkCapabilities(), 0, mContext,
                 null, new NetworkAgentConfig(), this, null,
-                null, null, 0, INVALID_UID,
+                null, 0, INVALID_UID,
                 mQosCallbackTracker);
     }
 
@@ -2043,25 +2043,24 @@
         return true;
     }
 
-    private class NetdEventCallback extends INetdEventListener.Stub {
+    class DnsResolverUnsolicitedEventCallback extends
+            IDnsResolverUnsolicitedEventListener.Stub {
         @Override
-        public void onPrivateDnsValidationEvent(int netId, String ipAddress,
-                String hostname, boolean validated) {
+        public void onPrivateDnsValidationEvent(final PrivateDnsValidationEventParcel event) {
             try {
                 mHandler.sendMessage(mHandler.obtainMessage(
                         EVENT_PRIVATE_DNS_VALIDATION_UPDATE,
-                        new PrivateDnsValidationUpdate(netId,
-                                InetAddresses.parseNumericAddress(ipAddress),
-                                hostname, validated)));
+                        new PrivateDnsValidationUpdate(event.netId,
+                                InetAddresses.parseNumericAddress(event.ipAddress),
+                                event.hostname, event.validation)));
             } catch (IllegalArgumentException e) {
                 loge("Error parsing ip address in validation event");
             }
         }
 
         @Override
-        public void onDnsEvent(int netId, int eventType, int returnCode, int latencyMs,
-                String hostname,  String[] ipAddresses, int ipAddressesCount, int uid) {
-            NetworkAgentInfo nai = getNetworkAgentInfoForNetId(netId);
+        public void onDnsHealthEvent(final DnsHealthEventParcel event) {
+            NetworkAgentInfo nai = getNetworkAgentInfoForNetId(event.netId);
             // Netd event only allow registrants from system. Each NetworkMonitor thread is under
             // the caller thread of registerNetworkAgent. Thus, it's not allowed to register netd
             // event callback for certain nai. e.g. cellular. Register here to pass to
@@ -2070,34 +2069,18 @@
             // callback from each caller type. Need to re-factor NetdEventListenerService to allow
             // multiple NetworkMonitor registrants.
             if (nai != null && nai.satisfies(mDefaultRequest.mRequests.get(0))) {
-                nai.networkMonitor().notifyDnsResponse(returnCode);
+                nai.networkMonitor().notifyDnsResponse(event.healthResult);
             }
         }
 
         @Override
-        public void onNat64PrefixEvent(int netId, boolean added,
-                                       String prefixString, int prefixLength) {
-            mHandler.post(() -> handleNat64PrefixEvent(netId, added, prefixString, prefixLength));
+        public void onNat64PrefixEvent(final Nat64PrefixEventParcel event) {
+            mHandler.post(() -> handleNat64PrefixEvent(event.netId, event.prefixOperation,
+                    event.prefixAddress, event.prefixLength));
         }
 
         @Override
-        public void onConnectEvent(int netId, int error, int latencyMs, String ipAddr, int port,
-                int uid) {
-        }
-
-        @Override
-        public void onWakeupEvent(String prefix, int uid, int ethertype, int ipNextHeader,
-                byte[] dstHw, String srcIp, String dstIp, int srcPort, int dstPort,
-                long timestampNs) {
-        }
-
-        @Override
-        public void onTcpSocketStatsEvent(int[] networkIds, int[] sentPackets, int[] lostPackets,
-                int[] rttsUs, int[] sentAckDiffsMs) {
-        }
-
-        @Override
-        public int getInterfaceVersion() throws RemoteException {
+        public int getInterfaceVersion() {
             return this.VERSION;
         }
 
@@ -2105,16 +2088,17 @@
         public String getInterfaceHash() {
             return this.HASH;
         }
-    };
+    }
 
     @VisibleForTesting
-    protected final INetdEventListener mNetdEventCallback = new NetdEventCallback();
+    protected final DnsResolverUnsolicitedEventCallback mResolverUnsolEventCallback =
+            new DnsResolverUnsolicitedEventCallback();
 
-    private void registerNetdEventCallback() {
+    private void registerDnsResolverUnsolicitedEventListener() {
         try {
-            mDnsResolver.registerEventListener(mNetdEventCallback);
+            mDnsResolver.registerUnsolicitedEventListener(mResolverUnsolEventCallback);
         } catch (Exception e) {
-            loge("Error registering DnsResolver callback: " + e);
+            loge("Error registering DnsResolver unsolicited event callback: " + e);
         }
     }
 
@@ -2204,8 +2188,45 @@
                 "ConnectivityService");
     }
 
+    /**
+     * Performs a strict and comprehensive check of whether a calling package is allowed to
+     * change the state of network, as the condition differs for pre-M, M+, and
+     * privileged/preinstalled apps. The caller is expected to have either the
+     * CHANGE_NETWORK_STATE or the WRITE_SETTINGS permission declared. Either of these
+     * permissions allow changing network state; WRITE_SETTINGS is a runtime permission and
+     * can be revoked, but (except in M, excluding M MRs), CHANGE_NETWORK_STATE is a normal
+     * permission and cannot be revoked. See http://b/23597341
+     *
+     * Note: if the check succeeds because the application holds WRITE_SETTINGS, the operation
+     * of this app will be updated to the current time.
+     */
     private void enforceChangePermission(String callingPkg, String callingAttributionTag) {
-        ConnectivityManager.enforceChangePermission(mContext, callingPkg, callingAttributionTag);
+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.CHANGE_NETWORK_STATE)
+                == PackageManager.PERMISSION_GRANTED) {
+            return;
+        }
+
+        if (callingPkg == null) {
+            throw new SecurityException("Calling package name is null.");
+        }
+
+        final AppOpsManager appOpsMgr = mContext.getSystemService(AppOpsManager.class);
+        final int uid = mDeps.getCallingUid();
+        final int mode = appOpsMgr.noteOpNoThrow(AppOpsManager.OPSTR_WRITE_SETTINGS, uid,
+                callingPkg, callingAttributionTag, null /* message */);
+
+        if (mode == AppOpsManager.MODE_ALLOWED) {
+            return;
+        }
+
+        if ((mode == AppOpsManager.MODE_DEFAULT) && (mContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.WRITE_SETTINGS) == PackageManager.PERMISSION_GRANTED)) {
+            return;
+        }
+
+        throw new SecurityException(callingPkg + " was not granted either of these permissions:"
+                + android.Manifest.permission.CHANGE_NETWORK_STATE + ","
+                + android.Manifest.permission.WRITE_SETTINGS + ".");
     }
 
     private void enforceSettingsPermission() {
@@ -2408,7 +2429,7 @@
         // to ensure the tracking will be initialized correctly.
         mPermissionMonitor.startMonitoring();
         mProxyTracker.loadGlobalProxy();
-        registerNetdEventCallback();
+        registerDnsResolverUnsolicitedEventListener();
 
         synchronized (this) {
             mSystemReady = true;
@@ -3049,9 +3070,6 @@
                 log(nai.toShortString() + " validation " + (valid ? "passed" : "failed") + logMsg);
             }
             if (valid != nai.lastValidated) {
-                if (wasDefault) {
-                    mMetricsLog.logDefaultNetworkValidity(valid);
-                }
                 final int oldScore = nai.getCurrentScore();
                 nai.lastValidated = valid;
                 nai.everValidated |= valid;
@@ -3339,21 +3357,21 @@
         handleUpdateLinkProperties(nai, new LinkProperties(nai.linkProperties));
     }
 
-    private void handleNat64PrefixEvent(int netId, boolean added, String prefixString,
+    private void handleNat64PrefixEvent(int netId, int operation, String prefixAddress,
             int prefixLength) {
         NetworkAgentInfo nai = mNetworkForNetId.get(netId);
         if (nai == null) return;
 
-        log(String.format("NAT64 prefix %s on netId %d: %s/%d",
-                          (added ? "added" : "removed"), netId, prefixString, prefixLength));
+        log(String.format("NAT64 prefix changed on netId %d: operation=%d, %s/%d",
+                netId, operation, prefixAddress, prefixLength));
 
         IpPrefix prefix = null;
-        if (added) {
+        if (operation == IDnsResolverUnsolicitedEventListener.PREFIX_OPERATION_ADDED) {
             try {
-                prefix = new IpPrefix(InetAddresses.parseNumericAddress(prefixString),
+                prefix = new IpPrefix(InetAddresses.parseNumericAddress(prefixAddress),
                         prefixLength);
             } catch (IllegalArgumentException e) {
-                loge("Invalid NAT64 prefix " + prefixString + "/" + prefixLength);
+                loge("Invalid NAT64 prefix " + prefixAddress + "/" + prefixLength);
                 return;
             }
         }
@@ -3472,14 +3490,6 @@
         final boolean wasDefault = isDefaultNetwork(nai);
         if (wasDefault) {
             mDefaultInetConditionPublished = 0;
-            // Log default network disconnection before required book-keeping.
-            // Let rematchAllNetworksAndRequests() below record a new default network event
-            // if there is a fallback. Taken together, the two form a X -> 0, 0 -> Y sequence
-            // whose timestamps tell how long it takes to recover a default network.
-            long now = SystemClock.elapsedRealtime();
-            mMetricsLog.logDefaultNetworkEvent(null, 0, false,
-                    null /* lp */, null /* nc */, nai.network, nai.getCurrentScore(),
-                    nai.linkProperties, nai.networkCapabilities);
         }
         notifyIfacesChangedForNetworkStats();
         // TODO - we shouldn't send CALLBACK_LOST to requests that can be satisfied
@@ -6033,7 +6043,7 @@
         final NetworkAgentInfo nai = new NetworkAgentInfo(na,
                 new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc,
                 currentScore, mContext, mTrackerHandler, new NetworkAgentConfig(networkAgentConfig),
-                this, mNetd, mDnsResolver, mNMS, providerId, uid, mQosCallbackTracker);
+                this, mNetd, mDnsResolver, providerId, uid, mQosCallbackTracker);
 
         // Make sure the LinkProperties and NetworkCapabilities reflect what the agent info says.
         processCapabilitiesFromAgent(nai, nc);
@@ -7115,27 +7125,6 @@
         updateTcpBufferSizes(null != newDefaultNetwork
                 ? newDefaultNetwork.linkProperties.getTcpBufferSizes() : null);
         notifyIfacesChangedForNetworkStats();
-
-        // Log 0 -> X and Y -> X default network transitions, where X is the new default.
-        final Network network = (newDefaultNetwork != null) ? newDefaultNetwork.network : null;
-        final int score = (newDefaultNetwork != null) ? newDefaultNetwork.getCurrentScore() : 0;
-        final boolean validated = newDefaultNetwork != null && newDefaultNetwork.lastValidated;
-        final LinkProperties lp = (newDefaultNetwork != null)
-                ? newDefaultNetwork.linkProperties : null;
-        final NetworkCapabilities nc = (newDefaultNetwork != null)
-                ? newDefaultNetwork.networkCapabilities : null;
-
-        final Network prevNetwork = (oldDefaultNetwork != null)
-                ? oldDefaultNetwork.network : null;
-        final int prevScore = (oldDefaultNetwork != null)
-                ? oldDefaultNetwork.getCurrentScore() : 0;
-        final LinkProperties prevLp = (oldDefaultNetwork != null)
-                ? oldDefaultNetwork.linkProperties : null;
-        final NetworkCapabilities prevNc = (oldDefaultNetwork != null)
-                ? oldDefaultNetwork.networkCapabilities : null;
-
-        mMetricsLog.logDefaultNetworkEvent(network, score, validated, lp, nc,
-                prevNetwork, prevScore, prevLp, prevNc);
     }
 
     private void makeDefaultForApps(@NonNull final NetworkRequestInfo nri,
@@ -7955,8 +7944,16 @@
 
         final UnderlyingNetworkInfo[] underlyingNetworkInfos = getAllVpnInfo();
         try {
-            mStatsService.forceUpdateIfaces(getDefaultNetworks(), getAllNetworkState(), activeIface,
-                    underlyingNetworkInfos);
+            final ArrayList<NetworkStateSnapshot> snapshots = new ArrayList<>();
+            // TODO: Directly use NetworkStateSnapshot when feasible.
+            for (final NetworkState state : getAllNetworkState()) {
+                final NetworkStateSnapshot snapshot = new NetworkStateSnapshot(state.network,
+                        state.networkCapabilities, state.linkProperties, state.subscriberId,
+                        state.legacyNetworkType);
+                snapshots.add(snapshot);
+            }
+            mStatsService.forceUpdateIfaces(getDefaultNetworks(), snapshots.toArray(
+                    new NetworkStateSnapshot[0]), activeIface, underlyingNetworkInfos);
         } catch (Exception ignored) {
         }
     }
@@ -8189,7 +8186,7 @@
             TestNetworkService.enforceTestNetworkPermissions(mContext);
 
             if (mTNS == null) {
-                mTNS = new TestNetworkService(mContext, mNMS);
+                mTNS = new TestNetworkService(mContext);
             }
 
             return mTNS;
@@ -8664,9 +8661,23 @@
 
     private class NetdCallback extends BaseNetdUnsolicitedEventListener {
         @Override
-        public void onInterfaceClassActivityChanged(boolean isActive, int timerLabel,
+        public void onInterfaceClassActivityChanged(boolean isActive, int transportType,
                 long timestampNs, int uid) {
-            mNetworkActivityTracker.setAndReportNetworkActive(isActive, timerLabel, timestampNs);
+            mNetworkActivityTracker.setAndReportNetworkActive(isActive, transportType, timestampNs);
+        }
+
+        @Override
+        public void onInterfaceLinkStateChanged(String iface, boolean up) {
+            for (NetworkAgentInfo nai : mNetworkAgentInfos) {
+                nai.clatd.interfaceLinkStateChanged(iface, up);
+            }
+        }
+
+        @Override
+        public void onInterfaceRemoved(String iface) {
+            for (NetworkAgentInfo nai : mNetworkAgentInfos) {
+                nai.clatd.interfaceRemoved(iface);
+            }
         }
     }
 
@@ -8700,7 +8711,7 @@
         }
 
         LegacyNetworkActivityTracker(@NonNull Context context, @NonNull Handler handler,
-                @NonNull INetworkManagementService nms, @NonNull INetd netd) {
+                @NonNull INetd netd) {
             mContext = context;
             mNetd = netd;
             mHandler = handler;
diff --git a/services/core/java/com/android/server/ConnectivityServiceInitializer.java b/services/core/java/com/android/server/ConnectivityServiceInitializer.java
index 0779f71..097441f 100644
--- a/services/core/java/com/android/server/ConnectivityServiceInitializer.java
+++ b/services/core/java/com/android/server/ConnectivityServiceInitializer.java
@@ -21,7 +21,6 @@
 
 import android.content.Context;
 import android.net.INetworkStatsService;
-import android.os.INetworkManagementService;
 import android.os.ServiceManager;
 import android.util.Log;
 
@@ -38,8 +37,7 @@
         // Load JNI libraries used by ConnectivityService and its dependencies
         System.loadLibrary("service-connectivity");
         // TODO: Define formal APIs to get the needed services.
-        mConnectivity = new ConnectivityService(context, getNetworkManagementService(),
-                getNetworkStatsService());
+        mConnectivity = new ConnectivityService(context, getNetworkStatsService());
     }
 
     @Override
@@ -49,11 +47,6 @@
                 /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL);
     }
 
-    private INetworkManagementService getNetworkManagementService() {
-        return INetworkManagementService.Stub.asInterface(
-               ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
-    }
-
     private INetworkStatsService getNetworkStatsService() {
         return INetworkStatsService.Stub.asInterface(
                 ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java
index 96f832d..55408ea 100644
--- a/services/core/java/com/android/server/TestNetworkService.java
+++ b/services/core/java/com/android/server/TestNetworkService.java
@@ -32,7 +32,6 @@
 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;
@@ -41,7 +40,6 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
-import android.os.INetworkManagementService;
 import android.os.Looper;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
@@ -51,6 +49,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.net.module.util.NetdUtils;
 import com.android.net.module.util.NetworkStackConstants;
+import com.android.net.module.util.PermissionUtils;
 
 import java.io.UncheckedIOException;
 import java.net.Inet4Address;
@@ -69,7 +68,6 @@
     @NonNull private static final AtomicInteger sTestTunIndex = new AtomicInteger();
 
     @NonNull private final Context mContext;
-    @NonNull private final INetworkManagementService mNMS;
     @NonNull private final INetd mNetd;
 
     @NonNull private final HandlerThread mHandlerThread;
@@ -82,14 +80,12 @@
     private static native int jniCreateTunTap(boolean isTun, @NonNull String iface);
 
     @VisibleForTesting
-    protected TestNetworkService(
-            @NonNull Context context, @NonNull INetworkManagementService netManager) {
+    protected TestNetworkService(@NonNull Context context) {
         mHandlerThread = new HandlerThread("TestNetworkServiceThread");
         mHandlerThread.start();
         mHandler = new Handler(mHandlerThread.getLooper());
 
         mContext = Objects.requireNonNull(context, "missing Context");
-        mNMS = Objects.requireNonNull(netManager, "missing INetworkManagementService");
         mNetd = Objects.requireNonNull(NetdService.getInstance(), "could not get netd instance");
         mCm = mContext.getSystemService(ConnectivityManager.class);
         mNetworkProvider = new NetworkProvider(mContext, mHandler.getLooper(),
@@ -324,7 +320,7 @@
         try {
             final long token = Binder.clearCallingIdentity();
             try {
-                NetworkStack.checkNetworkStackPermission(mContext);
+                PermissionUtils.enforceNetworkStackPermission(mContext);
                 NetdUtils.setInterfaceUp(mNetd, iface);
             } finally {
                 Binder.restoreCallingIdentity(token);
diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java
index 43d9ade..4f6b530 100644
--- a/services/core/java/com/android/server/connectivity/DnsManager.java
+++ b/services/core/java/com/android/server/connectivity/DnsManager.java
@@ -19,6 +19,8 @@
 import static android.net.ConnectivityManager.PRIVATE_DNS_DEFAULT_MODE_FALLBACK;
 import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
 import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
+import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_FAILURE;
+import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_SUCCESS;
 import static android.provider.Settings.Global.DNS_RESOLVER_MAX_SAMPLES;
 import static android.provider.Settings.Global.DNS_RESOLVER_MIN_SAMPLES;
 import static android.provider.Settings.Global.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS;
@@ -147,17 +149,18 @@
     }
 
     public static class PrivateDnsValidationUpdate {
-        final public int netId;
-        final public InetAddress ipAddress;
-        final public String hostname;
-        final public boolean validated;
+        public final int netId;
+        public final InetAddress ipAddress;
+        public final String hostname;
+        // Refer to IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_*.
+        public final int validationResult;
 
         public PrivateDnsValidationUpdate(int netId, InetAddress ipAddress,
-                String hostname, boolean validated) {
+                String hostname, int validationResult) {
             this.netId = netId;
             this.ipAddress = ipAddress;
             this.hostname = hostname;
-            this.validated = validated;
+            this.validationResult = validationResult;
         }
     }
 
@@ -216,10 +219,13 @@
             if (!mValidationMap.containsKey(p)) {
                 return;
             }
-            if (update.validated) {
+            if (update.validationResult == VALIDATION_RESULT_SUCCESS) {
                 mValidationMap.put(p, ValidationStatus.SUCCEEDED);
-            } else {
+            } else if (update.validationResult == VALIDATION_RESULT_FAILURE) {
                 mValidationMap.put(p, ValidationStatus.FAILED);
+            } else {
+                Log.e(TAG, "Unknown private dns validation operation="
+                        + update.validationResult);
             }
         }
 
diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
index 34d9ccc..7b20ded 100644
--- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
+++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
@@ -57,8 +57,8 @@
 import android.util.Pair;
 
 import com.android.internal.R;
-import com.android.internal.util.HexDump;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.net.module.util.HexDump;
 import com.android.net.module.util.IpUtils;
 
 import java.io.FileDescriptor;
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index 641287f..fa80b25 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -29,14 +29,12 @@
 import android.net.LinkProperties;
 import android.net.NetworkInfo;
 import android.net.RouteInfo;
-import android.os.INetworkManagementService;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.net.module.util.NetworkStackConstants;
-import com.android.server.net.BaseNetworkObserver;
 
 import java.net.Inet6Address;
 import java.util.Objects;
@@ -48,7 +46,7 @@
  *
  * @hide
  */
-public class Nat464Xlat extends BaseNetworkObserver {
+public class Nat464Xlat {
     private static final String TAG = Nat464Xlat.class.getSimpleName();
 
     // This must match the interface prefix in clatd.c.
@@ -70,7 +68,6 @@
 
     private final IDnsResolver mDnsResolver;
     private final INetd mNetd;
-    private final INetworkManagementService mNMService;
 
     // The network we're running on, and its type.
     private final NetworkAgentInfo mNetwork;
@@ -99,11 +96,9 @@
 
     private boolean mPrefixDiscoveryRunning;
 
-    public Nat464Xlat(NetworkAgentInfo nai, INetd netd, IDnsResolver dnsResolver,
-            INetworkManagementService nmService) {
+    public Nat464Xlat(NetworkAgentInfo nai, INetd netd, IDnsResolver dnsResolver) {
         mDnsResolver = dnsResolver;
         mNetd = netd;
-        mNMService = nmService;
         mNetwork = nai;
     }
 
@@ -174,13 +169,6 @@
      * and set internal state.
      */
     private void enterStartingState(String baseIface) {
-        try {
-            mNMService.registerObserver(this);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Can't register iface observer for clat on " + mNetwork.toShortString());
-            return;
-        }
-
         mNat64PrefixInUse = selectNat64Prefix();
         String addrStr = null;
         try {
@@ -216,11 +204,6 @@
      * Unregister as a base observer for the stacked interface, and clear internal state.
      */
     private void leaveStartedState() {
-        try {
-            mNMService.unregisterObserver(this);
-        } catch (RemoteException | IllegalStateException e) {
-            Log.e(TAG, "Error unregistering clatd observer on " + mBaseIface + ": " + e);
-        }
         mNat64PrefixInUse = null;
         mIface = null;
         mBaseIface = null;
@@ -507,12 +490,10 @@
         stop();
     }
 
-    @Override
     public void interfaceLinkStateChanged(String iface, boolean up) {
         mNetwork.handler().post(() -> { handleInterfaceLinkStateChanged(iface, up); });
     }
 
-    @Override
     public void interfaceRemoved(String iface) {
         mNetwork.handler().post(() -> handleInterfaceRemoved(iface));
     }
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 4cf5274..cac6cab 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -43,7 +43,6 @@
 import android.net.TcpKeepalivePacketData;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.INetworkManagementService;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.telephony.data.EpsBearerQosSessionAttributes;
@@ -341,8 +340,8 @@
     public NetworkAgentInfo(INetworkAgent na, Network net, NetworkInfo info,
             @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) {
+            IDnsResolver dnsResolver, int factorySerialNumber, int creatorUid,
+            QosCallbackTracker qosCallbackTracker) {
         Objects.requireNonNull(net);
         Objects.requireNonNull(info);
         Objects.requireNonNull(lp);
@@ -356,7 +355,7 @@
         linkProperties = lp;
         networkCapabilities = nc;
         mScore = score;
-        clatd = new Nat464Xlat(this, netd, dnsResolver, nms);
+        clatd = new Nat464Xlat(this, netd, dnsResolver);
         mConnService = connService;
         mContext = context;
         mHandler = handler;
diff --git a/tests/net/common/java/android/net/NetworkStateSnapshotTest.kt b/tests/net/common/java/android/net/NetworkStateSnapshotTest.kt
index 56b56ef..0ca4d95 100644
--- a/tests/net/common/java/android/net/NetworkStateSnapshotTest.kt
+++ b/tests/net/common/java/android/net/NetworkStateSnapshotTest.kt
@@ -63,10 +63,10 @@
 
     @Test
     fun testParcelUnparcel() {
-        val emptySnapshot = NetworkStateSnapshot(LinkProperties(), NetworkCapabilities(),
-                Network(TEST_NETID), null, TYPE_NONE)
+        val emptySnapshot = NetworkStateSnapshot(Network(TEST_NETID), NetworkCapabilities(),
+                LinkProperties(), null, TYPE_NONE)
         val snapshot = NetworkStateSnapshot(
-                TEST_LINK_PROPERTIES, TEST_CAPABILITIES, Network(TEST_NETID), TEST_IMSI, TYPE_WIFI)
+                Network(TEST_NETID), TEST_CAPABILITIES, TEST_LINK_PROPERTIES, TEST_IMSI, TYPE_WIFI)
         assertParcelSane(emptySnapshot, 5)
         assertParcelSane(snapshot, 5)
     }
diff --git a/tests/net/common/java/android/net/UidRangeTest.java b/tests/net/common/java/android/net/UidRangeTest.java
new file mode 100644
index 0000000..1b1c954
--- /dev/null
+++ b/tests/net/common/java/android/net/UidRangeTest.java
@@ -0,0 +1,113 @@
+/*
+ * 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;
+
+import static android.os.UserHandle.MIN_SECONDARY_USER_ID;
+import static android.os.UserHandle.SYSTEM;
+import static android.os.UserHandle.USER_SYSTEM;
+import static android.os.UserHandle.getUid;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.os.Build;
+import android.os.UserHandle;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class UidRangeTest {
+
+    /*
+     * UidRange is no longer passed to netd. UID ranges between the framework and netd are passed as
+     * UidRangeParcel objects.
+     */
+
+    @Rule
+    public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule();
+
+    @Test
+    public void testSingleItemUidRangeAllowed() {
+        new UidRange(123, 123);
+        new UidRange(0, 0);
+        new UidRange(Integer.MAX_VALUE, Integer.MAX_VALUE);
+    }
+
+    @Test
+    public void testNegativeUidsDisallowed() {
+        try {
+            new UidRange(-2, 100);
+            fail("Exception not thrown for negative start UID");
+        } catch (IllegalArgumentException expected) {
+        }
+
+        try {
+            new UidRange(-200, -100);
+            fail("Exception not thrown for negative stop UID");
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    @Test
+    public void testStopLessThanStartDisallowed() {
+        final int x = 4195000;
+        try {
+            new UidRange(x, x - 1);
+            fail("Exception not thrown for negative-length UID range");
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    @Test
+    public void testGetStartAndEndUser() throws Exception {
+        final UidRange uidRangeOfPrimaryUser = new UidRange(
+                getUid(USER_SYSTEM, 10000), getUid(USER_SYSTEM, 10100));
+        final UidRange uidRangeOfSecondaryUser = new UidRange(
+                getUid(MIN_SECONDARY_USER_ID, 10000), getUid(MIN_SECONDARY_USER_ID, 10100));
+        assertEquals(USER_SYSTEM, uidRangeOfPrimaryUser.getStartUser());
+        assertEquals(USER_SYSTEM, uidRangeOfPrimaryUser.getEndUser());
+        assertEquals(MIN_SECONDARY_USER_ID, uidRangeOfSecondaryUser.getStartUser());
+        assertEquals(MIN_SECONDARY_USER_ID, uidRangeOfSecondaryUser.getEndUser());
+
+        final UidRange uidRangeForDifferentUsers = new UidRange(
+                getUid(USER_SYSTEM, 10000), getUid(MIN_SECONDARY_USER_ID, 10100));
+        assertEquals(USER_SYSTEM, uidRangeOfPrimaryUser.getStartUser());
+        assertEquals(MIN_SECONDARY_USER_ID, uidRangeOfSecondaryUser.getEndUser());
+    }
+
+    @Test @IgnoreUpTo(Build.VERSION_CODES.R)
+    public void testCreateForUser() throws Exception {
+        final UidRange uidRangeOfPrimaryUser = UidRange.createForUser(SYSTEM);
+        final UidRange uidRangeOfSecondaryUser = UidRange.createForUser(
+                UserHandle.of(USER_SYSTEM + 1));
+        assertTrue(uidRangeOfPrimaryUser.stop < uidRangeOfSecondaryUser.start);
+        assertEquals(USER_SYSTEM, uidRangeOfPrimaryUser.getStartUser());
+        assertEquals(USER_SYSTEM, uidRangeOfPrimaryUser.getEndUser());
+        assertEquals(USER_SYSTEM + 1, uidRangeOfSecondaryUser.getStartUser());
+        assertEquals(USER_SYSTEM + 1, uidRangeOfSecondaryUser.getEndUser());
+    }
+}
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
index 9ed55f0..c10c573 100644
--- a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
+++ b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
@@ -177,7 +177,7 @@
     }
 
     private inner class TestConnectivityService(deps: Dependencies) : ConnectivityService(
-            context, netManager, statsService, dnsResolver, log, netd, deps)
+            context, statsService, dnsResolver, log, netd, deps)
 
     private fun makeDependencies(): ConnectivityService.Dependencies {
         val deps = spy(ConnectivityService.Dependencies())
diff --git a/tests/net/java/android/net/IpSecAlgorithmTest.java b/tests/net/java/android/net/IpSecAlgorithmTest.java
index 2e1c29a..3a8d600 100644
--- a/tests/net/java/android/net/IpSecAlgorithmTest.java
+++ b/tests/net/java/android/net/IpSecAlgorithmTest.java
@@ -129,6 +129,7 @@
             checkCryptKeyLenValidation(IpSecAlgorithm.CRYPT_AES_CTR, len);
         }
         checkAuthKeyAndTruncLenValidation(IpSecAlgorithm.AUTH_AES_XCBC, 128, 96);
+        checkAuthKeyAndTruncLenValidation(IpSecAlgorithm.AUTH_AES_CMAC, 128, 96);
         checkAuthKeyAndTruncLenValidation(IpSecAlgorithm.AUTH_CRYPT_CHACHA20_POLY1305, 288, 128);
     }
 
diff --git a/tests/net/java/android/net/NetworkTemplateTest.kt b/tests/net/java/android/net/NetworkTemplateTest.kt
index 27224c2..64b774c 100644
--- a/tests/net/java/android/net/NetworkTemplateTest.kt
+++ b/tests/net/java/android/net/NetworkTemplateTest.kt
@@ -20,14 +20,13 @@
 import android.net.ConnectivityManager.TYPE_MOBILE
 import android.net.ConnectivityManager.TYPE_WIFI
 import android.net.NetworkIdentity.SUBTYPE_COMBINED
-import android.net.NetworkIdentity.OEM_NONE;
-import android.net.NetworkIdentity.OEM_PAID;
-import android.net.NetworkIdentity.OEM_PRIVATE;
+import android.net.NetworkIdentity.OEM_NONE
+import android.net.NetworkIdentity.OEM_PAID
+import android.net.NetworkIdentity.OEM_PRIVATE
 import android.net.NetworkIdentity.buildNetworkIdentity
 import android.net.NetworkStats.DEFAULT_NETWORK_ALL
 import android.net.NetworkStats.METERED_ALL
 import android.net.NetworkStats.ROAMING_ALL
-import android.net.NetworkTemplate.MATCH_ETHERNET
 import android.net.NetworkTemplate.MATCH_MOBILE
 import android.net.NetworkTemplate.MATCH_MOBILE_WILDCARD
 import android.net.NetworkTemplate.MATCH_WIFI
@@ -50,7 +49,6 @@
 import kotlin.test.assertFalse
 import kotlin.test.assertNotEquals
 import kotlin.test.assertTrue
-import kotlin.test.fail
 
 private const val TEST_IMSI1 = "imsi1"
 private const val TEST_IMSI2 = "imsi2"
@@ -60,17 +58,17 @@
 class NetworkTemplateTest {
     private val mockContext = mock(Context::class.java)
 
-    private fun buildMobileNetworkState(subscriberId: String): NetworkState =
+    private fun buildMobileNetworkState(subscriberId: String): NetworkStateSnapshot =
             buildNetworkState(TYPE_MOBILE, subscriberId = subscriberId)
-    private fun buildWifiNetworkState(ssid: String): NetworkState =
+    private fun buildWifiNetworkState(ssid: String): NetworkStateSnapshot =
             buildNetworkState(TYPE_WIFI, ssid = ssid)
 
     private fun buildNetworkState(
         type: Int,
         subscriberId: String? = null,
         ssid: String? = null,
-        oemManaged: Int = OEM_NONE,
-    ): NetworkState {
+        oemManaged: Int = OEM_NONE
+    ): NetworkStateSnapshot {
         val lp = LinkProperties()
         val caps = NetworkCapabilities().apply {
             setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false)
@@ -81,7 +79,7 @@
             setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE,
                     (oemManaged and OEM_PRIVATE) == OEM_PRIVATE)
         }
-        return NetworkState(type, lp, caps, mock(Network::class.java), subscriberId)
+        return NetworkStateSnapshot(mock(Network::class.java), caps, lp, subscriberId, type)
     }
 
     private fun NetworkTemplate.assertMatches(ident: NetworkIdentity) =
@@ -179,7 +177,7 @@
                 OEM_PAID, OEM_PRIVATE, OEM_PAID or OEM_PRIVATE)
 
         // Verify that "not OEM managed network" constants are equal.
-        assertEquals(OEM_MANAGED_NO, OEM_NONE);
+        assertEquals(OEM_MANAGED_NO, OEM_NONE)
 
         // Verify the constants don't conflict.
         assertEquals(constantValues.size, constantValues.distinct().count())
@@ -201,8 +199,13 @@
      * @param identSsid If networkType is {@code TYPE_WIFI}, this value must *NOT* be null. Provide
      *         one of {@code TEST_SSID*}.
      */
-    private fun matchOemManagedIdent(networkType: Int, matchType:Int, subscriberId: String? = null,
-            templateSsid: String? = null, identSsid: String? = null) {
+    private fun matchOemManagedIdent(
+        networkType: Int,
+        matchType: Int,
+        subscriberId: String? = null,
+        templateSsid: String? = null,
+        identSsid: String? = null
+    ) {
         val oemManagedStates = arrayOf(OEM_NONE, OEM_PAID, OEM_PRIVATE, OEM_PAID or OEM_PRIVATE)
         // A null subscriberId needs a null matchSubscriberIds argument as well.
         val matchSubscriberIds = if (subscriberId == null) null else arrayOf(subscriberId)
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index bb822d8..c7e8282 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -90,6 +90,10 @@
 import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY;
 import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_UNINITIALIZED;
 import static android.net.RouteInfo.RTN_UNREACHABLE;
+import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.PREFIX_OPERATION_ADDED;
+import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.PREFIX_OPERATION_REMOVED;
+import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_FAILURE;
+import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_SUCCESS;
 import static android.os.Process.INVALID_UID;
 import static android.system.OsConstants.IPPROTO_TCP;
 
@@ -198,7 +202,7 @@
 import android.net.NetworkSpecifier;
 import android.net.NetworkStack;
 import android.net.NetworkStackClient;
-import android.net.NetworkState;
+import android.net.NetworkStateSnapshot;
 import android.net.NetworkTestResultParcelable;
 import android.net.OemNetworkPreferences;
 import android.net.ProxyInfo;
@@ -217,6 +221,8 @@
 import android.net.VpnManager;
 import android.net.VpnTransportInfo;
 import android.net.metrics.IpConnectivityLog;
+import android.net.resolv.aidl.Nat64PrefixEventParcel;
+import android.net.resolv.aidl.PrivateDnsValidationEventParcel;
 import android.net.shared.NetworkMonitorUtils;
 import android.net.shared.PrivateDnsConfig;
 import android.net.util.MultinetworkPolicyTracker;
@@ -1463,7 +1469,6 @@
         mDeps = makeDependencies();
         returnRealCallingUid();
         mService = new ConnectivityService(mServiceContext,
-                mNetworkManagementService,
                 mStatsService,
                 mMockDnsResolver,
                 mock(IpConnectivityLog.class),
@@ -5485,7 +5490,7 @@
                 UnderlyingNetworkInfo[].class);
 
         verify(mStatsService, atLeastOnce()).forceUpdateIfaces(networksCaptor.capture(),
-                any(NetworkState[].class), eq(defaultIface), vpnInfosCaptor.capture());
+                any(NetworkStateSnapshot[].class), eq(defaultIface), vpnInfosCaptor.capture());
 
         assertSameElementsNoDuplicates(networksCaptor.getValue(), networks);
 
@@ -5555,9 +5560,8 @@
         // Temp metered change shouldn't update ifaces
         mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED);
         waitForIdle();
-        verify(mStatsService, never())
-                .forceUpdateIfaces(eq(onlyCell), any(NetworkState[].class), eq(MOBILE_IFNAME),
-                        eq(new UnderlyingNetworkInfo[0]));
+        verify(mStatsService, never()).forceUpdateIfaces(eq(onlyCell), any(
+                NetworkStateSnapshot[].class), eq(MOBILE_IFNAME), eq(new UnderlyingNetworkInfo[0]));
         reset(mStatsService);
 
         // Roaming change should update ifaces
@@ -5639,7 +5643,7 @@
         // Confirm that we never tell NetworkStatsService that cell is no longer the underlying
         // network for the VPN...
         verify(mStatsService, never()).forceUpdateIfaces(any(Network[].class),
-                any(NetworkState[].class), any() /* anyString() doesn't match null */,
+                any(NetworkStateSnapshot[].class), any() /* anyString() doesn't match null */,
                 argThat(infos -> infos[0].underlyingIfaces.size() == 1
                         && WIFI_IFNAME.equals(infos[0].underlyingIfaces.get(0))));
         verifyNoMoreInteractions(mStatsService);
@@ -5653,7 +5657,7 @@
         mEthernetNetworkAgent.connect(false);
         waitForIdle();
         verify(mStatsService).forceUpdateIfaces(any(Network[].class),
-                any(NetworkState[].class), any() /* anyString() doesn't match null */,
+                any(NetworkStateSnapshot[].class), any() /* anyString() doesn't match null */,
                 argThat(vpnInfos -> vpnInfos[0].underlyingIfaces.size() == 1
                         && WIFI_IFNAME.equals(vpnInfos[0].underlyingIfaces.get(0))));
         mEthernetNetworkAgent.disconnect();
@@ -5921,6 +5925,16 @@
         assertEquals("strict.example.com", cbi.getLp().getPrivateDnsServerName());
     }
 
+    private PrivateDnsValidationEventParcel makePrivateDnsValidationEvent(
+            final int netId, final String ipAddress, final String hostname, final int validation) {
+        final PrivateDnsValidationEventParcel event = new PrivateDnsValidationEventParcel();
+        event.netId = netId;
+        event.ipAddress = ipAddress;
+        event.hostname = hostname;
+        event.validation = validation;
+        return event;
+    }
+
     @Test
     public void testLinkPropertiesWithPrivateDnsValidationEvents() throws Exception {
         // The default on Android is opportunistic mode ("Automatic").
@@ -5951,8 +5965,9 @@
 
         // Send a validation event for a server that is not part of the current
         // resolver config. The validation event should be ignored.
-        mService.mNetdEventCallback.onPrivateDnsValidationEvent(
-                mCellNetworkAgent.getNetwork().netId, "", "145.100.185.18", true);
+        mService.mResolverUnsolEventCallback.onPrivateDnsValidationEvent(
+                makePrivateDnsValidationEvent(mCellNetworkAgent.getNetwork().netId, "",
+                        "145.100.185.18", VALIDATION_RESULT_SUCCESS));
         cellNetworkCallback.assertNoCallback();
 
         // Add a dns server to the LinkProperties.
@@ -5969,20 +5984,23 @@
 
         // Send a validation event containing a hostname that is not part of
         // the current resolver config. The validation event should be ignored.
-        mService.mNetdEventCallback.onPrivateDnsValidationEvent(
-                mCellNetworkAgent.getNetwork().netId, "145.100.185.16", "hostname", true);
+        mService.mResolverUnsolEventCallback.onPrivateDnsValidationEvent(
+                makePrivateDnsValidationEvent(mCellNetworkAgent.getNetwork().netId,
+                        "145.100.185.16", "hostname", VALIDATION_RESULT_SUCCESS));
         cellNetworkCallback.assertNoCallback();
 
         // Send a validation event where validation failed.
-        mService.mNetdEventCallback.onPrivateDnsValidationEvent(
-                mCellNetworkAgent.getNetwork().netId, "145.100.185.16", "", false);
+        mService.mResolverUnsolEventCallback.onPrivateDnsValidationEvent(
+                makePrivateDnsValidationEvent(mCellNetworkAgent.getNetwork().netId,
+                        "145.100.185.16", "", VALIDATION_RESULT_FAILURE));
         cellNetworkCallback.assertNoCallback();
 
         // Send a validation event where validation succeeded for a server in
         // the current resolver config. A LinkProperties callback with updated
         // private dns fields should be sent.
-        mService.mNetdEventCallback.onPrivateDnsValidationEvent(
-                mCellNetworkAgent.getNetwork().netId, "145.100.185.16", "", true);
+        mService.mResolverUnsolEventCallback.onPrivateDnsValidationEvent(
+                makePrivateDnsValidationEvent(mCellNetworkAgent.getNetwork().netId,
+                        "145.100.185.16", "", VALIDATION_RESULT_SUCCESS));
         cbi = cellNetworkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED,
                 mCellNetworkAgent);
         cellNetworkCallback.assertNoCallback();
@@ -7826,6 +7844,16 @@
         return stacked;
     }
 
+    private Nat64PrefixEventParcel makeNat64PrefixEvent(final int netId, final int prefixOperation,
+            final String prefixAddress, final int prefixLength) {
+        final Nat64PrefixEventParcel event = new Nat64PrefixEventParcel();
+        event.netId = netId;
+        event.prefixOperation = prefixOperation;
+        event.prefixAddress = prefixAddress;
+        event.prefixLength = prefixLength;
+        return event;
+    }
+
     @Test
     public void testStackedLinkProperties() throws Exception {
         final LinkAddress myIpv4 = new LinkAddress("1.2.3.4/24");
@@ -7856,7 +7884,6 @@
         cellLp.addRoute(defaultRoute);
         cellLp.addRoute(ipv6Subnet);
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
-        reset(mNetworkManagementService);
         reset(mMockDnsResolver);
         reset(mMockNetd);
         reset(mBatteryStatsService);
@@ -7896,7 +7923,6 @@
 
         verifyNoMoreInteractions(mMockNetd);
         verifyNoMoreInteractions(mMockDnsResolver);
-        reset(mNetworkManagementService);
         reset(mMockNetd);
         reset(mMockDnsResolver);
         when(mMockNetd.interfaceGetCfg(CLAT_PREFIX + MOBILE_IFNAME))
@@ -7912,8 +7938,8 @@
         // When NAT64 prefix discovery succeeds, LinkProperties are updated and clatd is started.
         Nat464Xlat clat = getNat464Xlat(mCellNetworkAgent);
         assertNull(mCm.getLinkProperties(mCellNetworkAgent.getNetwork()).getNat64Prefix());
-        mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, true /* added */,
-                kNat64PrefixString, 96);
+        mService.mResolverUnsolEventCallback.onNat64PrefixEvent(
+                makeNat64PrefixEvent(cellNetId, PREFIX_OPERATION_ADDED, kNat64PrefixString, 96));
         LinkProperties lpBeforeClat = networkCallback.expectCallback(
                 CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent).getLp();
         assertEquals(0, lpBeforeClat.getStackedLinks().size());
@@ -7953,8 +7979,8 @@
                 .thenReturn(getClatInterfaceConfigParcel(myIpv4));
         // Change the NAT64 prefix without first removing it.
         // Expect clatd to be stopped and started with the new prefix.
-        mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, true /* added */,
-                kOtherNat64PrefixString, 96);
+        mService.mResolverUnsolEventCallback.onNat64PrefixEvent(makeNat64PrefixEvent(
+                cellNetId, PREFIX_OPERATION_ADDED, kOtherNat64PrefixString, 96));
         networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
                 (lp) -> lp.getStackedLinks().size() == 0);
         verify(mMockNetd, times(1)).clatdStop(MOBILE_IFNAME);
@@ -7996,15 +8022,14 @@
         verify(mMockNetd, times(1)).networkRemoveInterface(cellNetId, CLAT_PREFIX + MOBILE_IFNAME);
         verifyNoMoreInteractions(mMockNetd);
         verifyNoMoreInteractions(mMockDnsResolver);
-        reset(mNetworkManagementService);
         reset(mMockNetd);
         reset(mMockDnsResolver);
         when(mMockNetd.interfaceGetCfg(CLAT_PREFIX + MOBILE_IFNAME))
                 .thenReturn(getClatInterfaceConfigParcel(myIpv4));
 
         // Stopping prefix discovery causes netd to tell us that the NAT64 prefix is gone.
-        mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, false /* added */,
-                kOtherNat64PrefixString, 96);
+        mService.mResolverUnsolEventCallback.onNat64PrefixEvent(makeNat64PrefixEvent(
+                cellNetId, PREFIX_OPERATION_REMOVED, kOtherNat64PrefixString, 96));
         networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
                 (lp) -> lp.getNat64Prefix() == null);
 
@@ -8016,8 +8041,8 @@
         networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
         assertRoutesRemoved(cellNetId, ipv4Subnet);  // Directly-connected routes auto-added.
         verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
-        mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, true /* added */,
-                kNat64PrefixString, 96);
+        mService.mResolverUnsolEventCallback.onNat64PrefixEvent(makeNat64PrefixEvent(
+                cellNetId, PREFIX_OPERATION_ADDED, kNat64PrefixString, 96));
         networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
         verify(mMockNetd, times(1)).clatdStart(MOBILE_IFNAME, kNat64Prefix.toString());
 
@@ -8029,8 +8054,8 @@
         verify(mMockNetd, times(1)).networkAddInterface(cellNetId, CLAT_PREFIX + MOBILE_IFNAME);
 
         // NAT64 prefix is removed. Expect that clat is stopped.
-        mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, false /* added */,
-                kNat64PrefixString, 96);
+        mService.mResolverUnsolEventCallback.onNat64PrefixEvent(makeNat64PrefixEvent(
+                cellNetId, PREFIX_OPERATION_REMOVED, kNat64PrefixString, 96));
         networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
                 (lp) -> lp.getStackedLinks().size() == 0 && lp.getNat64Prefix() == null);
         assertRoutesRemoved(cellNetId, ipv4Subnet, stackedDefault);
@@ -8118,8 +8143,8 @@
         inOrder.verify(mMockDnsResolver).setPrefix64(netId, "");
         inOrder.verify(mMockDnsResolver).startPrefix64Discovery(netId);
 
-        mService.mNetdEventCallback.onNat64PrefixEvent(netId, true /* added */,
-                pref64FromDnsStr, 96);
+        mService.mResolverUnsolEventCallback.onNat64PrefixEvent(
+                makeNat64PrefixEvent(netId, PREFIX_OPERATION_ADDED, pref64FromDnsStr, 96));
         expectNat64PrefixChange(callback, mWiFiNetworkAgent, pref64FromDns);
         inOrder.verify(mMockNetd).clatdStart(iface, pref64FromDns.toString());
 
@@ -8152,8 +8177,8 @@
         inOrder.verify(mMockDnsResolver).stopPrefix64Discovery(netId);
 
         // Stopping prefix discovery results in a prefix removed notification.
-        mService.mNetdEventCallback.onNat64PrefixEvent(netId, false /* added */,
-                pref64FromDnsStr, 96);
+        mService.mResolverUnsolEventCallback.onNat64PrefixEvent(
+                makeNat64PrefixEvent(netId, PREFIX_OPERATION_REMOVED, pref64FromDnsStr, 96));
 
         inOrder.verify(mMockNetd).clatdStart(iface, pref64FromRa.toString());
         inOrder.verify(mMockDnsResolver).setPrefix64(netId, pref64FromRa.toString());
@@ -8191,8 +8216,8 @@
         inOrder.verify(mMockNetd).clatdStop(iface);
         inOrder.verify(mMockDnsResolver).setPrefix64(netId, "");
         inOrder.verify(mMockDnsResolver).startPrefix64Discovery(netId);
-        mService.mNetdEventCallback.onNat64PrefixEvent(netId, true /* added */,
-                pref64FromDnsStr, 96);
+        mService.mResolverUnsolEventCallback.onNat64PrefixEvent(
+                makeNat64PrefixEvent(netId, PREFIX_OPERATION_ADDED, pref64FromDnsStr, 96));
         expectNat64PrefixChange(callback, mWiFiNetworkAgent, pref64FromDns);
         inOrder.verify(mMockNetd).clatdStart(iface, pref64FromDns.toString());
         inOrder.verify(mMockDnsResolver, never()).setPrefix64(eq(netId), any());
@@ -8233,7 +8258,6 @@
         final LinkProperties cellLp = new LinkProperties();
         cellLp.setInterfaceName(MOBILE_IFNAME);
         mCellNetworkAgent.sendLinkProperties(cellLp);
-        reset(mNetworkManagementService);
         mCellNetworkAgent.connect(true);
         networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         verify(mMockNetd, times(1)).idletimerAddInterface(eq(MOBILE_IFNAME), anyInt(),
@@ -8927,8 +8951,8 @@
                 ConnectivityManager.getNetworkTypeName(TYPE_MOBILE),
                 TelephonyManager.getNetworkTypeName(TelephonyManager.NETWORK_TYPE_LTE));
         return new NetworkAgentInfo(null, new Network(NET_ID), info, new LinkProperties(),
-                nc, 0, mServiceContext, null, new NetworkAgentConfig(), mService, null, null, null,
-                0, INVALID_UID, mQosCallbackTracker);
+                nc, 0, mServiceContext, null, new NetworkAgentConfig(), mService, null, null, 0,
+                INVALID_UID, mQosCallbackTracker);
     }
 
     @Test
diff --git a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
index f5b85ca..5760211 100644
--- a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
+++ b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
@@ -22,6 +22,8 @@
 import static android.net.NetworkCapabilities.MIN_TRANSPORT;
 import static android.net.NetworkCapabilities.TRANSPORT_VPN;
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_FAILURE;
+import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_SUCCESS;
 import static android.provider.Settings.Global.PRIVATE_DNS_DEFAULT_MODE;
 import static android.provider.Settings.Global.PRIVATE_DNS_MODE;
 import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER;
@@ -164,7 +166,8 @@
         mDnsManager.flushVmDnsCache();
         mDnsManager.updatePrivateDnsValidation(
                 new DnsManager.PrivateDnsValidationUpdate(TEST_NETID_ALTERNATE,
-                InetAddress.parseNumericAddress("4.4.4.4"), "", true));
+                        InetAddress.parseNumericAddress("4.4.4.4"), "",
+                        VALIDATION_RESULT_SUCCESS));
         LinkProperties fixedLp = new LinkProperties(lp);
         mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp);
         assertFalse(fixedLp.isPrivateDnsActive());
@@ -204,7 +207,8 @@
         // Validate one.
         mDnsManager.updatePrivateDnsValidation(
                 new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
-                InetAddress.parseNumericAddress("6.6.6.6"), "strictmode.com", true));
+                        InetAddress.parseNumericAddress("6.6.6.6"), "strictmode.com",
+                        VALIDATION_RESULT_SUCCESS));
         fixedLp = new LinkProperties(lp);
         mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp);
         assertEquals(Arrays.asList(InetAddress.parseNumericAddress("6.6.6.6")),
@@ -212,7 +216,8 @@
         // Validate the 2nd one.
         mDnsManager.updatePrivateDnsValidation(
                 new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
-                InetAddress.parseNumericAddress("2001:db8:66:66::1"), "strictmode.com", true));
+                        InetAddress.parseNumericAddress("2001:db8:66:66::1"), "strictmode.com",
+                        VALIDATION_RESULT_SUCCESS));
         fixedLp = new LinkProperties(lp);
         mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp);
         assertEquals(Arrays.asList(
@@ -232,7 +237,8 @@
         mDnsManager.flushVmDnsCache();
         mDnsManager.updatePrivateDnsValidation(
                 new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
-                InetAddress.parseNumericAddress("3.3.3.3"), "", true));
+                        InetAddress.parseNumericAddress("3.3.3.3"), "",
+                        VALIDATION_RESULT_SUCCESS));
         mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
         assertFalse(lp.isPrivateDnsActive());
         assertNull(lp.getPrivateDnsServerName());
@@ -245,7 +251,8 @@
         mDnsManager.flushVmDnsCache();
         mDnsManager.updatePrivateDnsValidation(
                 new DnsManager.PrivateDnsValidationUpdate(TEST_NETID_UNTRACKED,
-                InetAddress.parseNumericAddress("3.3.3.3"), "", true));
+                        InetAddress.parseNumericAddress("3.3.3.3"), "",
+                        VALIDATION_RESULT_SUCCESS));
         mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
         assertFalse(lp.isPrivateDnsActive());
         assertNull(lp.getPrivateDnsServerName());
@@ -253,7 +260,8 @@
         // Validation event has untracked ipAddress
         mDnsManager.updatePrivateDnsValidation(
                 new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
-                InetAddress.parseNumericAddress("4.4.4.4"), "", true));
+                        InetAddress.parseNumericAddress("4.4.4.4"), "",
+                        VALIDATION_RESULT_SUCCESS));
         mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
         assertFalse(lp.isPrivateDnsActive());
         assertNull(lp.getPrivateDnsServerName());
@@ -261,8 +269,8 @@
         // Validation event has untracked hostname
         mDnsManager.updatePrivateDnsValidation(
                 new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
-                InetAddress.parseNumericAddress("3.3.3.3"), "hostname",
-                true));
+                        InetAddress.parseNumericAddress("3.3.3.3"), "hostname",
+                        VALIDATION_RESULT_SUCCESS));
         mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
         assertFalse(lp.isPrivateDnsActive());
         assertNull(lp.getPrivateDnsServerName());
@@ -270,7 +278,8 @@
         // Validation event failed
         mDnsManager.updatePrivateDnsValidation(
                 new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
-                InetAddress.parseNumericAddress("3.3.3.3"), "", false));
+                        InetAddress.parseNumericAddress("3.3.3.3"), "",
+                        VALIDATION_RESULT_FAILURE));
         mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
         assertFalse(lp.isPrivateDnsActive());
         assertNull(lp.getPrivateDnsServerName());
@@ -279,7 +288,7 @@
         mDnsManager.removeNetwork(new Network(TEST_NETID));
         mDnsManager.updatePrivateDnsValidation(
                 new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
-                InetAddress.parseNumericAddress("3.3.3.3"), "", true));
+                        InetAddress.parseNumericAddress("3.3.3.3"), "", VALIDATION_RESULT_SUCCESS));
         mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
         assertFalse(lp.isPrivateDnsActive());
         assertNull(lp.getPrivateDnsServerName());
@@ -293,7 +302,8 @@
         mDnsManager.flushVmDnsCache();
         mDnsManager.updatePrivateDnsValidation(
                 new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
-                InetAddress.parseNumericAddress("3.3.3.3"), "", true));
+                        InetAddress.parseNumericAddress("3.3.3.3"), "",
+                        VALIDATION_RESULT_SUCCESS));
         mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
         assertFalse(lp.isPrivateDnsActive());
         assertNull(lp.getPrivateDnsServerName());
@@ -398,7 +408,8 @@
         mDnsManager.updatePrivateDns(network, mDnsManager.getPrivateDnsConfig());
         mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp);
         mDnsManager.updatePrivateDnsValidation(
-                new DnsManager.PrivateDnsValidationUpdate(TEST_NETID, dnsAddr, "", true));
+                new DnsManager.PrivateDnsValidationUpdate(TEST_NETID, dnsAddr, "",
+                        VALIDATION_RESULT_SUCCESS));
         mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
         privateDnsCfg = mDnsManager.getPrivateDnsConfig(network);
         assertTrue(privateDnsCfg.useTls);
diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
index 52cb836..a913673 100644
--- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -41,7 +41,6 @@
 import android.net.NetworkInfo;
 import android.net.NetworkProvider;
 import android.os.Binder;
-import android.os.INetworkManagementService;
 import android.text.format.DateUtils;
 
 import androidx.test.filters.SmallTest;
@@ -74,7 +73,6 @@
     @Mock ConnectivityService mConnService;
     @Mock IDnsResolver mDnsResolver;
     @Mock INetd mNetd;
-    @Mock INetworkManagementService mNMS;
     @Mock Context mCtx;
     @Mock NetworkNotificationManager mNotifier;
     @Mock Resources mResources;
@@ -358,8 +356,8 @@
         caps.addTransportType(transport);
         NetworkAgentInfo nai = new NetworkAgentInfo(null, new Network(netId), info,
                 new LinkProperties(), caps, 50, mCtx, null, new NetworkAgentConfig() /* config */,
-                mConnService, mNetd, mDnsResolver, mNMS, NetworkProvider.ID_NONE,
-                Binder.getCallingUid(), mQosCallbackTracker);
+                mConnService, mNetd, mDnsResolver, NetworkProvider.ID_NONE, Binder.getCallingUid(),
+                mQosCallbackTracker);
         nai.everValidated = true;
         return nai;
     }
diff --git a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
index 4f65b67..5f56e25 100644
--- a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
+++ b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
@@ -36,7 +36,6 @@
 import android.net.NetworkAgentConfig;
 import android.net.NetworkInfo;
 import android.os.Handler;
-import android.os.INetworkManagementService;
 import android.os.test.TestLooper;
 
 import androidx.test.filters.SmallTest;
@@ -67,7 +66,6 @@
     @Mock ConnectivityService mConnectivity;
     @Mock IDnsResolver mDnsResolver;
     @Mock INetd mNetd;
-    @Mock INetworkManagementService mNms;
     @Mock NetworkAgentInfo mNai;
 
     TestLooper mLooper;
@@ -75,7 +73,7 @@
     NetworkAgentConfig mAgentConfig = new NetworkAgentConfig();
 
     Nat464Xlat makeNat464Xlat() {
-        return new Nat464Xlat(mNai, mNetd, mDnsResolver, mNms) {
+        return new Nat464Xlat(mNai, mNetd, mDnsResolver) {
             @Override protected int getNetId() {
                 return NETID;
             }
@@ -206,7 +204,6 @@
         // Start clat.
         nat.start();
 
-        verify(mNms).registerObserver(eq(nat));
         verify(mNetd).clatdStart(eq(BASE_IFACE), eq(NAT64_PREFIX));
 
         // Stacked interface up notification arrives.
@@ -225,7 +222,6 @@
 
         verify(mNetd).clatdStop(eq(BASE_IFACE));
         verify(mConnectivity, times(2)).handleUpdateLinkProperties(eq(mNai), c.capture());
-        verify(mNms).unregisterObserver(eq(nat));
         assertTrue(c.getValue().getStackedLinks().isEmpty());
         assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
         verify(mDnsResolver).stopPrefix64Discovery(eq(NETID));
@@ -235,7 +231,7 @@
         nat.interfaceRemoved(STACKED_IFACE);
         mLooper.dispatchNext();
 
-        verifyNoMoreInteractions(mNetd, mNms, mConnectivity);
+        verifyNoMoreInteractions(mNetd, mConnectivity);
     }
 
     @Test
@@ -346,7 +342,6 @@
 
         nat.start();
 
-        verify(mNms).registerObserver(eq(nat));
         verify(mNetd).clatdStart(eq(BASE_IFACE), eq(NAT64_PREFIX));
 
         // Stacked interface up notification arrives.
@@ -365,7 +360,6 @@
 
         verify(mNetd).clatdStop(eq(BASE_IFACE));
         verify(mConnectivity, times(2)).handleUpdateLinkProperties(eq(mNai), c.capture());
-        verify(mNms).unregisterObserver(eq(nat));
         verify(mDnsResolver).stopPrefix64Discovery(eq(NETID));
         assertTrue(c.getValue().getStackedLinks().isEmpty());
         assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
@@ -374,7 +368,7 @@
         // ConnectivityService stops clat: no-op.
         nat.stop();
 
-        verifyNoMoreInteractions(mNetd, mNms, mConnectivity);
+        verifyNoMoreInteractions(mNetd, mConnectivity);
     }
 
     private void checkStopBeforeClatdStarts(boolean dueToDisconnect) throws Exception {
@@ -386,7 +380,6 @@
 
         nat.start();
 
-        verify(mNms).registerObserver(eq(nat));
         verify(mNetd).clatdStart(eq(BASE_IFACE), eq(NAT64_PREFIX));
 
         // ConnectivityService immediately stops clat (Network disconnects, IPv4 addr appears, ...)
@@ -394,7 +387,6 @@
         nat.stop();
 
         verify(mNetd).clatdStop(eq(BASE_IFACE));
-        verify(mNms).unregisterObserver(eq(nat));
         verify(mDnsResolver).stopPrefix64Discovery(eq(NETID));
         assertIdle(nat);
 
@@ -408,7 +400,7 @@
 
         assertIdle(nat);
 
-        verifyNoMoreInteractions(mNetd, mNms, mConnectivity);
+        verifyNoMoreInteractions(mNetd, mConnectivity);
     }
 
     @Test
@@ -430,7 +422,6 @@
 
         nat.start();
 
-        verify(mNms).registerObserver(eq(nat));
         verify(mNetd).clatdStart(eq(BASE_IFACE), eq(NAT64_PREFIX));
 
         // ConnectivityService immediately stops clat (Network disconnects, IPv4 addr appears, ...)
@@ -438,11 +429,10 @@
         nat.stop();
 
         verify(mNetd).clatdStop(eq(BASE_IFACE));
-        verify(mNms).unregisterObserver(eq(nat));
         verify(mDnsResolver).stopPrefix64Discovery(eq(NETID));
         assertIdle(nat);
 
-        verifyNoMoreInteractions(mNetd, mNms, mConnectivity);
+        verifyNoMoreInteractions(mNetd, mConnectivity);
     }
 
     @Test
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index 54d6fb9..9334e2c 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -19,9 +19,7 @@
 import static android.content.Intent.ACTION_UID_REMOVED;
 import static android.content.Intent.EXTRA_UID;
 import static android.net.ConnectivityManager.TYPE_MOBILE;
-import static android.net.ConnectivityManager.TYPE_VPN;
 import static android.net.ConnectivityManager.TYPE_WIFI;
-import static android.net.NetworkIdentity.OEM_NONE;
 import static android.net.NetworkIdentity.OEM_PAID;
 import static android.net.NetworkIdentity.OEM_PRIVATE;
 import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
@@ -86,7 +84,7 @@
 import android.net.LinkProperties;
 import android.net.Network;
 import android.net.NetworkCapabilities;
-import android.net.NetworkState;
+import android.net.NetworkStateSnapshot;
 import android.net.NetworkStats;
 import android.net.NetworkStatsHistory;
 import android.net.NetworkTemplate;
@@ -286,7 +284,7 @@
         // pretend that wifi network comes online; service should ask about full
         // network state, and poll any existing interfaces before updating.
         expectDefaultSettings();
-        NetworkState[] states = new NetworkState[] {buildWifiState()};
+        NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
@@ -329,7 +327,7 @@
         // pretend that wifi network comes online; service should ask about full
         // network state, and poll any existing interfaces before updating.
         expectDefaultSettings();
-        NetworkState[] states = new NetworkState[] {buildWifiState()};
+        NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
@@ -403,7 +401,7 @@
         // pretend that wifi network comes online; service should ask about full
         // network state, and poll any existing interfaces before updating.
         expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS);
-        NetworkState[] states = new NetworkState[] {buildWifiState()};
+        NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
@@ -444,7 +442,7 @@
     public void testUidStatsAcrossNetworks() throws Exception {
         // pretend first mobile network comes online
         expectDefaultSettings();
-        NetworkState[] states = new NetworkState[] {buildMobile3gState(IMSI_1)};
+        NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildMobile3gState(IMSI_1)};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
@@ -475,7 +473,7 @@
         // disappearing, to verify we don't count backwards.
         incrementCurrentTime(HOUR_IN_MILLIS);
         expectDefaultSettings();
-        states = new NetworkState[] {buildMobile3gState(IMSI_2)};
+        states = new NetworkStateSnapshot[] {buildMobile3gState(IMSI_2)};
         expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
                 .insertEntry(TEST_IFACE, 2048L, 16L, 512L, 4L));
         expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3)
@@ -519,7 +517,7 @@
     public void testUidRemovedIsMoved() throws Exception {
         // pretend that network comes online
         expectDefaultSettings();
-        NetworkState[] states = new NetworkState[] {buildWifiState()};
+        NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
@@ -583,7 +581,8 @@
                 buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_LTE);
         final NetworkTemplate template5g =
                 buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_NR);
-        final NetworkState[] states = new NetworkState[]{buildMobile3gState(IMSI_1)};
+        final NetworkStateSnapshot[] states =
+                new NetworkStateSnapshot[]{buildMobile3gState(IMSI_1)};
 
         // 3G network comes online.
         expectNetworkStatsSummary(buildEmptyStats());
@@ -673,7 +672,8 @@
                 METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_NO);
 
         // OEM_PAID network comes online.
-        NetworkState[] states = new NetworkState[]{buildOemManagedMobileState(IMSI_1, false,
+        NetworkStateSnapshot[] states = new NetworkStateSnapshot[]{
+                buildOemManagedMobileState(IMSI_1, false,
                 new int[]{NetworkCapabilities.NET_CAPABILITY_OEM_PAID})};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
@@ -688,7 +688,7 @@
         forcePollAndWaitForIdle();
 
         // OEM_PRIVATE network comes online.
-        states = new NetworkState[]{buildOemManagedMobileState(IMSI_1, false,
+        states = new NetworkStateSnapshot[]{buildOemManagedMobileState(IMSI_1, false,
                 new int[]{NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE})};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
@@ -703,7 +703,7 @@
         forcePollAndWaitForIdle();
 
         // OEM_PAID + OEM_PRIVATE network comes online.
-        states = new NetworkState[]{buildOemManagedMobileState(IMSI_1, false,
+        states = new NetworkStateSnapshot[]{buildOemManagedMobileState(IMSI_1, false,
                 new int[]{NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE,
                           NetworkCapabilities.NET_CAPABILITY_OEM_PAID})};
         expectNetworkStatsSummary(buildEmptyStats());
@@ -719,7 +719,7 @@
         forcePollAndWaitForIdle();
 
         // OEM_NONE network comes online.
-        states = new NetworkState[]{buildOemManagedMobileState(IMSI_1, false, new int[]{})};
+        states = new NetworkStateSnapshot[]{buildOemManagedMobileState(IMSI_1, false, new int[]{})};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
         mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
@@ -771,7 +771,7 @@
     public void testSummaryForAllUid() throws Exception {
         // pretend that network comes online
         expectDefaultSettings();
-        NetworkState[] states = new NetworkState[] {buildWifiState()};
+        NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
@@ -830,7 +830,7 @@
     public void testDetailedUidStats() throws Exception {
         // pretend that network comes online
         expectDefaultSettings();
-        NetworkState[] states = new NetworkState[] {buildWifiState()};
+        NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
@@ -871,9 +871,9 @@
         final String stackedIface = "stacked-test0";
         final LinkProperties stackedProp = new LinkProperties();
         stackedProp.setInterfaceName(stackedIface);
-        final NetworkState wifiState = buildWifiState();
+        final NetworkStateSnapshot wifiState = buildWifiState();
         wifiState.linkProperties.addStackedLink(stackedProp);
-        NetworkState[] states = new NetworkState[] {wifiState};
+        NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {wifiState};
 
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
@@ -929,7 +929,7 @@
     public void testForegroundBackground() throws Exception {
         // pretend that network comes online
         expectDefaultSettings();
-        NetworkState[] states = new NetworkState[] {buildWifiState()};
+        NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
@@ -986,8 +986,8 @@
     public void testMetered() throws Exception {
         // pretend that network comes online
         expectDefaultSettings();
-        NetworkState[] states =
-                new NetworkState[] {buildWifiState(true /* isMetered */, TEST_IFACE)};
+        NetworkStateSnapshot[] states =
+                new NetworkStateSnapshot[] {buildWifiState(true /* isMetered */, TEST_IFACE)};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
@@ -1026,8 +1026,8 @@
     public void testRoaming() throws Exception {
         // pretend that network comes online
         expectDefaultSettings();
-        NetworkState[] states =
-            new NetworkState[] {buildMobile3gState(IMSI_1, true /* isRoaming */)};
+        NetworkStateSnapshot[] states =
+            new NetworkStateSnapshot[] {buildMobile3gState(IMSI_1, true /* isRoaming */)};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
@@ -1065,7 +1065,8 @@
     public void testTethering() throws Exception {
         // pretend first mobile network comes online
         expectDefaultSettings();
-        final NetworkState[] states = new NetworkState[]{buildMobile3gState(IMSI_1)};
+        final NetworkStateSnapshot[] states =
+                new NetworkStateSnapshot[]{buildMobile3gState(IMSI_1)};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
@@ -1122,7 +1123,7 @@
         // pretend that wifi network comes online; service should ask about full
         // network state, and poll any existing interfaces before updating.
         expectDefaultSettings();
-        NetworkState[] states = new NetworkState[] {buildWifiState()};
+        NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
@@ -1220,8 +1221,8 @@
     public void testStatsProviderUpdateStats() throws Exception {
         // Pretend that network comes online.
         expectDefaultSettings();
-        final NetworkState[] states =
-                new NetworkState[]{buildWifiState(true /* isMetered */, TEST_IFACE)};
+        final NetworkStateSnapshot[] states =
+                new NetworkStateSnapshot[]{buildWifiState(true /* isMetered */, TEST_IFACE)};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
@@ -1282,8 +1283,8 @@
     public void testStatsProviderSetAlert() throws Exception {
         // Pretend that network comes online.
         expectDefaultSettings();
-        NetworkState[] states =
-                new NetworkState[]{buildWifiState(true /* isMetered */, TEST_IFACE)};
+        NetworkStateSnapshot[] states =
+                new NetworkStateSnapshot[]{buildWifiState(true /* isMetered */, TEST_IFACE)};
         mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
                 new UnderlyingNetworkInfo[0]);
 
@@ -1326,7 +1327,8 @@
                 buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_UNKNOWN);
         final NetworkTemplate templateAll =
                 buildTemplateMobileWithRatType(null, NETWORK_TYPE_ALL);
-        final NetworkState[] states = new NetworkState[]{buildMobile3gState(IMSI_1)};
+        final NetworkStateSnapshot[] states =
+                new NetworkStateSnapshot[]{buildMobile3gState(IMSI_1)};
 
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
@@ -1401,7 +1403,7 @@
     public void testOperationCount_nonDefault_traffic() throws Exception {
         // Pretend mobile network comes online, but wifi is the default network.
         expectDefaultSettings();
-        NetworkState[] states = new NetworkState[]{
+        NetworkStateSnapshot[] states = new NetworkStateSnapshot[]{
                 buildWifiState(true /*isMetered*/, TEST_IFACE2), buildMobile3gState(IMSI_1)};
         expectNetworkStatsUidDetail(buildEmptyStats());
         mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
@@ -1489,7 +1491,7 @@
         expectNetworkStatsSummary(buildEmptyStats());
     }
 
-    private String getActiveIface(NetworkState... states) throws Exception {
+    private String getActiveIface(NetworkStateSnapshot... states) throws Exception {
         if (states == null || states.length == 0 || states[0].linkProperties == null) {
             return null;
         }
@@ -1565,11 +1567,11 @@
         assertEquals("unexpected operations", operations, entry.operations);
     }
 
-    private static NetworkState buildWifiState() {
+    private static NetworkStateSnapshot buildWifiState() {
         return buildWifiState(false, TEST_IFACE);
     }
 
-    private static NetworkState buildWifiState(boolean isMetered, @NonNull String iface) {
+    private static NetworkStateSnapshot buildWifiState(boolean isMetered, @NonNull String iface) {
         final LinkProperties prop = new LinkProperties();
         prop.setInterfaceName(iface);
         final NetworkCapabilities capabilities = new NetworkCapabilities();
@@ -1577,35 +1579,30 @@
         capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true);
         capabilities.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
         capabilities.setSSID(TEST_SSID);
-        return new NetworkState(TYPE_WIFI, prop, capabilities, WIFI_NETWORK, null);
+        return new NetworkStateSnapshot(WIFI_NETWORK, capabilities, prop, null, TYPE_WIFI);
     }
 
-    private static NetworkState buildMobile3gState(String subscriberId) {
+    private static NetworkStateSnapshot buildMobile3gState(String subscriberId) {
         return buildMobile3gState(subscriberId, false /* isRoaming */);
     }
 
-    private static NetworkState buildMobile3gState(String subscriberId, boolean isRoaming) {
+    private static NetworkStateSnapshot buildMobile3gState(String subscriberId, boolean isRoaming) {
         final LinkProperties prop = new LinkProperties();
         prop.setInterfaceName(TEST_IFACE);
         final NetworkCapabilities capabilities = new NetworkCapabilities();
         capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false);
         capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, !isRoaming);
         capabilities.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
-        return new NetworkState(TYPE_MOBILE, prop, capabilities, MOBILE_NETWORK, subscriberId);
+        return new NetworkStateSnapshot(
+                MOBILE_NETWORK, capabilities, prop, subscriberId, TYPE_MOBILE);
     }
 
     private NetworkStats buildEmptyStats() {
         return new NetworkStats(getElapsedRealtime(), 0);
     }
 
-    private static NetworkState buildVpnState() {
-        final LinkProperties prop = new LinkProperties();
-        prop.setInterfaceName(TUN_IFACE);
-        return new NetworkState(TYPE_VPN, prop, new NetworkCapabilities(), VPN_NETWORK, null);
-    }
-
-    private static NetworkState buildOemManagedMobileState(String subscriberId, boolean isRoaming,
-                int[] oemNetCapabilities) {
+    private static NetworkStateSnapshot buildOemManagedMobileState(
+            String subscriberId, boolean isRoaming, int[] oemNetCapabilities) {
         final LinkProperties prop = new LinkProperties();
         prop.setInterfaceName(TEST_IFACE);
         final NetworkCapabilities capabilities = new NetworkCapabilities();
@@ -1615,7 +1612,8 @@
             capabilities.setCapability(nc, true);
         }
         capabilities.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
-        return new NetworkState(TYPE_MOBILE, prop, capabilities, MOBILE_NETWORK, subscriberId);
+        return new NetworkStateSnapshot(MOBILE_NETWORK, capabilities, prop, subscriberId,
+                TYPE_MOBILE);
     }
 
     private long getElapsedRealtime() {