Merge "Make tests compatible with mockito-extended"
diff --git a/Tethering/Android.bp b/Tethering/Android.bp
index 5a08b23..d3b9393 100644
--- a/Tethering/Android.bp
+++ b/Tethering/Android.bp
@@ -156,7 +156,5 @@
 
 sdk {
     name: "tethering-module-sdk",
-    java_sdk_libs: [
-        "framework-tethering",
-    ],
+    bootclasspath_fragments: ["com.android.tethering-bootclasspath-fragment"],
 }
diff --git a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
index 36a2f10..4a05c9f 100644
--- a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
+++ b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
@@ -786,6 +786,7 @@
         dumpIpv6ForwardingRules(pw);
         dumpIpv4ForwardingRules(pw);
         pw.decreaseIndent();
+        pw.println();
 
         pw.println("Device map:");
         pw.increaseIndent();
@@ -872,24 +873,33 @@
         }
     }
 
-    private String ipv4RuleToString(long now, Tether4Key key, Tether4Value value) {
-        final String private4, public4, dst4;
+    private String ipv4RuleToString(long now, boolean downstream,
+            Tether4Key key, Tether4Value value) {
+        final String src4, public4, dst4;
+        final int publicPort;
         try {
-            private4 = InetAddress.getByAddress(key.src4).getHostAddress();
-            dst4 = InetAddress.getByAddress(key.dst4).getHostAddress();
-            public4 = InetAddress.getByAddress(value.src46).getHostAddress();
+            src4 = InetAddress.getByAddress(key.src4).getHostAddress();
+            if (downstream) {
+                public4 = InetAddress.getByAddress(key.dst4).getHostAddress();
+                publicPort = key.dstPort;
+            } else {
+                public4 = InetAddress.getByAddress(value.src46).getHostAddress();
+                publicPort = value.srcPort;
+            }
+            dst4 = InetAddress.getByAddress(value.dst46).getHostAddress();
         } catch (UnknownHostException impossible) {
-            throw new AssertionError("4-byte array not valid IPv4 address!");
+            throw new AssertionError("IP address array not valid IPv4 address!");
         }
-        long ageMs = (now - value.lastUsed) / 1_000_000;
-        return String.format("[%s] %d(%s) %s:%d -> %d(%s) %s:%d -> %s:%d %dms",
-                key.dstMac, key.iif, getIfName(key.iif), private4, key.srcPort,
+
+        final long ageMs = (now - value.lastUsed) / 1_000_000;
+        return String.format("[%s] %d(%s) %s:%d -> %d(%s) %s:%d -> %s:%d [%s] %dms",
+                key.dstMac, key.iif, getIfName(key.iif), src4, key.srcPort,
                 value.oif, getIfName(value.oif),
-                public4, value.srcPort, dst4, key.dstPort, ageMs);
+                public4, publicPort, dst4, value.dstPort, value.ethDstMac, ageMs);
     }
 
-    private void dumpIpv4ForwardingRuleMap(long now, BpfMap<Tether4Key, Tether4Value> map,
-            IndentingPrintWriter pw) throws ErrnoException {
+    private void dumpIpv4ForwardingRuleMap(long now, boolean downstream,
+            BpfMap<Tether4Key, Tether4Value> map, IndentingPrintWriter pw) throws ErrnoException {
         if (map == null) {
             pw.println("No IPv4 support");
             return;
@@ -898,7 +908,7 @@
             pw.println("No rules");
             return;
         }
-        map.forEach((k, v) -> pw.println(ipv4RuleToString(now, k, v)));
+        map.forEach((k, v) -> pw.println(ipv4RuleToString(now, downstream, k, v)));
     }
 
     private void dumpIpv4ForwardingRules(IndentingPrintWriter pw) {
@@ -906,14 +916,14 @@
 
         try (BpfMap<Tether4Key, Tether4Value> upstreamMap = mDeps.getBpfUpstream4Map();
                 BpfMap<Tether4Key, Tether4Value> downstreamMap = mDeps.getBpfDownstream4Map()) {
-            pw.println("IPv4 Upstream: [inDstMac] iif(iface) src -> nat -> dst");
+            pw.println("IPv4 Upstream: [inDstMac] iif(iface) src -> nat -> dst [outDstMac] age");
             pw.increaseIndent();
-            dumpIpv4ForwardingRuleMap(now, upstreamMap, pw);
+            dumpIpv4ForwardingRuleMap(now, UPSTREAM, upstreamMap, pw);
             pw.decreaseIndent();
 
-            pw.println("IPv4 Downstream: [inDstMac] iif(iface) src -> nat -> dst");
+            pw.println("IPv4 Downstream: [inDstMac] iif(iface) src -> nat -> dst [outDstMac] age");
             pw.increaseIndent();
-            dumpIpv4ForwardingRuleMap(now, downstreamMap, pw);
+            dumpIpv4ForwardingRuleMap(now, DOWNSTREAM, downstreamMap, pw);
             pw.decreaseIndent();
         } catch (ErrnoException e) {
             pw.println("Error dumping IPv4 map: " + e);
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index 8b91a45..fd8397f 100644
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -79,6 +79,8 @@
 import static android.net.NetworkCapabilities.TRANSPORT_VPN;
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
 import static android.net.NetworkRequest.Type.LISTEN_FOR_BEST;
+import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_TEST;
+import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_TEST_ONLY;
 import static android.net.shared.NetworkMonitorUtils.isPrivateDnsValidationRequired;
 import static android.os.Process.INVALID_UID;
 import static android.os.Process.VPN_UID;
@@ -2636,6 +2638,12 @@
                 "ConnectivityService");
     }
 
+    private void enforceManageTestNetworksPermission() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.MANAGE_TEST_NETWORKS,
+                "ConnectivityService");
+    }
+
     private boolean checkNetworkStackPermission() {
         return checkAnyPermissionOf(
                 android.Manifest.permission.NETWORK_STACK,
@@ -9967,8 +9975,15 @@
             @NonNull final OemNetworkPreferences preference,
             @Nullable final IOnCompleteListener listener) {
 
-        enforceAutomotiveDevice();
-        enforceOemNetworkPreferencesPermission();
+        Objects.requireNonNull(preference, "OemNetworkPreferences must be non-null");
+        // Only bypass the permission/device checks if this is a valid test request.
+        if (isValidTestOemNetworkPreference(preference)) {
+            enforceManageTestNetworksPermission();
+        } else {
+            enforceAutomotiveDevice();
+            enforceOemNetworkPreferencesPermission();
+            validateOemNetworkPreferences(preference);
+        }
 
         // TODO: Have a priority for each preference.
         if (!mProfileNetworkPreferences.isEmpty() || !mMobileDataPreferredUids.isEmpty()) {
@@ -9980,18 +9995,41 @@
             throwConcurrentPreferenceException();
         }
 
-        Objects.requireNonNull(preference, "OemNetworkPreferences must be non-null");
-        validateOemNetworkPreferences(preference);
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_OEM_NETWORK_PREFERENCE,
                 new Pair<>(preference, listener)));
     }
 
+    /**
+     * Check the validity of an OEM network preference to be used for testing purposes.
+     * @param preference the preference to validate
+     * @return true if this is a valid OEM network preference test request.
+     */
+    private boolean isValidTestOemNetworkPreference(
+            @NonNull final OemNetworkPreferences preference) {
+        // Allow for clearing of an existing OemNetworkPreference used for testing.
+        // This isn't called on the handler thread so it is possible that mOemNetworkPreferences
+        // changes after this check is complete. This is an unlikely scenario as calling of this API
+        // is controlled by the OEM therefore the added complexity is not worth adding given those
+        // circumstances. That said, it is an edge case to be aware of hence this comment.
+        final boolean isValidTestClearPref = preference.getNetworkPreferences().size() == 0
+                && isTestOemNetworkPreference(mOemNetworkPreferences);
+        return isTestOemNetworkPreference(preference) || isValidTestClearPref;
+    }
+
+    private boolean isTestOemNetworkPreference(@NonNull final OemNetworkPreferences preference) {
+        final Map<String, Integer> prefMap = preference.getNetworkPreferences();
+        return prefMap.size() == 1
+                && (prefMap.containsValue(OEM_NETWORK_PREFERENCE_TEST)
+                || prefMap.containsValue(OEM_NETWORK_PREFERENCE_TEST_ONLY));
+    }
+
     private void validateOemNetworkPreferences(@NonNull OemNetworkPreferences preference) {
         for (@OemNetworkPreferences.OemNetworkPreference final int pref
                 : preference.getNetworkPreferences().values()) {
-            if (OemNetworkPreferences.OEM_NETWORK_PREFERENCE_UNINITIALIZED == pref) {
-                final String msg = "OEM_NETWORK_PREFERENCE_UNINITIALIZED is an invalid value.";
-                throw new IllegalArgumentException(msg);
+            if (pref <= 0 || OemNetworkPreferences.OEM_NETWORK_PREFERENCE_MAX < pref) {
+                throw new IllegalArgumentException(
+                        OemNetworkPreferences.oemNetworkPreferenceToString(pref)
+                                + " is an invalid value.");
             }
         }
     }
@@ -10215,13 +10253,21 @@
                 case OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY:
                     requests.add(createOemPrivateNetworkRequest());
                     break;
+                case OEM_NETWORK_PREFERENCE_TEST:
+                    requests.add(createUnmeteredNetworkRequest());
+                    requests.add(createTestNetworkRequest());
+                    requests.add(createDefaultRequest());
+                    break;
+                case OEM_NETWORK_PREFERENCE_TEST_ONLY:
+                    requests.add(createTestNetworkRequest());
+                    break;
                 default:
                     // This should never happen.
                     throw new IllegalArgumentException("createNriFromOemNetworkPreferences()"
                             + " called with invalid preference of " + preference);
             }
 
-            final ArraySet ranges = new ArraySet<Integer>();
+            final ArraySet<UidRange> ranges = new ArraySet<>();
             for (final int uid : uids) {
                 ranges.add(new UidRange(uid, uid));
             }
@@ -10254,10 +10300,17 @@
         }
 
         private NetworkCapabilities createDefaultPerAppNetCap() {
-            final NetworkCapabilities netCap = new NetworkCapabilities();
-            netCap.addCapability(NET_CAPABILITY_INTERNET);
-            netCap.setRequestorUidAndPackageName(Process.myUid(), mContext.getPackageName());
-            return netCap;
+            final NetworkCapabilities netcap = new NetworkCapabilities();
+            netcap.addCapability(NET_CAPABILITY_INTERNET);
+            netcap.setRequestorUidAndPackageName(Process.myUid(), mContext.getPackageName());
+            return netcap;
+        }
+
+        private NetworkRequest createTestNetworkRequest() {
+            final NetworkCapabilities netcap = new NetworkCapabilities();
+            netcap.clearAll();
+            netcap.addTransportType(TRANSPORT_TEST);
+            return createNetworkRequest(NetworkRequest.Type.REQUEST, netcap);
         }
     }
 }
diff --git a/tests/common/java/android/net/NetworkProviderTest.kt b/tests/common/java/android/net/NetworkProviderTest.kt
index 7424157..97d3c5a 100644
--- a/tests/common/java/android/net/NetworkProviderTest.kt
+++ b/tests/common/java/android/net/NetworkProviderTest.kt
@@ -18,6 +18,7 @@
 
 import android.app.Instrumentation
 import android.content.Context
