[automerger skipped] Merge "Fix cannot find removeUnwantedCapability on R device" am: 3ef6584f1b am: f85195ae06 am: b5d62d1f83 -s ours

am skip reason: skip tag Change-Id Icf2cda325795acee22a6c634e8d978f64c5ac3cb with SHA-1 8428118d0f is already in history

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1649302

Change-Id: I74d0e6ea112c4714c09a12f908fb9273c8477584
diff --git a/framework/Android.bp b/framework/Android.bp
index 017ff51..3553c1f 100644
--- a/framework/Android.bp
+++ b/framework/Android.bp
@@ -25,6 +25,7 @@
 
 java_library {
     name: "framework-connectivity-protos",
+    sdk_version: "module_current",
     proto: {
         type: "nano",
     },
@@ -82,8 +83,7 @@
     name: "framework-connectivity",
     api_only: true,
     defaults: ["framework-module-defaults"],
-    // TODO: build against module API
-    platform_apis: true,
+    installable: true,
     srcs: [
         ":framework-connectivity-sources",
     ],
@@ -100,18 +100,58 @@
     libs: [
         "unsupportedappusage",
     ],
-    permitted_packages: ["android.net", "com.android.connectivity.aidl"],
+    permitted_packages: ["android.net"],
+}
+
+cc_defaults {
+    name: "libframework-connectivity-defaults",
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-unused-parameter",
+        "-Wthread-safety",
+    ],
+    shared_libs: [
+        "libbase",
+        "liblog",
+        "libnativehelper",
+        "libnetd_client",
+    ],
+    header_libs: [
+        "dnsproxyd_protocol_headers",
+    ],
+}
+
+cc_library_static {
+    name: "libconnectivityframeworkutils",
+    defaults: ["libframework-connectivity-defaults"],
+    srcs: [
+        "jni/android_net_NetworkUtils.cpp",
+    ],
+    shared_libs: ["libandroid_net"],
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.tethering",
+    ],
+}
+
+cc_library_shared {
+    name: "libframework-connectivity-jni",
+    defaults: ["libframework-connectivity-defaults"],
+    srcs: [
+        "jni/onload.cpp",
+    ],
+    shared_libs: ["libandroid"],
+    static_libs: ["libconnectivityframeworkutils"],
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.tethering",
+    ],
 }
 
 java_library {
     name: "framework-connectivity.impl",
-    // Instead of building against private API (framework.jar),
-    // build against core_platform + framework-minus-apex + module
-    // stub libs. This allows framework.jar to depend on this library,
-    // so it can be part of the private API until all clients have been migrated.
-    // TODO: just build against module_api, and remove this jar from
-    // the private API.
-    sdk_version: "core_platform",
+    sdk_version: "module_current",
     srcs: [
         ":framework-connectivity-sources",
     ],
@@ -122,12 +162,11 @@
         ],
     },
     libs: [
-        "framework-minus-apex",
-        // TODO: just framework-tethering, framework-wifi when building against module_api
-        "framework-tethering.stubs.module_lib",
-        "framework-wifi.stubs.module_lib",
+        // TODO (b/183097033) remove once module_current includes core_current
+        "stable.core.platform.api.stubs",
+        "framework-tethering",
+        "framework-wifi",
         "unsupportedappusage",
-        "ServiceConnectivityResources",
     ],
     static_libs: [
         "framework-connectivity-protos",
@@ -136,5 +175,5 @@
     jarjar_rules: "jarjar-rules.txt",
     apex_available: ["com.android.tethering"],
     installable: true,
-    permitted_packages: ["android.net", "com.android.connectivity.aidl"],
+    permitted_packages: ["android.net"],
 }
diff --git a/framework/api/current.txt b/framework/api/current.txt
index ad44b27..0a9560a 100644
--- a/framework/api/current.txt
+++ b/framework/api/current.txt
@@ -68,6 +68,7 @@
     method public boolean bindProcessToNetwork(@Nullable android.net.Network);
     method @NonNull public android.net.SocketKeepalive createSocketKeepalive(@NonNull android.net.Network, @NonNull android.net.IpSecManager.UdpEncapsulationSocket, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
     method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.Network getActiveNetwork();
+    method @Nullable @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public android.net.Network getActiveNetworkForUid(int);
     method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo getActiveNetworkInfo();
     method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo[] getAllNetworkInfo();
     method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.Network[] getAllNetworks();
@@ -387,7 +388,9 @@
   public class NetworkRequest implements android.os.Parcelable {
     method public boolean canBeSatisfiedBy(@Nullable android.net.NetworkCapabilities);
     method public int describeContents();
+    method @NonNull public int[] getCapabilities();
     method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier();
+    method @NonNull public int[] getTransportTypes();
     method public boolean hasCapability(int);
     method public boolean hasTransport(int);
     method public void writeToParcel(android.os.Parcel, int);
diff --git a/framework/api/module-lib-current.txt b/framework/api/module-lib-current.txt
index 1bb6a12..f7c3965 100644
--- a/framework/api/module-lib-current.txt
+++ b/framework/api/module-lib-current.txt
@@ -14,14 +14,20 @@
     method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void registerDefaultNetworkCallbackAsUid(int, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
     method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void registerSystemDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void requestBackgroundNetwork(@NonNull android.net.NetworkRequest, @NonNull android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback);
+    method @Deprecated public boolean requestRouteToHostAddress(int, java.net.InetAddress);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAcceptPartialConnectivity(@NonNull android.net.Network, boolean, boolean);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAcceptUnvalidated(@NonNull android.net.Network, boolean, boolean);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAvoidUnvalidated(@NonNull android.net.Network);
     method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setGlobalProxy(@Nullable android.net.ProxyInfo);
+    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void setLegacyLockdownVpnEnabled(boolean);
     method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setProfileNetworkPreference(@NonNull android.os.UserHandle, int, @Nullable java.util.concurrent.Executor, @Nullable Runnable);
+    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void setRequireVpnForUids(boolean, @NonNull java.util.Collection<android.util.Range<java.lang.Integer>>);
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_TEST_NETWORKS, android.Manifest.permission.NETWORK_STACK}) public void simulateDataStall(int, long, @NonNull android.net.Network, @NonNull android.os.PersistableBundle);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void startCaptivePortalApp(@NonNull android.net.Network);
     method public void systemReady();
+    field public static final String ACTION_PROMPT_LOST_VALIDATION = "android.net.action.PROMPT_LOST_VALIDATION";
+    field public static final String ACTION_PROMPT_PARTIAL_CONNECTIVITY = "android.net.action.PROMPT_PARTIAL_CONNECTIVITY";
+    field public static final String ACTION_PROMPT_UNVALIDATED = "android.net.action.PROMPT_UNVALIDATED";
     field public static final String PRIVATE_DNS_MODE_OFF = "off";
     field public static final String PRIVATE_DNS_MODE_OPPORTUNISTIC = "opportunistic";
     field public static final String PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = "hostname";
@@ -56,6 +62,7 @@
   }
 
   public class NetworkRequest implements android.os.Parcelable {
+    method @NonNull public int[] getUnwantedCapabilities();
     method public boolean hasUnwantedCapability(int);
   }
 
diff --git a/framework/api/system-current.txt b/framework/api/system-current.txt
index 703fca4..b19efa3 100644
--- a/framework/api/system-current.txt
+++ b/framework/api/system-current.txt
@@ -212,10 +212,12 @@
 
   public abstract class NetworkAgent {
     ctor public NetworkAgent(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String, @NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties, int, @NonNull android.net.NetworkAgentConfig, @Nullable android.net.NetworkProvider);
+    ctor public NetworkAgent(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String, @NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties, @NonNull android.net.NetworkScore, @NonNull android.net.NetworkAgentConfig, @Nullable android.net.NetworkProvider);
     method @Nullable public android.net.Network getNetwork();
     method public void markConnected();
     method public void onAddKeepalivePacketFilter(int, @NonNull android.net.KeepalivePacketData);
     method public void onAutomaticReconnectDisabled();
+    method public void onBandwidthUpdateRequested();
     method public void onNetworkUnwanted();
     method public void onQosCallbackRegistered(int, @NonNull android.net.QosFilter);
     method public void onQosCallbackUnregistered(int);
@@ -233,6 +235,7 @@
     method public final void sendQosSessionAvailable(int, int, @NonNull android.telephony.data.EpsBearerQosSessionAttributes);
     method public final void sendQosSessionLost(int, int);
     method public final void sendSocketKeepaliveEvent(int, int);
+    method @Deprecated public void setLegacySubtype(int, @NonNull String);
     method public final void setUnderlyingNetworks(@Nullable java.util.List<android.net.Network>);
     method public void unregister();
     field public static final int VALIDATION_STATUS_NOT_VALID = 2; // 0x2
@@ -253,7 +256,12 @@
   public static final class NetworkAgentConfig.Builder {
     ctor public NetworkAgentConfig.Builder();
     method @NonNull public android.net.NetworkAgentConfig build();
+    method @NonNull public android.net.NetworkAgentConfig.Builder disableNat64Detection();
+    method @NonNull public android.net.NetworkAgentConfig.Builder disableProvisioningNotification();
     method @NonNull public android.net.NetworkAgentConfig.Builder setExplicitlySelected(boolean);
+    method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyExtraInfo(@NonNull String);
+    method @NonNull public android.net.NetworkAgentConfig.Builder setLegacySubType(int);
+    method @NonNull public android.net.NetworkAgentConfig.Builder setLegacySubTypeName(@NonNull String);
     method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyType(int);
     method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyTypeName(@NonNull String);
     method @NonNull public android.net.NetworkAgentConfig.Builder setPartialConnectivityAcceptable(boolean);
@@ -316,6 +324,19 @@
     method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkRequest.Builder setSignalStrength(int);
   }
 
+  public final class NetworkScore implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getLegacyInt();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkScore> CREATOR;
+  }
+
+  public static final class NetworkScore.Builder {
+    ctor public NetworkScore.Builder();
+    method @NonNull public android.net.NetworkScore build();
+    method @NonNull public android.net.NetworkScore.Builder setLegacyInt(int);
+  }
+
   public final class OemNetworkPreferences implements android.os.Parcelable {
     method public int describeContents();
     method @NonNull public java.util.Map<java.lang.String,java.lang.Integer> getNetworkPreferences();
@@ -388,6 +409,7 @@
   }
 
   public abstract class SocketKeepalive implements java.lang.AutoCloseable {
+    field public static final int ERROR_NO_SUCH_SLOT = -33; // 0xffffffdf
     field public static final int SUCCESS = 0; // 0x0
   }
 
diff --git a/framework/jarjar-rules.txt b/framework/jarjar-rules.txt
index 0959840..7474c24 100644
--- a/framework/jarjar-rules.txt
+++ b/framework/jarjar-rules.txt
@@ -1,4 +1,5 @@
 rule com.android.net.module.util.** android.net.connectivity.framework.util.@1
+rule android.net.NetworkFactory* android.net.connectivity.framework.NetworkFactory@1
 
 # TODO (b/149403767): remove the annotations from net-utils-device-common instead of here
 zap android.annotation.**
