Merge "register callback to pull NetworkBpfMapInfo atom"
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 1e8babf..6e30fd1 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -205,6 +205,9 @@
     },
     {
       "path": "packages/modules/CaptivePortalLogin"
+    },
+    {
+      "path": "vendor/xts/gts-tests/hostsidetests/networkstack"
     }
   ]
 }
diff --git a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
index 880a285..c6d2b3b 100644
--- a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
+++ b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
@@ -139,6 +139,9 @@
     // Kernel treats a confirmed UDP connection which active after two seconds as stream mode.
     // See upstream commit b7b1d02fc43925a4d569ec221715db2dfa1ce4f5.
     private static final int UDP_STREAM_TS_MS = 2000;
+    // Give slack time for waiting UDP stream mode because handling conntrack event in user space
+    // may not in precise time. Used to reduce the flaky rate.
+    private static final int UDP_STREAM_SLACK_MS = 500;
     // Per RX UDP packet size: iphdr (20) + udphdr (8) + payload (2) = 30 bytes.
     private static final int RX_UDP_PACKET_SIZE = 30;
     private static final int RX_UDP_PACKET_COUNT = 456;
@@ -1171,6 +1174,9 @@
             Thread.sleep(UDP_STREAM_TS_MS);
             sendUploadPacketUdp(srcMac, dstMac, clientIp, remoteIp, tester, false /* is4To6 */);
 
+            // Give a slack time for handling conntrack event in user space.
+            Thread.sleep(UDP_STREAM_SLACK_MS);
+
             // [1] Verify IPv4 upstream rule map.
             final HashMap<Tether4Key, Tether4Value> upstreamMap = pollRawMapFromDump(
                     Tether4Key.class, Tether4Value.class, DUMPSYS_RAWMAP_ARG_UPSTREAM4);
diff --git a/service-t/src/com/android/server/ethernet/EthernetConfigStore.java b/service-t/src/com/android/server/ethernet/EthernetConfigStore.java
index 17abbab..156b526 100644
--- a/service-t/src/com/android/server/ethernet/EthernetConfigStore.java
+++ b/service-t/src/com/android/server/ethernet/EthernetConfigStore.java
@@ -116,6 +116,10 @@
     }
 
     public void write(String iface, IpConfiguration config) {
+        final File directory = new File(APEX_IP_CONFIG_FILE_PATH);
+        if (!directory.exists()) {
+            directory.mkdirs();
+        }
         write(iface, config, APEX_IP_CONFIG_FILE_PATH + CONFIG_FILE);
     }
 
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index 36c81dd..7e63761 100755
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -4584,7 +4584,7 @@
             if (req.isListen() || req.isListenForBest()) {
                 continue;
             }