+import android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED
 import android.net.NetworkCapabilities.TRANSPORT_TEST
 import android.net.NetworkProviderTest.TestNetworkCallback.CallbackEntry.OnUnavailable
 import android.net.NetworkProviderTest.TestNetworkProvider.CallbackEntry.OnNetworkRequestWithdrawn
@@ -25,14 +26,18 @@
 import android.os.Build
 import android.os.HandlerThread
 import android.os.Looper
+import android.util.Log
 import androidx.test.InstrumentationRegistry
 import com.android.net.module.util.ArrayTrackRecord
 import com.android.testutils.CompatUtil
+import com.android.testutils.DevSdkIgnoreRule
+import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter
 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
 import com.android.testutils.DevSdkIgnoreRunner
 import com.android.testutils.isDevSdkInRange
 import org.junit.After
 import org.junit.Before
+import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mockito.doReturn
@@ -41,6 +46,7 @@
 import java.util.UUID
 import kotlin.test.assertEquals
 import kotlin.test.assertNotEquals
+import kotlin.test.fail
 
 private const val DEFAULT_TIMEOUT_MS = 5000L
 private val instrumentation: Instrumentation
@@ -51,6 +57,8 @@
 @RunWith(DevSdkIgnoreRunner::class)
 @IgnoreUpTo(Build.VERSION_CODES.Q)
 class NetworkProviderTest {
+    @Rule @JvmField
+    val mIgnoreRule = DevSdkIgnoreRule()
     private val mCm = context.getSystemService(ConnectivityManager::class.java)
     private val mHandlerThread = HandlerThread("${javaClass.simpleName} handler thread")
 
@@ -68,6 +76,7 @@
 
     private class TestNetworkProvider(context: Context, looper: Looper) :
             NetworkProvider(context, looper, PROVIDER_NAME) {
+        private val TAG = this::class.simpleName
         private val seenEvents = ArrayTrackRecord<CallbackEntry>().newReadHead()
 
         sealed class CallbackEntry {
@@ -80,22 +89,30 @@
         }
 
         override fun onNetworkRequested(request: NetworkRequest, score: Int, id: Int) {
+            Log.d(TAG, "onNetworkRequested $request, $score, $id")
             seenEvents.add(OnNetworkRequested(request, score, id))
         }
 
         override fun onNetworkRequestWithdrawn(request: NetworkRequest) {
+            Log.d(TAG, "onNetworkRequestWithdrawn $request")
             seenEvents.add(OnNetworkRequestWithdrawn(request))
         }
 
-        inline fun <reified T : CallbackEntry> expectCallback(
+        inline fun <reified T : CallbackEntry> eventuallyExpectCallbackThat(
             crossinline predicate: (T) -> Boolean
         ) = seenEvents.poll(DEFAULT_TIMEOUT_MS) { it is T && predicate(it) }
+                ?: fail("Did not receive callback after ${DEFAULT_TIMEOUT_MS}ms")
     }
 
     private fun createNetworkProvider(ctx: Context = context): TestNetworkProvider {
         return TestNetworkProvider(ctx, mHandlerThread.looper)
     }
 
+    // In S+ framework, do not run this test, since the provider will no longer receive
+    // onNetworkRequested for every request. Instead, provider needs to
+    // call {@code registerNetworkOffer} with the description of networks they
+    // might have ability to setup, and expects {@link NetworkOfferCallback#onNetworkNeeded}.
+    @IgnoreAfter(Build.VERSION_CODES.R)
     @Test
     fun testOnNetworkRequested() {
         val provider = createNetworkProvider()
@@ -105,13 +122,15 @@
 
         val specifier = CompatUtil.makeTestNetworkSpecifier(
                 UUID.randomUUID().toString())
+        // Test network is not allowed to be trusted.
         val nr: NetworkRequest = NetworkRequest.Builder()
                 .addTransportType(TRANSPORT_TEST)
+                .removeCapability(NET_CAPABILITY_TRUSTED)
                 .setNetworkSpecifier(specifier)
                 .build()
         val cb = ConnectivityManager.NetworkCallback()
         mCm.requestNetwork(nr, cb)
-        provider.expectCallback<OnNetworkRequested>() { callback ->
+        provider.eventuallyExpectCallbackThat<OnNetworkRequested>() { callback ->
             callback.request.getNetworkSpecifier() == specifier &&
             callback.request.hasTransport(TRANSPORT_TEST)
         }
@@ -131,22 +150,24 @@
         val config = NetworkAgentConfig.Builder().build()
         val agent = object : NetworkAgent(context, mHandlerThread.looper, "TestAgent", nc, lp,
                 initialScore, config, provider) {}
+        agent.register()
+        agent.markConnected()
 
-        provider.expectCallback<OnNetworkRequested>() { callback ->
+        provider.eventuallyExpectCallbackThat<OnNetworkRequested>() { callback ->
             callback.request.getNetworkSpecifier() == specifier &&
             callback.score == initialScore &&
             callback.id == agent.providerId
         }
 
         agent.sendNetworkScore(updatedScore)
-        provider.expectCallback<OnNetworkRequested>() { callback ->
+        provider.eventuallyExpectCallbackThat<OnNetworkRequested>() { callback ->
             callback.request.getNetworkSpecifier() == specifier &&
             callback.score == updatedScore &&
             callback.id == agent.providerId
         }
 
         mCm.unregisterNetworkCallback(cb)
-        provider.expectCallback<OnNetworkRequestWithdrawn>() { callback ->
+        provider.eventuallyExpectCallbackThat<OnNetworkRequestWithdrawn>() { callback ->
             callback.request.getNetworkSpecifier() == specifier &&
             callback.request.hasTransport(TRANSPORT_TEST)
         }
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java
index 532fd86..8485263 100755
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java
@@ -17,6 +17,7 @@
 package com.android.cts.net.hostside;
 
 import static android.Manifest.permission.NETWORK_SETTINGS;
+import static android.net.ConnectivityManager.TYPE_VPN;
 import static android.net.NetworkCapabilities.TRANSPORT_VPN;
 import static android.os.Process.INVALID_UID;
 import static android.system.OsConstants.AF_INET;
@@ -759,6 +760,7 @@
         assertEquals(vpnNetwork, mCM.getActiveNetwork());
         assertNotEqual(defaultNetwork, vpnNetwork);
         maybeExpectVpnTransportInfo(vpnNetwork);
+        assertTrue(mCM.getNetworkInfo(vpnNetwork).getType() == TYPE_VPN);
 
         if (SdkLevel.isAtLeastS()) {
             // Check that system default network callback has not seen any network changes, even
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index 1d84a1b..73dcfef 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -65,11 +65,13 @@
 import static android.system.OsConstants.AF_INET6;
 import static android.system.OsConstants.AF_UNSPEC;
 
+import static com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity;
 import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
 import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
 import static com.android.networkstack.apishim.ConstantsShim.BLOCKED_REASON_LOCKDOWN_VPN;
 import static com.android.networkstack.apishim.ConstantsShim.BLOCKED_REASON_NONE;
 import static com.android.testutils.MiscAsserts.assertThrows;
+import static com.android.testutils.TestNetworkTrackerKt.initTestNetwork;
 import static com.android.testutils.TestPermissionUtil.runAsShell;
 
 import static org.junit.Assert.assertEquals;
@@ -112,6 +114,7 @@
 import android.net.NetworkSpecifier;
 import android.net.NetworkStateSnapshot;
 import android.net.NetworkUtils;
+import android.net.OemNetworkPreferences;
 import android.net.ProxyInfo;
 import android.net.SocketKeepalive;
 import android.net.TelephonyNetworkSpecifier;
@@ -155,6 +158,7 @@
 import com.android.testutils.DevSdkIgnoreRuleKt;
 import com.android.testutils.RecorderCallback.CallbackEntry;
 import com.android.testutils.SkipPresubmit;
+import com.android.testutils.TestNetworkTracker;
 import com.android.testutils.TestableNetworkCallback;
 
 import junit.framework.AssertionFailedError;
@@ -191,6 +195,7 @@
 import java.util.concurrent.Executor;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 import java.util.function.Supplier;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -461,6 +466,7 @@
                 android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
     }
 
+    @AppModeFull(reason = "Cannot request network in instant app mode")
     @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
     @Test
     public void testGetAllNetworkStateSnapshots()
@@ -517,13 +523,8 @@
     @Test
     @SkipPresubmit(reason = "Virtual devices use a single internet connection for all networks")
     public void testOpenConnection() throws Exception {
-        boolean canRunTest = mPackageManager.hasSystemFeature(FEATURE_WIFI)
-                && mPackageManager.hasSystemFeature(FEATURE_TELEPHONY);
-        if (!canRunTest) {
-            Log.i(TAG,"testOpenConnection cannot execute unless device supports both WiFi "
-                    + "and a cellular connection");
-            return;
-        }
+        assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
+        assumeTrue(mPackageManager.hasSystemFeature(FEATURE_TELEPHONY));
 
         Network wifiNetwork = mCtsNetUtils.connectToWifi();
         Network cellNetwork = mCtsNetUtils.connectToCell();
@@ -649,6 +650,18 @@
         mCm.getBackgroundDataSetting();
     }
 
+    private NetworkRequest makeDefaultRequest() {
+        // Make a request that is similar to the way framework tracks the system
+        // default network.
+        return new NetworkRequest.Builder()
+                .clearCapabilities()
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+                .build();
+    }
+
     private NetworkRequest makeWifiNetworkRequest() {
         return new NetworkRequest.Builder()
                 .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
@@ -698,10 +711,7 @@
     @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
     @Test
     public void testRegisterNetworkCallback() {
-        if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
-            Log.i(TAG, "testRegisterNetworkCallback cannot execute unless device supports WiFi");
-            return;
-        }
+        assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
 
         // We will register for a WIFI network being available or lost.
         final TestNetworkCallback callback = new TestNetworkCallback();
@@ -712,12 +722,14 @@
 
         final TestNetworkCallback systemDefaultCallback = new TestNetworkCallback();
         final TestNetworkCallback perUidCallback = new TestNetworkCallback();
+        final TestNetworkCallback bestMatchingCallback = new TestNetworkCallback();
         final Handler h = new Handler(Looper.getMainLooper());
         if (TestUtils.shouldTestSApis()) {
             runWithShellPermissionIdentity(() -> {
                 mCmShim.registerSystemDefaultNetworkCallback(systemDefaultCallback, h);
                 mCmShim.registerDefaultNetworkCallbackForUid(Process.myUid(), perUidCallback, h);
             }, NETWORK_SETTINGS);
+            mCm.registerBestMatchingNetworkCallback(makeDefaultRequest(), bestMatchingCallback, h);
         }
 
         Network wifiNetwork = null;
@@ -743,6 +755,10 @@
                 assertNotNull("Did not receive onAvailable on per-UID default network callback",
                         perUidNetwork);
                 assertEquals(defaultNetwork, perUidNetwork);
+                final Network bestMatchingNetwork = bestMatchingCallback.waitForAvailable();
+                assertNotNull("Did not receive onAvailable on best matching network callback",
+                        bestMatchingNetwork);
+                assertEquals(defaultNetwork, bestMatchingNetwork);
             }
 
         } catch (InterruptedException e) {
@@ -753,6 +769,7 @@
             if (TestUtils.shouldTestSApis()) {
                 mCm.unregisterNetworkCallback(systemDefaultCallback);
                 mCm.unregisterNetworkCallback(perUidCallback);
+                mCm.unregisterNetworkCallback(bestMatchingCallback);
             }
         }
     }
@@ -765,10 +782,7 @@
     @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
     @Test
     public void testRegisterNetworkCallback_withPendingIntent() {
-        if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
-            Log.i(TAG, "testRegisterNetworkCallback cannot execute unless device supports WiFi");
-            return;
-        }
+        assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
 
         // Create a ConnectivityActionReceiver that has an IntentFilter for our locally defined
         // action, NETWORK_CALLBACK_ACTION.
@@ -939,7 +953,8 @@
         }
     }
 
-    private void waitForActiveNetworkMetered(int targetTransportType, boolean requestedMeteredness)
+    private void waitForActiveNetworkMetered(final int targetTransportType,
+            final boolean requestedMeteredness, final boolean useSystemDefault)
             throws Exception {
         final CountDownLatch latch = new CountDownLatch(1);
         final NetworkCallback networkCallback = new NetworkCallback() {
@@ -953,17 +968,36 @@
                 }
             }
         };
-        // Registering a callback here guarantees onCapabilitiesChanged is called immediately
-        // with the current setting. Therefore, if the setting has already been changed,
-        // this method will return right away, and if not it will wait for the setting to change.
-        mCm.registerDefaultNetworkCallback(networkCallback);
-        // Changing meteredness on wifi involves reconnecting, which can take several seconds
-        // (involves re-associating, DHCP...).
-        if (!latch.await(NETWORK_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
-            fail("Timed out waiting for active network metered status to change to "
-                 + requestedMeteredness + " ; network = " + mCm.getActiveNetwork());
+
+        try {
+            // Registering a callback here guarantees onCapabilitiesChanged is called immediately
+            // with the current setting. Therefore, if the setting has already been changed,
+            // this method will return right away, and if not, it'll wait for the setting to change.
+            if (useSystemDefault) {
+                runWithShellPermissionIdentity(() ->
+                                mCmShim.registerSystemDefaultNetworkCallback(networkCallback,
+                                        new Handler(Looper.getMainLooper())),
+                        NETWORK_SETTINGS);
+            } else {
+                mCm.registerDefaultNetworkCallback(networkCallback);
+            }
+
+            // Changing meteredness on wifi involves reconnecting, which can take several seconds
+            // (involves re-associating, DHCP...).
+            if (!latch.await(NETWORK_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+                fail("Timed out waiting for active network metered status to change to "
+                        + requestedMeteredness + " ; network = " + mCm.getActiveNetwork());
+            }
+        } finally {
+            mCm.unregisterNetworkCallback(networkCallback);
         }
-        mCm.unregisterNetworkCallback(networkCallback);
+    }
+
+    private void setWifiMeteredStatusAndWait(String ssid, boolean isMetered) throws Exception {
+        setWifiMeteredStatus(ssid, Boolean.toString(isMetered) /* metered */);
+        waitForActiveNetworkMetered(TRANSPORT_WIFI,
+                isMetered /* requestedMeteredness */,
+                true /* useSystemDefault */);
     }
 
     private void assertMultipathPreferenceIsEventually(Network network, int oldValue,
@@ -1025,10 +1059,9 @@
             int newMeteredPreference = findNextPrefValue(resolver);
             Settings.Global.putString(resolver, NETWORK_METERED_MULTIPATH_PREFERENCE,
                     Integer.toString(newMeteredPreference));
-            setWifiMeteredStatus(ssid, "true");
-            waitForActiveNetworkMetered(TRANSPORT_WIFI, true);
             // Wifi meterness changes from unmetered to metered will disconnect and reconnect since
             // R.
+            setWifiMeteredStatusAndWait(ssid, true);
             final Network network = mCtsNetUtils.ensureWifiConnected();
             assertEquals(ssid, unquoteSSID(mWifiManager.getConnectionInfo().getSSID()));
             assertEquals(mCm.getNetworkCapabilities(network).hasCapability(
@@ -1045,9 +1078,8 @@
             assertMultipathPreferenceIsEventually(network,
                     oldMeteredPreference, newMeteredPreference);
 
-            setWifiMeteredStatus(ssid, "false");
             // No disconnect from unmetered to metered.
-            waitForActiveNetworkMetered(TRANSPORT_WIFI, false);
+            setWifiMeteredStatusAndWait(ssid, false);
             assertEquals(mCm.getNetworkCapabilities(network).hasCapability(
                     NET_CAPABILITY_NOT_METERED), true);
             assertMultipathPreferenceIsEventually(network, newMeteredPreference,
@@ -1237,11 +1269,7 @@
     @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
     @Test
     public void testKeepaliveWifiUnsupported() throws Exception {
-        if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
-            Log.i(TAG, "testKeepaliveUnsupported cannot execute unless device"
-                    + " supports WiFi");
-            return;
-        }
+        assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
 
         final Network network = mCtsNetUtils.ensureWifiConnected();
         if (getSupportedKeepalivesForNet(network) != 0) return;
@@ -1258,10 +1286,7 @@
     @Test
     @SkipPresubmit(reason = "Keepalive is not supported on virtual hardware")
     public void testCreateTcpKeepalive() throws Exception {
-        if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
-            Log.i(TAG, "testCreateTcpKeepalive cannot execute unless device supports WiFi");
-            return;
-        }
+        assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
 
         final Network network = mCtsNetUtils.ensureWifiConnected();
         if (getSupportedKeepalivesForNet(network) == 0) return;
@@ -1468,11 +1493,7 @@
     @Test
     @SkipPresubmit(reason = "Keepalive is not supported on virtual hardware")
     public void testSocketKeepaliveLimitWifi() throws Exception {
-        if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
-            Log.i(TAG, "testSocketKeepaliveLimitWifi cannot execute unless device"
-                    + " supports WiFi");
-            return;
-        }
+        assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
 
         final Network network = mCtsNetUtils.ensureWifiConnected();
         final int supported = getSupportedKeepalivesForNet(network);
@@ -1565,11 +1586,7 @@
     @Test
     @SkipPresubmit(reason = "Keepalive is not supported on virtual hardware")
     public void testSocketKeepaliveUnprivileged() throws Exception {
-        if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
-            Log.i(TAG, "testSocketKeepaliveUnprivileged cannot execute unless device"
-                    + " supports WiFi");
-            return;
-        }
+        assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
 
         final Network network = mCtsNetUtils.ensureWifiConnected();
         final int supported = getSupportedKeepalivesForNet(network);
@@ -1716,6 +1733,24 @@
                 c -> c instanceof CallbackEntry.Available);
     }
 
+    private void waitForAvailable(
+            @NonNull final TestableNetworkCallback cb, final int expectedTransport) {
+        cb.eventuallyExpect(
+                CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS,
+                entry -> {
+                    final NetworkCapabilities nc = mCm.getNetworkCapabilities(entry.getNetwork());
+                    return nc.hasTransport(expectedTransport);
+                }
+        );
+    }
+
+    private void waitForAvailable(
+            @NonNull final TestableNetworkCallback cb, @NonNull final Network expectedNetwork) {
+        cb.expectAvailableCallbacks(expectedNetwork, false /* suspended */,
+                true /* validated */,
+                false /* blocked */, NETWORK_CALLBACK_TIMEOUT_MS);
+    }
+
     private void waitForLost(@NonNull final TestableNetworkCallback cb) {
         cb.eventuallyExpect(CallbackEntry.LOST, NETWORK_CALLBACK_TIMEOUT_MS,
                 c -> c instanceof CallbackEntry.Lost);
@@ -2036,6 +2071,7 @@
         assertThrows(SecurityException.class, () -> mCm.factoryReset());
     }
 
+    @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
     @Test
     public void testFactoryReset() throws Exception {
         assumeTrue(TestUtils.shouldTestSApis());
@@ -2101,4 +2137,172 @@
         startTetheringCallback.verifyTetheringStarted();
         callback.expectTetheredInterfacesChanged(wifiRegexs, TETHERING_WIFI);
     }
+
+    /**
+     * Verify that per-app OEM network preference functions as expected for network preference TEST.
+     * For specified apps, validate networks are prioritized in order: unmetered, TEST transport,
+     * default network.
+     */
+    @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
+    @Test
+    public void testSetOemNetworkPreferenceForTestPref() throws Exception {
+        // Cannot use @IgnoreUpTo(Build.VERSION_CODES.R) because this test also requires API 31
+        // shims, and @IgnoreUpTo does not check that.
+        assumeTrue(TestUtils.shouldTestSApis());
+        assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
+
+        final TestNetworkTracker tnt = callWithShellPermissionIdentity(
+                () -> initTestNetwork(mContext, TEST_LINKADDR, NETWORK_CALLBACK_TIMEOUT_MS));
+        final TestableNetworkCallback defaultCallback = new TestableNetworkCallback();
+        final TestableNetworkCallback systemDefaultCallback = new TestableNetworkCallback();
+
+        final Network wifiNetwork = mCtsNetUtils.ensureWifiConnected();
+        final NetworkCapabilities wifiNetworkCapabilities = callWithShellPermissionIdentity(
+                () -> mCm.getNetworkCapabilities(wifiNetwork));
+        final String ssid = unquoteSSID(wifiNetworkCapabilities.getSsid());
+        final boolean oldMeteredValue = wifiNetworkCapabilities.isMetered();
+
+        try {
+            // This network will be used for unmetered.
+            setWifiMeteredStatusAndWait(ssid, false /* isMetered */);
+
+            setOemNetworkPreferenceForMyPackage(OemNetworkPreferences.OEM_NETWORK_PREFERENCE_TEST);
+            registerTestOemNetworkPreferenceCallbacks(defaultCallback, systemDefaultCallback);
+
+            // Validate that an unmetered network is used over other networks.
+            waitForAvailable(defaultCallback, wifiNetwork);
+            waitForAvailable(systemDefaultCallback, wifiNetwork);
+
+            // Validate when setting unmetered to metered, unmetered is lost and replaced by the
+            // network with the TEST transport.
+            setWifiMeteredStatusAndWait(ssid, true /* isMetered */);
+            defaultCallback.expectCallback(CallbackEntry.LOST, wifiNetwork);
+            waitForAvailable(defaultCallback, tnt.getNetwork());
+            // Depending on if this device has cellular connectivity or not, multiple available
+            // callbacks may be received. Eventually, metered Wi-Fi should be the final available
+            // callback in any case therefore confirm its receipt before continuing to assure the
+            // system is in the expected state.
+            waitForAvailable(systemDefaultCallback, TRANSPORT_WIFI);
+        } finally {
+            // Validate that removing the test network will fallback to the default network.
+            runWithShellPermissionIdentity(tnt::teardown);
+            defaultCallback.expectCallback(CallbackEntry.LOST, tnt.getNetwork());
+            waitForAvailable(defaultCallback);
+
+            setWifiMeteredStatusAndWait(ssid, oldMeteredValue);
+
+            // Cleanup any prior test state from setOemNetworkPreference
+            clearOemNetworkPreference();
+            unregisterTestOemNetworkPreferenceCallbacks(defaultCallback, systemDefaultCallback);
+        }
+    }
+
+    /**
+     * Verify that per-app OEM network preference functions as expected for network pref TEST_ONLY.
+     * For specified apps, validate that only TEST transport type networks are used.
+     */
+    @Test
+    public void testSetOemNetworkPreferenceForTestOnlyPref() throws Exception {
+        // Cannot use @IgnoreUpTo(Build.VERSION_CODES.R) because this test also requires API 31
+        // shims, and @IgnoreUpTo does not check that.
+        assumeTrue(TestUtils.shouldTestSApis());
+
+        final TestNetworkTracker tnt = callWithShellPermissionIdentity(
+                () -> initTestNetwork(mContext, TEST_LINKADDR, NETWORK_CALLBACK_TIMEOUT_MS));
+        final TestableNetworkCallback defaultCallback = new TestableNetworkCallback();
+        final TestableNetworkCallback systemDefaultCallback = new TestableNetworkCallback();
+
+        final Network wifiNetwork = mCtsNetUtils.ensureWifiConnected();
+
+        try {
+            setOemNetworkPreferenceForMyPackage(
+                    OemNetworkPreferences.OEM_NETWORK_PREFERENCE_TEST_ONLY);
+            registerTestOemNetworkPreferenceCallbacks(defaultCallback, systemDefaultCallback);
+            waitForAvailable(defaultCallback, tnt.getNetwork());
+            waitForAvailable(systemDefaultCallback, wifiNetwork);
+        } finally {
+            runWithShellPermissionIdentity(tnt::teardown);
+            defaultCallback.expectCallback(CallbackEntry.LOST, tnt.getNetwork());
+
+            // This network preference should only ever use the test network therefore available
+            // should not trigger when the test network goes down (e.g. switch to cellular).
+            defaultCallback.assertNoCallback();
+            // The system default should still be connected to Wi-fi
+            assertEquals(wifiNetwork, systemDefaultCallback.getLastAvailableNetwork());
+
+            // Cleanup any prior test state from setOemNetworkPreference
+            clearOemNetworkPreference();
+
+            // The default (non-test) network should be available as the network pref was cleared.
+            waitForAvailable(defaultCallback);
+            unregisterTestOemNetworkPreferenceCallbacks(defaultCallback, systemDefaultCallback);
+        }
+    }
+
+    private void unregisterTestOemNetworkPreferenceCallbacks(
+            @NonNull final TestableNetworkCallback defaultCallback,
+            @NonNull final TestableNetworkCallback systemDefaultCallback) {
+        mCm.unregisterNetworkCallback(defaultCallback);
+        mCm.unregisterNetworkCallback(systemDefaultCallback);
+    }
+
+    private void registerTestOemNetworkPreferenceCallbacks(
+            @NonNull final TestableNetworkCallback defaultCallback,
+            @NonNull final TestableNetworkCallback systemDefaultCallback) {
+        mCm.registerDefaultNetworkCallback(defaultCallback);
+        runWithShellPermissionIdentity(() ->
+                mCmShim.registerSystemDefaultNetworkCallback(systemDefaultCallback,
+                        new Handler(Looper.getMainLooper())), NETWORK_SETTINGS);
+    }
+
+    private static final class OnCompleteListenerCallback {
+        final CompletableFuture<Object> mDone = new CompletableFuture<>();
+
+        public void onComplete() {
+            mDone.complete(new Object());
+        }
+
+        void expectOnComplete() throws Exception {
+            try {
+                mDone.get(NETWORK_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+            } catch (TimeoutException e) {
+                fail("Expected onComplete() not received after "
+                        + NETWORK_CALLBACK_TIMEOUT_MS + " ms");
+            }
+        }
+    }
+
+    private void setOemNetworkPreferenceForMyPackage(final int networkPref) throws Exception {
+        final OemNetworkPreferences pref = new OemNetworkPreferences.Builder()
+                .addNetworkPreference(mContext.getPackageName(), networkPref)
+                .build();
+        final OnCompleteListenerCallback oemPrefListener = new OnCompleteListenerCallback();
+        mUiAutomation.adoptShellPermissionIdentity();
+        try {
+            mCm.setOemNetworkPreference(
+                    pref, mContext.getMainExecutor(), oemPrefListener::onComplete);
+        } finally {
+            mUiAutomation.dropShellPermissionIdentity();
+        }
+        oemPrefListener.expectOnComplete();
+    }
+
+    /**
+     * This will clear the OEM network preference on the device. As there is currently no way of
+     * getting the existing preference, if this is executed while an existing preference is in
+     * place, that preference will need to be reapplied after executing this test.
+     * @throws Exception
+     */
+    private void clearOemNetworkPreference() throws Exception {
+        final OemNetworkPreferences clearPref = new OemNetworkPreferences.Builder().build();
+        final OnCompleteListenerCallback oemPrefListener = new OnCompleteListenerCallback();
+        mUiAutomation.adoptShellPermissionIdentity();
+        try {
+            mCm.setOemNetworkPreference(
+                    clearPref, mContext.getMainExecutor(), oemPrefListener::onComplete);
+        } finally {
+            mUiAutomation.dropShellPermissionIdentity();
+        }
+        oemPrefListener.expectOnComplete();
+    }
 }
diff --git a/tests/cts/net/src/android/net/cts/IpSecAlgorithmImplTest.java b/tests/cts/net/src/android/net/cts/IpSecAlgorithmImplTest.java
index 080f7f9..2f29273 100644
--- a/tests/cts/net/src/android/net/cts/IpSecAlgorithmImplTest.java
+++ b/tests/cts/net/src/android/net/cts/IpSecAlgorithmImplTest.java
@@ -16,9 +16,13 @@
 
 package android.net.cts;
 
+import static android.net.IpSecAlgorithm.AUTH_AES_CMAC;
 import static android.net.IpSecAlgorithm.AUTH_AES_XCBC;
 import static android.net.IpSecAlgorithm.AUTH_CRYPT_CHACHA20_POLY1305;
 import static android.net.IpSecAlgorithm.CRYPT_AES_CTR;
+import static android.net.cts.PacketUtils.AES_CMAC;
+import static android.net.cts.PacketUtils.AES_CMAC_ICV_LEN;
+import static android.net.cts.PacketUtils.AES_CMAC_KEY_LEN;
 import static android.net.cts.PacketUtils.AES_CTR;
 import static android.net.cts.PacketUtils.AES_CTR_BLK_SIZE;
 import static android.net.cts.PacketUtils.AES_CTR_IV_LEN;
@@ -82,7 +86,7 @@
             InetAddress.parseNumericAddress("2001:db8:1::2");
 
     private static final int REMOTE_PORT = 12345;
-    private static final IpSecManager IPSEC_MANAGER =
+    private static final IpSecManager sIpSecManager =
             InstrumentationRegistry.getContext().getSystemService(IpSecManager.class);
 
     private static class CheckCryptoImplTest implements TestNetworkRunnable.Test {
@@ -92,7 +96,7 @@
         private final EspCipher mEspCipher;
         private final EspAuth mEspAuth;
 
-        public CheckCryptoImplTest(
+        CheckCryptoImplTest(
                 IpSecAlgorithm ipsecEncryptAlgo,
                 IpSecAlgorithm ipsecAuthAlgo,
                 IpSecAlgorithm ipsecAeadAlgo,
@@ -145,19 +149,19 @@
                 }
             }
 
-            try (final IpSecManager.SecurityParameterIndex outSpi =
-                            IPSEC_MANAGER.allocateSecurityParameterIndex(REMOTE_ADDRESS);
-                    final IpSecManager.SecurityParameterIndex inSpi =
-                            IPSEC_MANAGER.allocateSecurityParameterIndex(LOCAL_ADDRESS);
-                    final IpSecTransform outTransform =
+            try (IpSecManager.SecurityParameterIndex outSpi =
+                            sIpSecManager.allocateSecurityParameterIndex(REMOTE_ADDRESS);
+                    IpSecManager.SecurityParameterIndex inSpi =
+                            sIpSecManager.allocateSecurityParameterIndex(LOCAL_ADDRESS);
+                    IpSecTransform outTransform =
                             transformBuilder.buildTransportModeTransform(LOCAL_ADDRESS, outSpi);
-                    final IpSecTransform inTransform =
+                    IpSecTransform inTransform =
                             transformBuilder.buildTransportModeTransform(REMOTE_ADDRESS, inSpi);
                     // Bind localSocket to a random available port.
-                    final DatagramSocket localSocket = new DatagramSocket(0)) {
-                IPSEC_MANAGER.applyTransportModeTransform(
+                    DatagramSocket localSocket = new DatagramSocket(0)) {
+                sIpSecManager.applyTransportModeTransform(
                         localSocket, IpSecManager.DIRECTION_IN, inTransform);
-                IPSEC_MANAGER.applyTransportModeTransform(
+                sIpSecManager.applyTransportModeTransform(
                         localSocket, IpSecManager.DIRECTION_OUT, outTransform);
 
                 // Send ESP packet
@@ -170,7 +174,7 @@
                         tunUtils.awaitEspPacket(outSpi.getSpi(), false /* useEncap */);
 
                 // Remove transform for good hygiene
-                IPSEC_MANAGER.removeTransportModeTransforms(localSocket);
+                sIpSecManager.removeTransportModeTransforms(localSocket);
 
                 // Get the kernel-generated ESP payload
                 final byte[] outEspPayload = new byte[outEspPacket.length - IP6_HDRLEN];
@@ -258,6 +262,20 @@
     }
 
     @Test
+    public void testAesCmac() throws Exception {
+        assumeTrue(hasIpSecAlgorithm(AUTH_AES_CMAC));
+
+        final byte[] authKey = getKeyBytes(AES_CMAC_KEY_LEN);
+        final IpSecAlgorithm ipsecAuthAlgo =
+                new IpSecAlgorithm(IpSecAlgorithm.AUTH_AES_CMAC, authKey, AES_CMAC_ICV_LEN * 8);
+        final EspAuth espAuth = new EspAuth(AES_CMAC, authKey, AES_CMAC_ICV_LEN);
+
+        runWithShellPermissionIdentity(new TestNetworkRunnable(new CheckCryptoImplTest(
+                null /* ipsecEncryptAlgo */, ipsecAuthAlgo, null /* ipsecAeadAlgo */,
+                EspCipherNull.getInstance(), espAuth)));
+    }
+
+    @Test
     public void testChaCha20Poly1305() throws Exception {
         assumeTrue(hasIpSecAlgorithm(AUTH_CRYPT_CHACHA20_POLY1305));
 
diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java
index 5f79a3e..5c95aa3 100644
--- a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java
@@ -74,7 +74,6 @@
 
 import com.android.testutils.DevSdkIgnoreRule;
 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
-import com.android.testutils.SkipPresubmit;
 
 import org.junit.Rule;
 import org.junit.Test;
@@ -771,7 +770,6 @@
     }
 
     @Test
-    @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
     public void testAesCbcHmacMd5Tcp6() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96);
@@ -804,7 +802,6 @@
     }
 
     @Test
-    @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
     public void testAesCbcHmacSha1Tcp6() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, getKey(160), 96);
@@ -837,7 +834,6 @@
     }
 
     @Test
-    @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
     public void testAesCbcHmacSha256Tcp6() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128);
@@ -870,7 +866,6 @@
     }
 
     @Test
-    @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
     public void testAesCbcHmacSha384Tcp6() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA384, getKey(384), 192);
@@ -903,7 +898,6 @@
     }
 
     @Test
-    @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
     public void testAesCbcHmacSha512Tcp6() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA512, getKey(512), 256);
@@ -947,7 +941,6 @@
     }
 
     @Test