diff --git a/core/jni/android_net_NetworkUtils.cpp b/framework/jni/android_net_NetworkUtils.cpp
similarity index 86%
rename from core/jni/android_net_NetworkUtils.cpp
rename to framework/jni/android_net_NetworkUtils.cpp
index a781a37..c7c0bee 100644
--- a/core/jni/android_net_NetworkUtils.cpp
+++ b/framework/jni/android_net_NetworkUtils.cpp
@@ -19,6 +19,7 @@
 #include <vector>
 
 #include <android/file_descriptor_jni.h>
+#include <android/multinetwork.h>
 #include <arpa/inet.h>
 #include <linux/filter.h>
 #include <linux/if_arp.h>
@@ -30,13 +31,13 @@
 
 #include <DnsProxydProtocol.h> // NETID_USE_LOCAL_NAMESERVERS
 #include <cutils/properties.h>
+#include <nativehelper/JNIHelp.h>
 #include <nativehelper/JNIPlatformHelp.h>
 #include <nativehelper/ScopedLocalRef.h>
 #include <utils/Log.h>
 #include <utils/misc.h>
 
 #include "NetdClient.h"
-#include "core_jni_helpers.h"
 #include "jni.h"
 
 extern "C" {
@@ -52,6 +53,19 @@
 // FrameworkListener limits the size of commands to 4096 bytes.
 constexpr int MAXCMDSIZE = 4096;
 
+static inline jclass FindClassOrDie(JNIEnv* env, const char* class_name) {
+    jclass clazz = env->FindClass(class_name);
+    LOG_ALWAYS_FATAL_IF(clazz == NULL, "Unable to find class %s", class_name);
+    return clazz;
+}
+
+template <typename T>
+static inline T MakeGlobalRefOrDie(JNIEnv* env, T in) {
+    jobject res = env->NewGlobalRef(in);
+    LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to create global reference.");
+    return static_cast<T>(res);
+}
+
 static void android_net_utils_attachDropAllBPFFilter(JNIEnv *env, jobject clazz, jobject javaFd)
 {
     struct sock_filter filter_code[] = {
@@ -81,14 +95,21 @@
     }
 }
 
-static jboolean android_net_utils_bindProcessToNetwork(JNIEnv *env, jobject thiz, jint netId)
+static jboolean android_net_utils_bindProcessToNetworkHandle(JNIEnv *env, jobject thiz,
+        jlong netHandle)
 {
-    return (jboolean) !setNetworkForProcess(netId);
+    return (jboolean) !android_setprocnetwork(netHandle);
 }
 
-static jint android_net_utils_getBoundNetworkForProcess(JNIEnv *env, jobject thiz)
+static jlong android_net_utils_getBoundNetworkHandleForProcess(JNIEnv *env, jobject thiz)
 {
-    return getNetworkForProcess();
+    net_handle_t network;
+    if (android_getprocnetwork(&network) != 0) {
+        jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
+                "android_getprocnetwork(): %s", strerror(errno));
+        return NETWORK_UNSPECIFIED;
+    }
+    return (jlong) network;
 }
 
 static jboolean android_net_utils_bindProcessToNetworkForHostResolution(JNIEnv *env, jobject thiz,
@@ -242,8 +263,8 @@
 // clang-format off
 static const JNINativeMethod gNetworkUtilMethods[] = {
     /* name, signature, funcPtr */
-    { "bindProcessToNetwork", "(I)Z", (void*) android_net_utils_bindProcessToNetwork },
-    { "getBoundNetworkForProcess", "()I", (void*) android_net_utils_getBoundNetworkForProcess },
+    { "bindProcessToNetworkHandle", "(J)Z", (void*) android_net_utils_bindProcessToNetworkHandle },
+    { "getBoundNetworkHandleForProcess", "()J", (void*) android_net_utils_getBoundNetworkHandleForProcess },
     { "bindProcessToNetworkForHostResolution", "(I)Z", (void*) android_net_utils_bindProcessToNetworkForHostResolution },
     { "bindSocketToNetwork", "(Ljava/io/FileDescriptor;I)I", (void*) android_net_utils_bindSocketToNetwork },
     { "queryUserAccess", "(II)Z", (void*)android_net_utils_queryUserAccess },
@@ -260,8 +281,8 @@
 
 int register_android_net_NetworkUtils(JNIEnv* env)
 {
-    return RegisterMethodsOrDie(env, NETUTILS_PKG_NAME, gNetworkUtilMethods,
-                                NELEM(gNetworkUtilMethods));
+    return jniRegisterNativeMethods(env, NETUTILS_PKG_NAME, gNetworkUtilMethods,
+                                    NELEM(gNetworkUtilMethods));
 }
 
 }; // namespace android
diff --git a/framework/jni/onload.cpp b/framework/jni/onload.cpp
new file mode 100644
index 0000000..435f434
--- /dev/null
+++ b/framework/jni/onload.cpp
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+#include <nativehelper/JNIHelp.h>
+#include <log/log.h>
+
+namespace android {
+
+int register_android_net_NetworkUtils(JNIEnv* env);
+
+extern "C" jint JNI_OnLoad(JavaVM* vm, void*) {
+    JNIEnv *env;
+    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+        ALOGE("GetEnv failed");
+        return JNI_ERR;
+    }
+
+    if (register_android_net_NetworkUtils(env) < 0) {
+        return JNI_ERR;
+    }
+
+    return JNI_VERSION_1_6;
+}
+
+};
\ No newline at end of file
diff --git a/framework/src/android/net/CaptivePortalData.java b/framework/src/android/net/CaptivePortalData.java
index 82dbd0f..53aa1b9 100644
--- a/framework/src/android/net/CaptivePortalData.java
+++ b/framework/src/android/net/CaptivePortalData.java
@@ -42,7 +42,7 @@
     private final long mByteLimit;
     private final long mExpiryTimeMillis;
     private final boolean mCaptive;
-    private final CharSequence mVenueFriendlyName;
+    private final String mVenueFriendlyName;
     private final int mVenueInfoUrlSource;
     private final int mUserPortalUrlSource;
 
@@ -73,14 +73,14 @@
         mByteLimit = byteLimit;
         mExpiryTimeMillis = expiryTimeMillis;
         mCaptive = captive;
-        mVenueFriendlyName = venueFriendlyName;
+        mVenueFriendlyName = venueFriendlyName == null ? null : venueFriendlyName.toString();
         mVenueInfoUrlSource = venueInfoUrlSource;
         mUserPortalUrlSource = userPortalUrlSource;
     }
 
     private CaptivePortalData(Parcel p) {
         this(p.readLong(), p.readParcelable(null), p.readParcelable(null), p.readBoolean(),
-                p.readLong(), p.readLong(), p.readBoolean(), p.readCharSequence(), p.readInt(),
+                p.readLong(), p.readLong(), p.readBoolean(), p.readString(), p.readInt(),
                 p.readInt());
     }
 
@@ -98,7 +98,7 @@
         dest.writeLong(mByteLimit);
         dest.writeLong(mExpiryTimeMillis);
         dest.writeBoolean(mCaptive);
-        dest.writeCharSequence(mVenueFriendlyName);
+        dest.writeString(mVenueFriendlyName);
         dest.writeInt(mVenueInfoUrlSource);
         dest.writeInt(mUserPortalUrlSource);
     }
diff --git a/framework/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java
index b3e2286..20ff93f 100644
--- a/framework/src/android/net/ConnectivityManager.java
+++ b/framework/src/android/net/ConnectivityManager.java
@@ -423,7 +423,8 @@
      *
      * @hide
      */
-    public static final String ACTION_PROMPT_UNVALIDATED = "android.net.conn.PROMPT_UNVALIDATED";
+    @SystemApi(client = MODULE_LIBRARIES)
+    public static final String ACTION_PROMPT_UNVALIDATED = "android.net.action.PROMPT_UNVALIDATED";
 
     /**
      * Action used to display a dialog that asks the user whether to avoid a network that is no
@@ -431,8 +432,9 @@
      *
      * @hide
      */
+    @SystemApi(client = MODULE_LIBRARIES)
     public static final String ACTION_PROMPT_LOST_VALIDATION =
-            "android.net.conn.PROMPT_LOST_VALIDATION";
+            "android.net.action.PROMPT_LOST_VALIDATION";
 
     /**
      * Action used to display a dialog that asks the user whether to stay connected to a network
@@ -441,8 +443,9 @@
      *
      * @hide
      */
+    @SystemApi(client = MODULE_LIBRARIES)
     public static final String ACTION_PROMPT_PARTIAL_CONNECTIVITY =
-            "android.net.conn.PROMPT_PARTIAL_CONNECTIVITY";
+            "android.net.action.PROMPT_PARTIAL_CONNECTIVITY";
 
     /**
      * Invalid tethering type.
@@ -1080,8 +1083,7 @@
      *
      * @return a {@link Network} object for the current default network for the
      *         given UID or {@code null} if no default network is currently active
-     *
-     * @hide
+     * TODO: b/183465229 Cleanup getActiveNetworkForUid once b/165835257 is fixed
      */
     @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
     @Nullable
@@ -1122,12 +1124,13 @@
      * @param ranges the UID ranges to restrict
      * @param requireVpn whether the specified UID ranges must use a VPN
      *
