[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
This commit is contained in:
Chalard Jean
2020-02-14 23:33:47 +09:00
parent 822a150c03
commit c736e76394
2 changed files with 68 additions and 8 deletions

View File

@@ -16,6 +16,9 @@
package com.android.server.connectivity; 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 android.net.NetworkScore.POLICY_IGNORE_ON_WIFI;
import static com.android.internal.util.FunctionalUtils.findFirst; import static com.android.internal.util.FunctionalUtils.findFirst;
@@ -42,8 +45,15 @@ public class NetworkRanker {
@NonNull final Collection<NetworkAgentInfo> nais) { @NonNull final Collection<NetworkAgentInfo> nais) {
final ArrayList<NetworkAgentInfo> candidates = new ArrayList<>(nais); final ArrayList<NetworkAgentInfo> candidates = new ArrayList<>(nais);
candidates.removeIf(nai -> !nai.satisfies(request)); 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; NetworkAgentInfo bestNetwork = null;
int bestScore = Integer.MIN_VALUE; int bestScore = Integer.MIN_VALUE;
@@ -57,9 +67,27 @@ public class NetworkRanker {
return bestNetwork; return bestNetwork;
} }
// If some network with wifi transport is present, drop all networks with POLICY_IGNORE_ON_WIFI. // If a network is a VPN it has priority.
private void filterBadWifiAvoidancePolicy( 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) { @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, final NetworkAgentInfo wifi = findFirst(candidates,
nai -> nai.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) nai -> nai.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
&& nai.everValidated && nai.everValidated
@@ -71,4 +99,16 @@ public class NetworkRanker {
if (null == wifi) return; // No wifi : this policy doesn't apply if (null == wifi) return; // No wifi : this policy doesn't apply
candidates.removeIf(nai -> nai.getNetworkScore().hasPolicy(POLICY_IGNORE_ON_WIFI)); 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));
}
} }

View File

@@ -16,8 +16,14 @@
package com.android.server.connectivity 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.NetworkCapabilities
import android.net.NetworkInfo
import android.net.NetworkRequest import android.net.NetworkRequest
import android.net.NetworkScore
import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4 import androidx.test.runner.AndroidJUnit4
import org.junit.Test import org.junit.Test
@@ -33,10 +39,24 @@ import kotlin.test.assertNull
class NetworkRankerTest { class NetworkRankerTest {
private val ranker = NetworkRanker() private val ranker = NetworkRanker()
private fun makeNai(satisfy: Boolean, score: Int) = mock(NetworkAgentInfo::class.java).also { private fun makeNai(satisfy: Boolean, score: Int) = object : NetworkAgentInfo(
doReturn(satisfy).`when`(it).satisfies(any()) null /* messenger */,
doReturn(score).`when`(it).currentScore null /* asyncChannel*/,
it.networkCapabilities = NetworkCapabilities() 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 @Test