From b3c546ce0c283dbee35fb1398279f9ad82a2f37b Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 14 Feb 2020 17:05:02 +0900 Subject: [PATCH] [NS D03] Migrate the bad wifi avoidance policy Test: ConnectivityServiceTest Bug: 113554781 Change-Id: I688593cc0379a0d2042e30fbe83e549dcb02723e --- .../internal/util/FunctionalUtils.java | 20 ++++++++++++++ .../server/connectivity/NetworkRanker.java | 27 +++++++++++++++++-- .../server/connectivity/NetworkRankerTest.kt | 2 ++ 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/core/java/com/android/internal/util/FunctionalUtils.java b/core/java/com/android/internal/util/FunctionalUtils.java index 3c9791791a689..720f4feeaebed 100644 --- a/core/java/com/android/internal/util/FunctionalUtils.java +++ b/core/java/com/android/internal/util/FunctionalUtils.java @@ -16,12 +16,16 @@ package com.android.internal.util; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.os.RemoteException; import android.util.ExceptionUtils; +import java.util.Collection; import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Function; +import java.util.function.Predicate; import java.util.function.Supplier; /** @@ -218,4 +222,20 @@ public class FunctionalUtils { } } } + + /** + * Find the first element in the list that matches the predicate. + * + * The standard Java way of doing this is to use streams, which is very expensive. + * + * @return the first matching element, or null if none. + */ + @Nullable + public static T findFirst(@NonNull final Collection haystack, + @NonNull final Predicate p) { + for (final T needle : haystack) { + if (p.test(needle)) return needle; + } + return null; + } } diff --git a/services/core/java/com/android/server/connectivity/NetworkRanker.java b/services/core/java/com/android/server/connectivity/NetworkRanker.java index 1ae7dc5c36767..c536ab25e9254 100644 --- a/services/core/java/com/android/server/connectivity/NetworkRanker.java +++ b/services/core/java/com/android/server/connectivity/NetworkRanker.java @@ -16,8 +16,13 @@ package com.android.server.connectivity; +import static android.net.NetworkScore.POLICY_IGNORE_ON_WIFI; + +import static com.android.internal.util.FunctionalUtils.findFirst; + import android.annotation.NonNull; import android.annotation.Nullable; +import android.net.NetworkCapabilities; import android.net.NetworkRequest; import java.util.ArrayList; @@ -37,15 +42,33 @@ public class NetworkRanker { @NonNull final Collection nais) { final ArrayList candidates = new ArrayList<>(nais); candidates.removeIf(nai -> !nai.satisfies(request)); + // Enforce policy. + filterBadWifiAvoidancePolicy(candidates); NetworkAgentInfo bestNetwork = null; int bestScore = Integer.MIN_VALUE; for (final NetworkAgentInfo nai : candidates) { - if (nai.getCurrentScore() > bestScore) { + final int score = nai.getCurrentScore(); + if (score > bestScore) { bestNetwork = nai; - bestScore = nai.getCurrentScore(); + bestScore = score; } } return bestNetwork; } + + // If some network with wifi transport is present, drop all networks with POLICY_IGNORE_ON_WIFI. + private void filterBadWifiAvoidancePolicy( + @NonNull final ArrayList candidates) { + final NetworkAgentInfo wifi = findFirst(candidates, + nai -> nai.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) + && nai.everValidated + // Horrible hack : there is old UI that will let a user say they want to + // override the policy only for this network only at this time and it + // feeds into the following member. This old UI should probably be removed + // but for now keep backward compatibility. + && !nai.avoidUnvalidated); + if (null == wifi) return; // No wifi : this policy doesn't apply + candidates.removeIf(nai -> nai.getNetworkScore().hasPolicy(POLICY_IGNORE_ON_WIFI)); + } } diff --git a/tests/net/java/com/android/server/connectivity/NetworkRankerTest.kt b/tests/net/java/com/android/server/connectivity/NetworkRankerTest.kt index 86c91165f61b1..a6b371a23b587 100644 --- a/tests/net/java/com/android/server/connectivity/NetworkRankerTest.kt +++ b/tests/net/java/com/android/server/connectivity/NetworkRankerTest.kt @@ -16,6 +16,7 @@ package com.android.server.connectivity +import android.net.NetworkCapabilities import android.net.NetworkRequest import androidx.test.filters.SmallTest import androidx.test.runner.AndroidJUnit4 @@ -35,6 +36,7 @@ class NetworkRankerTest { private fun makeNai(satisfy: Boolean, score: Int) = mock(NetworkAgentInfo::class.java).also { doReturn(satisfy).`when`(it).satisfies(any()) doReturn(score).`when`(it).currentScore + it.networkCapabilities = NetworkCapabilities() } @Test