-     * TODO: expose as @SystemApi.
      * @hide
      */
     @RequiresPermission(anyOf = {
             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
-            android.Manifest.permission.NETWORK_STACK})
+            android.Manifest.permission.NETWORK_STACK,
+            android.Manifest.permission.NETWORK_SETTINGS})
+    @SystemApi(client = MODULE_LIBRARIES)
     public void setRequireVpnForUids(boolean requireVpn,
             @NonNull Collection<Range<Integer>> ranges) {
         Objects.requireNonNull(ranges);
@@ -1171,13 +1174,13 @@
      *
      * @param enabled whether legacy lockdown VPN is enabled or disabled
      *
-     * TODO: @SystemApi(client = MODULE_LIBRARIES)
-     *
      * @hide
      */
     @RequiresPermission(anyOf = {
             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+            android.Manifest.permission.NETWORK_STACK,
             android.Manifest.permission.NETWORK_SETTINGS})
+    @SystemApi(client = MODULE_LIBRARIES)
     public void setLegacyLockdownVpnEnabled(boolean enabled) {
         try {
             mService.setLegacyLockdownVpnEnabled(enabled);
@@ -2124,6 +2127,7 @@
      */
     @Deprecated
     @UnsupportedAppUsage
+    @SystemApi(client = MODULE_LIBRARIES)
     public boolean requestRouteToHostAddress(int networkType, InetAddress hostAddress) {
         checkLegacyRoutingApiAccess();
         try {
@@ -2319,7 +2323,7 @@
             @NonNull String callingPackage, @Nullable String callingAttributionTag,
             boolean throwException) {
         return Settings.checkAndNoteWriteSettingsOperation(context, uid, callingPackage,
-                throwException);
+                callingAttributionTag, throwException);
     }
 
     /**
diff --git a/framework/src/android/net/Network.java b/framework/src/android/net/Network.java
index 0741414..41fad63 100644
--- a/framework/src/android/net/Network.java
+++ b/framework/src/android/net/Network.java
@@ -27,7 +27,6 @@
 import android.system.ErrnoException;
 import android.system.Os;
 import android.system.OsConstants;
-import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.GuardedBy;
 
@@ -526,11 +525,4 @@
     public String toString() {
         return Integer.toString(netId);
     }
-
-    /** @hide */
-    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
-        final long token = proto.start(fieldId);
-        proto.write(NetworkProto.NET_ID, netId);
-        proto.end(token);
-    }
 }
diff --git a/framework/src/android/net/NetworkAgent.java b/framework/src/android/net/NetworkAgent.java
index 3863ed1..b3d9616 100644
--- a/framework/src/android/net/NetworkAgent.java
+++ b/framework/src/android/net/NetworkAgent.java
@@ -362,9 +362,8 @@
     public static final int CMD_UNREGISTER_QOS_CALLBACK = BASE + 21;
 
     private static NetworkInfo getLegacyNetworkInfo(final NetworkAgentConfig config) {
-        // The subtype can be changed with (TODO) setLegacySubtype, but it starts
-        // with 0 (TelephonyManager.NETWORK_TYPE_UNKNOWN) and an empty description.
-        final NetworkInfo ni = new NetworkInfo(config.legacyType, 0, config.legacyTypeName, "");
+        final NetworkInfo ni = new NetworkInfo(config.legacyType, config.legacySubType,
+                config.legacyTypeName, config.legacySubTypeName);
         ni.setIsAvailable(true);
         ni.setDetailedState(NetworkInfo.DetailedState.CONNECTING, null /* reason */,
                 config.getLegacyExtraInfo());
@@ -390,7 +389,6 @@
      * @param score the initial score of this network. Update with sendNetworkScore.
      * @param config an immutable {@link NetworkAgentConfig} for this agent.
      * @param provider the {@link NetworkProvider} managing this agent.
-     * @hide TODO : unhide when impl is complete
      */
     public NetworkAgent(@NonNull Context context, @NonNull Looper looper, @NonNull String logTag,
             @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp,
@@ -829,6 +827,7 @@
      * @hide
      */
     @Deprecated
+    @SystemApi
     public void setLegacySubtype(final int legacySubtype, @NonNull final String legacySubtypeName) {
         mNetworkInfo.setSubtype(legacySubtype, legacySubtypeName);
         queueOrSendNetworkInfo(mNetworkInfo);
@@ -962,6 +961,7 @@
      * shall try to overwrite this method and produce a bandwidth update if capable.
      * @hide
      */
+    @SystemApi
     public void onBandwidthUpdateRequested() {
         pollLceData();
     }
diff --git a/framework/src/android/net/NetworkAgentConfig.java b/framework/src/android/net/NetworkAgentConfig.java
index 0bd2371..3f058d8 100644
--- a/framework/src/android/net/NetworkAgentConfig.java
+++ b/framework/src/android/net/NetworkAgentConfig.java
@@ -175,6 +175,12 @@
     }
 
     /**
+     * The legacy Sub type of this network agent, or TYPE_NONE if unset.
+     * @hide
+     */
+    public int legacySubType = ConnectivityManager.TYPE_NONE;
+
+    /**
      * Set to true if the PRIVATE_DNS_BROKEN notification has shown for this network.
      * Reset this bit when private DNS mode is changed from strict mode to opportunistic/off mode.
      *
@@ -200,6 +206,13 @@
     }
 
     /**
+     * The name of the legacy Sub network type. It's a free-form string.
+     * @hide
+     */
+    @NonNull
+    public String legacySubTypeName = "";
+
+    /**
      * The legacy extra info of the agent. The extra info should only be :
      * <ul>
      *   <li>For cellular agents, the APN name.</li>
@@ -235,6 +248,8 @@
             skip464xlat = nac.skip464xlat;
             legacyType = nac.legacyType;
             legacyTypeName = nac.legacyTypeName;
+            legacySubType = nac.legacySubType;
+            legacySubTypeName = nac.legacySubTypeName;
             mLegacyExtraInfo = nac.mLegacyExtraInfo;
         }
     }
@@ -300,7 +315,6 @@
          * and reduce idle traffic on networks that are known to be IPv6-only without a NAT64.
          *
          * @return this builder, to facilitate chaining.
-         * @hide
          */
         @NonNull
         public Builder disableNat64Detection() {
@@ -313,7 +327,6 @@
          * perform its own carrier-specific provisioning procedure.
          *
          * @return this builder, to facilitate chaining.
-         * @hide
          */
         @NonNull
         public Builder disableProvisioningNotification() {
@@ -334,6 +347,18 @@
         }
 
         /**
+         * Sets the legacy sub-type for this network.
+         *
+         * @param legacySubType the type
+         * @return this builder, to facilitate chaining.
+         */
+        @NonNull
+        public Builder setLegacySubType(final int legacySubType) {
+            mConfig.legacySubType = legacySubType;
+            return this;
+        }
+
+        /**
          * Sets the name of the legacy type of the agent. It's a free-form string used in logging.
          * @param legacyTypeName the name
          * @return this builder, to facilitate chaining.
@@ -345,10 +370,20 @@
         }
 
         /**
+         * Sets the name of the legacy Sub-type of the agent. It's a free-form string.
+         * @param legacySubTypeName the name
+         * @return this builder, to facilitate chaining.
+         */
+        @NonNull
+        public Builder setLegacySubTypeName(@NonNull String legacySubTypeName) {
+            mConfig.legacySubTypeName = legacySubTypeName;
+            return this;
+        }
+
+        /**
          * Sets the legacy extra info of the agent.
          * @param legacyExtraInfo the legacy extra info.
          * @return this builder, to facilitate chaining.
-         * @hide
          */
         @NonNull
         public Builder setLegacyExtraInfo(@NonNull String legacyExtraInfo) {
@@ -435,6 +470,8 @@
         out.writeInt(skip464xlat ? 1 : 0);
         out.writeInt(legacyType);
         out.writeString(legacyTypeName);
+        out.writeInt(legacySubType);
+        out.writeString(legacySubTypeName);
         out.writeString(mLegacyExtraInfo);
     }
 
@@ -452,6 +489,8 @@
             networkAgentConfig.skip464xlat = in.readInt() != 0;
             networkAgentConfig.legacyType = in.readInt();
             networkAgentConfig.legacyTypeName = in.readString();
+            networkAgentConfig.legacySubType = in.readInt();
+            networkAgentConfig.legacySubTypeName = in.readString();
             networkAgentConfig.mLegacyExtraInfo = in.readString();
             return networkAgentConfig;
         }
diff --git a/framework/src/android/net/NetworkCapabilities.java b/framework/src/android/net/NetworkCapabilities.java
index 881fa8c..27f7ee2 100644
--- a/framework/src/android/net/NetworkCapabilities.java
+++ b/framework/src/android/net/NetworkCapabilities.java
@@ -35,7 +35,6 @@
 import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.Range;
-import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.net.module.util.CollectionUtils;
@@ -538,43 +537,6 @@
             | (1 << NET_CAPABILITY_NOT_VPN);
 
     /**
-     * Capabilities that suggest that a network is restricted.
-     * {@see #maybeMarkCapabilitiesRestricted}, {@see #FORCE_RESTRICTED_CAPABILITIES}
-     */
-    @VisibleForTesting
-    /* package */ static final long RESTRICTED_CAPABILITIES =
-            (1 << NET_CAPABILITY_CBS)
-            | (1 << NET_CAPABILITY_DUN)
-            | (1 << NET_CAPABILITY_EIMS)
-            | (1 << NET_CAPABILITY_FOTA)
-            | (1 << NET_CAPABILITY_IA)
-            | (1 << NET_CAPABILITY_IMS)
-            | (1 << NET_CAPABILITY_MCX)
-            | (1 << NET_CAPABILITY_RCS)
-            | (1 << NET_CAPABILITY_VEHICLE_INTERNAL)
-            | (1 << NET_CAPABILITY_XCAP)
-            | (1 << NET_CAPABILITY_ENTERPRISE);
-
-    /**
-     * Capabilities that force network to be restricted.
-     * {@see #maybeMarkCapabilitiesRestricted}.
-     */
-    private static final long FORCE_RESTRICTED_CAPABILITIES =
-            (1 << NET_CAPABILITY_OEM_PAID)
-            | (1 << NET_CAPABILITY_OEM_PRIVATE);
-
-    /**
-     * Capabilities that suggest that a network is unrestricted.
-     * {@see #maybeMarkCapabilitiesRestricted}.
-     */
-    @VisibleForTesting
-    /* package */ static final long UNRESTRICTED_CAPABILITIES =
-            (1 << NET_CAPABILITY_INTERNET)
-            | (1 << NET_CAPABILITY_MMS)
-            | (1 << NET_CAPABILITY_SUPL)
-            | (1 << NET_CAPABILITY_WIFI_P2P);
-
-    /**
      * Capabilities that are managed by ConnectivityService.
      */
     private static final long CONNECTIVITY_MANAGED_CAPABILITIES =
@@ -811,37 +773,12 @@
     }
 
     /**
-     * Deduces that all the capabilities it provides are typically provided by restricted networks
-     * or not.
-     *
-     * @return {@code true} if the network should be restricted.
-     * @hide
-     */
-    public boolean deduceRestrictedCapability() {
-        // Check if we have any capability that forces the network to be restricted.
-        final boolean forceRestrictedCapability =
-                (mNetworkCapabilities & FORCE_RESTRICTED_CAPABILITIES) != 0;
-
-        // Verify there aren't any unrestricted capabilities.  If there are we say
-        // the whole thing is unrestricted unless it is forced to be restricted.
-        final boolean hasUnrestrictedCapabilities =
-                (mNetworkCapabilities & UNRESTRICTED_CAPABILITIES) != 0;
-
-        // Must have at least some restricted capabilities.
-        final boolean hasRestrictedCapabilities =
-                (mNetworkCapabilities & RESTRICTED_CAPABILITIES) != 0;
-
-        return forceRestrictedCapability
-                || (hasRestrictedCapabilities && !hasUnrestrictedCapabilities);
-    }
-
-    /**
-     * Removes the NET_CAPABILITY_NOT_RESTRICTED capability if deducing the network is restricted.
+     * Removes the NET_CAPABILITY_NOT_RESTRICTED capability if inferring the network is restricted.
      *
      * @hide
      */
     public void maybeMarkCapabilitiesRestricted() {
-        if (deduceRestrictedCapability()) {
+        if (NetworkCapabilitiesUtils.inferRestrictedCapability(this)) {
             removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
         }
     }
@@ -2087,34 +2024,6 @@
         }
     }
 
-    /** @hide */
-    public void dumpDebug(@NonNull ProtoOutputStream proto, long fieldId) {
-        final long token = proto.start(fieldId);
-
-        for (int transport : getTransportTypes()) {
-            proto.write(NetworkCapabilitiesProto.TRANSPORTS, transport);
-        }
-
-        for (int capability : getCapabilities()) {
-            proto.write(NetworkCapabilitiesProto.CAPABILITIES, capability);
-        }
-
-        proto.write(NetworkCapabilitiesProto.LINK_UP_BANDWIDTH_KBPS, mLinkUpBandwidthKbps);
-        proto.write(NetworkCapabilitiesProto.LINK_DOWN_BANDWIDTH_KBPS, mLinkDownBandwidthKbps);
-
-        if (mNetworkSpecifier != null) {
-            proto.write(NetworkCapabilitiesProto.NETWORK_SPECIFIER, mNetworkSpecifier.toString());
-        }
-        if (mTransportInfo != null) {
-            // TODO b/120653863: write transport-specific info to proto?
-        }
-
-        proto.write(NetworkCapabilitiesProto.CAN_REPORT_SIGNAL_STRENGTH, hasSignalStrength());
-        proto.write(NetworkCapabilitiesProto.SIGNAL_STRENGTH, mSignalStrength);
-
-        proto.end(token);
-    }
-
     /**
      * @hide
      */
diff --git a/framework/src/android/net/NetworkRequest.java b/framework/src/android/net/NetworkRequest.java
index bcbc04f7..5313f08 100644
--- a/framework/src/android/net/NetworkRequest.java
+++ b/framework/src/android/net/NetworkRequest.java
@@ -47,7 +47,6 @@
 import android.os.Process;
 import android.text.TextUtils;
 import android.util.Range;
-import android.util.proto.ProtoOutputStream;
 
 import java.util.Arrays;
 import java.util.List;
@@ -675,18 +674,6 @@
         }
     }
 