-    @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
     public void testAesCtrHmacSha512Tcp6() throws Exception {
         assumeTrue(hasIpSecAlgorithm(CRYPT_AES_CTR));
 
@@ -1002,7 +995,6 @@
     }
 
     @Test
-    @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
     public void testAesCbcAesXCbcTcp6() throws Exception {
         assumeTrue(hasIpSecAlgorithm(AUTH_AES_XCBC));
 
@@ -1043,7 +1035,6 @@
     }
 
     @Test
-    @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
     public void testAesCbcAesCmacTcp6() throws Exception {
         assumeTrue(hasIpSecAlgorithm(AUTH_AES_CMAC));
 
@@ -1082,7 +1073,6 @@
     }
 
     @Test
-    @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
     public void testAesGcm64Tcp6() throws Exception {
         IpSecAlgorithm authCrypt =
                 new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 64);
@@ -1115,7 +1105,6 @@
     }
 
     @Test
-    @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
     public void testAesGcm96Tcp6() throws Exception {
         IpSecAlgorithm authCrypt =
                 new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 96);
@@ -1148,7 +1137,6 @@
     }
 
     @Test
-    @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
     public void testAesGcm128Tcp6() throws Exception {
         IpSecAlgorithm authCrypt =
                 new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);
@@ -1187,7 +1175,6 @@
     }
 
     @Test
