[NS D06] Implement more policies
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
diff --git a/services/core/java/com/android/server/connectivity/NetworkRanker.java b/services/core/java/com/android/server/connectivity/NetworkRanker.java
index c536ab2..fd5a4e8 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 @@
@NonNull final Collection<NetworkAgentInfo> nais) {
final ArrayList<NetworkAgentInfo> 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 @@
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<NetworkAgentInfo> 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<NetworkAgentInfo> 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<NetworkAgentInfo> candidates) {
final NetworkAgentInfo wifi = findFirst(candidates,
nai -> nai.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
&& nai.everValidated
@@ -71,4 +99,16 @@
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<NetworkAgentInfo> 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 a6b371a..2b0c2c7 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 @@
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