-    /** @hide */
-    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
-        final long token = proto.start(fieldId);
-
-        proto.write(NetworkRequestProto.TYPE, typeToProtoEnum(type));
-        proto.write(NetworkRequestProto.REQUEST_ID, requestId);
-        proto.write(NetworkRequestProto.LEGACY_TYPE, legacyType);
-        networkCapabilities.dumpDebug(proto, NetworkRequestProto.NETWORK_CAPABILITIES);
-
-        proto.end(token);
-    }
-
     public boolean equals(@Nullable Object obj) {
         if (obj instanceof NetworkRequest == false) return false;
         NetworkRequest that = (NetworkRequest)obj;
@@ -699,4 +686,43 @@
     public int hashCode() {
         return Objects.hash(requestId, legacyType, networkCapabilities, type);
     }
+
+    /**
+     * Gets all the capabilities set on this {@code NetworkRequest} instance.
+     *
+     * @return an array of capability values for this instance.
+     */
+    @NonNull
+    public @NetCapability int[] getCapabilities() {
+        // No need to make a defensive copy here as NC#getCapabilities() already returns
+        // a new array.
+        return networkCapabilities.getCapabilities();
+    }
+
+    /**
+     * Gets all the unwanted capabilities set on this {@code NetworkRequest} instance.
+     *
+     * @return an array of unwanted capability values for this instance.
+     *
+     * @hide
+     */
+    @NonNull
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public @NetCapability int[] getUnwantedCapabilities() {
+        // No need to make a defensive copy here as NC#getUnwantedCapabilities() already returns
+        // a new array.
+        return networkCapabilities.getUnwantedCapabilities();
+    }
+
+    /**
+     * Gets all the transports set on this {@code NetworkRequest} instance.
+     *
+     * @return an array of transport type values for this instance.
+     */
+    @NonNull
+    public @Transport int[] getTransportTypes() {
+        // No need to make a defensive copy here as NC#getTransportTypes() already returns
+        // a new array.
+        return networkCapabilities.getTransportTypes();
+    }
 }
diff --git a/framework/src/android/net/NetworkScore.java b/framework/src/android/net/NetworkScore.java
index eadcb2d..6584993 100644
--- a/framework/src/android/net/NetworkScore.java
+++ b/framework/src/android/net/NetworkScore.java
@@ -17,6 +17,7 @@
 package android.net;
 
 import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -29,7 +30,7 @@
  * network is considered for a particular use.
  * @hide
  */
-// TODO : @SystemApi when the implementation is complete
+@SystemApi
 public final class NetworkScore implements Parcelable {
     // This will be removed soon. Do *NOT* depend on it for any new code that is not part of
     // a migration.
@@ -62,6 +63,8 @@
 
     /**
      * @return whether this score has a particular policy.
+     *
+     * @hide
      */
     @VisibleForTesting
     public boolean hasPolicy(final int policy) {
diff --git a/framework/src/android/net/NetworkUtils.java b/framework/src/android/net/NetworkUtils.java
index c4bebc0..16ae55f 100644
--- a/framework/src/android/net/NetworkUtils.java
+++ b/framework/src/android/net/NetworkUtils.java
@@ -16,6 +16,8 @@
 
 package android.net;
 
+import static android.net.ConnectivityManager.NETID_UNSET;
+
 import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.system.ErrnoException;
@@ -55,6 +57,8 @@
      */
     public static native void detachBPFFilter(FileDescriptor fd) throws SocketException;
 
+    private static native boolean bindProcessToNetworkHandle(long netHandle);
+
     /**
      * Binds the current process to the network designated by {@code netId}.  All sockets created
      * in the future (and not explicitly bound via a bound {@link SocketFactory} (see
@@ -63,13 +67,20 @@
      * is by design so an application doesn't accidentally use sockets it thinks are still bound to
      * a particular {@code Network}.  Passing NETID_UNSET clears the binding.
      */
-    public native static boolean bindProcessToNetwork(int netId);
+    public static boolean bindProcessToNetwork(int netId) {
+        return bindProcessToNetworkHandle(new Network(netId).getNetworkHandle());
+    }
+
+    private static native long getBoundNetworkHandleForProcess();
 
     /**
      * Return the netId last passed to {@link #bindProcessToNetwork}, or NETID_UNSET if
      * {@link #unbindProcessToNetwork} has been called since {@link #bindProcessToNetwork}.
      */
-    public native static int getBoundNetworkForProcess();
+    public static int getBoundNetworkForProcess() {
+        final long netHandle = getBoundNetworkHandleForProcess();
+        return netHandle == 0L ? NETID_UNSET : Network.fromNetworkHandle(netHandle).getNetId();
+    }
 
     /**
      * Binds host resolutions performed by this process to the network designated by {@code netId}.
diff --git a/framework/src/android/net/SocketKeepalive.java b/framework/src/android/net/SocketKeepalive.java
index d007a95..f6cae72 100644
--- a/framework/src/android/net/SocketKeepalive.java
+++ b/framework/src/android/net/SocketKeepalive.java
@@ -55,36 +55,68 @@
     static final String TAG = "SocketKeepalive";
 
     /**
-     * No errors.
+     * Success. It indicates there is no error.
      * @hide
      */
     @SystemApi
     public static final int SUCCESS = 0;
 
-    /** @hide */
+    /**
+     * No keepalive. This should only be internally as it indicates There is no keepalive.
+     * It should not propagate to applications.
+     * @hide
+     */
     public static final int NO_KEEPALIVE = -1;
 
-    /** @hide */
+    /**
+     * Data received.
+     * @hide
+     */
     public static final int DATA_RECEIVED = -2;
 
-    /** @hide */
+    /**
+     * The binder died.
+     * @hide
+     */
     public static final int BINDER_DIED = -10;
 
-    /** The specified {@code Network} is not connected. */
+    /**
+     * The invalid network. It indicates the specified {@code Network} is not connected.
+     */
     public static final int ERROR_INVALID_NETWORK = -20;
-    /** The specified IP addresses are invalid. For example, the specified source IP address is
-     * not configured on the specified {@code Network}. */
+
+    /**
+     * The invalid IP addresses. Indicates the specified IP addresses are invalid.
+     * For example, the specified source IP address is not configured on the
+     * specified {@code Network}.
+     */
     public static final int ERROR_INVALID_IP_ADDRESS = -21;
-    /** The requested port is invalid. */
+
+    /**
+     * The port is invalid.
+     */
     public static final int ERROR_INVALID_PORT = -22;
-    /** The packet length is invalid (e.g., too long). */
+
+    /**
+     * The length is invalid (e.g. too long).
+     */
     public static final int ERROR_INVALID_LENGTH = -23;
-    /** The packet transmission interval is invalid (e.g., too short). */
+
+    /**
+     * The interval is invalid (e.g. too short).
+     */
     public static final int ERROR_INVALID_INTERVAL = -24;
-    /** The target socket is invalid. */
+
+    /**
+     * The socket is invalid.
+     */
     public static final int ERROR_INVALID_SOCKET = -25;
-    /** The target socket is not idle. */
+
+    /**
+     * The socket is not idle.
+     */
     public static final int ERROR_SOCKET_NOT_IDLE = -26;
+
     /**
      * The stop reason is uninitialized. This should only be internally used as initial state
      * of stop reason, instead of propagating to application.
@@ -92,15 +124,29 @@
      */
     public static final int ERROR_STOP_REASON_UNINITIALIZED = -27;
 
-    /** The device does not support this request. */
+    /**
+     * The request is unsupported.
+     */
     public static final int ERROR_UNSUPPORTED = -30;
-    /** @hide TODO: delete when telephony code has been updated. */
-    public static final int ERROR_HARDWARE_UNSUPPORTED = ERROR_UNSUPPORTED;
-    /** The hardware returned an error. */
+
+    /**
+     * There was a hardware error.
+     */
     public static final int ERROR_HARDWARE_ERROR = -31;
-    /** The limitation of resource is reached. */
+
+    /**
+     * Resources are insufficient (e.g. all hardware slots are in use).
+     */
     public static final int ERROR_INSUFFICIENT_RESOURCES = -32;
 
+    /**
+     * There was no such slot. This should only be internally as it indicates
+     * a programming error in the system server. It should not propagate to
+     * applications.
+     * @hide
+     */
+    @SystemApi
+    public static final int ERROR_NO_SUCH_SLOT = -33;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
@@ -111,7 +157,8 @@
             ERROR_INVALID_LENGTH,
             ERROR_INVALID_INTERVAL,
             ERROR_INVALID_SOCKET,
-            ERROR_SOCKET_NOT_IDLE
+            ERROR_SOCKET_NOT_IDLE,
+            ERROR_NO_SUCH_SLOT
     })
     public @interface ErrorCode {}
 
@@ -122,7 +169,6 @@
             ERROR_INVALID_LENGTH,
             ERROR_UNSUPPORTED,
             ERROR_INSUFFICIENT_RESOURCES,
-            ERROR_HARDWARE_UNSUPPORTED
     })
     public @interface KeepaliveEvent {}
 