-    @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
     public void testChaCha20Poly1305Tcp6() throws Exception {
         assumeTrue(hasIpSecAlgorithm(AUTH_CRYPT_CHACHA20_POLY1305));
 
@@ -1463,7 +1450,6 @@
     }
 
     @Test
-    @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
     public void testCryptTcp6() throws Exception {
         IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
         checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, null, null, false, 1, false);
@@ -1471,7 +1457,6 @@
     }
 
     @Test
-    @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
     public void testAuthTcp6() throws Exception {
         IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128);
         checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, auth, null, false, 1, false);
diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
index 9017f1b..c505cef 100644
--- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
+++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
@@ -66,6 +66,7 @@
 import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnStopSocketKeepalive
 import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnValidationStatus
 import android.os.Build
+import android.os.Handler
 import android.os.HandlerThread
 import android.os.Looper
 import android.os.Message
@@ -269,10 +270,9 @@
             history.add(OnSignalStrengthThresholdsUpdated(thresholds))
         }
 
-        fun expectEmptySignalStrengths() {
+        fun expectSignalStrengths(thresholds: IntArray? = intArrayOf()) {
             expectCallback<OnSignalStrengthThresholdsUpdated>().let {
-                // intArrayOf() without arguments makes an empty array
-                assertArrayEquals(intArrayOf(), it.thresholds)
+                assertArrayEquals(thresholds, it.thresholds)
             }
         }
 
@@ -292,7 +292,7 @@
         // a NetworkAgent whose network does not require validation (which test networks do
         // not, since they lack the INTERNET capability). It always contains the default argument
         // for the URI.
-        fun expectNoInternetValidationStatus() = expectCallback<OnValidationStatus>().let {
+        fun expectValidationBypassedStatus() = expectCallback<OnValidationStatus>().let {
             assertEquals(it.status, VALID_NETWORK)
             // The returned Uri is parsed from the empty string, which means it's an
             // instance of the (private) Uri.StringUri. There are no real good ways
@@ -332,9 +332,30 @@
         callbacksToCleanUp.add(callback)
     }
 
+    private fun registerBestMatchingNetworkCallback(
+        request: NetworkRequest,
+        callback: TestableNetworkCallback,
+        handler: Handler
+    ) {
+        mCM!!.registerBestMatchingNetworkCallback(request, callback, handler)
+        callbacksToCleanUp.add(callback)
+    }
+
+    private fun makeTestNetworkRequest(specifier: String? = null): NetworkRequest {
+        return NetworkRequest.Builder()
+                .clearCapabilities()
+                .addTransportType(TRANSPORT_TEST)
+                .also {
+                    if (specifier != null) {
+                        it.setNetworkSpecifier(CompatUtil.makeEthernetNetworkSpecifier(specifier))
+                    }
+                }
+                .build()
+    }
+
     private fun createNetworkAgent(
         context: Context = realContext,
-        name: String? = null,
+        specifier: String? = null,
         initialNc: NetworkCapabilities? = null,
         initialLp: LinkProperties? = null,
         initialConfig: NetworkAgentConfig? = null
@@ -349,8 +370,8 @@
             if (SdkLevel.isAtLeastS()) {
                 addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
             }
-            if (null != name) {
-                setNetworkSpecifier(CompatUtil.makeEthernetNetworkSpecifier(name))
+            if (null != specifier) {
+                setNetworkSpecifier(CompatUtil.makeEthernetNetworkSpecifier(specifier))
             }
         }
         val lp = initialLp ?: LinkProperties().apply {
@@ -365,21 +386,22 @@
 
     private fun createConnectedNetworkAgent(
         context: Context = realContext,
-        name: String? = null,
-        initialConfig: NetworkAgentConfig? = null
+        specifier: String? = UUID.randomUUID().toString(),
+        initialConfig: NetworkAgentConfig? = null,
+        expectedInitSignalStrengthThresholds: IntArray? = intArrayOf()
     ): Pair<TestableNetworkAgent, TestableNetworkCallback> {
-        val request: NetworkRequest = NetworkRequest.Builder()
-                .clearCapabilities()
-                .addTransportType(TRANSPORT_TEST)
-                .build()
         val callback = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS)
-        requestNetwork(request, callback)
-        val config = initialConfig ?: NetworkAgentConfig.Builder().build()
-        val agent = createNetworkAgent(context, name, initialConfig = config)
+        // Ensure this NetworkAgent is never unneeded by filing a request with its specifier.
+        requestNetwork(makeTestNetworkRequest(specifier = specifier), callback)
+        val agent = createNetworkAgent(context, specifier, initialConfig = initialConfig)
         agent.setTeardownDelayMillis(0)
+        // Connect the agent and verify initial status callbacks.
         agent.register()
         agent.markConnected()
         agent.expectCallback<OnNetworkCreated>()
+        agent.expectSignalStrengths(expectedInitSignalStrengthThresholds)
+        agent.expectValidationBypassedStatus()
+        callback.expectAvailableThenValidatedCallbacks(agent.network!!)
         return agent to callback
     }
 
@@ -413,7 +435,6 @@
                 .setLegacySubType(subtypeLTE)
                 .setLegacySubTypeName(subtypeNameLTE).build()
         val (agent, callback) = createConnectedNetworkAgent(initialConfig = config)
-            callback.expectAvailableThenValidatedCallbacks(agent.network)
             agent.setLegacySubtype(subtypeUMTS, subtypeNameUMTS)
 
             // There is no callback when networkInfo changes,
@@ -433,12 +454,8 @@
     @Test
     fun testConnectAndUnregister() {
         val (agent, callback) = createConnectedNetworkAgent()
-        callback.expectAvailableThenValidatedCallbacks(agent.network)
-        agent.expectEmptySignalStrengths()
-        agent.expectNoInternetValidationStatus()
-
         unregister(agent)
-        callback.expectCallback<Lost>(agent.network)
+        callback.expectCallback<Lost>(agent.network!!)
         assertFailsWith<IllegalStateException>("Must not be able to register an agent twice") {
             agent.register()
         }
@@ -446,11 +463,8 @@
 
     @Test
     fun testOnBandwidthUpdateRequested() {
-        val (agent, callback) = createConnectedNetworkAgent()
-        callback.expectAvailableThenValidatedCallbacks(agent.network)
-        agent.expectEmptySignalStrengths()
-        agent.expectNoInternetValidationStatus()
-        mCM.requestBandwidthUpdate(agent.network)
+        val (agent, _) = createConnectedNetworkAgent()
+        mCM.requestBandwidthUpdate(agent.network!!)
         agent.expectCallback<OnBandwidthUpdateRequested>()
         unregister(agent)
     }
@@ -468,13 +482,8 @@
                 registerNetworkCallback(request, it)
             }
         }
-        createConnectedNetworkAgent().let { (agent, callback) ->
-            callback.expectAvailableThenValidatedCallbacks(agent.network)
-            agent.expectCallback<OnSignalStrengthThresholdsUpdated>().let {
-                assertArrayEquals(it.thresholds, thresholds)
-            }
-            agent.expectNoInternetValidationStatus()
-
+        createConnectedNetworkAgent(expectedInitSignalStrengthThresholds = thresholds).let {
+            (agent, callback) ->
             // Send signal strength and check that the callbacks are called appropriately.
             val nc = NetworkCapabilities(agent.nc)
             nc.setSignalStrength(20)
@@ -483,21 +492,21 @@
 
             nc.setSignalStrength(40)
             agent.sendNetworkCapabilities(nc)
-            callbacks[0].expectAvailableCallbacks(agent.network)
+            callbacks[0].expectAvailableCallbacks(agent.network!!)
             callbacks[1].assertNoCallback(NO_CALLBACK_TIMEOUT)
             callbacks[2].assertNoCallback(NO_CALLBACK_TIMEOUT)
 
             nc.setSignalStrength(80)
             agent.sendNetworkCapabilities(nc)
-            callbacks[0].expectCapabilitiesThat(agent.network) { it.signalStrength == 80 }
-            callbacks[1].expectAvailableCallbacks(agent.network)
-            callbacks[2].expectAvailableCallbacks(agent.network)
+            callbacks[0].expectCapabilitiesThat(agent.network!!) { it.signalStrength == 80 }
+            callbacks[1].expectAvailableCallbacks(agent.network!!)
+            callbacks[2].expectAvailableCallbacks(agent.network!!)
 
             nc.setSignalStrength(55)
             agent.sendNetworkCapabilities(nc)
-            callbacks[0].expectCapabilitiesThat(agent.network) { it.signalStrength == 55 }
-            callbacks[1].expectCapabilitiesThat(agent.network) { it.signalStrength == 55 }
-            callbacks[2].expectCallback<Lost>(agent.network)
+            callbacks[0].expectCapabilitiesThat(agent.network!!) { it.signalStrength == 55 }
+            callbacks[1].expectCapabilitiesThat(agent.network!!) { it.signalStrength == 55 }
+            callbacks[2].expectCallback<Lost>(agent.network!!)
         }
         callbacks.forEach {
             mCM.unregisterNetworkCallback(it)
@@ -546,20 +555,17 @@
 
     @Test
     fun testSendUpdates(): Unit = createConnectedNetworkAgent().let { (agent, callback) ->
-        callback.expectAvailableThenValidatedCallbacks(agent.network)
-        agent.expectEmptySignalStrengths()
-        agent.expectNoInternetValidationStatus()
         val ifaceName = "adhocIface"
         val lp = LinkProperties(agent.lp)
         lp.setInterfaceName(ifaceName)
         agent.sendLinkProperties(lp)
-        callback.expectLinkPropertiesThat(agent.network) {
+        callback.expectLinkPropertiesThat(agent.network!!) {
             it.getInterfaceName() == ifaceName
         }
         val nc = NetworkCapabilities(agent.nc)
         nc.addCapability(NET_CAPABILITY_NOT_METERED)
         agent.sendNetworkCapabilities(nc)
-        callback.expectCapabilitiesThat(agent.network) {
+        callback.expectCapabilitiesThat(agent.network!!) {
             it.hasCapability(NET_CAPABILITY_NOT_METERED)
         }
     }
@@ -568,56 +574,32 @@
     fun testSendScore() {
         // This test will create two networks and check that the one with the stronger
         // score wins out for a request that matches them both.
-        // First create requests to make sure both networks are kept up, using the
-        // specifier so they are specific to each network
-        val name1 = UUID.randomUUID().toString()
-        val name2 = UUID.randomUUID().toString()
-        val request1 = NetworkRequest.Builder()
-                .clearCapabilities()
-                .addTransportType(TRANSPORT_TEST)
-                .setNetworkSpecifier(CompatUtil.makeEthernetNetworkSpecifier(name1))
-                .build()
-        val request2 = NetworkRequest.Builder()
-                .clearCapabilities()
-                .addTransportType(TRANSPORT_TEST)
-                .setNetworkSpecifier(CompatUtil.makeEthernetNetworkSpecifier(name2))
-                .build()
-        val callback1 = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS)
-        val callback2 = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS)
-        requestNetwork(request1, callback1)
-        requestNetwork(request2, callback2)
 
-        // Then file the interesting request
-        val request = NetworkRequest.Builder()
-                .clearCapabilities()
-                .addTransportType(TRANSPORT_TEST)
-                .build()
+        // File the interesting request
         val callback = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS)
-        requestNetwork(request, callback)
+        requestNetwork(makeTestNetworkRequest(), callback)
 
-        // Connect the first Network
-        createConnectedNetworkAgent(name = name1).let { (agent1, _) ->
-            callback.expectAvailableThenValidatedCallbacks(agent1.network)
-            // If using the int ranking, agent1 must be upgraded to a better score so that there is
-            // no ambiguity when agent2 connects that agent1 is still better. If using policy
-            // ranking, this is not necessary.
-            agent1.sendNetworkScore(NetworkScore.Builder().setLegacyInt(BETTER_NETWORK_SCORE)
-                    .build())
-            // Connect the second agent
-            createConnectedNetworkAgent(name = name2).let { (agent2, _) ->
-                agent2.markConnected()
-                // The callback should not see anything yet. With int ranking, agent1 was upgraded
-                // to a stronger score beforehand. With policy ranking, agent1 is preferred by
-                // virtue of already satisfying the request.
-                callback.assertNoCallback(NO_CALLBACK_TIMEOUT)
-                // Now downgrade the score and expect the callback now prefers agent2
-                agent1.sendNetworkScore(NetworkScore.Builder()
-                        .setLegacyInt(WORSE_NETWORK_SCORE)
-                        .setExiting(true)
-                        .build())
-                callback.expectCallback<Available>(agent2.network)
-            }
-        }
+        // Connect the first Network, with an unused callback that kept the network up.
+        val (agent1, _) = createConnectedNetworkAgent()
+        callback.expectAvailableThenValidatedCallbacks(agent1.network!!)
+        // If using the int ranking, agent1 must be upgraded to a better score so that there is
+        // no ambiguity when agent2 connects that agent1 is still better. If using policy
+        // ranking, this is not necessary.
+        agent1.sendNetworkScore(NetworkScore.Builder().setLegacyInt(BETTER_NETWORK_SCORE)
+                .build())
+
+        // Connect the second agent.
+        val (agent2, _) = createConnectedNetworkAgent()
+        // The callback should not see anything yet. With int ranking, agent1 was upgraded
+        // to a stronger score beforehand. With policy ranking, agent1 is preferred by
+        // virtue of already satisfying the request.
+        callback.assertNoCallback(NO_CALLBACK_TIMEOUT)
+        // Now downgrade the score and expect the callback now prefers agent2
+        agent1.sendNetworkScore(NetworkScore.Builder()
+                .setLegacyInt(WORSE_NETWORK_SCORE)
+                .setExiting(true)
+                .build())
+        callback.expectCallback<Available>(agent2.network!!)
 
         // tearDown() will unregister the requests and agents
     }
@@ -658,7 +640,7 @@
         callback.expectAvailableThenValidatedCallbacks(agent.network!!)
 
         // Check that the default network's transport is propagated to the VPN.
-        var vpnNc = mCM.getNetworkCapabilities(agent.network)
+        var vpnNc = mCM.getNetworkCapabilities(agent.network!!)
         assertNotNull(vpnNc)
         assertEquals(VpnManager.TYPE_VPN_SERVICE,
                 (vpnNc.transportInfo as VpnTransportInfo).type)
@@ -690,7 +672,7 @@
         // This is not very accurate because the test does not control the capabilities of the
         // underlying networks, and because not congested, not roaming, and not suspended are the
         // default anyway. It's still useful as an extra check though.
-        vpnNc = mCM.getNetworkCapabilities(agent.network)
+        vpnNc = mCM.getNetworkCapabilities(agent.network!!)
         for (cap in listOf(NET_CAPABILITY_NOT_CONGESTED,
                 NET_CAPABILITY_NOT_ROAMING,
                 NET_CAPABILITY_NOT_SUSPENDED)) {
@@ -701,7 +683,7 @@
         }
 
         unregister(agent)
-        callback.expectCallback<Lost>(agent.network)
+        callback.expectCallback<Lost>(agent.network!!)
     }
 
     private fun unregister(agent: TestableNetworkAgent) {
@@ -789,43 +771,24 @@
     fun testTemporarilyUnmeteredCapability() {
         // This test will create a networks with/without NET_CAPABILITY_TEMPORARILY_NOT_METERED
         // and check that the callback reflects the capability changes.
-        // First create a request to make sure the network is kept up
-        val request1 = NetworkRequest.Builder()
-                .clearCapabilities()
-                .addTransportType(TRANSPORT_TEST)
-                .build()
-        val callback1 = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS).also {
-            registerNetworkCallback(request1, it)
-        }
-        requestNetwork(request1, callback1)
-
-        // Then file the interesting request
-        val request = NetworkRequest.Builder()
-                .clearCapabilities()
-                .addTransportType(TRANSPORT_TEST)
-                .build()
-        val callback = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS)
-        requestNetwork(request, callback)
 
         // Connect the network
-        createConnectedNetworkAgent().let { (agent, _) ->
-            callback.expectAvailableThenValidatedCallbacks(agent.network)
+        val (agent, callback) = createConnectedNetworkAgent()
 
-            // Send TEMP_NOT_METERED and check that the callback is called appropriately.
-            val nc1 = NetworkCapabilities(agent.nc)
-                    .addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)
-            agent.sendNetworkCapabilities(nc1)
-            callback.expectCapabilitiesThat(agent.network) {
-                it.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)
-            }
+        // Send TEMP_NOT_METERED and check that the callback is called appropriately.
+        val nc1 = NetworkCapabilities(agent.nc)
+                .addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)
+        agent.sendNetworkCapabilities(nc1)
+        callback.expectCapabilitiesThat(agent.network!!) {
+            it.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)
+        }
 