-            // If this Network is already the highest scoring Network for a request, or if
+            // If this Network is already the best Network for a request, or if
             // there is hope for it to become one if it validated, then it is needed.
             if (candidate.satisfies(req)) {
                 // As soon as a network is found that satisfies a request, return. Specifically for
diff --git a/service/src/com/android/server/connectivity/FullScore.java b/service/src/com/android/server/connectivity/FullScore.java
index c4754eb..22a820b 100644
--- a/service/src/com/android/server/connectivity/FullScore.java
+++ b/service/src/com/android/server/connectivity/FullScore.java
@@ -23,7 +23,6 @@
 import static android.net.NetworkScore.KEEP_CONNECTED_NONE;
 import static android.net.NetworkScore.POLICY_YIELD_TO_BAD_WIFI;
 
-import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.net.NetworkAgentConfig;
 import android.net.NetworkCapabilities;
@@ -35,8 +34,6 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.MessageUtils;
 
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
 import java.util.StringJoiner;
 
 /**
@@ -49,53 +46,44 @@
 public class FullScore {
     private static final String TAG = FullScore.class.getSimpleName();
 
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = {"POLICY_"}, value = {
-            POLICY_IS_VALIDATED,
-            POLICY_IS_VPN,
-            POLICY_EVER_USER_SELECTED,
-            POLICY_ACCEPT_UNVALIDATED,
-            POLICY_IS_UNMETERED
-    })
-    public @interface Policy {
-    }
-
     // Agent-managed policies are in NetworkScore. They start from 1.
     // CS-managed policies, counting from 63 downward
     // This network is validated. CS-managed because the source of truth is in NetworkCapabilities.
     /** @hide */
     public static final int POLICY_IS_VALIDATED = 63;
 
+    // This network has been validated at least once since it was connected.
+    /** @hide */
+    public static final int POLICY_EVER_VALIDATED = 62;
+
     // This is a VPN and behaves as one for scoring purposes.
     /** @hide */
-    public static final int POLICY_IS_VPN = 62;
+    public static final int POLICY_IS_VPN = 61;
 
     // This network has been selected by the user manually from settings or a 3rd party app
     // at least once. @see NetworkAgentConfig#explicitlySelected.
     /** @hide */
-    public static final int POLICY_EVER_USER_SELECTED = 61;
+    public static final int POLICY_EVER_USER_SELECTED = 60;
 
     // The user has indicated in UI that this network should be used even if it doesn't
     // validate. @see NetworkAgentConfig#acceptUnvalidated.
     /** @hide */
-    public static final int POLICY_ACCEPT_UNVALIDATED = 60;
+    public static final int POLICY_ACCEPT_UNVALIDATED = 59;
+
+    // The user explicitly said in UI to avoid this network when unvalidated.
+    // TODO : remove setAvoidUnvalidated and instead disconnect the network when the user
+    // chooses to move away from this network, and remove this flag.
+    /** @hide */
+    public static final int POLICY_AVOIDED_WHEN_UNVALIDATED = 58;
 
     // This network is unmetered. @see NetworkCapabilities.NET_CAPABILITY_NOT_METERED.
     /** @hide */
-    public static final int POLICY_IS_UNMETERED = 59;
+    public static final int POLICY_IS_UNMETERED = 57;
 
     // This network is invincible. This is useful for offers until there is an API to listen
     // to requests.
     /** @hide */
-    public static final int POLICY_IS_INVINCIBLE = 58;
-
-    // This network has been validated at least once since it was connected, but not explicitly
-    // avoided in UI.
-    // TODO : remove setAvoidUnvalidated and instead disconnect the network when the user
-    // chooses to move away from this network, and remove this flag.
-    /** @hide */
-    public static final int POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD = 57;
+    public static final int POLICY_IS_INVINCIBLE = 56;
 
     // The network agent has communicated that this network no longer functions, and the underlying
     // native network has been destroyed. The network will still be reported to clients as connected
@@ -103,7 +91,7 @@
     // This network should lose to an identical network that has not been destroyed, but should
     // otherwise be scored exactly the same.
     /** @hide */
-    public static final int POLICY_IS_DESTROYED = 56;
+    public static final int POLICY_IS_DESTROYED = 55;
 
     // To help iterate when printing
     @VisibleForTesting
@@ -154,6 +142,7 @@
      * @param caps the NetworkCapabilities of the network
      * @param config the NetworkAgentConfig of the network
      * @param everValidated whether this network has ever validated
+     * @param avoidUnvalidated whether the user said in UI to avoid this network when unvalidated
      * @param yieldToBadWiFi whether this network yields to a previously validated wifi gone bad
      * @param destroyed whether this network has been destroyed pending a replacement connecting
      * @return a FullScore that is appropriate to use for ranking.
@@ -163,18 +152,19 @@
     // connectivity for backward compatibility.
     public static FullScore fromNetworkScore(@NonNull final NetworkScore score,
             @NonNull final NetworkCapabilities caps, @NonNull final NetworkAgentConfig config,
-            final boolean everValidated, final boolean yieldToBadWiFi, final boolean destroyed) {
+            final boolean everValidated, final boolean avoidUnvalidated,
+            final boolean yieldToBadWiFi, final boolean destroyed) {
         return withPolicies(score.getPolicies(),
                 score.getKeepConnectedReason(),
                 caps.hasCapability(NET_CAPABILITY_VALIDATED),
-                caps.hasTransport(TRANSPORT_VPN),
-                caps.hasCapability(NET_CAPABILITY_NOT_METERED),
-                everValidated,
+                everValidated, caps.hasTransport(TRANSPORT_VPN),
                 config.explicitlySelected,
                 config.acceptUnvalidated,
+                avoidUnvalidated,
+                caps.hasCapability(NET_CAPABILITY_NOT_METERED),
                 yieldToBadWiFi,
-                destroyed,
-                false /* invincible */); // only prospective scores can be invincible
+                false /* invincible */, // only prospective scores can be invincible
+                destroyed);
     }
 
     /**
@@ -194,25 +184,29 @@
             @NonNull final NetworkCapabilities caps, final boolean yieldToBadWiFi) {
         // If the network offers Internet access, it may validate.
         final boolean mayValidate = caps.hasCapability(NET_CAPABILITY_INTERNET);
-        // VPN transports are known in advance.
-        final boolean vpn = caps.hasTransport(TRANSPORT_VPN);
-        // Prospective scores are always unmetered, because unmetered networks are stronger
-        // than metered networks, and it's not known in advance whether the network is metered.
-        final boolean unmetered = true;
         // If the offer may validate, then it should be considered to have validated at some point
         final boolean everValidated = mayValidate;
+        // VPN transports are known in advance.
+        final boolean vpn = caps.hasTransport(TRANSPORT_VPN);
         // The network hasn't been chosen by the user (yet, at least).
         final boolean everUserSelected = false;
         // Don't assume the user will accept unvalidated connectivity.
         final boolean acceptUnvalidated = false;
+        // A prospective network is never avoided when unvalidated, because the user has never
+        // had the opportunity to say so in UI.
+        final boolean avoidUnvalidated = false;
+        // Prospective scores are always unmetered, because unmetered networks are stronger
+        // than metered networks, and it's not known in advance whether the network is metered.
+        final boolean unmetered = true;
         // A network can only be destroyed once it has connected.
         final boolean destroyed = false;
         // A prospective score is invincible if the legacy int in the filter is over the maximum
         // score.
         final boolean invincible = score.getLegacyInt() > NetworkRanker.LEGACY_INT_MAX;
         return withPolicies(score.getPolicies(), KEEP_CONNECTED_NONE,
-                mayValidate, vpn, unmetered, everValidated, everUserSelected, acceptUnvalidated,
-                yieldToBadWiFi, destroyed, invincible);
+                mayValidate, everValidated, vpn, everUserSelected, acceptUnvalidated,
+                avoidUnvalidated, unmetered,
+                yieldToBadWiFi, invincible, destroyed);
     }
 
     /**
@@ -228,18 +222,19 @@
     public FullScore mixInScore(@NonNull final NetworkCapabilities caps,
             @NonNull final NetworkAgentConfig config,
             final boolean everValidated,
+            final boolean avoidUnvalidated,
             final boolean yieldToBadWifi,
             final boolean destroyed) {
         return withPolicies(mPolicies, mKeepConnectedReason,
                 caps.hasCapability(NET_CAPABILITY_VALIDATED),
-                caps.hasTransport(TRANSPORT_VPN),
-                caps.hasCapability(NET_CAPABILITY_NOT_METERED),
-                everValidated,
+                everValidated, caps.hasTransport(TRANSPORT_VPN),
                 config.explicitlySelected,
                 config.acceptUnvalidated,
+                avoidUnvalidated,
+                caps.hasCapability(NET_CAPABILITY_NOT_METERED),
                 yieldToBadWifi,
-                destroyed,
-                false /* invincible */); // only prospective scores can be invincible
+                false /* invincible */, // only prospective scores can be invincible
+                destroyed);
     }
 
     // TODO : this shouldn't manage bad wifi avoidance – instead this should be done by the