diff --git a/service/Android.bp b/service/Android.bp
index 1330e71..37dd9ff 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -51,22 +51,33 @@
 
 java_library {
     name: "service-connectivity-pre-jarjar",
+    sdk_version: "system_server_current",
     srcs: [
-        ":framework-connectivity-shared-srcs",
         ":connectivity-service-srcs",
+        ":framework-connectivity-shared-srcs",
+        ":services-connectivity-shared-srcs",
+        // TODO: move to net-utils-device-common, enable shrink optimization to avoid extra classes
+        ":net-module-utils-srcs",
     ],
     libs: [
-        "android.net.ipsec.ike",
-        "services.core",
-        "services.net",
+        // TODO (b/183097033) remove once system_server_current includes core_current
+        "stable.core.platform.api.stubs",
+        "android_system_server_stubs_current",
+        "framework-annotations-lib",
+        "framework-connectivity.impl",
+        "framework-tethering.stubs.module_lib",
+        "framework-wifi.stubs.module_lib",
         "unsupportedappusage",
         "ServiceConnectivityResources",
     ],
     static_libs: [
+        "dnsresolver_aidl_interface-V7-java",
         "modules-utils-os",
         "net-utils-device-common",
         "net-utils-framework-common",
         "netd-client",
+        "netlink-client",
+        "networkstack-client",
         "PlatformProperties",
         "service-connectivity-protos",
     ],
@@ -78,6 +89,7 @@
 
 java_library {
     name: "service-connectivity-protos",
+    sdk_version: "system_current",
     proto: {
         type: "nano",
     },
@@ -93,6 +105,7 @@
 
 java_library {
     name: "service-connectivity",
+    sdk_version: "system_server_current",
     installable: true,
     static_libs: [
         "service-connectivity-pre-jarjar",
diff --git a/service/ServiceConnectivityResources/res/values/config.xml b/service/ServiceConnectivityResources/res/values/config.xml
index 71674e4..9ff2a22 100644
--- a/service/ServiceConnectivityResources/res/values/config.xml
+++ b/service/ServiceConnectivityResources/res/values/config.xml
@@ -78,6 +78,11 @@
         <item>1,3</item>
     </string-array>
 
+    <!-- Reserved privileged keepalive slots per transport. -->
+    <integer translatable="false" name="config_reservedPrivilegedKeepaliveSlots">2</integer>
+
+    <!-- Allowed unprivileged keepalive slots per uid. -->
+    <integer translatable="false" name="config_allowedUnprivilegedKeepalivePerUid">2</integer>
 
     <!-- Default value for ConnectivityManager.getMultipathPreference() on metered networks. Actual
          device behaviour is controlled by the metered multipath preference in
@@ -89,4 +94,33 @@
          Settings.Global.NETWORK_AVOID_BAD_WIFI. This is the default value of that setting. -->
     <integer translatable="false" name="config_networkAvoidBadWifi">1</integer>
 
+    <!-- Array of ConnectivityManager.TYPE_xxxx constants for networks that may only
+         be controlled by systemOrSignature apps.  -->
+    <integer-array translatable="false" name="config_protectedNetworks">
+        <item>10</item>
+        <item>11</item>
+        <item>12</item>
+        <item>14</item>
+        <item>15</item>
+    </integer-array>
+
+    <!-- Whether the internal vehicle network should remain active even when no
+         apps requested it. -->
+    <bool name="config_vehicleInternalNetworkAlwaysRequested">false</bool>
+
+
+    <!-- If the hardware supports specially marking packets that caused a wakeup of the
+         main CPU, set this value to the mark used. -->
+    <integer name="config_networkWakeupPacketMark">0</integer>
+
+    <!-- Mask to use when checking skb mark defined in config_networkWakeupPacketMark above. -->
+    <integer name="config_networkWakeupPacketMask">0</integer>
+
+    <!-- Whether/how to notify the user on network switches. See LingerMonitor.java. -->
+    <integer translatable="false" name="config_networkNotifySwitchType">0</integer>
+
+    <!-- What types of network switches to notify. See LingerMonitor.java. -->
+    <string-array translatable="false" name="config_networkNotifySwitches">
+    </string-array>
+
 </resources>
diff --git a/service/ServiceConnectivityResources/res/values/overlayable.xml b/service/ServiceConnectivityResources/res/values/overlayable.xml
index 25e19ce..717d08e 100644
--- a/service/ServiceConnectivityResources/res/values/overlayable.xml
+++ b/service/ServiceConnectivityResources/res/values/overlayable.xml
@@ -26,6 +26,12 @@
             <item type="integer" name="config_networkMeteredMultipathPreference"/>
             <item type="array" name="config_networkSupportedKeepaliveCount"/>
             <item type="integer" name="config_networkAvoidBadWifi"/>
+            <item type="array" name="config_protectedNetworks"/>
+            <item type="bool" name="config_vehicleInternalNetworkAlwaysRequested"/>
+            <item type="integer" name="config_networkWakeupPacketMark"/>
+            <item type="integer" name="config_networkWakeupPacketMask"/>
+            <item type="integer" name="config_networkNotifySwitchType"/>
+            <item type="array" name="config_networkNotifySwitches"/>
 
         </policy>
     </overlayable>
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index a0bdd7f..63639ed 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -87,7 +87,6 @@
 import static java.util.Map.Entry;
 
 import android.Manifest;
-import android.annotation.BoolRes;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.AppOpsManager;
@@ -146,7 +145,6 @@
 import android.net.NetworkScore;
 import android.net.NetworkSpecifier;
 import android.net.NetworkStack;
-import android.net.NetworkStackClient;
 import android.net.NetworkState;
 import android.net.NetworkStateSnapshot;
 import android.net.NetworkTestResultParcelable;
@@ -173,13 +171,14 @@
 import android.net.metrics.IpConnectivityLog;
 import android.net.metrics.NetworkEvent;
 import android.net.netlink.InetDiagMessage;
+import android.net.networkstack.ModuleNetworkStackClient;
+import android.net.networkstack.NetworkStackClientBase;
 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;
 import android.os.BatteryStatsManager;
 import android.os.Binder;
 import android.os.Build;
@@ -214,6 +213,7 @@
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 
+import com.android.connectivity.resources.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.IndentingPrintWriter;
@@ -820,8 +820,7 @@
 
         private ArrayMap<Integer, Integer> loadRestoreTimers() {
             final String[] configs = mService.mResources.get().getStringArray(
-                    com.android.connectivity.resources.R.array
-                            .config_legacy_networktype_restore_timers);
+                    R.array.config_legacy_networktype_restore_timers);
             final ArrayMap<Integer, Integer> ret = new ArrayMap<>(configs.length);
             for (final String config : configs) {
                 final String[] splits = TextUtils.split(config, ",");
@@ -1122,10 +1121,10 @@
         }
 
         /**
-         * Get a reference to the NetworkStackClient.
+         * Get a reference to the ModuleNetworkStackClient.
          */
-        public NetworkStackClient getNetworkStack() {
-            return NetworkStackClient.getInstance();
+        public NetworkStackClientBase getNetworkStack() {
+            return ModuleNetworkStackClient.getInstance(null);
         }
 
         /**
@@ -1184,7 +1183,8 @@
 
     public ConnectivityService(Context context) {
         this(context, getDnsResolver(context), new IpConnectivityLog(),
-                NetdService.getInstance(), new Dependencies());
+                INetd.Stub.asInterface((IBinder) context.getSystemService(Context.NETD_SERVICE)),
+                new Dependencies());
     }
 
     @VisibleForTesting
@@ -1259,8 +1259,7 @@
 
         mLegacyTypeTracker.loadSupportedTypes(mContext, mTelephonyManager);
         mProtectedNetworks = new ArrayList<>();
-        int[] protectedNetworks = context.getResources().getIntArray(
-                com.android.internal.R.array.config_protectedNetworks);
+        int[] protectedNetworks = mResources.get().getIntArray(R.array.config_protectedNetworks);
         for (int p : protectedNetworks) {
             if (mLegacyTypeTracker.isTypeSupported(p) && !mProtectedNetworks.contains(p)) {
                 mProtectedNetworks.add(p);
@@ -1390,7 +1389,7 @@
         mHandler.sendEmptyMessage(EVENT_PRIVATE_DNS_SETTINGS_CHANGED);
     }
 
-    private void handleAlwaysOnNetworkRequest(NetworkRequest networkRequest, @BoolRes int id) {
+    private void handleAlwaysOnNetworkRequest(NetworkRequest networkRequest, int id) {
         final boolean enable = mContext.getResources().getBoolean(id);
         handleAlwaysOnNetworkRequest(networkRequest, enable);
     }
@@ -1424,8 +1423,14 @@
                 ConnectivitySettingsManager.MOBILE_DATA_ALWAYS_ON, true /* defaultValue */);
         handleAlwaysOnNetworkRequest(mDefaultWifiRequest,
                 ConnectivitySettingsManager.WIFI_ALWAYS_REQUESTED, false /* defaultValue */);
+        final boolean vehicleAlwaysRequested = mResources.get().getBoolean(
+                R.bool.config_vehicleInternalNetworkAlwaysRequested);
+        // TODO (b/183076074): remove legacy fallback after migrating overlays
+        final boolean legacyAlwaysRequested = mContext.getResources().getBoolean(
+                mContext.getResources().getIdentifier(
+                        "config_vehicleInternalNetworkAlwaysRequested", "bool", "android"));
         handleAlwaysOnNetworkRequest(mDefaultVehicleRequest,
-                com.android.internal.R.bool.config_vehicleInternalNetworkAlwaysRequested);
+                vehicleAlwaysRequested || legacyAlwaysRequested);
     }
 
     private void registerSettingsCallbacks() {
@@ -2901,10 +2906,6 @@
         }
 
         pw.println();
-        pw.println("NetworkStackClient logs:");
-        pw.increaseIndent();
-        NetworkStackClient.getInstance().dump(pw);
-        pw.decreaseIndent();
 
         pw.println();
         pw.println("Permission Monitor:");
@@ -4733,7 +4734,7 @@
         mWakelockLogs.log("ACQUIRE for " + forWhom);
         Message msg = mHandler.obtainMessage(EVENT_EXPIRE_NET_TRANSITION_WAKELOCK);
         final int lockTimeout = mResources.get().getInteger(
-                com.android.connectivity.resources.R.integer.config_networkTransitionTimeout);
+                R.integer.config_networkTransitionTimeout);
         mHandler.sendMessageDelayed(msg, lockTimeout);
     }
 
@@ -5086,7 +5087,7 @@
 
     @Override
     public void setRequireVpnForUids(boolean requireVpn, UidRange[] ranges) {
-        PermissionUtils.enforceNetworkStackPermission(mContext);
+        enforceNetworkStackOrSettingsPermission();
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_REQUIRE_VPN_FOR_UIDS,
                 encodeBool(requireVpn), 0 /* arg2 */, ranges));
     }
@@ -5124,7 +5125,7 @@
 
     @Override
     public void setLegacyLockdownVpnEnabled(boolean enabled) {
-        enforceSettingsPermission();
+        enforceNetworkStackOrSettingsPermission();
         mHandler.post(() -> mLockdownEnabled = enabled);
     }
 
@@ -6495,10 +6496,16 @@
             return;
         }
 
-        int mark = mContext.getResources().getInteger(
-            com.android.internal.R.integer.config_networkWakeupPacketMark);
-        int mask = mContext.getResources().getInteger(
-            com.android.internal.R.integer.config_networkWakeupPacketMask);
+        int mark = mResources.get().getInteger(R.integer.config_networkWakeupPacketMark);
+        int mask = mResources.get().getInteger(R.integer.config_networkWakeupPacketMask);
+
+        // TODO (b/183076074): remove legacy fallback after migrating overlays
+        final int legacyMark = mContext.getResources().getInteger(mContext.getResources()
+                .getIdentifier("config_networkWakeupPacketMark", "integer", "android"));
+        final int legacyMask = mContext.getResources().getInteger(mContext.getResources()
+                .getIdentifier("config_networkWakeupPacketMask", "integer", "android"));
+        mark = mark == 0 ? legacyMark : mark;
+        mask = mask == 0 ? legacyMask : mask;
 
         // Mask/mark of zero will not detect anything interesting.
         // Don't install rules unless both values are nonzero.