-            // Remove TEMP_NOT_METERED and check that the callback is called appropriately.
-            val nc2 = NetworkCapabilities(agent.nc)
-                    .removeCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)
-            agent.sendNetworkCapabilities(nc2)
-            callback.expectCapabilitiesThat(agent.network) {
-                !it.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)
-            }
+        // Remove TEMP_NOT_METERED and check that the callback is called appropriately.
+        val nc2 = NetworkCapabilities(agent.nc)
+                .removeCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)
+        agent.sendNetworkCapabilities(nc2)
+        callback.expectCapabilitiesThat(agent.network!!) {
+            !it.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)
         }
 
         // tearDown() will unregister the requests and agents
@@ -838,88 +801,137 @@
         // score wins out for a request that matches them both. And the weaker agent will
         // be disconnected after customized linger duration.
 
-        // Connect the first Network
-        val name1 = UUID.randomUUID().toString()
-        val name2 = UUID.randomUUID().toString()
-        val (agent1, callback) = createConnectedNetworkAgent(name = name1)
-        callback.expectAvailableThenValidatedCallbacks(agent1.network!!)
-        // Downgrade agent1 to a worse score so that there is no ambiguity when
-        // agent2 connects.
-        agent1.sendNetworkScore(NetworkScore.Builder().setLegacyInt(WORSE_NETWORK_SCORE)
+        // Request the first Network, with a request that could moved to agentStronger in order to
+        // make agentWeaker linger later.
+        val specifierWeaker = UUID.randomUUID().toString()
+        val specifierStronger = UUID.randomUUID().toString()
+        val commonCallback = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS)
+        requestNetwork(makeTestNetworkRequest(), commonCallback)
+        val agentWeaker = createNetworkAgent(specifier = specifierWeaker)
+        agentWeaker.register()
+        agentWeaker.markConnected()
+        commonCallback.expectAvailableThenValidatedCallbacks(agentWeaker.network!!)
+        // Downgrade agentWeaker to a worse score so that there is no ambiguity when
+        // agentStronger connects.
+        agentWeaker.sendNetworkScore(NetworkScore.Builder().setLegacyInt(WORSE_NETWORK_SCORE)
                 .setExiting(true).build())
 
         // Verify invalid linger duration cannot be set.
         assertFailsWith<IllegalArgumentException> {
-            agent1.setLingerDuration(Duration.ofMillis(-1))
+            agentWeaker.setLingerDuration(Duration.ofMillis(-1))
         }