@@ -248,24 +243,26 @@
     private static FullScore withPolicies(final long externalPolicies,
             @KeepConnectedReason final int keepConnectedReason,
             final boolean isValidated,
-            final boolean isVpn,
-            final boolean isUnmetered,
             final boolean everValidated,
+            final boolean isVpn,
             final boolean everUserSelected,
             final boolean acceptUnvalidated,
+            final boolean avoidUnvalidated,
+            final boolean isUnmetered,
             final boolean yieldToBadWiFi,
-            final boolean destroyed,
-            final boolean invincible) {
+            final boolean invincible,
+            final boolean destroyed) {
         return new FullScore((externalPolicies & EXTERNAL_POLICIES_MASK)
                 | (isValidated       ? 1L << POLICY_IS_VALIDATED : 0)
+                | (everValidated     ? 1L << POLICY_EVER_VALIDATED : 0)
                 | (isVpn             ? 1L << POLICY_IS_VPN : 0)
-                | (isUnmetered       ? 1L << POLICY_IS_UNMETERED : 0)
-                | (everValidated     ? 1L << POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD : 0)
                 | (everUserSelected  ? 1L << POLICY_EVER_USER_SELECTED : 0)
                 | (acceptUnvalidated ? 1L << POLICY_ACCEPT_UNVALIDATED : 0)
+                | (avoidUnvalidated  ? 1L << POLICY_AVOIDED_WHEN_UNVALIDATED : 0)
+                | (isUnmetered       ? 1L << POLICY_IS_UNMETERED : 0)
                 | (yieldToBadWiFi    ? 1L << POLICY_YIELD_TO_BAD_WIFI : 0)
-                | (destroyed         ? 1L << POLICY_IS_DESTROYED : 0)
-                | (invincible        ? 1L << POLICY_IS_INVINCIBLE : 0),
+                | (invincible        ? 1L << POLICY_IS_INVINCIBLE : 0)
+                | (destroyed         ? 1L << POLICY_IS_DESTROYED : 0),
                 keepConnectedReason);
     }
 