@@ -6691,8 +6698,7 @@
     private void updateWakeOnLan(@NonNull LinkProperties lp) {
         if (mWolSupportedInterfaces == null) {
             mWolSupportedInterfaces = new ArraySet<>(mResources.get().getStringArray(
-                    com.android.connectivity.resources.R.array
-                            .config_wakeonlan_supported_interfaces));
+                    R.array.config_wakeonlan_supported_interfaces));
         }
         lp.setWakeOnLanSupported(mWolSupportedInterfaces.contains(lp.getInterfaceName()));
     }
@@ -8256,7 +8262,7 @@
     public String getCaptivePortalServerUrl() {
         enforceNetworkStackOrSettingsPermission();
         String settingUrl = mResources.get().getString(
-                com.android.connectivity.resources.R.string.config_networkCaptivePortalServerUrl);
+                R.string.config_networkCaptivePortalServerUrl);
 
         if (!TextUtils.isEmpty(settingUrl)) {
             return settingUrl;
@@ -8433,7 +8439,7 @@
         }
     }
 
-    private @VpnManager.VpnType int getVpnType(@Nullable NetworkAgentInfo vpn) {
+    private int getVpnType(@Nullable NetworkAgentInfo vpn) {
         if (vpn == null) return VpnManager.TYPE_VPN_NONE;
         final TransportInfo ti = vpn.networkCapabilities.getTransportInfo();
         if (!(ti instanceof VpnTransportInfo)) return VpnManager.TYPE_VPN_NONE;
diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java
index f566277..09873f4 100644
--- a/services/core/java/com/android/server/TestNetworkService.java
+++ b/services/core/java/com/android/server/TestNetworkService.java
@@ -35,7 +35,6 @@
 import android.net.RouteInfo;
 import android.net.TestNetworkInterface;
 import android.net.TestNetworkSpecifier;
-import android.net.util.NetdService;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -86,7 +85,9 @@
         mHandler = new Handler(mHandlerThread.getLooper());
 
         mContext = Objects.requireNonNull(context, "missing Context");
-        mNetd = Objects.requireNonNull(NetdService.getInstance(), "could not get netd instance");
+        mNetd = Objects.requireNonNull(
+                INetd.Stub.asInterface((IBinder) context.getSystemService(Context.NETD_SERVICE)),
+                "could not get netd instance");
         mCm = mContext.getSystemService(ConnectivityManager.class);
         mNetworkProvider = new NetworkProvider(mContext, mHandler.getLooper(),
                 TEST_NETWORK_PROVIDER_NAME);
diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
index 7b20ded..acf39f0 100644
--- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
+++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
@@ -26,6 +26,7 @@
 import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS;
 import static android.net.SocketKeepalive.ERROR_INVALID_NETWORK;
 import static android.net.SocketKeepalive.ERROR_INVALID_SOCKET;
+import static android.net.SocketKeepalive.ERROR_NO_SUCH_SLOT;
 import static android.net.SocketKeepalive.ERROR_STOP_REASON_UNINITIALIZED;
 import static android.net.SocketKeepalive.ERROR_UNSUPPORTED;
 import static android.net.SocketKeepalive.MAX_INTERVAL_SEC;
@@ -36,6 +37,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
+import android.net.ConnectivityResources;
 import android.net.ISocketKeepaliveCallback;
 import android.net.InetAddresses;
 import android.net.InvalidPacketException;
@@ -56,7 +58,7 @@
 import android.util.Log;
 import android.util.Pair;
 
-import com.android.internal.R;
+import com.android.connectivity.resources.R;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.net.module.util.HexDump;
 import com.android.net.module.util.IpUtils;
@@ -111,10 +113,19 @@
         mTcpController = new TcpKeepaliveController(handler);
         mContext = context;
         mSupportedKeepalives = KeepaliveUtils.getSupportedKeepalives(mContext);
-        mReservedPrivilegedSlots = mContext.getResources().getInteger(
-                R.integer.config_reservedPrivilegedKeepaliveSlots);
-        mAllowedUnprivilegedSlotsForUid = mContext.getResources().getInteger(
-                R.integer.config_allowedUnprivilegedKeepalivePerUid);
+
+        // TODO (b/183076074): stop reading legacy resources after migrating overlays
+        final int legacyReservedSlots = mContext.getResources().getInteger(
+                mContext.getResources().getIdentifier(
+                        "config_reservedPrivilegedKeepaliveSlots", "integer", "android"));
+        final int legacyAllowedSlots = mContext.getResources().getInteger(
+                mContext.getResources().getIdentifier(
+                        "config_allowedUnprivilegedKeepalivePerUid", "integer", "android"));
+        final ConnectivityResources res = new ConnectivityResources(mContext);
+        mReservedPrivilegedSlots = Math.min(legacyReservedSlots, res.get().getInteger(
+                R.integer.config_reservedPrivilegedKeepaliveSlots));
+        mAllowedUnprivilegedSlotsForUid = Math.min(legacyAllowedSlots, res.get().getInteger(
+                R.integer.config_allowedUnprivilegedKeepalivePerUid));
     }
 
     /**
@@ -518,6 +529,8 @@
             }
         } else if (reason == ERROR_STOP_REASON_UNINITIALIZED) {
             throw new IllegalStateException("Unexpected stop reason: " + reason);
+        } else if (reason == ERROR_NO_SUCH_SLOT) {
+            throw new IllegalStateException("No such slot: " + reason);
         } else {
             notifyErrorCallback(ki.mCallback, reason);
         }
diff --git a/services/core/java/com/android/server/connectivity/LingerMonitor.java b/services/core/java/com/android/server/connectivity/LingerMonitor.java
index adec7ad..032612c 100644
--- a/services/core/java/com/android/server/connectivity/LingerMonitor.java
+++ b/services/core/java/com/android/server/connectivity/LingerMonitor.java
@@ -24,6 +24,8 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.Resources;
+import android.net.ConnectivityResources;
 import android.net.NetworkCapabilities;
 import android.os.SystemClock;
 import android.os.UserHandle;
@@ -34,7 +36,7 @@
 import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
 
-import com.android.internal.R;
+import com.android.connectivity.resources.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.MessageUtils;
 import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
@@ -72,6 +74,7 @@
             new Class[] { LingerMonitor.class }, new String[]{ "NOTIFY_TYPE_" });
 
     private final Context mContext;
+    final Resources mResources;
     private final NetworkNotificationManager mNotifier;
     private final int mDailyLimit;
     private final long mRateLimitMillis;
@@ -89,6 +92,7 @@
     public LingerMonitor(Context context, NetworkNotificationManager notifier,
             int dailyLimit, long rateLimitMillis) {
         mContext = context;
+        mResources = new ConnectivityResources(mContext).get();
         mNotifier = notifier;
         mDailyLimit = dailyLimit;
         mRateLimitMillis = rateLimitMillis;
@@ -128,8 +132,7 @@
     @VisibleForTesting
     public boolean isNotificationEnabled(NetworkAgentInfo fromNai, NetworkAgentInfo toNai) {
         // TODO: Evaluate moving to CarrierConfigManager.
-        String[] notifySwitches =
-                mContext.getResources().getStringArray(R.array.config_networkNotifySwitches);
+        String[] notifySwitches = mResources.getStringArray(R.array.config_networkNotifySwitches);
 
         if (VDBG) {
             Log.d(TAG, "Notify on network switches: " + Arrays.toString(notifySwitches));
@@ -178,8 +181,7 @@
 
     // Notify the user of a network switch using a notification or a toast.
     private void notify(NetworkAgentInfo fromNai, NetworkAgentInfo toNai, boolean forceToast) {
-        int notifyType =
-                mContext.getResources().getInteger(R.integer.config_networkNotifySwitchType);
+        int notifyType = mResources.getInteger(R.integer.config_networkNotifySwitchType);
         if (notifyType == NOTIFY_TYPE_NOTIFICATION && forceToast) {
             notifyType = NOTIFY_TYPE_TOAST;
         }
diff --git a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
index 5e6b9f3..2e51be3 100644
--- a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
+++ b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
@@ -36,7 +36,7 @@
 import android.util.Pair;
 
 import com.android.internal.util.IndentingPrintWriter;
-import com.android.internal.util.TrafficStatsConstants;
+import com.android.net.module.util.NetworkStackConstants;
 
 import libcore.io.IoUtils;
 
@@ -446,7 +446,7 @@
                 int sockType, int protocol, long writeTimeout, long readTimeout, int dstPort)
                 throws ErrnoException, IOException {
             final int oldTag = TrafficStats.getAndSetThreadStatsTag(
-                    TrafficStatsConstants.TAG_SYSTEM_PROBE);
+                    NetworkStackConstants.TAG_SYSTEM_PROBE);
             try {
                 mFileDescriptor = Os.socket(mAddressFamily, sockType, protocol);
             } finally {
@@ -745,7 +745,7 @@
             if (ensureMeasurementNecessary()) return;
 
             // No need to restore the tag, since this thread is only used for this measurement.
-            TrafficStats.getAndSetThreadStatsTag(TrafficStatsConstants.TAG_SYSTEM_PROBE);
+            TrafficStats.getAndSetThreadStatsTag(NetworkStackConstants.TAG_SYSTEM_PROBE);
 
             try (SSLSocket sslSocket = setupSSLSocket()) {
                 sendDoTProbe(sslSocket);
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index 0c0d459..b57ad5d 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -84,7 +84,7 @@
 
     // The context is for the current user (system server)
     private final Context mContext;
-    private final Resources mResources;
+    private final ConnectivityResources mResources;
     private final TelephonyManager mTelephonyManager;
     // The notification manager is created from a context for User.ALL, so notifications
     // will be sent to all users.
@@ -99,7 +99,7 @@
                 (NotificationManager) c.createContextAsUser(UserHandle.ALL, 0 /* flags */)
                         .getSystemService(Context.NOTIFICATION_SERVICE);
         mNotificationTypeMap = new SparseIntArray();
-        mResources = new ConnectivityResources(mContext).get();
+        mResources = new ConnectivityResources(mContext);
     }
 
     @VisibleForTesting
@@ -118,11 +118,11 @@
     }
 
     private String getTransportName(final int transportType) {
-        String[] networkTypes = mResources.getStringArray(R.array.network_switch_type_name);
+        String[] networkTypes = mResources.get().getStringArray(R.array.network_switch_type_name);
         try {
             return networkTypes[transportType];
         } catch (IndexOutOfBoundsException e) {
-            return mResources.getString(R.string.network_switch_type_name_unknown);
+            return mResources.get().getString(R.string.network_switch_type_name_unknown);
         }
     }
 
@@ -197,10 +197,11 @@
                     tag, nameOf(eventId), getTransportName(transportType), name, highPriority));
         }
 
-        final Resources r = mResources;
+        final Resources r = mResources.get();
         final CharSequence title;
         final CharSequence details;