-        assertFailsWith<IllegalArgumentException> { agent1.setLingerDuration(Duration.ZERO) }
+        assertFailsWith<IllegalArgumentException> { agentWeaker.setLingerDuration(Duration.ZERO) }
         assertFailsWith<IllegalArgumentException> {
-            agent1.setLingerDuration(Duration.ofMillis(Integer.MIN_VALUE.toLong()))
+            agentWeaker.setLingerDuration(Duration.ofMillis(Integer.MIN_VALUE.toLong()))
         }
         assertFailsWith<IllegalArgumentException> {
-            agent1.setLingerDuration(Duration.ofMillis(Integer.MAX_VALUE.toLong() + 1))
+            agentWeaker.setLingerDuration(Duration.ofMillis(Integer.MAX_VALUE.toLong() + 1))
         }
         assertFailsWith<IllegalArgumentException> {
-            agent1.setLingerDuration(Duration.ofMillis(
+            agentWeaker.setLingerDuration(Duration.ofMillis(
                     NetworkAgent.MIN_LINGER_TIMER_MS.toLong() - 1))
         }
         // Verify valid linger timer can be set, but it should not take effect since the network
         // is still needed.
-        agent1.setLingerDuration(Duration.ofMillis(Integer.MAX_VALUE.toLong()))
-        callback.assertNoCallback(NO_CALLBACK_TIMEOUT)
+        agentWeaker.setLingerDuration(Duration.ofMillis(Integer.MAX_VALUE.toLong()))
+        commonCallback.assertNoCallback(NO_CALLBACK_TIMEOUT)
         // Set to the value we want to verify the functionality.
-        agent1.setLingerDuration(Duration.ofMillis(NetworkAgent.MIN_LINGER_TIMER_MS.toLong()))
-        // Make a listener which can observe agent1 lost later.
+        agentWeaker.setLingerDuration(Duration.ofMillis(NetworkAgent.MIN_LINGER_TIMER_MS.toLong()))
+        // Make a listener which can observe agentWeaker lost later.
         val callbackWeaker = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS)
         registerNetworkCallback(NetworkRequest.Builder()
                 .clearCapabilities()
                 .addTransportType(TRANSPORT_TEST)
-                .setNetworkSpecifier(CompatUtil.makeEthernetNetworkSpecifier(name1))
+                .setNetworkSpecifier(CompatUtil.makeEthernetNetworkSpecifier(specifierWeaker))
                 .build(), callbackWeaker)
-        callbackWeaker.expectAvailableCallbacks(agent1.network!!)
+        callbackWeaker.expectAvailableCallbacks(agentWeaker.network!!)
 
-        // Connect the second agent with a score better than agent1. Verify the callback for
-        // agent1 sees the linger expiry while the callback for both sees the winner.
+        // Connect the agentStronger with a score better than agentWeaker. Verify the callback for
+        // agentWeaker sees the linger expiry while the callback for both sees the winner.
         // Record linger start timestamp prior to send score to prevent possible race, the actual
         // timestamp should be slightly late than this since the service handles update
         // network score asynchronously.
         val lingerStart = SystemClock.elapsedRealtime()
-        val agent2 = createNetworkAgent(name = name2)
-        agent2.register()
-        agent2.markConnected()
-        callback.expectAvailableCallbacks(agent2.network!!)
-        callbackWeaker.expectCallback<Losing>(agent1.network!!)
+        val agentStronger = createNetworkAgent(specifier = specifierStronger)
+        agentStronger.register()
+        agentStronger.markConnected()
+        commonCallback.expectAvailableCallbacks(agentStronger.network!!)
+        callbackWeaker.expectCallback<Losing>(agentWeaker.network!!)
         val expectedRemainingLingerDuration = lingerStart +
                 NetworkAgent.MIN_LINGER_TIMER_MS.toLong() - SystemClock.elapsedRealtime()
         // If the available callback is too late. The remaining duration will be reduced.
         assertTrue(expectedRemainingLingerDuration > 0,
                 "expected remaining linger duration is $expectedRemainingLingerDuration")
         callbackWeaker.assertNoCallback(expectedRemainingLingerDuration)
-        callbackWeaker.expectCallback<Lost>(agent1.network!!)
+        callbackWeaker.expectCallback<Lost>(agentWeaker.network!!)
     }
 
     @Test
     @IgnoreUpTo(Build.VERSION_CODES.R)
     fun testSetSubscriberId() {
-        val name = "TEST-AGENT"
         val imsi = UUID.randomUUID().toString()
         val config = NetworkAgentConfig.Builder().setSubscriberId(imsi).build()
 
-        val request: NetworkRequest = NetworkRequest.Builder()
-                .clearCapabilities()
-                .addTransportType(TRANSPORT_TEST)
-                .setNetworkSpecifier(CompatUtil.makeEthernetNetworkSpecifier(name))
-                .build()
-        val callback = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS)
-        requestNetwork(request, callback)
-
-        val agent = createNetworkAgent(name = name, initialConfig = config)
-        agent.register()
-        agent.markConnected()
-        callback.expectAvailableThenValidatedCallbacks(agent.network!!)
+        val (agent, _) = createConnectedNetworkAgent(initialConfig = config)
         val snapshots = runWithShellPermissionIdentity(ThrowingSupplier {
                 mCM!!.allNetworkStateSnapshots }, NETWORK_SETTINGS)
         val testNetworkSnapshot = snapshots.findLast { it.network == agent.network }
         assertEquals(imsi, testNetworkSnapshot!!.subscriberId)
     }