diff --git a/service/src/com/android/server/connectivity/NetworkAgentInfo.java b/service/src/com/android/server/connectivity/NetworkAgentInfo.java
index d4d7d96..654d195 100644
--- a/service/src/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/service/src/com/android/server/connectivity/NetworkAgentInfo.java
@@ -970,8 +970,8 @@
             @NonNull final NetworkCapabilities nc) {
         final NetworkCapabilities oldNc = networkCapabilities;
         networkCapabilities = nc;
-        mScore = mScore.mixInScore(networkCapabilities, networkAgentConfig, everValidatedForYield(),
-                yieldToBadWiFi(), isDestroyed());
+        mScore = mScore.mixInScore(networkCapabilities, networkAgentConfig, everValidated(),
+                0L != getAvoidUnvalidated(), yieldToBadWiFi(), isDestroyed());
         final NetworkMonitorManager nm = mNetworkMonitor;
         if (nm != null) {
             nm.notifyNetworkCapabilitiesChanged(nc);
@@ -1174,7 +1174,7 @@
      */
     public void setScore(final NetworkScore score) {
         mScore = FullScore.fromNetworkScore(score, networkCapabilities, networkAgentConfig,
-                everValidatedForYield(), yieldToBadWiFi(), isDestroyed());
+                everValidated(), 0L == getAvoidUnvalidated(), yieldToBadWiFi(), isDestroyed());
     }
 
     /**
@@ -1184,11 +1184,7 @@
      */
     public void updateScoreForNetworkAgentUpdate() {
         mScore = mScore.mixInScore(networkCapabilities, networkAgentConfig,
-                everValidatedForYield(), yieldToBadWiFi(), isDestroyed());
-    }
-
-    private boolean everValidatedForYield() {
-        return everValidated() && 0L == mAvoidUnvalidated;
+                everValidated(), 0L != getAvoidUnvalidated(), yieldToBadWiFi(), isDestroyed());
     }
 
     /**
diff --git a/service/src/com/android/server/connectivity/NetworkRanker.java b/service/src/com/android/server/connectivity/NetworkRanker.java
index babc353..f2c6aa1 100644
--- a/service/src/com/android/server/connectivity/NetworkRanker.java
+++ b/service/src/com/android/server/connectivity/NetworkRanker.java
@@ -26,8 +26,9 @@
 
 import static com.android.net.module.util.CollectionUtils.filter;
 import static com.android.server.connectivity.FullScore.POLICY_ACCEPT_UNVALIDATED;
+import static com.android.server.connectivity.FullScore.POLICY_AVOIDED_WHEN_UNVALIDATED;
 import static com.android.server.connectivity.FullScore.POLICY_EVER_USER_SELECTED;
-import static com.android.server.connectivity.FullScore.POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD;
+import static com.android.server.connectivity.FullScore.POLICY_EVER_VALIDATED;
 import static com.android.server.connectivity.FullScore.POLICY_IS_DESTROYED;
 import static com.android.server.connectivity.FullScore.POLICY_IS_INVINCIBLE;
 import static com.android.server.connectivity.FullScore.POLICY_IS_VALIDATED;
@@ -104,7 +105,9 @@
     }
 
     private <T extends Scoreable> boolean isBadWiFi(@NonNull final T candidate) {
-        return candidate.getScore().hasPolicy(POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD)
+        final FullScore score = candidate.getScore();
+        return score.hasPolicy(POLICY_EVER_VALIDATED)
+                && !score.hasPolicy(POLICY_AVOIDED_WHEN_UNVALIDATED)
                 && candidate.getCapsNoCopy().hasTransport(TRANSPORT_WIFI);
     }
 
diff --git a/tests/unit/java/com/android/server/connectivity/FullScoreTest.kt b/tests/unit/java/com/android/server/connectivity/FullScoreTest.kt
index a194131..c8a62be 100644
--- a/tests/unit/java/com/android/server/connectivity/FullScoreTest.kt
+++ b/tests/unit/java/com/android/server/connectivity/FullScoreTest.kt
@@ -66,7 +66,8 @@
             if (vpn) addTransportType(NetworkCapabilities.TRANSPORT_VPN)
             if (validated) addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
         }.build()
-        return mixInScore(nc, nac, validated, false /* yieldToBadWifi */, destroyed)
+        return mixInScore(nc, nac, validated, false /* avoidUnvalidated */,
+                false /* yieldToBadWifi */, destroyed)
     }
 
     private val TAG = this::class.simpleName