-        Icon icon = Icon.createWithResource(r, getIcon(transportType));
+        Icon icon = Icon.createWithResource(
+                mResources.getResourcesContext(), getIcon(transportType));
         if (notifyType == NotificationType.NO_INTERNET && transportType == TRANSPORT_WIFI) {
             title = r.getString(R.string.wifi_no_internet, name);
             details = r.getString(R.string.wifi_no_internet_detailed);
@@ -355,7 +356,7 @@
     public void showToast(NetworkAgentInfo fromNai, NetworkAgentInfo toNai) {
         String fromTransport = getTransportName(approximateTransportType(fromNai));
         String toTransport = getTransportName(approximateTransportType(toNai));
-        String text = mResources.getString(
+        String text = mResources.get().getString(
                 R.string.network_switch_metered_toast, fromTransport, toTransport);
         Toast.makeText(mContext, text, Toast.LENGTH_LONG).show();
     }
diff --git a/services/core/java/com/android/server/connectivity/OsCompat.java b/services/core/java/com/android/server/connectivity/OsCompat.java
new file mode 100644
index 0000000..57e3dcd
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/OsCompat.java
@@ -0,0 +1,75 @@
+/*
+ * 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 com.android.server.connectivity;
+
+import android.system.ErrnoException;
+import android.system.Os;
+
+import java.io.FileDescriptor;
+
+/**
+ * Compatibility utility for android.system.Os core platform APIs.
+ *
+ * Connectivity has access to such APIs, but they are not part of the module_current stubs yet
+ * (only core_current). Most stable core platform APIs are included manually in the connectivity
+ * build rules, but because Os is also part of the base java SDK that is earlier on the
+ * classpath, the extra core platform APIs are not seen.
+ *
+ * TODO (b/157639992, b/183097033): remove as soon as core_current is part of system_server_current
+ * @hide
+ */
+public class OsCompat {
+    // This value should be correct on all architectures supported by Android, but hardcoding ioctl
+    // numbers should be avoided.
+    /**
+     * @see android.system.OsConstants#TIOCOUTQ
+     */
+    public static final int TIOCOUTQ = 0x5411;
+
+    /**
+     * @see android.system.Os#getsockoptInt(FileDescriptor, int, int)
+     */
+    public static int getsockoptInt(FileDescriptor fd, int level, int option) throws
+            ErrnoException {
+        try {
+            return (int) Os.class.getMethod(
+                    "getsockoptInt", FileDescriptor.class, int.class, int.class)
+                    .invoke(null, fd, level, option);
+        } catch (ReflectiveOperationException e) {
+            if (e.getCause() instanceof ErrnoException) {
+                throw (ErrnoException) e.getCause();
+            }
+            throw new IllegalStateException("Error calling getsockoptInt", e);
+        }
+    }
+
+    /**
+     * @see android.system.Os#ioctlInt(FileDescriptor, int)
+     */
+    public static int ioctlInt(FileDescriptor fd, int cmd) throws
+            ErrnoException {
+        try {
+            return (int) Os.class.getMethod(
+                    "ioctlInt", FileDescriptor.class, int.class).invoke(null, fd, cmd);
+        } catch (ReflectiveOperationException e) {
+            if (e.getCause() instanceof ErrnoException) {
+                throw (ErrnoException) e.getCause();
+            }
+            throw new IllegalStateException("Error calling ioctlInt", e);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java b/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java
index c480594..73f3475 100644
--- a/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java
+++ b/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java
@@ -27,7 +27,8 @@
 import static android.system.OsConstants.IPPROTO_TCP;
 import static android.system.OsConstants.IP_TOS;
 import static android.system.OsConstants.IP_TTL;
-import static android.system.OsConstants.TIOCOUTQ;
+
+import static com.android.server.connectivity.OsCompat.TIOCOUTQ;
 
 import android.annotation.NonNull;
 import android.net.InvalidPacketException;
@@ -175,10 +176,10 @@
             }
             // Query write sequence number from SEND_QUEUE.
             Os.setsockoptInt(fd, IPPROTO_TCP, TCP_REPAIR_QUEUE, TCP_SEND_QUEUE);
-            tcpDetails.seq = Os.getsockoptInt(fd, IPPROTO_TCP, TCP_QUEUE_SEQ);
+            tcpDetails.seq = OsCompat.getsockoptInt(fd, IPPROTO_TCP, TCP_QUEUE_SEQ);
             // Query read sequence number from RECV_QUEUE.
             Os.setsockoptInt(fd, IPPROTO_TCP, TCP_REPAIR_QUEUE, TCP_RECV_QUEUE);
-            tcpDetails.ack = Os.getsockoptInt(fd, IPPROTO_TCP, TCP_QUEUE_SEQ);
+            tcpDetails.ack = OsCompat.getsockoptInt(fd, IPPROTO_TCP, TCP_QUEUE_SEQ);
             // Switch to NO_QUEUE to prevent illegal socket read/write in repair mode.
             Os.setsockoptInt(fd, IPPROTO_TCP, TCP_REPAIR_QUEUE, TCP_NO_QUEUE);
             // Finally, check if socket is still idle. TODO : this check needs to move to
@@ -198,9 +199,9 @@
             tcpDetails.rcvWndScale = trw.rcvWndScale;
             if (tcpDetails.srcAddress.length == 4 /* V4 address length */) {
                 // Query TOS.
-                tcpDetails.tos = Os.getsockoptInt(fd, IPPROTO_IP, IP_TOS);
+                tcpDetails.tos = OsCompat.getsockoptInt(fd, IPPROTO_IP, IP_TOS);
                 // Query TTL.
-                tcpDetails.ttl = Os.getsockoptInt(fd, IPPROTO_IP, IP_TTL);
+                tcpDetails.ttl = OsCompat.getsockoptInt(fd, IPPROTO_IP, IP_TTL);
             }
         } catch (ErrnoException e) {
             Log.e(TAG, "Exception reading TCP state from socket", e);
@@ -305,7 +306,7 @@
 
     private static boolean isReceiveQueueEmpty(FileDescriptor fd)
             throws ErrnoException {
-        final int result = Os.ioctlInt(fd, SIOCINQ);
+        final int result = OsCompat.ioctlInt(fd, SIOCINQ);
         if (result != 0) {
             Log.e(TAG, "Read queue has data");
             return false;
@@ -315,7 +316,7 @@
 
     private static boolean isSendQueueEmpty(FileDescriptor fd)
             throws ErrnoException {
-        final int result = Os.ioctlInt(fd, SIOCOUTQ);
+        final int result = OsCompat.ioctlInt(fd, SIOCOUTQ);
         if (result != 0) {
             Log.e(TAG, "Write queue has data");
             return false;
diff --git a/tests/net/common/java/android/net/NetworkAgentConfigTest.kt b/tests/net/common/java/android/net/NetworkAgentConfigTest.kt
index a4d8353..fd126ad 100644
--- a/tests/net/common/java/android/net/NetworkAgentConfigTest.kt
+++ b/tests/net/common/java/android/net/NetworkAgentConfigTest.kt
@@ -44,7 +44,7 @@
             setPartialConnectivityAcceptable(false)
             setUnvalidatedConnectivityAcceptable(true)
         }.build()
-        assertParcelSane(config, 10)
+        assertParcelSane(config, 12)
     }
 
     @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
index 1f50e31..e7718b5 100644
--- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
@@ -38,14 +38,12 @@
 import static android.net.NetworkCapabilities.REDACT_FOR_ACCESS_FINE_LOCATION;
 import static android.net.NetworkCapabilities.REDACT_FOR_LOCAL_MAC_ADDRESS;
 import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS;
-import static android.net.NetworkCapabilities.RESTRICTED_CAPABILITIES;
 import static android.net.NetworkCapabilities.SIGNAL_STRENGTH_UNSPECIFIED;
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 import static android.net.NetworkCapabilities.TRANSPORT_TEST;
 import static android.net.NetworkCapabilities.TRANSPORT_VPN;
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
-import static android.net.NetworkCapabilities.UNRESTRICTED_CAPABILITIES;
 import static android.os.Process.INVALID_UID;
 
 import static com.android.modules.utils.build.SdkLevel.isAtLeastR;
@@ -103,20 +101,6 @@
 
     @Test
     public void testMaybeMarkCapabilitiesRestricted() {
-        // verify EIMS is restricted
-        assertEquals((1 << NET_CAPABILITY_EIMS) & RESTRICTED_CAPABILITIES,
-                (1 << NET_CAPABILITY_EIMS));
-
-        // verify CBS is also restricted
-        assertEquals((1 << NET_CAPABILITY_CBS) & RESTRICTED_CAPABILITIES,
-                (1 << NET_CAPABILITY_CBS));
-
-        // verify default is not restricted
-        assertEquals((1 << NET_CAPABILITY_INTERNET) & RESTRICTED_CAPABILITIES, 0);
-
-        // just to see
-        assertEquals(RESTRICTED_CAPABILITIES & UNRESTRICTED_CAPABILITIES, 0);
-
         // check that internet does not get restricted
         NetworkCapabilities netCap = new NetworkCapabilities();
         netCap.addCapability(NET_CAPABILITY_INTERNET);
@@ -985,26 +969,6 @@
         assertNotEquals(-50, nc.getSignalStrength());
     }
 
-    @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
-    public void testDeduceRestrictedCapability() {
-        final NetworkCapabilities nc = new NetworkCapabilities();
-        // Default capabilities don't have restricted capability.
-        assertFalse(nc.deduceRestrictedCapability());
-        // If there is a force restricted capability, then the network capabilities is restricted.
-        nc.addCapability(NET_CAPABILITY_OEM_PAID);
-        nc.addCapability(NET_CAPABILITY_INTERNET);
-        assertTrue(nc.deduceRestrictedCapability());
-        // Except for the force restricted capability, if there is any unrestricted capability in
-        // capabilities, then the network capabilities is not restricted.
-        nc.removeCapability(NET_CAPABILITY_OEM_PAID);
-        nc.addCapability(NET_CAPABILITY_CBS);
-        assertFalse(nc.deduceRestrictedCapability());
-        // Except for the force restricted capability, the network capabilities will only be treated
-        // as restricted when there is no any unrestricted capability.
-        nc.removeCapability(NET_CAPABILITY_INTERNET);
-        assertTrue(nc.deduceRestrictedCapability());
-    }
-
     private void assertNoTransport(NetworkCapabilities nc) {
         for (int i = MIN_TRANSPORT; i <= MAX_TRANSPORT; i++) {
             assertFalse(nc.hasTransport(i));
diff --git a/tests/net/integration/src/android/net/TestNetworkStackClient.kt b/tests/net/integration/src/android/net/TestNetworkStackClient.kt
index 01eb514..61ef5bd 100644
--- a/tests/net/integration/src/android/net/TestNetworkStackClient.kt
+++ b/tests/net/integration/src/android/net/TestNetworkStackClient.kt
@@ -19,6 +19,7 @@
 import android.content.ComponentName
 import android.content.Context
 import android.content.Intent
+import android.net.networkstack.NetworkStackClientBase
 import android.os.IBinder
 import com.android.server.net.integrationtests.TestNetworkStackService
 import org.mockito.Mockito.any
@@ -29,28 +30,22 @@
 
 const val TEST_ACTION_SUFFIX = ".Test"
 
-class TestNetworkStackClient(context: Context) : NetworkStackClient(TestDependencies(context)) {
+class TestNetworkStackClient(private val context: Context) : NetworkStackClientBase() {
     // TODO: consider switching to TrackRecord for more expressive checks
     private val lastCallbacks = HashMap<Network, INetworkMonitorCallbacks>()
+    private val moduleConnector = ConnectivityModuleConnector { _, action, _, _ ->
+        val intent = Intent(action)
+        val serviceName = TestNetworkStackService::class.qualifiedName
+                ?: fail("TestNetworkStackService name not found")
+        intent.component = ComponentName(context.packageName, serviceName)
+        return@ConnectivityModuleConnector intent
+    }.also { it.init(context) }
 
-    private class TestDependencies(private val context: Context) : Dependencies {
-        override fun addToServiceManager(service: IBinder) = Unit
-        override fun checkCallerUid() = Unit
-
-        override fun getConnectivityModuleConnector(): ConnectivityModuleConnector {
-            return ConnectivityModuleConnector { _, _, _, inSystemProcess ->
-                getNetworkStackIntent(inSystemProcess)
-            }.also { it.init(context) }
-        }
-
-        private fun getNetworkStackIntent(inSystemProcess: Boolean): Intent? {
-            // Simulate out-of-system-process config: in-process service not found (null intent)
-            if (inSystemProcess) return null
-            val intent = Intent(INetworkStackConnector::class.qualifiedName + TEST_ACTION_SUFFIX)
-            val serviceName = TestNetworkStackService::class.qualifiedName
-                    ?: fail("TestNetworkStackService name not found")
-            intent.component = ComponentName(context.packageName, serviceName)
-            return intent
+    fun start() {
+        moduleConnector.startModuleService(
+                INetworkStackConnector::class.qualifiedName + TEST_ACTION_SUFFIX,
+                NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) { connector ->
+            onNetworkStackConnected(INetworkStackConnector.Stub.asInterface(connector))
         }
     }
 
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 db49e0b..14dddcb 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
@@ -157,7 +157,6 @@
         doReturn(IntArray(0)).`when`(systemConfigManager).getSystemPermissionUids(anyString())
 
         networkStackClient = TestNetworkStackClient(realContext)
-        networkStackClient.init()
         networkStackClient.start()
 
         service = TestConnectivityService(makeDependencies())
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index ee17d75..2af4117 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -216,7 +216,6 @@
 import android.net.NetworkScore;
 import android.net.NetworkSpecifier;
 import android.net.NetworkStack;
-import android.net.NetworkStackClient;
 import android.net.NetworkStateSnapshot;
 import android.net.NetworkTestResultParcelable;
 import android.net.OemNetworkPreferences;
@@ -236,6 +235,7 @@
 import android.net.VpnManager;
 import android.net.VpnTransportInfo;
 import android.net.metrics.IpConnectivityLog;
+import android.net.networkstack.NetworkStackClientBase;
 import android.net.resolv.aidl.Nat64PrefixEventParcel;
 import android.net.resolv.aidl.PrivateDnsValidationEventParcel;
 import android.net.shared.NetworkMonitorUtils;
@@ -446,7 +446,7 @@
     @Mock NetworkStatsManager mStatsManager;
     @Mock IDnsResolver mMockDnsResolver;
     @Mock INetd mMockNetd;
-    @Mock NetworkStackClient mNetworkStack;
+    @Mock NetworkStackClientBase mNetworkStack;
     @Mock PackageManager mPackageManager;
     @Mock UserManager mUserManager;
     @Mock NotificationManager mNotificationManager;
@@ -1178,11 +1178,6 @@
         }
 
         @Override
-        public int getNetId() {
-            return (mMockNetworkAgent == null) ? NETID_UNSET : mMockNetworkAgent.getNetwork().netId;
-        }
-
-        @Override
         public int getActiveVpnType() {
             return mVpnType;
         }
@@ -1206,10 +1201,12 @@
                     mNetworkCapabilities);
             mMockNetworkAgent.waitForIdle(TIMEOUT_MS);
 
-            verify(mMockNetd, times(1)).networkAddUidRanges(eq(mMockVpn.getNetId()),
+            final int expectedNetId = mMockVpn.getNetwork() == null ? NETID_UNSET
+                    : mMockVpn.getNetwork().getNetId();
+            verify(mMockNetd, times(1)).networkAddUidRanges(eq(expectedNetId),
                     eq(toUidRangeStableParcels(uids)));
             verify(mMockNetd, never())
-                    .networkRemoveUidRanges(eq(mMockVpn.getNetId()), any());
+                    .networkRemoveUidRanges(eq(expectedNetId), any());
             mAgentRegistered = true;
             updateState(NetworkInfo.DetailedState.CONNECTED, "registerAgent");
             mNetworkCapabilities.set(mMockNetworkAgent.getNetworkCapabilities());
@@ -1584,25 +1581,26 @@
         }).when(deps).makeMultinetworkPolicyTracker(any(), any(), any());
         doReturn(true).when(deps).getCellular464XlatEnabled();
 
-        doReturn(60000).when(mResources).getInteger(
-                com.android.connectivity.resources.R.integer.config_networkTransitionTimeout);
-        doReturn("").when(mResources).getString(
-                com.android.connectivity.resources.R.string.config_networkCaptivePortalServerUrl);
+        doReturn(60000).when(mResources).getInteger(R.integer.config_networkTransitionTimeout);
+        doReturn("").when(mResources).getString(R.string.config_networkCaptivePortalServerUrl);
         doReturn(new String[]{ WIFI_WOL_IFNAME }).when(mResources).getStringArray(
-                com.android.connectivity.resources.R.array.config_wakeonlan_supported_interfaces);
+                R.array.config_wakeonlan_supported_interfaces);
         doReturn(new String[] { "0,1", "1,3" }).when(mResources).getStringArray(
-                com.android.connectivity.resources.R.array.config_networkSupportedKeepaliveCount);
-        doReturn(com.android.connectivity.resources.R.array.config_networkSupportedKeepaliveCount)
-                .when(mResources).getIdentifier(eq("config_networkSupportedKeepaliveCount"),
-                eq("array"), any());
-        doReturn(com.android.connectivity.resources.R.array.network_switch_type_name)
-                .when(mResources).getIdentifier(eq("network_switch_type_name"),
-                eq("array"), any());
-
+                R.array.config_networkSupportedKeepaliveCount);
+        doReturn(new String[0]).when(mResources).getStringArray(
+                R.array.config_networkNotifySwitches);
+        doReturn(new int[]{10, 11, 12, 14, 15}).when(mResources).getIntArray(
+                R.array.config_protectedNetworks);
         // We don't test the actual notification value strings, so just return an empty array.
         // It doesn't matter what the values are as long as it's not null.
         doReturn(new String[0]).when(mResources).getStringArray(R.array.network_switch_type_name);
 
+        doReturn(R.array.config_networkSupportedKeepaliveCount).when(mResources)
+                .getIdentifier(eq("config_networkSupportedKeepaliveCount"), eq("array"), any());
+        doReturn(R.array.network_switch_type_name).when(mResources)
+                .getIdentifier(eq("network_switch_type_name"), eq("array"), any());
+
+
         final ConnectivityResources connRes = mock(ConnectivityResources.class);
         doReturn(mResources).when(connRes).get();
         doReturn(connRes).when(deps).getResources(any());
@@ -3816,7 +3814,7 @@
      * @return the context's attribution tag
      */
     private String getAttributionTag() {
-        return null;
+        return mContext.getAttributionTag();
     }
 
     @Test
@@ -9801,11 +9799,14 @@
                 exemptUidCaptor.capture());
         assertContainsExactly(exemptUidCaptor.getValue(), Process.VPN_UID, exemptUid);
 
+        final int expectedNetId = mMockVpn.getNetwork() == null ? NETID_UNSET
+                : mMockVpn.getNetwork().getNetId();
+
         if (add) {
-            inOrder.verify(mMockNetd, times(1)).networkAddUidRanges(eq(mMockVpn.getNetId()),
+            inOrder.verify(mMockNetd, times(1)).networkAddUidRanges(eq(expectedNetId),
                     eq(toUidRangeStableParcels(vpnRanges)));
         } else {
-            inOrder.verify(mMockNetd, times(1)).networkRemoveUidRanges(eq(mMockVpn.getNetId()),
+            inOrder.verify(mMockNetd, times(1)).networkRemoveUidRanges(eq(expectedNetId),
                     eq(toUidRangeStableParcels(vpnRanges)));
         }
 
diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
index 9ab60a4..116d755 100644
--- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -32,6 +32,7 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.net.ConnectivityManager;
+import android.net.ConnectivityResources;
 import android.net.IDnsResolver;
 import android.net.INetd;
 import android.net.LinkProperties;
@@ -47,10 +48,11 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import com.android.internal.R;
+import com.android.connectivity.resources.R;
 import com.android.server.ConnectivityService;
 import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -84,10 +86,16 @@
         MockitoAnnotations.initMocks(this);
         when(mCtx.getResources()).thenReturn(mResources);
         when(mCtx.getPackageName()).thenReturn("com.android.server.connectivity");
+        ConnectivityResources.setResourcesContextForTest(mCtx);
 
         mMonitor = new TestableLingerMonitor(mCtx, mNotifier, HIGH_DAILY_LIMIT, HIGH_RATE_LIMIT);
     }
 
+    @After
+    public void tearDown() {
+        ConnectivityResources.setResourcesContextForTest(null);
+    }
+
     @Test
     public void testTransitions() {
         setNotificationSwitch(transition(WIFI, CELLULAR));
diff --git a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
index 3adf08c..dde77b0 100644
--- a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
+++ b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
@@ -41,6 +41,7 @@
 import android.net.NetworkInfo;
 import android.os.UserHandle;
 import android.telephony.TelephonyManager;
+import android.util.DisplayMetrics;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -91,6 +92,7 @@
 
     @Mock Context mCtx;
     @Mock Resources mResources;
+    @Mock DisplayMetrics mDisplayMetrics;
     @Mock PackageManager mPm;
     @Mock TelephonyManager mTelephonyManager;
     @Mock NotificationManager mNotificationManager;
@@ -102,6 +104,17 @@
 
     NetworkNotificationManager mManager;
 
+
+    @BeforeClass
+    public static void setUpClass() {
+        Notification.DevFlags.sForceDefaults = true;
+    }
+
+    @AfterClass
+    public static void tearDownClass() {
+        Notification.DevFlags.sForceDefaults = false;
+    }
+
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
@@ -112,6 +125,7 @@
         mCellNai.networkInfo = mNetworkInfo;
         mVpnNai.networkCapabilities = VPN_CAPABILITIES;
         mVpnNai.networkInfo = mNetworkInfo;
+        mDisplayMetrics.density = 2.275f;
         doReturn(true).when(mVpnNai).isVPN();
         when(mCtx.getResources()).thenReturn(mResources);
         when(mCtx.getPackageManager()).thenReturn(mPm);
@@ -124,6 +138,7 @@
         when(mNetworkInfo.getExtraInfo()).thenReturn(TEST_EXTRA_INFO);
         ConnectivityResources.setResourcesContextForTest(mCtx);
         when(mResources.getColor(anyInt(), any())).thenReturn(0xFF607D8B);
+        when(mResources.getDisplayMetrics()).thenReturn(mDisplayMetrics);
 
         // Come up with some credible-looking transport names. The actual values do not matter.
         String[] transportNames = new String[NetworkCapabilities.MAX_TRANSPORT + 1];