+
+    @Test
+    @IgnoreUpTo(Build.VERSION_CODES.R)
+    // TODO: Refactor helper functions to util class and move this test case to
+    //  {@link android.net.cts.ConnectivityManagerTest}.
+    fun testRegisterBestMatchingNetworkCallback() {
+        // Register best matching network callback with additional condition that will be
+        // exercised later. This assumes the test network agent has NOT_VCN_MANAGED in it and
+        // does not have NET_CAPABILITY_TEMPORARILY_NOT_METERED.
+        val bestMatchingCb = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS)
+        registerBestMatchingNetworkCallback(NetworkRequest.Builder()
+                .clearCapabilities()
+                .addTransportType(TRANSPORT_TEST)
+                .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
+                .build(), bestMatchingCb, mHandlerThread.threadHandler)
+
+        val (agent1, _) = createConnectedNetworkAgent(specifier = "AGENT-1")
+        bestMatchingCb.expectAvailableThenValidatedCallbacks(agent1.network!!)
+        // Make agent1 worse so when agent2 shows up, the callback will see that.
+        agent1.sendNetworkScore(NetworkScore.Builder().setExiting(true).build())
+        bestMatchingCb.assertNoCallback(NO_CALLBACK_TIMEOUT)
+
+        val (agent2, _) = createConnectedNetworkAgent(specifier = "AGENT-2")
+        bestMatchingCb.expectAvailableDoubleValidatedCallbacks(agent2.network!!)
+
+        // Change something on agent1 to trigger capabilities changed, since the callback
+        // only cares about the best network, verify it received nothing from agent1.
+        val ncAgent1 = agent1.nc
+        ncAgent1.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)
+        agent1.sendNetworkCapabilities(ncAgent1)
+        bestMatchingCb.assertNoCallback(NO_CALLBACK_TIMEOUT)
+
+        // Make agent1 the best network again, verify the callback now tracks agent1.
+        agent1.sendNetworkScore(NetworkScore.Builder()
+                .setExiting(false).setTransportPrimary(true).build())
+        bestMatchingCb.expectAvailableCallbacks(agent1.network!!)
+
+        // Make agent1 temporary vcn managed, which will not satisfying the request.
+        // Verify the callback switch from/to the other network accordingly.
+        ncAgent1.removeCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
+        agent1.sendNetworkCapabilities(ncAgent1)
+        bestMatchingCb.expectAvailableCallbacks(agent2.network!!)
+        ncAgent1.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
+        agent1.sendNetworkCapabilities(ncAgent1)
+        bestMatchingCb.expectAvailableDoubleValidatedCallbacks(agent1.network!!)
+
+        // Verify the callback doesn't care about agent2 disconnect.
+        agent2.unregister()
+        agentsToCleanUp.remove(agent2)
+        bestMatchingCb.assertNoCallback()
+        agent1.unregister()
+        agentsToCleanUp.remove(agent1)
+        bestMatchingCb.expectCallback<Lost>(agent1.network!!)
+
+        // tearDown() will unregister the requests and agents
+    }
 }
diff --git a/tests/cts/net/src/android/net/cts/PacketUtils.java b/tests/cts/net/src/android/net/cts/PacketUtils.java
index 0b3bad4..4d924d1 100644
--- a/tests/cts/net/src/android/net/cts/PacketUtils.java
+++ b/tests/cts/net/src/android/net/cts/PacketUtils.java
@@ -19,6 +19,8 @@
 import static android.system.OsConstants.IPPROTO_IPV6;
 import static android.system.OsConstants.IPPROTO_UDP;
 
+import android.util.ArraySet;
+
 import com.android.internal.net.ipsec.ike.crypto.AesXCbcImpl;
 
 import java.net.Inet4Address;
@@ -29,7 +31,6 @@
 import java.security.GeneralSecurityException;
 import java.security.SecureRandom;
 import java.util.Arrays;
-import java.util.HashSet;
 import java.util.Set;
 
 import javax.crypto.Cipher;
@@ -101,6 +102,7 @@
     static final String HMAC_SHA_256 = "HmacSHA256";
     static final String HMAC_SHA_384 = "HmacSHA384";
     static final String HMAC_SHA_512 = "HmacSHA512";
