Loading services/core/java/com/android/server/ConnectivityService.java +6 −15 Original line number Diff line number Diff line Loading @@ -194,6 +194,7 @@ import com.android.server.connectivity.NetworkAgentInfo; import com.android.server.connectivity.NetworkDiagnostics; import com.android.server.connectivity.NetworkNotificationManager; import com.android.server.connectivity.NetworkNotificationManager.NotificationType; import com.android.server.connectivity.NetworkRanker; import com.android.server.connectivity.PermissionMonitor; import com.android.server.connectivity.ProxyTracker; import com.android.server.connectivity.Vpn; Loading Loading @@ -579,6 +580,7 @@ public class ConnectivityService extends IConnectivityManager.Stub final ConnectivityDiagnosticsHandler mConnectivityDiagnosticsHandler; private final DnsManager mDnsManager; private final NetworkRanker mNetworkRanker; private boolean mSystemReady; private Intent mInitialBroadcast; Loading Loading @@ -958,6 +960,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mMetricsLog = logger; mDefaultRequest = createDefaultInternetRequestForTransport(-1, NetworkRequest.Type.REQUEST); mNetworkRanker = new NetworkRanker(); NetworkRequestInfo defaultNRI = new NetworkRequestInfo(null, mDefaultRequest, new Binder()); mNetworkRequests.put(mDefaultRequest, defaultNRI); mNetworkRequestInfoLogs.log("REGISTER " + defaultNRI); Loading Loading @@ -6660,24 +6663,12 @@ public class ConnectivityService extends IConnectivityManager.Stub changes.addRematchedNetwork(new NetworkReassignment.NetworkBgStatePair(nai, nai.isBackgroundNetwork())); } Collections.sort(nais); for (final NetworkRequestInfo nri : mNetworkRequests.values()) { if (nri.request.isListen()) continue; // Find the top scoring network satisfying this request. NetworkAgentInfo bestNetwork = null; for (final NetworkAgentInfo nai : nais) { if (!nai.satisfies(nri.request)) continue; bestNetwork = nai; // As the nais are sorted by score, this is the top-scoring network that can // satisfy this request. The best network for this request has been found, // go process the next NRI break; } // If no NAI satisfies this request, bestNetwork is still null. That's fine : it // means no network can satisfy the request. If nri.mSatisfier is not null, it just // means the network that used to satisfy the request stopped satisfying it. if (nri.mSatisfier != bestNetwork) { final NetworkAgentInfo bestNetwork = mNetworkRanker.getBestNetwork(nri.request, nais); if (bestNetwork != nri.mSatisfier) { // bestNetwork may be null if no network can satisfy this request. changes.addRequestReassignment(new NetworkReassignment.RequestReassignment( nri, nri.mSatisfier, bestNetwork)); } Loading services/core/java/com/android/server/connectivity/NetworkRanker.java 0 → 100644 +50 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.connectivity; import android.annotation.NonNull; import android.annotation.Nullable; import android.net.NetworkRequest; import java.util.Collection; /** * A class that knows how to find the best network matching a request out of a list of networks. */ public class NetworkRanker { public NetworkRanker() { } /** * Find the best network satisfying this request among the list of passed networks. */ // Almost equivalent to Collections.max(nais), but allows returning null if no network // satisfies the request. @Nullable public NetworkAgentInfo getBestNetwork(@NonNull final NetworkRequest request, @NonNull final Collection<NetworkAgentInfo> nais) { NetworkAgentInfo bestNetwork = null; int bestScore = Integer.MIN_VALUE; for (final NetworkAgentInfo nai : nais) { if (!nai.satisfies(request)) continue; if (nai.getCurrentScore() > bestScore) { bestNetwork = nai; bestScore = nai.getCurrentScore(); } } return bestNetwork; } } tests/net/java/com/android/server/connectivity/NetworkRankerTest.kt 0 → 100644 +84 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.connectivity import android.net.NetworkRequest import androidx.test.filters.SmallTest import androidx.test.runner.AndroidJUnit4 import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.any import org.mockito.Mockito.doReturn import org.mockito.Mockito.mock import kotlin.test.assertEquals import kotlin.test.assertNull @RunWith(AndroidJUnit4::class) @SmallTest 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 } @Test fun testGetBestNetwork() { val scores = listOf(20, 50, 90, 60, 23, 68) val nais = scores.map { makeNai(true, it) } val bestNetwork = nais[2] // The one with the top score val someRequest = mock(NetworkRequest::class.java) assertEquals(bestNetwork, ranker.getBestNetwork(someRequest, nais)) } @Test fun testIgnoreNonSatisfying() { val nais = listOf(makeNai(true, 20), makeNai(true, 50), makeNai(false, 90), makeNai(false, 60), makeNai(true, 23), makeNai(false, 68)) val bestNetwork = nais[1] // Top score that's satisfying val someRequest = mock(NetworkRequest::class.java) assertEquals(bestNetwork, ranker.getBestNetwork(someRequest, nais)) } @Test fun testNoMatch() { val nais = listOf(makeNai(false, 20), makeNai(false, 50), makeNai(false, 90)) val someRequest = mock(NetworkRequest::class.java) assertNull(ranker.getBestNetwork(someRequest, nais)) } @Test fun testEmpty() { val someRequest = mock(NetworkRequest::class.java) assertNull(ranker.getBestNetwork(someRequest, emptyList())) } // Make sure the ranker is "stable" (as in stable sort), that is, it always returns the FIRST // network satisfying the request if multiple of them have the same score. @Test fun testStable() { val nais1 = listOf(makeNai(true, 30), makeNai(true, 30), makeNai(true, 30), makeNai(true, 30), makeNai(true, 30), makeNai(true, 30)) val someRequest = mock(NetworkRequest::class.java) assertEquals(nais1[0], ranker.getBestNetwork(someRequest, nais1)) val nais2 = listOf(makeNai(true, 30), makeNai(true, 50), makeNai(true, 20), makeNai(true, 50), makeNai(true, 50), makeNai(true, 40)) assertEquals(nais2[1], ranker.getBestNetwork(someRequest, nais2)) } } Loading
services/core/java/com/android/server/ConnectivityService.java +6 −15 Original line number Diff line number Diff line Loading @@ -194,6 +194,7 @@ import com.android.server.connectivity.NetworkAgentInfo; import com.android.server.connectivity.NetworkDiagnostics; import com.android.server.connectivity.NetworkNotificationManager; import com.android.server.connectivity.NetworkNotificationManager.NotificationType; import com.android.server.connectivity.NetworkRanker; import com.android.server.connectivity.PermissionMonitor; import com.android.server.connectivity.ProxyTracker; import com.android.server.connectivity.Vpn; Loading Loading @@ -579,6 +580,7 @@ public class ConnectivityService extends IConnectivityManager.Stub final ConnectivityDiagnosticsHandler mConnectivityDiagnosticsHandler; private final DnsManager mDnsManager; private final NetworkRanker mNetworkRanker; private boolean mSystemReady; private Intent mInitialBroadcast; Loading Loading @@ -958,6 +960,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mMetricsLog = logger; mDefaultRequest = createDefaultInternetRequestForTransport(-1, NetworkRequest.Type.REQUEST); mNetworkRanker = new NetworkRanker(); NetworkRequestInfo defaultNRI = new NetworkRequestInfo(null, mDefaultRequest, new Binder()); mNetworkRequests.put(mDefaultRequest, defaultNRI); mNetworkRequestInfoLogs.log("REGISTER " + defaultNRI); Loading Loading @@ -6660,24 +6663,12 @@ public class ConnectivityService extends IConnectivityManager.Stub changes.addRematchedNetwork(new NetworkReassignment.NetworkBgStatePair(nai, nai.isBackgroundNetwork())); } Collections.sort(nais); for (final NetworkRequestInfo nri : mNetworkRequests.values()) { if (nri.request.isListen()) continue; // Find the top scoring network satisfying this request. NetworkAgentInfo bestNetwork = null; for (final NetworkAgentInfo nai : nais) { if (!nai.satisfies(nri.request)) continue; bestNetwork = nai; // As the nais are sorted by score, this is the top-scoring network that can // satisfy this request. The best network for this request has been found, // go process the next NRI break; } // If no NAI satisfies this request, bestNetwork is still null. That's fine : it // means no network can satisfy the request. If nri.mSatisfier is not null, it just // means the network that used to satisfy the request stopped satisfying it. if (nri.mSatisfier != bestNetwork) { final NetworkAgentInfo bestNetwork = mNetworkRanker.getBestNetwork(nri.request, nais); if (bestNetwork != nri.mSatisfier) { // bestNetwork may be null if no network can satisfy this request. changes.addRequestReassignment(new NetworkReassignment.RequestReassignment( nri, nri.mSatisfier, bestNetwork)); } Loading
services/core/java/com/android/server/connectivity/NetworkRanker.java 0 → 100644 +50 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.connectivity; import android.annotation.NonNull; import android.annotation.Nullable; import android.net.NetworkRequest; import java.util.Collection; /** * A class that knows how to find the best network matching a request out of a list of networks. */ public class NetworkRanker { public NetworkRanker() { } /** * Find the best network satisfying this request among the list of passed networks. */ // Almost equivalent to Collections.max(nais), but allows returning null if no network // satisfies the request. @Nullable public NetworkAgentInfo getBestNetwork(@NonNull final NetworkRequest request, @NonNull final Collection<NetworkAgentInfo> nais) { NetworkAgentInfo bestNetwork = null; int bestScore = Integer.MIN_VALUE; for (final NetworkAgentInfo nai : nais) { if (!nai.satisfies(request)) continue; if (nai.getCurrentScore() > bestScore) { bestNetwork = nai; bestScore = nai.getCurrentScore(); } } return bestNetwork; } }
tests/net/java/com/android/server/connectivity/NetworkRankerTest.kt 0 → 100644 +84 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.connectivity import android.net.NetworkRequest import androidx.test.filters.SmallTest import androidx.test.runner.AndroidJUnit4 import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.any import org.mockito.Mockito.doReturn import org.mockito.Mockito.mock import kotlin.test.assertEquals import kotlin.test.assertNull @RunWith(AndroidJUnit4::class) @SmallTest 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 } @Test fun testGetBestNetwork() { val scores = listOf(20, 50, 90, 60, 23, 68) val nais = scores.map { makeNai(true, it) } val bestNetwork = nais[2] // The one with the top score val someRequest = mock(NetworkRequest::class.java) assertEquals(bestNetwork, ranker.getBestNetwork(someRequest, nais)) } @Test fun testIgnoreNonSatisfying() { val nais = listOf(makeNai(true, 20), makeNai(true, 50), makeNai(false, 90), makeNai(false, 60), makeNai(true, 23), makeNai(false, 68)) val bestNetwork = nais[1] // Top score that's satisfying val someRequest = mock(NetworkRequest::class.java) assertEquals(bestNetwork, ranker.getBestNetwork(someRequest, nais)) } @Test fun testNoMatch() { val nais = listOf(makeNai(false, 20), makeNai(false, 50), makeNai(false, 90)) val someRequest = mock(NetworkRequest::class.java) assertNull(ranker.getBestNetwork(someRequest, nais)) } @Test fun testEmpty() { val someRequest = mock(NetworkRequest::class.java) assertNull(ranker.getBestNetwork(someRequest, emptyList())) } // Make sure the ranker is "stable" (as in stable sort), that is, it always returns the FIRST // network satisfying the request if multiple of them have the same score. @Test fun testStable() { val nais1 = listOf(makeNai(true, 30), makeNai(true, 30), makeNai(true, 30), makeNai(true, 30), makeNai(true, 30), makeNai(true, 30)) val someRequest = mock(NetworkRequest::class.java) assertEquals(nais1[0], ranker.getBestNetwork(someRequest, nais1)) val nais2 = listOf(makeNai(true, 30), makeNai(true, 50), makeNai(true, 20), makeNai(true, 50), makeNai(true, 50), makeNai(true, 40)) assertEquals(nais2[1], ranker.getBestNetwork(someRequest, nais2)) } }