From c736e7639402df760b621d53e7f5e04de75a2c2f Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 14 Feb 2020 23:33:47 +0900 Subject: [PATCH] [NS D06] Implement more policies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Namely : • Explicitly selected policy • VPN policy • Validated policy These go together to avoid breaking any test, because multiple tests rely on all of these working. Test: ConnectivityServiceTest Change-Id: I7d815f87320c2becbfc93a60a3c54346ff4f47c9 --- .../server/connectivity/NetworkRanker.java | 48 +++++++++++++++++-- .../server/connectivity/NetworkRankerTest.kt | 28 +++++++++-- 2 files changed, 68 insertions(+), 8 deletions(-) diff --git a/services/core/java/com/android/server/connectivity/NetworkRanker.java b/services/core/java/com/android/server/connectivity/NetworkRanker.java index c536ab25e9..fd5a4e82de 100644 --- a/services/core/java/com/android/server/connectivity/NetworkRanker.java +++ b/services/core/java/com/android/server/connectivity/NetworkRanker.java @@ -16,6 +16,9 @@ package com.android.server.connectivity; +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; +import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; +import static android.net.NetworkCapabilities.TRANSPORT_VPN; import static android.net.NetworkScore.POLICY_IGNORE_ON_WIFI; import static com.android.internal.util.FunctionalUtils.findFirst; @@ -42,8 +45,15 @@ public class NetworkRanker { @NonNull final Collection nais) { final ArrayList candidates = new ArrayList<>(nais); candidates.removeIf(nai -> !nai.satisfies(request)); - // Enforce policy. - filterBadWifiAvoidancePolicy(candidates); + + // Enforce policy. The order in which the policy is computed is essential, because each + // step may remove some of the candidates. For example, filterValidated drops non-validated + // networks in presence of validated networks for INTERNET requests, but the bad wifi + // avoidance policy takes priority over this, so it must be done before. + filterVpn(candidates); + filterExplicitlySelected(candidates); + filterBadWifiAvoidance(candidates); + filterValidated(request, candidates); NetworkAgentInfo bestNetwork = null; int bestScore = Integer.MIN_VALUE; @@ -57,9 +67,27 @@ public class NetworkRanker { return bestNetwork; } - // If some network with wifi transport is present, drop all networks with POLICY_IGNORE_ON_WIFI. - private void filterBadWifiAvoidancePolicy( + // If a network is a VPN it has priority. + private void filterVpn(@NonNull final ArrayList candidates) { + final NetworkAgentInfo vpn = findFirst(candidates, + nai -> nai.networkCapabilities.hasTransport(TRANSPORT_VPN)); + if (null == vpn) return; // No VPN : this policy doesn't apply. + candidates.removeIf(nai -> !nai.networkCapabilities.hasTransport(TRANSPORT_VPN)); + } + + // If some network is explicitly selected and set to accept unvalidated connectivity, then + // drop all networks that are not explicitly selected. + private void filterExplicitlySelected( @NonNull final ArrayList candidates) { + final NetworkAgentInfo explicitlySelected = findFirst(candidates, + nai -> nai.networkAgentConfig.explicitlySelected + && nai.networkAgentConfig.acceptUnvalidated); + if (null == explicitlySelected) return; // No explicitly selected network accepting unvalid + candidates.removeIf(nai -> !nai.networkAgentConfig.explicitlySelected); + } + + // If some network with wifi transport is present, drop all networks with POLICY_IGNORE_ON_WIFI. + private void filterBadWifiAvoidance(@NonNull final ArrayList candidates) { final NetworkAgentInfo wifi = findFirst(candidates, nai -> nai.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) && nai.everValidated @@ -71,4 +99,16 @@ public class NetworkRanker { if (null == wifi) return; // No wifi : this policy doesn't apply candidates.removeIf(nai -> nai.getNetworkScore().hasPolicy(POLICY_IGNORE_ON_WIFI)); } + + // If some network is validated and the request asks for INTERNET, drop all networks that are + // not validated. + private void filterValidated(@NonNull final NetworkRequest request, + @NonNull final ArrayList candidates) { + if (!request.hasCapability(NET_CAPABILITY_INTERNET)) return; + final NetworkAgentInfo validated = findFirst(candidates, + nai -> nai.networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)); + if (null == validated) return; // No validated network + candidates.removeIf(nai -> + !nai.networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)); + } } diff --git a/tests/net/java/com/android/server/connectivity/NetworkRankerTest.kt b/tests/net/java/com/android/server/connectivity/NetworkRankerTest.kt index a6b371a23b..2b0c2c7215 100644 --- a/tests/net/java/com/android/server/connectivity/NetworkRankerTest.kt +++ b/tests/net/java/com/android/server/connectivity/NetworkRankerTest.kt @@ -16,8 +16,14 @@ package com.android.server.connectivity +import android.net.ConnectivityManager.TYPE_WIFI +import android.net.LinkProperties +import android.net.Network +import android.net.NetworkAgentConfig import android.net.NetworkCapabilities +import android.net.NetworkInfo import android.net.NetworkRequest +import android.net.NetworkScore import androidx.test.filters.SmallTest import androidx.test.runner.AndroidJUnit4 import org.junit.Test @@ -33,10 +39,24 @@ import kotlin.test.assertNull class NetworkRankerTest { private val ranker = NetworkRanker() - 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() + private fun makeNai(satisfy: Boolean, score: Int) = object : NetworkAgentInfo( + null /* messenger */, + null /* asyncChannel*/, + Network(100), + NetworkInfo(TYPE_WIFI, 0 /* subtype */, "" /* typename */, "" /* subtypename */), + LinkProperties(), + NetworkCapabilities(), + NetworkScore.Builder().setLegacyScore(score).build(), + null /* context */, + null /* handler */, + NetworkAgentConfig(), + null /* connectivityService */, + null /* netd */, + null /* dnsResolver */, + null /* networkManagementService */, + 0 /* factorySerialNumber */) { + override fun satisfies(request: NetworkRequest?): Boolean = satisfy + override fun getCurrentScore(): Int = score } @Test