+    static final String AES_CMAC = "AESCMAC";
     static final String AES_XCBC = "AesXCbc";
 
     public interface Payload {
@@ -501,7 +503,7 @@
         public final byte[] key;
         public final int ivLen;
         public final int saltLen;
-        protected byte[] iv;
+        protected byte[] mIv;
 
         public EspCipher(String algoName, int blockSize, byte[] key, int ivLen, int saltLen) {
             this.algoName = algoName;
@@ -509,11 +511,11 @@
             this.key = key;
             this.ivLen = ivLen;
             this.saltLen = saltLen;
-            this.iv = getIv(ivLen);
+            this.mIv = getIv(ivLen);
         }
 
         public void updateIv(byte[] iv) {
-            this.iv = iv;
+            this.mIv = iv;
         }
 
         public static byte[] getPaddedPayload(int nextHeader, byte[] payload, int blockSize) {
@@ -544,19 +546,19 @@
                 throws GeneralSecurityException;
     }
 
-    public static class EspCipherNull extends EspCipher {
+    public static final class EspCipherNull extends EspCipher {
         private static final String CRYPT_NULL = "CRYPT_NULL";
         private static final int IV_LEN_UNUSED = 0;
         private static final byte[] KEY_UNUSED = new byte[0];
 
-        private static final EspCipherNull INSTANCE = new EspCipherNull();
+        private static final EspCipherNull sInstance = new EspCipherNull();
 
         private EspCipherNull() {
             super(CRYPT_NULL, ESP_BLK_SIZE, KEY_UNUSED, IV_LEN_UNUSED, SALT_LEN_UNUSED);
         }
 
         public static EspCipherNull getInstance() {
-            return INSTANCE;
+            return sInstance;
         }
 
         @Override
@@ -566,7 +568,7 @@
         }
     }
 
-    public static class EspCryptCipher extends EspCipher {
+    public static final class EspCryptCipher extends EspCipher {
         public EspCryptCipher(String algoName, int blockSize, byte[] key, int ivLen) {
             this(algoName, blockSize, key, ivLen, SALT_LEN_UNUSED);
         }
@@ -582,7 +584,7 @@
             final SecretKeySpec secretKeySpec;
 
             if (AES_CBC.equals(algoName)) {
-                ivParameterSpec = new IvParameterSpec(iv);
+                ivParameterSpec = new IvParameterSpec(mIv);
                 secretKeySpec = new SecretKeySpec(key, algoName);
             } else if (AES_CTR.equals(algoName)) {
                 // Provided key consists of encryption/decryption key plus 4-byte salt. Salt is used
@@ -592,9 +594,9 @@
                 secretKeySpec = new SecretKeySpec(secretKey, algoName);
 
                 final ByteBuffer ivParameterBuffer =
-                        ByteBuffer.allocate(iv.length + saltLen + AES_CTR_INITIAL_COUNTER.length);
+                        ByteBuffer.allocate(mIv.length + saltLen + AES_CTR_INITIAL_COUNTER.length);
                 ivParameterBuffer.put(salt);
-                ivParameterBuffer.put(iv);
+                ivParameterBuffer.put(mIv);
                 ivParameterBuffer.put(AES_CTR_INITIAL_COUNTER);
                 ivParameterSpec = new IvParameterSpec(ivParameterBuffer.array());
             } else {
@@ -608,15 +610,15 @@
                     cipher.doFinal(getPaddedPayload(nextHeader, payload, blockSize));
 
             // Build ciphertext
-            final ByteBuffer cipherText = ByteBuffer.allocate(iv.length + encrypted.length);
-            cipherText.put(iv);
+            final ByteBuffer cipherText = ByteBuffer.allocate(mIv.length + encrypted.length);
+            cipherText.put(mIv);
             cipherText.put(encrypted);
 
             return getByteArrayFromBuffer(cipherText);
         }
     }
 
-    public static class EspAeadCipher extends EspCipher {
+    public static final class EspAeadCipher extends EspCipher {
         public final int icvLen;
 
         public EspAeadCipher(
@@ -635,9 +637,9 @@
 
             final SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey, algoName);
 
-            final ByteBuffer ivParameterBuffer = ByteBuffer.allocate(saltLen + iv.length);
+            final ByteBuffer ivParameterBuffer = ByteBuffer.allocate(saltLen + mIv.length);
             ivParameterBuffer.put(salt);
-            ivParameterBuffer.put(iv);
+            ivParameterBuffer.put(mIv);
             final IvParameterSpec ivParameterSpec = new IvParameterSpec(ivParameterBuffer.array());
 
             final ByteBuffer aadBuffer = ByteBuffer.allocate(ESP_HDRLEN);
@@ -653,8 +655,8 @@
 
             // Build ciphertext
             final ByteBuffer cipherText =
-                    ByteBuffer.allocate(iv.length + encryptedTextAndIcv.length);
-            cipherText.put(iv);
+                    ByteBuffer.allocate(mIv.length + encryptedTextAndIcv.length);
+            cipherText.put(mIv);
             cipherText.put(encryptedTextAndIcv);
 
             return getByteArrayFromBuffer(cipherText);
@@ -666,14 +668,15 @@
         public final byte[] key;
         public final int icvLen;
 
-        private static final Set<String> SUPPORTED_HMAC_ALGOS = new HashSet<>();
+        private static final Set<String> JCE_SUPPORTED_MACS = new ArraySet<>();
 
         static {
-            SUPPORTED_HMAC_ALGOS.add(HMAC_MD5);
-            SUPPORTED_HMAC_ALGOS.add(HMAC_SHA1);
-            SUPPORTED_HMAC_ALGOS.add(HMAC_SHA_256);
-            SUPPORTED_HMAC_ALGOS.add(HMAC_SHA_384);
-            SUPPORTED_HMAC_ALGOS.add(HMAC_SHA_512);
+            JCE_SUPPORTED_MACS.add(HMAC_MD5);
+            JCE_SUPPORTED_MACS.add(HMAC_SHA1);
+            JCE_SUPPORTED_MACS.add(HMAC_SHA_256);
+            JCE_SUPPORTED_MACS.add(HMAC_SHA_384);
+            JCE_SUPPORTED_MACS.add(HMAC_SHA_512);
+            JCE_SUPPORTED_MACS.add(AES_CMAC);
         }
 
         public EspAuth(String algoName, byte[] key, int icvLen) {
@@ -686,7 +689,7 @@
             if (AES_XCBC.equals(algoName)) {
                 final Cipher aesCipher = Cipher.getInstance(AES_CBC);
                 return new AesXCbcImpl().mac(key, authenticatedSection, true /* needTruncation */);
-            } else if (SUPPORTED_HMAC_ALGOS.contains(algoName)) {
+            } else if (JCE_SUPPORTED_MACS.contains(algoName)) {
                 final Mac mac = Mac.getInstance(algoName);
                 final SecretKeySpec authKey = new SecretKeySpec(key, algoName);
                 mac.init(authKey);
@@ -701,20 +704,20 @@
         }
     }
 
-    public static class EspAuthNull extends EspAuth {
+    public static final class EspAuthNull extends EspAuth {
         private static final String AUTH_NULL = "AUTH_NULL";
         private static final int ICV_LEN_UNUSED = 0;
         private static final byte[] KEY_UNUSED = new byte[0];
         private static final byte[] ICV_EMPTY = new byte[0];
 
-        private static final EspAuthNull INSTANCE = new EspAuthNull();
+        private static final EspAuthNull sInstance = new EspAuthNull();
 
         private EspAuthNull() {
             super(AUTH_NULL, KEY_UNUSED, ICV_LEN_UNUSED);
         }
 
         public static EspAuthNull getInstance() {
-            return INSTANCE;
+            return sInstance;
         }
 
         @Override
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index d206914..3b030d6 100644
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -114,6 +114,8 @@
 import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK;
 import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY;
 import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY;
+import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_TEST;
+import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_TEST_ONLY;
 import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_UNINITIALIZED;
 import static android.net.RouteInfo.RTN_UNREACHABLE;
 import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.PREFIX_OPERATION_ADDED;
@@ -10758,8 +10760,7 @@
     }
 
     @Test
-    public void testOemNetworkRequestFactoryPreferenceUninitializedThrowsError()
-            throws PackageManager.NameNotFoundException {
+    public void testOemNetworkRequestFactoryPreferenceUninitializedThrowsError() {
         @OemNetworkPreferences.OemNetworkPreference final int prefToTest =
                 OEM_NETWORK_PREFERENCE_UNINITIALIZED;
 
@@ -11026,7 +11027,48 @@
         assertThrows(UnsupportedOperationException.class,
                 () -> mService.setOemNetworkPreference(
                         createDefaultOemNetworkPreferences(networkPref),
-                        new TestOemListenerCallback()));
+                        null));
+    }
+
+    @Test
+    public void testSetOemNetworkPreferenceFailsForTestRequestWithoutPermission() {
+        // Calling setOemNetworkPreference() with a test pref requires the permission
+        // MANAGE_TEST_NETWORKS.
+        mockHasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, false);
+        @OemNetworkPreferences.OemNetworkPreference final int networkPref =
+                OEM_NETWORK_PREFERENCE_TEST;
+
+        // Act on ConnectivityService.setOemNetworkPreference()
+        assertThrows(SecurityException.class,
+                () -> mService.setOemNetworkPreference(
+                        createDefaultOemNetworkPreferences(networkPref),
+                        null));
+    }
+
+    @Test
+    public void testSetOemNetworkPreferenceFailsForInvalidTestRequest() {
+        assertSetOemNetworkPreferenceFailsForInvalidTestRequest(OEM_NETWORK_PREFERENCE_TEST);
+    }
+
+    @Test
+    public void testSetOemNetworkPreferenceFailsForInvalidTestOnlyRequest() {
+        assertSetOemNetworkPreferenceFailsForInvalidTestRequest(OEM_NETWORK_PREFERENCE_TEST_ONLY);
+    }
+
+    private void assertSetOemNetworkPreferenceFailsForInvalidTestRequest(
+            @OemNetworkPreferences.OemNetworkPreference final int oemNetworkPreferenceForTest) {
+        mockHasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, true);
+        final String secondPackage = "does.not.matter";
+
+        // A valid test request would only have a single mapping.
+        final OemNetworkPreferences pref = new OemNetworkPreferences.Builder()
+                .addNetworkPreference(TEST_PACKAGE_NAME, oemNetworkPreferenceForTest)
+                .addNetworkPreference(secondPackage, oemNetworkPreferenceForTest)
+                .build();
+
+        // Act on ConnectivityService.setOemNetworkPreference()
+        assertThrows(IllegalArgumentException.class,
+                () -> mService.setOemNetworkPreference(pref, null));
     }
 
     private void setOemNetworkPreferenceAgentConnected(final int transportType,
@@ -11203,8 +11245,18 @@
     private void setupSetOemNetworkPreferenceForPreferenceTest(
             @OemNetworkPreferences.OemNetworkPreference final int networkPrefToSetup,
             @NonNull final UidRangeParcel[] uidRanges,
-            @NonNull final String testPackageName)
-            throws Exception {
+            @NonNull final String testPackageName) throws Exception {
+        setupSetOemNetworkPreferenceForPreferenceTest(
+                networkPrefToSetup, uidRanges, testPackageName, true);
+    }
+
+    private void setupSetOemNetworkPreferenceForPreferenceTest(
+            @OemNetworkPreferences.OemNetworkPreference final int networkPrefToSetup,
+            @NonNull final UidRangeParcel[] uidRanges,
+            @NonNull final String testPackageName,
+            final boolean hasAutomotiveFeature) throws Exception {
+        mockHasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, hasAutomotiveFeature);
+
         // These tests work off a single UID therefore using 'start' is valid.
         mockGetApplicationInfo(testPackageName, uidRanges[0].start);
 
@@ -11509,6 +11561,55 @@
     }
 
     /**
+     * Test the tracked default requests allows test requests without standard setup.
+     */
+    @Test
+    public void testSetOemNetworkPreferenceAllowsValidTestRequestWithoutChecks() throws Exception {
+        @OemNetworkPreferences.OemNetworkPreference int networkPref =
+                OEM_NETWORK_PREFERENCE_TEST;
+        validateSetOemNetworkPreferenceAllowsValidTestPrefRequest(networkPref);
+    }
+
+    /**
+     * Test the tracked default requests allows test only requests without standard setup.
+     */
+    @Test
+    public void testSetOemNetworkPreferenceAllowsValidTestOnlyRequestWithoutChecks()
+            throws Exception {
+        @OemNetworkPreferences.OemNetworkPreference int networkPref =
+                OEM_NETWORK_PREFERENCE_TEST_ONLY;
+        validateSetOemNetworkPreferenceAllowsValidTestPrefRequest(networkPref);
+    }
+
+    private void validateSetOemNetworkPreferenceAllowsValidTestPrefRequest(int networkPref)
+            throws Exception {
+        // The caller must have the MANAGE_TEST_NETWORKS permission.
+        final int testPackageUid = 123;
+        final String validTestPackageName = "does.not.matter";
+        final UidRangeParcel[] uidRanges =
+                toUidRangeStableParcels(uidRangesForUids(testPackageUid));
+        mServiceContext.setPermission(
+                Manifest.permission.MANAGE_TEST_NETWORKS, PERMISSION_GRANTED);
+
+        // Put the system into a state in which setOemNetworkPreference() would normally fail. This
+        // will confirm that a valid test request can bypass these checks.
+        mockHasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, false);
+        mServiceContext.setPermission(
+                Manifest.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE, PERMISSION_DENIED);
+
+        // Validate the starting requests only includes the system default request.
+        assertEquals(1, mService.mDefaultNetworkRequests.size());
+
+        // Add an OEM default network request to track.
+        setupSetOemNetworkPreferenceForPreferenceTest(
+                networkPref, uidRanges, validTestPackageName,
+                false /* hasAutomotiveFeature */);
+
+        // Two requests should now exist; the system default and the test request.
+        assertEquals(2, mService.mDefaultNetworkRequests.size());
+    }
+
+    /**
      * Test the tracked default requests clear previous OEM requests on setOemNetworkPreference().
      */
     @Test
@@ -11520,7 +11621,7 @@
         final UidRangeParcel[] uidRanges =
                 toUidRangeStableParcels(uidRangesForUids(testPackageUid));
 
-        // Validate the starting requests only includes the fallback request.
+        // Validate the starting requests only includes the system default request.
         assertEquals(1, mService.mDefaultNetworkRequests.size());
 
         // Add an OEM default network request to track.