diff --git a/tests/unit/java/com/android/server/connectivity/NetworkRankerTest.kt b/tests/unit/java/com/android/server/connectivity/NetworkRankerTest.kt
index 6f9f430..8b1c510 100644
--- a/tests/unit/java/com/android/server/connectivity/NetworkRankerTest.kt
+++ b/tests/unit/java/com/android/server/connectivity/NetworkRankerTest.kt
@@ -25,7 +25,8 @@
 import android.net.NetworkScore.POLICY_YIELD_TO_BAD_WIFI
 import android.os.Build
 import androidx.test.filters.SmallTest
-import com.android.server.connectivity.FullScore.POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD
+import com.android.server.connectivity.FullScore.POLICY_AVOIDED_WHEN_UNVALIDATED
+import com.android.server.connectivity.FullScore.POLICY_EVER_VALIDATED
 import com.android.server.connectivity.FullScore.POLICY_IS_VALIDATED
 import com.android.testutils.DevSdkIgnoreRule
 import com.android.testutils.DevSdkIgnoreRunner
@@ -61,8 +62,7 @@
     @Test
     fun testYieldToBadWiFiOneCellOneBadWiFi() {
         // Bad wifi wins against yielding validated cell
-        val winner = TestScore(score(POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD),
-                caps(TRANSPORT_WIFI))
+        val winner = TestScore(score(POLICY_EVER_VALIDATED), caps(TRANSPORT_WIFI))
         val scores = listOf(
                 winner,
                 TestScore(score(POLICY_YIELD_TO_BAD_WIFI, POLICY_IS_VALIDATED),
@@ -72,14 +72,26 @@
     }
 
     @Test
+    fun testYieldToBadWifiAvoidUnvalidated() {
+        // Bad wifi avoided when unvalidated loses against yielding validated cell
+        val winner = TestScore(score(POLICY_YIELD_TO_BAD_WIFI, POLICY_IS_VALIDATED),
+                caps(TRANSPORT_CELLULAR))
+        val scores = listOf(
+                winner,
+                TestScore(score(POLICY_EVER_VALIDATED, POLICY_AVOIDED_WHEN_UNVALIDATED),
+                        caps(TRANSPORT_WIFI))
+        )
+        assertEquals(winner, mRanker.getBestNetworkByPolicy(scores, null))
+    }
+
+    @Test
     fun testYieldToBadWiFiOneCellTwoBadWiFi() {
         // Bad wifi wins against yielding validated cell. Prefer the one that's primary.
-        val winner = TestScore(score(POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD,
+        val winner = TestScore(score(POLICY_EVER_VALIDATED,
                 POLICY_TRANSPORT_PRIMARY), caps(TRANSPORT_WIFI))
         val scores = listOf(
                 winner,
-                TestScore(score(POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD),
-                        caps(TRANSPORT_WIFI)),
+                TestScore(score(POLICY_EVER_VALIDATED), caps(TRANSPORT_WIFI)),
                 TestScore(score(POLICY_YIELD_TO_BAD_WIFI, POLICY_IS_VALIDATED),
                         caps(TRANSPORT_CELLULAR))
         )
@@ -90,8 +102,7 @@
     fun testYieldToBadWiFiOneCellTwoBadWiFiOneNotAvoided() {
         // Bad wifi ever validated wins against bad wifi that never was validated (or was
         // avoided when bad).
-        val winner = TestScore(score(POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD),
-                caps(TRANSPORT_WIFI))
+        val winner = TestScore(score(POLICY_EVER_VALIDATED), caps(TRANSPORT_WIFI))
         val scores = listOf(
                 winner,
                 TestScore(score(), caps(TRANSPORT_WIFI)),
@@ -104,12 +115,12 @@
     @Test
     fun testYieldToBadWiFiOneCellOneBadWiFiOneGoodWiFi() {
         // Good wifi wins
-        val winner = TestScore(score(POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD,
-                POLICY_IS_VALIDATED), caps(TRANSPORT_WIFI))
+        val winner = TestScore(score(POLICY_EVER_VALIDATED, POLICY_IS_VALIDATED),
+                caps(TRANSPORT_WIFI))
         val scores = listOf(
                 winner,
-                TestScore(score(POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD,
-                        POLICY_TRANSPORT_PRIMARY), caps(TRANSPORT_WIFI)),
+                TestScore(score(POLICY_EVER_VALIDATED, POLICY_TRANSPORT_PRIMARY),
+                        caps(TRANSPORT_WIFI)),
                 TestScore(score(POLICY_YIELD_TO_BAD_WIFI, POLICY_IS_VALIDATED),
                         caps(TRANSPORT_CELLULAR))
         )
@@ -122,8 +133,8 @@
         val winner = TestScore(score(POLICY_IS_VALIDATED), caps(TRANSPORT_CELLULAR))
         val scores = listOf(
                 winner,
-                TestScore(score(POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD,
-                        POLICY_TRANSPORT_PRIMARY), caps(TRANSPORT_WIFI)),
+                TestScore(score(POLICY_EVER_VALIDATED, POLICY_TRANSPORT_PRIMARY),
+                        caps(TRANSPORT_WIFI)),
                 TestScore(score(POLICY_YIELD_TO_BAD_WIFI, POLICY_IS_VALIDATED),
                         caps(TRANSPORT_CELLULAR))
         )
@@ -136,8 +147,8 @@
         val winner = TestScore(score(POLICY_IS_VALIDATED), caps(TRANSPORT_WIFI))
         val scores = listOf(
                 winner,
-                TestScore(score(POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD,
-                        POLICY_TRANSPORT_PRIMARY), caps(TRANSPORT_WIFI)),
+                TestScore(score(POLICY_EVER_VALIDATED, POLICY_TRANSPORT_PRIMARY),
+                        caps(TRANSPORT_WIFI)),
                 TestScore(score(POLICY_IS_VALIDATED), caps(TRANSPORT_CELLULAR)),
                 TestScore(score(POLICY_YIELD_TO_BAD_WIFI, POLICY_IS_VALIDATED),
                         caps(TRANSPORT_CELLULAR))
@@ -164,8 +175,7 @@
                 caps(TRANSPORT_CELLULAR))
         val scores = listOf(
                 winner,
-                TestScore(score(POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD,
-                        POLICY_EXITING), caps(TRANSPORT_WIFI))
+                TestScore(score(POLICY_EVER_VALIDATED, POLICY_EXITING), caps(TRANSPORT_WIFI))
         )
         assertEquals(winner, mRanker.getBestNetworkByPolicy(scores, null))
     }
diff --git a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
index 2febd2f..e053252 100644
--- a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -88,7 +88,6 @@
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
 
 import android.annotation.NonNull;
 import android.app.AlarmManager;
@@ -344,9 +343,9 @@
 
         final Context context = InstrumentationRegistry.getContext();
         mServiceContext = new MockContext(context);
-        when(mLocationPermissionChecker.checkCallersLocationPermission(
-                any(), any(), anyInt(), anyBoolean(), any())).thenReturn(true);
-        when(sWifiInfo.getNetworkKey()).thenReturn(TEST_WIFI_NETWORK_KEY);
+        doReturn(true).when(mLocationPermissionChecker).checkCallersLocationPermission(
+                any(), any(), anyInt(), anyBoolean(), any());
+        doReturn(TEST_WIFI_NETWORK_KEY).when(sWifiInfo).getNetworkKey();
         mStatsDir = TestIoUtils.createTemporaryDirectory(getClass().getSimpleName());
         mLegacyStatsDir = TestIoUtils.createTemporaryDirectory(
                 getClass().getSimpleName() + "-legacy");
@@ -1079,8 +1078,8 @@
 
     // TODO: support per IMSI state
     private void setMobileRatTypeAndWaitForIdle(int ratType) {
-        when(mNetworkStatsSubscriptionsMonitor.getRatTypeForSubscriberId(anyString()))
-                .thenReturn(ratType);
+        doReturn(ratType).when(mNetworkStatsSubscriptionsMonitor)
+                .getRatTypeForSubscriberId(anyString());
         mService.handleOnCollapsedRatTypeChanged();
         HandlerUtils.waitForIdle(mHandlerThread, WAIT_TIMEOUT);
     }
@@ -1524,8 +1523,8 @@
         mUsageCallback.expectOnThresholdReached(request);
 
         // Allow binder to disconnect
-        when(mUsageCallbackBinder.unlinkToDeath(any(IBinder.DeathRecipient.class), anyInt()))
-                .thenReturn(true);
+        doReturn(true).when(mUsageCallbackBinder)
+                .unlinkToDeath(any(IBinder.DeathRecipient.class), anyInt());
 
         // Unregister request
         mService.unregisterUsageRequest(request);
@@ -1707,7 +1706,7 @@
     }
 
     private void setCombineSubtypeEnabled(boolean enable) {
-        when(mSettings.getCombineSubtypeEnabled()).thenReturn(enable);
+        doReturn(enable).when(mSettings).getCombineSubtypeEnabled();
         mHandler.post(() -> mContentObserver.onChange(false, Settings.Global
                     .getUriFor(Settings.Global.NETSTATS_COMBINE_SUBTYPE_ENABLED)));
         waitForIdle();
@@ -1867,8 +1866,8 @@
      */
     @Test
     public void testEnforceTemplateLocationPermission() throws Exception {
-        when(mLocationPermissionChecker.checkCallersLocationPermission(
-                any(), any(), anyInt(), anyBoolean(), any())).thenReturn(false);
+        doReturn(false).when(mLocationPermissionChecker)
+                .checkCallersLocationPermission(any(), any(), anyInt(), anyBoolean(), any());
         initWifiStats(buildWifiState(true, TEST_IFACE, IMSI_1));
         assertThrows(SecurityException.class, () ->
                 assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0));
@@ -1876,8 +1875,8 @@
         assertNetworkTotal(sTemplateCarrierWifi1, 0L, 0L, 0L, 0L, 0);
         assertNetworkTotal(sTemplateImsi1, 0L, 0L, 0L, 0L, 0);
 
-        when(mLocationPermissionChecker.checkCallersLocationPermission(
-                any(), any(), anyInt(), anyBoolean(), any())).thenReturn(true);
+        doReturn(true).when(mLocationPermissionChecker)
+                .checkCallersLocationPermission(any(), any(), anyInt(), anyBoolean(), any());
         assertNetworkTotal(sTemplateCarrierWifi1, 0L, 0L, 0L, 0L, 0);
         assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
         assertNetworkTotal(sTemplateImsi1, 0L, 0L, 0L, 0L, 0);
@@ -2205,11 +2204,11 @@
     }
 
     private void mockNetworkStatsSummaryDev(NetworkStats summary) throws Exception {
-        when(mStatsFactory.readNetworkStatsSummaryDev()).thenReturn(summary);
+        doReturn(summary).when(mStatsFactory).readNetworkStatsSummaryDev();
     }
 
     private void mockNetworkStatsSummaryXt(NetworkStats summary) throws Exception {
-        when(mStatsFactory.readNetworkStatsSummaryXt()).thenReturn(summary);
+        doReturn(summary).when(mStatsFactory).readNetworkStatsSummaryXt();
     }
 
     private void mockNetworkStatsUidDetail(NetworkStats detail) throws Exception {
@@ -2219,11 +2218,11 @@
 
     private void mockNetworkStatsUidDetail(NetworkStats detail,
             TetherStatsParcel[] tetherStatsParcels) throws Exception {
-        when(mStatsFactory.readNetworkStatsDetail(UID_ALL, INTERFACES_ALL, TAG_ALL))
-                .thenReturn(detail);
+        doReturn(detail).when(mStatsFactory)
+                .readNetworkStatsDetail(UID_ALL, INTERFACES_ALL, TAG_ALL);
 
         // also include tethering details, since they are folded into UID
-        when(mNetd.tetherGetStats()).thenReturn(tetherStatsParcels);
+        doReturn(tetherStatsParcels).when(mNetd).tetherGetStats();
     }
 
     private void mockDefaultSettings() throws Exception {
@@ -2231,22 +2230,22 @@
     }
 
     private void mockSettings(long bucketDuration, long deleteAge) throws Exception {
-        when(mSettings.getPollInterval()).thenReturn(HOUR_IN_MILLIS);
-        when(mSettings.getPollDelay()).thenReturn(0L);
-        when(mSettings.getSampleEnabled()).thenReturn(true);
-        when(mSettings.getCombineSubtypeEnabled()).thenReturn(false);
+        doReturn(HOUR_IN_MILLIS).when(mSettings).getPollInterval();
+        doReturn(0L).when(mSettings).getPollDelay();
+        doReturn(true).when(mSettings).getSampleEnabled();
+        doReturn(false).when(mSettings).getCombineSubtypeEnabled();
 
         final Config config = new Config(bucketDuration, deleteAge, deleteAge);
-        when(mSettings.getDevConfig()).thenReturn(config);
-        when(mSettings.getXtConfig()).thenReturn(config);
-        when(mSettings.getUidConfig()).thenReturn(config);
-        when(mSettings.getUidTagConfig()).thenReturn(config);
+        doReturn(config).when(mSettings).getDevConfig();
+        doReturn(config).when(mSettings).getXtConfig();
+        doReturn(config).when(mSettings).getUidConfig();
+        doReturn(config).when(mSettings).getUidTagConfig();
 
-        when(mSettings.getGlobalAlertBytes(anyLong())).thenReturn(MB_IN_BYTES);
-        when(mSettings.getDevPersistBytes(anyLong())).thenReturn(MB_IN_BYTES);
-        when(mSettings.getXtPersistBytes(anyLong())).thenReturn(MB_IN_BYTES);
-        when(mSettings.getUidPersistBytes(anyLong())).thenReturn(MB_IN_BYTES);
-        when(mSettings.getUidTagPersistBytes(anyLong())).thenReturn(MB_IN_BYTES);
+        doReturn(MB_IN_BYTES).when(mSettings).getGlobalAlertBytes(anyLong());
+        doReturn(MB_IN_BYTES).when(mSettings).getDevPersistBytes(anyLong());
+        doReturn(MB_IN_BYTES).when(mSettings).getXtPersistBytes(anyLong());
+        doReturn(MB_IN_BYTES).when(mSettings).getUidPersistBytes(anyLong());
+        doReturn(MB_IN_BYTES).when(mSettings).getUidTagPersistBytes(anyLong());
     }
 
     private void assertStatsFilesExist(boolean exist) {