Merge changes I627dcd0f,I81abc174,Id7948d21

* changes:
  Fix expectCallback does not fail when no callback received
  Add CTS for registerBestMatchingNetworkCallback
  No-op refactoring of NetworkAgentTest
This commit is contained in:
Junyu Lai
2021-06-16 11:46:34 +00:00
committed by Gerrit Code Review
3 changed files with 226 additions and 174 deletions

View File

@@ -18,6 +18,7 @@ package android.net
import android.app.Instrumentation import android.app.Instrumentation
import android.content.Context import android.content.Context
import android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED
import android.net.NetworkCapabilities.TRANSPORT_TEST import android.net.NetworkCapabilities.TRANSPORT_TEST
import android.net.NetworkProviderTest.TestNetworkCallback.CallbackEntry.OnUnavailable import android.net.NetworkProviderTest.TestNetworkCallback.CallbackEntry.OnUnavailable
import android.net.NetworkProviderTest.TestNetworkProvider.CallbackEntry.OnNetworkRequestWithdrawn import android.net.NetworkProviderTest.TestNetworkProvider.CallbackEntry.OnNetworkRequestWithdrawn
@@ -25,14 +26,18 @@ import android.net.NetworkProviderTest.TestNetworkProvider.CallbackEntry.OnNetwo
import android.os.Build import android.os.Build
import android.os.HandlerThread import android.os.HandlerThread
import android.os.Looper import android.os.Looper
import android.util.Log
import androidx.test.InstrumentationRegistry import androidx.test.InstrumentationRegistry
import com.android.net.module.util.ArrayTrackRecord import com.android.net.module.util.ArrayTrackRecord
import com.android.testutils.CompatUtil import com.android.testutils.CompatUtil
import com.android.testutils.DevSdkIgnoreRule
import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
import com.android.testutils.DevSdkIgnoreRunner import com.android.testutils.DevSdkIgnoreRunner
import com.android.testutils.isDevSdkInRange import com.android.testutils.isDevSdkInRange
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.mockito.Mockito.doReturn import org.mockito.Mockito.doReturn
@@ -41,6 +46,7 @@ import org.mockito.Mockito.verifyNoMoreInteractions
import java.util.UUID import java.util.UUID
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertNotEquals import kotlin.test.assertNotEquals
import kotlin.test.fail
private const val DEFAULT_TIMEOUT_MS = 5000L private const val DEFAULT_TIMEOUT_MS = 5000L
private val instrumentation: Instrumentation private val instrumentation: Instrumentation
@@ -51,6 +57,8 @@ private val PROVIDER_NAME = "NetworkProviderTest"
@RunWith(DevSdkIgnoreRunner::class) @RunWith(DevSdkIgnoreRunner::class)
@IgnoreUpTo(Build.VERSION_CODES.Q) @IgnoreUpTo(Build.VERSION_CODES.Q)
class NetworkProviderTest { class NetworkProviderTest {
@Rule @JvmField
val mIgnoreRule = DevSdkIgnoreRule()
private val mCm = context.getSystemService(ConnectivityManager::class.java) private val mCm = context.getSystemService(ConnectivityManager::class.java)
private val mHandlerThread = HandlerThread("${javaClass.simpleName} handler thread") private val mHandlerThread = HandlerThread("${javaClass.simpleName} handler thread")
@@ -68,6 +76,7 @@ class NetworkProviderTest {
private class TestNetworkProvider(context: Context, looper: Looper) : private class TestNetworkProvider(context: Context, looper: Looper) :
NetworkProvider(context, looper, PROVIDER_NAME) { NetworkProvider(context, looper, PROVIDER_NAME) {
private val TAG = this::class.simpleName
private val seenEvents = ArrayTrackRecord<CallbackEntry>().newReadHead() private val seenEvents = ArrayTrackRecord<CallbackEntry>().newReadHead()
sealed class CallbackEntry { sealed class CallbackEntry {
@@ -80,22 +89,30 @@ class NetworkProviderTest {
} }
override fun onNetworkRequested(request: NetworkRequest, score: Int, id: Int) { override fun onNetworkRequested(request: NetworkRequest, score: Int, id: Int) {
Log.d(TAG, "onNetworkRequested $request, $score, $id")
seenEvents.add(OnNetworkRequested(request, score, id)) seenEvents.add(OnNetworkRequested(request, score, id))
} }
override fun onNetworkRequestWithdrawn(request: NetworkRequest) { override fun onNetworkRequestWithdrawn(request: NetworkRequest) {
Log.d(TAG, "onNetworkRequestWithdrawn $request")
seenEvents.add(OnNetworkRequestWithdrawn(request)) seenEvents.add(OnNetworkRequestWithdrawn(request))
} }
inline fun <reified T : CallbackEntry> expectCallback( inline fun <reified T : CallbackEntry> eventuallyExpectCallbackThat(
crossinline predicate: (T) -> Boolean crossinline predicate: (T) -> Boolean
) = seenEvents.poll(DEFAULT_TIMEOUT_MS) { it is T && predicate(it) } ) = seenEvents.poll(DEFAULT_TIMEOUT_MS) { it is T && predicate(it) }
?: fail("Did not receive callback after ${DEFAULT_TIMEOUT_MS}ms")
} }
private fun createNetworkProvider(ctx: Context = context): TestNetworkProvider { private fun createNetworkProvider(ctx: Context = context): TestNetworkProvider {
return TestNetworkProvider(ctx, mHandlerThread.looper) return TestNetworkProvider(ctx, mHandlerThread.looper)
} }
// In S+ framework, do not run this test, since the provider will no longer receive
// onNetworkRequested for every request. Instead, provider needs to
// call {@code registerNetworkOffer} with the description of networks they
// might have ability to setup, and expects {@link NetworkOfferCallback#onNetworkNeeded}.
@IgnoreAfter(Build.VERSION_CODES.R)
@Test @Test
fun testOnNetworkRequested() { fun testOnNetworkRequested() {
val provider = createNetworkProvider() val provider = createNetworkProvider()
@@ -105,13 +122,15 @@ class NetworkProviderTest {
val specifier = CompatUtil.makeTestNetworkSpecifier( val specifier = CompatUtil.makeTestNetworkSpecifier(
UUID.randomUUID().toString()) UUID.randomUUID().toString())
// Test network is not allowed to be trusted.
val nr: NetworkRequest = NetworkRequest.Builder() val nr: NetworkRequest = NetworkRequest.Builder()
.addTransportType(TRANSPORT_TEST) .addTransportType(TRANSPORT_TEST)
.removeCapability(NET_CAPABILITY_TRUSTED)
.setNetworkSpecifier(specifier) .setNetworkSpecifier(specifier)
.build() .build()
val cb = ConnectivityManager.NetworkCallback() val cb = ConnectivityManager.NetworkCallback()
mCm.requestNetwork(nr, cb) mCm.requestNetwork(nr, cb)
provider.expectCallback<OnNetworkRequested>() { callback -> provider.eventuallyExpectCallbackThat<OnNetworkRequested>() { callback ->
callback.request.getNetworkSpecifier() == specifier && callback.request.getNetworkSpecifier() == specifier &&
callback.request.hasTransport(TRANSPORT_TEST) callback.request.hasTransport(TRANSPORT_TEST)
} }
@@ -131,22 +150,24 @@ class NetworkProviderTest {
val config = NetworkAgentConfig.Builder().build() val config = NetworkAgentConfig.Builder().build()
val agent = object : NetworkAgent(context, mHandlerThread.looper, "TestAgent", nc, lp, val agent = object : NetworkAgent(context, mHandlerThread.looper, "TestAgent", nc, lp,
initialScore, config, provider) {} initialScore, config, provider) {}
agent.register()
agent.markConnected()
provider.expectCallback<OnNetworkRequested>() { callback -> provider.eventuallyExpectCallbackThat<OnNetworkRequested>() { callback ->
callback.request.getNetworkSpecifier() == specifier && callback.request.getNetworkSpecifier() == specifier &&
callback.score == initialScore && callback.score == initialScore &&
callback.id == agent.providerId callback.id == agent.providerId
} }
agent.sendNetworkScore(updatedScore) agent.sendNetworkScore(updatedScore)
provider.expectCallback<OnNetworkRequested>() { callback -> provider.eventuallyExpectCallbackThat<OnNetworkRequested>() { callback ->
callback.request.getNetworkSpecifier() == specifier && callback.request.getNetworkSpecifier() == specifier &&
callback.score == updatedScore && callback.score == updatedScore &&
callback.id == agent.providerId callback.id == agent.providerId
} }
mCm.unregisterNetworkCallback(cb) mCm.unregisterNetworkCallback(cb)
provider.expectCallback<OnNetworkRequestWithdrawn>() { callback -> provider.eventuallyExpectCallbackThat<OnNetworkRequestWithdrawn>() { callback ->
callback.request.getNetworkSpecifier() == specifier && callback.request.getNetworkSpecifier() == specifier &&
callback.request.hasTransport(TRANSPORT_TEST) callback.request.hasTransport(TRANSPORT_TEST)
} }

View File

@@ -650,6 +650,18 @@ public class ConnectivityManagerTest {
mCm.getBackgroundDataSetting(); mCm.getBackgroundDataSetting();
} }
private NetworkRequest makeDefaultRequest() {
// Make a request that is similar to the way framework tracks the system
// default network.
return new NetworkRequest.Builder()
.clearCapabilities()
.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
.addCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.build();
}
private NetworkRequest makeWifiNetworkRequest() { private NetworkRequest makeWifiNetworkRequest() {
return new NetworkRequest.Builder() return new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI) .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
@@ -710,12 +722,14 @@ public class ConnectivityManagerTest {
final TestNetworkCallback systemDefaultCallback = new TestNetworkCallback(); final TestNetworkCallback systemDefaultCallback = new TestNetworkCallback();
final TestNetworkCallback perUidCallback = new TestNetworkCallback(); final TestNetworkCallback perUidCallback = new TestNetworkCallback();
final TestNetworkCallback bestMatchingCallback = new TestNetworkCallback();
final Handler h = new Handler(Looper.getMainLooper()); final Handler h = new Handler(Looper.getMainLooper());
if (TestUtils.shouldTestSApis()) { if (TestUtils.shouldTestSApis()) {
runWithShellPermissionIdentity(() -> { runWithShellPermissionIdentity(() -> {
mCmShim.registerSystemDefaultNetworkCallback(systemDefaultCallback, h); mCmShim.registerSystemDefaultNetworkCallback(systemDefaultCallback, h);
mCmShim.registerDefaultNetworkCallbackForUid(Process.myUid(), perUidCallback, h); mCmShim.registerDefaultNetworkCallbackForUid(Process.myUid(), perUidCallback, h);
}, NETWORK_SETTINGS); }, NETWORK_SETTINGS);
mCm.registerBestMatchingNetworkCallback(makeDefaultRequest(), bestMatchingCallback, h);
} }
Network wifiNetwork = null; Network wifiNetwork = null;
@@ -741,6 +755,10 @@ public class ConnectivityManagerTest {
assertNotNull("Did not receive onAvailable on per-UID default network callback", assertNotNull("Did not receive onAvailable on per-UID default network callback",
perUidNetwork); perUidNetwork);
assertEquals(defaultNetwork, perUidNetwork); assertEquals(defaultNetwork, perUidNetwork);
final Network bestMatchingNetwork = bestMatchingCallback.waitForAvailable();
assertNotNull("Did not receive onAvailable on best matching network callback",
bestMatchingNetwork);
assertEquals(defaultNetwork, bestMatchingNetwork);
} }
} catch (InterruptedException e) { } catch (InterruptedException e) {
@@ -751,6 +769,7 @@ public class ConnectivityManagerTest {
if (TestUtils.shouldTestSApis()) { if (TestUtils.shouldTestSApis()) {
mCm.unregisterNetworkCallback(systemDefaultCallback); mCm.unregisterNetworkCallback(systemDefaultCallback);
mCm.unregisterNetworkCallback(perUidCallback); mCm.unregisterNetworkCallback(perUidCallback);
mCm.unregisterNetworkCallback(bestMatchingCallback);
} }
} }
} }

View File

@@ -66,6 +66,7 @@ import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnSta
import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnStopSocketKeepalive import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnStopSocketKeepalive
import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnValidationStatus import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnValidationStatus
import android.os.Build import android.os.Build
import android.os.Handler
import android.os.HandlerThread import android.os.HandlerThread
import android.os.Looper import android.os.Looper
import android.os.Message import android.os.Message
@@ -269,10 +270,9 @@ class NetworkAgentTest {
history.add(OnSignalStrengthThresholdsUpdated(thresholds)) history.add(OnSignalStrengthThresholdsUpdated(thresholds))
} }
fun expectEmptySignalStrengths() { fun expectSignalStrengths(thresholds: IntArray? = intArrayOf()) {
expectCallback<OnSignalStrengthThresholdsUpdated>().let { expectCallback<OnSignalStrengthThresholdsUpdated>().let {
// intArrayOf() without arguments makes an empty array assertArrayEquals(thresholds, it.thresholds)
assertArrayEquals(intArrayOf(), it.thresholds)
} }
} }
@@ -292,7 +292,7 @@ class NetworkAgentTest {
// a NetworkAgent whose network does not require validation (which test networks do // a NetworkAgent whose network does not require validation (which test networks do
// not, since they lack the INTERNET capability). It always contains the default argument // not, since they lack the INTERNET capability). It always contains the default argument
// for the URI. // for the URI.
fun expectNoInternetValidationStatus() = expectCallback<OnValidationStatus>().let { fun expectValidationBypassedStatus() = expectCallback<OnValidationStatus>().let {
assertEquals(it.status, VALID_NETWORK) assertEquals(it.status, VALID_NETWORK)
// The returned Uri is parsed from the empty string, which means it's an // The returned Uri is parsed from the empty string, which means it's an
// instance of the (private) Uri.StringUri. There are no real good ways // instance of the (private) Uri.StringUri. There are no real good ways
@@ -332,9 +332,30 @@ class NetworkAgentTest {
callbacksToCleanUp.add(callback) callbacksToCleanUp.add(callback)
} }
private fun registerBestMatchingNetworkCallback(
request: NetworkRequest,
callback: TestableNetworkCallback,
handler: Handler
) {
mCM!!.registerBestMatchingNetworkCallback(request, callback, handler)
callbacksToCleanUp.add(callback)
}
private fun makeTestNetworkRequest(specifier: String? = null): NetworkRequest {
return NetworkRequest.Builder()
.clearCapabilities()
.addTransportType(TRANSPORT_TEST)
.also {
if (specifier != null) {
it.setNetworkSpecifier(CompatUtil.makeEthernetNetworkSpecifier(specifier))
}
}
.build()
}
private fun createNetworkAgent( private fun createNetworkAgent(
context: Context = realContext, context: Context = realContext,
name: String? = null, specifier: String? = null,
initialNc: NetworkCapabilities? = null, initialNc: NetworkCapabilities? = null,
initialLp: LinkProperties? = null, initialLp: LinkProperties? = null,
initialConfig: NetworkAgentConfig? = null initialConfig: NetworkAgentConfig? = null
@@ -349,8 +370,8 @@ class NetworkAgentTest {
if (SdkLevel.isAtLeastS()) { if (SdkLevel.isAtLeastS()) {
addCapability(NET_CAPABILITY_NOT_VCN_MANAGED) addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
} }
if (null != name) { if (null != specifier) {
setNetworkSpecifier(CompatUtil.makeEthernetNetworkSpecifier(name)) setNetworkSpecifier(CompatUtil.makeEthernetNetworkSpecifier(specifier))
} }
} }
val lp = initialLp ?: LinkProperties().apply { val lp = initialLp ?: LinkProperties().apply {
@@ -365,21 +386,22 @@ class NetworkAgentTest {
private fun createConnectedNetworkAgent( private fun createConnectedNetworkAgent(
context: Context = realContext, context: Context = realContext,
name: String? = null, specifier: String? = UUID.randomUUID().toString(),
initialConfig: NetworkAgentConfig? = null initialConfig: NetworkAgentConfig? = null,
expectedInitSignalStrengthThresholds: IntArray? = intArrayOf()
): Pair<TestableNetworkAgent, TestableNetworkCallback> { ): Pair<TestableNetworkAgent, TestableNetworkCallback> {
val request: NetworkRequest = NetworkRequest.Builder()
.clearCapabilities()
.addTransportType(TRANSPORT_TEST)
.build()
val callback = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS) val callback = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS)
requestNetwork(request, callback) // Ensure this NetworkAgent is never unneeded by filing a request with its specifier.
val config = initialConfig ?: NetworkAgentConfig.Builder().build() requestNetwork(makeTestNetworkRequest(specifier = specifier), callback)
val agent = createNetworkAgent(context, name, initialConfig = config) val agent = createNetworkAgent(context, specifier, initialConfig = initialConfig)
agent.setTeardownDelayMillis(0) agent.setTeardownDelayMillis(0)
// Connect the agent and verify initial status callbacks.
agent.register() agent.register()
agent.markConnected() agent.markConnected()
agent.expectCallback<OnNetworkCreated>() agent.expectCallback<OnNetworkCreated>()
agent.expectSignalStrengths(expectedInitSignalStrengthThresholds)
agent.expectValidationBypassedStatus()
callback.expectAvailableThenValidatedCallbacks(agent.network!!)
return agent to callback return agent to callback
} }
@@ -413,7 +435,6 @@ class NetworkAgentTest {
.setLegacySubType(subtypeLTE) .setLegacySubType(subtypeLTE)
.setLegacySubTypeName(subtypeNameLTE).build() .setLegacySubTypeName(subtypeNameLTE).build()
val (agent, callback) = createConnectedNetworkAgent(initialConfig = config) val (agent, callback) = createConnectedNetworkAgent(initialConfig = config)
callback.expectAvailableThenValidatedCallbacks(agent.network)
agent.setLegacySubtype(subtypeUMTS, subtypeNameUMTS) agent.setLegacySubtype(subtypeUMTS, subtypeNameUMTS)
// There is no callback when networkInfo changes, // There is no callback when networkInfo changes,
@@ -433,12 +454,8 @@ class NetworkAgentTest {
@Test @Test
fun testConnectAndUnregister() { fun testConnectAndUnregister() {
val (agent, callback) = createConnectedNetworkAgent() val (agent, callback) = createConnectedNetworkAgent()
callback.expectAvailableThenValidatedCallbacks(agent.network)
agent.expectEmptySignalStrengths()
agent.expectNoInternetValidationStatus()
unregister(agent) unregister(agent)
callback.expectCallback<Lost>(agent.network) callback.expectCallback<Lost>(agent.network!!)
assertFailsWith<IllegalStateException>("Must not be able to register an agent twice") { assertFailsWith<IllegalStateException>("Must not be able to register an agent twice") {
agent.register() agent.register()
} }
@@ -446,11 +463,8 @@ class NetworkAgentTest {
@Test @Test
fun testOnBandwidthUpdateRequested() { fun testOnBandwidthUpdateRequested() {
val (agent, callback) = createConnectedNetworkAgent() val (agent, _) = createConnectedNetworkAgent()
callback.expectAvailableThenValidatedCallbacks(agent.network) mCM.requestBandwidthUpdate(agent.network!!)
agent.expectEmptySignalStrengths()
agent.expectNoInternetValidationStatus()
mCM.requestBandwidthUpdate(agent.network)
agent.expectCallback<OnBandwidthUpdateRequested>() agent.expectCallback<OnBandwidthUpdateRequested>()
unregister(agent) unregister(agent)
} }
@@ -468,13 +482,8 @@ class NetworkAgentTest {
registerNetworkCallback(request, it) registerNetworkCallback(request, it)
} }
} }
createConnectedNetworkAgent().let { (agent, callback) -> createConnectedNetworkAgent(expectedInitSignalStrengthThresholds = thresholds).let {
callback.expectAvailableThenValidatedCallbacks(agent.network) (agent, callback) ->
agent.expectCallback<OnSignalStrengthThresholdsUpdated>().let {
assertArrayEquals(it.thresholds, thresholds)
}
agent.expectNoInternetValidationStatus()
// Send signal strength and check that the callbacks are called appropriately. // Send signal strength and check that the callbacks are called appropriately.
val nc = NetworkCapabilities(agent.nc) val nc = NetworkCapabilities(agent.nc)
nc.setSignalStrength(20) nc.setSignalStrength(20)
@@ -483,21 +492,21 @@ class NetworkAgentTest {
nc.setSignalStrength(40) nc.setSignalStrength(40)
agent.sendNetworkCapabilities(nc) agent.sendNetworkCapabilities(nc)
callbacks[0].expectAvailableCallbacks(agent.network) callbacks[0].expectAvailableCallbacks(agent.network!!)
callbacks[1].assertNoCallback(NO_CALLBACK_TIMEOUT) callbacks[1].assertNoCallback(NO_CALLBACK_TIMEOUT)
callbacks[2].assertNoCallback(NO_CALLBACK_TIMEOUT) callbacks[2].assertNoCallback(NO_CALLBACK_TIMEOUT)
nc.setSignalStrength(80) nc.setSignalStrength(80)
agent.sendNetworkCapabilities(nc) agent.sendNetworkCapabilities(nc)
callbacks[0].expectCapabilitiesThat(agent.network) { it.signalStrength == 80 } callbacks[0].expectCapabilitiesThat(agent.network!!) { it.signalStrength == 80 }
callbacks[1].expectAvailableCallbacks(agent.network) callbacks[1].expectAvailableCallbacks(agent.network!!)
callbacks[2].expectAvailableCallbacks(agent.network) callbacks[2].expectAvailableCallbacks(agent.network!!)
nc.setSignalStrength(55) nc.setSignalStrength(55)
agent.sendNetworkCapabilities(nc) agent.sendNetworkCapabilities(nc)
callbacks[0].expectCapabilitiesThat(agent.network) { it.signalStrength == 55 } callbacks[0].expectCapabilitiesThat(agent.network!!) { it.signalStrength == 55 }
callbacks[1].expectCapabilitiesThat(agent.network) { it.signalStrength == 55 } callbacks[1].expectCapabilitiesThat(agent.network!!) { it.signalStrength == 55 }
callbacks[2].expectCallback<Lost>(agent.network) callbacks[2].expectCallback<Lost>(agent.network!!)
} }
callbacks.forEach { callbacks.forEach {
mCM.unregisterNetworkCallback(it) mCM.unregisterNetworkCallback(it)
@@ -546,20 +555,17 @@ class NetworkAgentTest {
@Test @Test
fun testSendUpdates(): Unit = createConnectedNetworkAgent().let { (agent, callback) -> fun testSendUpdates(): Unit = createConnectedNetworkAgent().let { (agent, callback) ->
callback.expectAvailableThenValidatedCallbacks(agent.network)
agent.expectEmptySignalStrengths()
agent.expectNoInternetValidationStatus()
val ifaceName = "adhocIface" val ifaceName = "adhocIface"
val lp = LinkProperties(agent.lp) val lp = LinkProperties(agent.lp)
lp.setInterfaceName(ifaceName) lp.setInterfaceName(ifaceName)
agent.sendLinkProperties(lp) agent.sendLinkProperties(lp)
callback.expectLinkPropertiesThat(agent.network) { callback.expectLinkPropertiesThat(agent.network!!) {
it.getInterfaceName() == ifaceName it.getInterfaceName() == ifaceName
} }
val nc = NetworkCapabilities(agent.nc) val nc = NetworkCapabilities(agent.nc)
nc.addCapability(NET_CAPABILITY_NOT_METERED) nc.addCapability(NET_CAPABILITY_NOT_METERED)
agent.sendNetworkCapabilities(nc) agent.sendNetworkCapabilities(nc)
callback.expectCapabilitiesThat(agent.network) { callback.expectCapabilitiesThat(agent.network!!) {
it.hasCapability(NET_CAPABILITY_NOT_METERED) it.hasCapability(NET_CAPABILITY_NOT_METERED)
} }
} }
@@ -568,44 +574,22 @@ class NetworkAgentTest {
fun testSendScore() { fun testSendScore() {
// This test will create two networks and check that the one with the stronger // This test will create two networks and check that the one with the stronger
// score wins out for a request that matches them both. // score wins out for a request that matches them both.
// First create requests to make sure both networks are kept up, using the
// specifier so they are specific to each network
val name1 = UUID.randomUUID().toString()
val name2 = UUID.randomUUID().toString()
val request1 = NetworkRequest.Builder()
.clearCapabilities()
.addTransportType(TRANSPORT_TEST)
.setNetworkSpecifier(CompatUtil.makeEthernetNetworkSpecifier(name1))
.build()
val request2 = NetworkRequest.Builder()
.clearCapabilities()
.addTransportType(TRANSPORT_TEST)
.setNetworkSpecifier(CompatUtil.makeEthernetNetworkSpecifier(name2))
.build()
val callback1 = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS)
val callback2 = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS)
requestNetwork(request1, callback1)
requestNetwork(request2, callback2)
// Then file the interesting request // File the interesting request
val request = NetworkRequest.Builder()
.clearCapabilities()
.addTransportType(TRANSPORT_TEST)
.build()
val callback = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS) val callback = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS)
requestNetwork(request, callback) requestNetwork(makeTestNetworkRequest(), callback)
// Connect the first Network // Connect the first Network, with an unused callback that kept the network up.
createConnectedNetworkAgent(name = name1).let { (agent1, _) -> val (agent1, _) = createConnectedNetworkAgent()
callback.expectAvailableThenValidatedCallbacks(agent1.network) callback.expectAvailableThenValidatedCallbacks(agent1.network!!)
// If using the int ranking, agent1 must be upgraded to a better score so that there is // If using the int ranking, agent1 must be upgraded to a better score so that there is
// no ambiguity when agent2 connects that agent1 is still better. If using policy // no ambiguity when agent2 connects that agent1 is still better. If using policy
// ranking, this is not necessary. // ranking, this is not necessary.
agent1.sendNetworkScore(NetworkScore.Builder().setLegacyInt(BETTER_NETWORK_SCORE) agent1.sendNetworkScore(NetworkScore.Builder().setLegacyInt(BETTER_NETWORK_SCORE)
.build()) .build())
// Connect the second agent
createConnectedNetworkAgent(name = name2).let { (agent2, _) -> // Connect the second agent.
agent2.markConnected() val (agent2, _) = createConnectedNetworkAgent()
// The callback should not see anything yet. With int ranking, agent1 was upgraded // The callback should not see anything yet. With int ranking, agent1 was upgraded
// to a stronger score beforehand. With policy ranking, agent1 is preferred by // to a stronger score beforehand. With policy ranking, agent1 is preferred by
// virtue of already satisfying the request. // virtue of already satisfying the request.
@@ -615,9 +599,7 @@ class NetworkAgentTest {
.setLegacyInt(WORSE_NETWORK_SCORE) .setLegacyInt(WORSE_NETWORK_SCORE)
.setExiting(true) .setExiting(true)
.build()) .build())
callback.expectCallback<Available>(agent2.network) callback.expectCallback<Available>(agent2.network!!)
}
}
// tearDown() will unregister the requests and agents // tearDown() will unregister the requests and agents
} }
@@ -658,7 +640,7 @@ class NetworkAgentTest {
callback.expectAvailableThenValidatedCallbacks(agent.network!!) callback.expectAvailableThenValidatedCallbacks(agent.network!!)
// Check that the default network's transport is propagated to the VPN. // Check that the default network's transport is propagated to the VPN.
var vpnNc = mCM.getNetworkCapabilities(agent.network) var vpnNc = mCM.getNetworkCapabilities(agent.network!!)
assertNotNull(vpnNc) assertNotNull(vpnNc)
assertEquals(VpnManager.TYPE_VPN_SERVICE, assertEquals(VpnManager.TYPE_VPN_SERVICE,
(vpnNc.transportInfo as VpnTransportInfo).type) (vpnNc.transportInfo as VpnTransportInfo).type)
@@ -690,7 +672,7 @@ class NetworkAgentTest {
// This is not very accurate because the test does not control the capabilities of the // This is not very accurate because the test does not control the capabilities of the
// underlying networks, and because not congested, not roaming, and not suspended are the // underlying networks, and because not congested, not roaming, and not suspended are the
// default anyway. It's still useful as an extra check though. // default anyway. It's still useful as an extra check though.
vpnNc = mCM.getNetworkCapabilities(agent.network) vpnNc = mCM.getNetworkCapabilities(agent.network!!)
for (cap in listOf(NET_CAPABILITY_NOT_CONGESTED, for (cap in listOf(NET_CAPABILITY_NOT_CONGESTED,
NET_CAPABILITY_NOT_ROAMING, NET_CAPABILITY_NOT_ROAMING,
NET_CAPABILITY_NOT_SUSPENDED)) { NET_CAPABILITY_NOT_SUSPENDED)) {
@@ -701,7 +683,7 @@ class NetworkAgentTest {
} }
unregister(agent) unregister(agent)
callback.expectCallback<Lost>(agent.network) callback.expectCallback<Lost>(agent.network!!)
} }
private fun unregister(agent: TestableNetworkAgent) { private fun unregister(agent: TestableNetworkAgent) {
@@ -789,33 +771,15 @@ class NetworkAgentTest {
fun testTemporarilyUnmeteredCapability() { fun testTemporarilyUnmeteredCapability() {
// This test will create a networks with/without NET_CAPABILITY_TEMPORARILY_NOT_METERED // This test will create a networks with/without NET_CAPABILITY_TEMPORARILY_NOT_METERED
// and check that the callback reflects the capability changes. // and check that the callback reflects the capability changes.
// First create a request to make sure the network is kept up
val request1 = NetworkRequest.Builder()
.clearCapabilities()
.addTransportType(TRANSPORT_TEST)
.build()
val callback1 = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS).also {
registerNetworkCallback(request1, it)
}
requestNetwork(request1, callback1)
// Then file the interesting request
val request = NetworkRequest.Builder()
.clearCapabilities()
.addTransportType(TRANSPORT_TEST)
.build()
val callback = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS)
requestNetwork(request, callback)
// Connect the network // Connect the network
createConnectedNetworkAgent().let { (agent, _) -> val (agent, callback) = createConnectedNetworkAgent()
callback.expectAvailableThenValidatedCallbacks(agent.network)
// Send TEMP_NOT_METERED and check that the callback is called appropriately. // Send TEMP_NOT_METERED and check that the callback is called appropriately.
val nc1 = NetworkCapabilities(agent.nc) val nc1 = NetworkCapabilities(agent.nc)
.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED) .addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)
agent.sendNetworkCapabilities(nc1) agent.sendNetworkCapabilities(nc1)
callback.expectCapabilitiesThat(agent.network) { callback.expectCapabilitiesThat(agent.network!!) {
it.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED) it.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)
} }
@@ -823,10 +787,9 @@ class NetworkAgentTest {
val nc2 = NetworkCapabilities(agent.nc) val nc2 = NetworkCapabilities(agent.nc)
.removeCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED) .removeCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)
agent.sendNetworkCapabilities(nc2) agent.sendNetworkCapabilities(nc2)
callback.expectCapabilitiesThat(agent.network) { callback.expectCapabilitiesThat(agent.network!!) {
!it.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED) !it.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)
} }
}
// tearDown() will unregister the requests and agents // tearDown() will unregister the requests and agents
} }
@@ -838,88 +801,137 @@ class NetworkAgentTest {
// score wins out for a request that matches them both. And the weaker agent will // score wins out for a request that matches them both. And the weaker agent will
// be disconnected after customized linger duration. // be disconnected after customized linger duration.
// Connect the first Network // Request the first Network, with a request that could moved to agentStronger in order to
val name1 = UUID.randomUUID().toString() // make agentWeaker linger later.
val name2 = UUID.randomUUID().toString() val specifierWeaker = UUID.randomUUID().toString()
val (agent1, callback) = createConnectedNetworkAgent(name = name1) val specifierStronger = UUID.randomUUID().toString()
callback.expectAvailableThenValidatedCallbacks(agent1.network!!) val commonCallback = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS)
// Downgrade agent1 to a worse score so that there is no ambiguity when requestNetwork(makeTestNetworkRequest(), commonCallback)
// agent2 connects. val agentWeaker = createNetworkAgent(specifier = specifierWeaker)
agent1.sendNetworkScore(NetworkScore.Builder().setLegacyInt(WORSE_NETWORK_SCORE) agentWeaker.register()
agentWeaker.markConnected()
commonCallback.expectAvailableThenValidatedCallbacks(agentWeaker.network!!)
// Downgrade agentWeaker to a worse score so that there is no ambiguity when
// agentStronger connects.
agentWeaker.sendNetworkScore(NetworkScore.Builder().setLegacyInt(WORSE_NETWORK_SCORE)
.setExiting(true).build()) .setExiting(true).build())
// Verify invalid linger duration cannot be set. // Verify invalid linger duration cannot be set.
assertFailsWith<IllegalArgumentException> { assertFailsWith<IllegalArgumentException> {
agent1.setLingerDuration(Duration.ofMillis(-1)) agentWeaker.setLingerDuration(Duration.ofMillis(-1))
} }
assertFailsWith<IllegalArgumentException> { agent1.setLingerDuration(Duration.ZERO) } assertFailsWith<IllegalArgumentException> { agentWeaker.setLingerDuration(Duration.ZERO) }
assertFailsWith<IllegalArgumentException> { assertFailsWith<IllegalArgumentException> {
agent1.setLingerDuration(Duration.ofMillis(Integer.MIN_VALUE.toLong())) agentWeaker.setLingerDuration(Duration.ofMillis(Integer.MIN_VALUE.toLong()))
} }
assertFailsWith<IllegalArgumentException> { assertFailsWith<IllegalArgumentException> {
agent1.setLingerDuration(Duration.ofMillis(Integer.MAX_VALUE.toLong() + 1)) agentWeaker.setLingerDuration(Duration.ofMillis(Integer.MAX_VALUE.toLong() + 1))
} }
assertFailsWith<IllegalArgumentException> { assertFailsWith<IllegalArgumentException> {
agent1.setLingerDuration(Duration.ofMillis( agentWeaker.setLingerDuration(Duration.ofMillis(
NetworkAgent.MIN_LINGER_TIMER_MS.toLong() - 1)) NetworkAgent.MIN_LINGER_TIMER_MS.toLong() - 1))
} }
// Verify valid linger timer can be set, but it should not take effect since the network // Verify valid linger timer can be set, but it should not take effect since the network
// is still needed. // is still needed.
agent1.setLingerDuration(Duration.ofMillis(Integer.MAX_VALUE.toLong())) agentWeaker.setLingerDuration(Duration.ofMillis(Integer.MAX_VALUE.toLong()))
callback.assertNoCallback(NO_CALLBACK_TIMEOUT) commonCallback.assertNoCallback(NO_CALLBACK_TIMEOUT)
// Set to the value we want to verify the functionality. // Set to the value we want to verify the functionality.
agent1.setLingerDuration(Duration.ofMillis(NetworkAgent.MIN_LINGER_TIMER_MS.toLong())) agentWeaker.setLingerDuration(Duration.ofMillis(NetworkAgent.MIN_LINGER_TIMER_MS.toLong()))
// Make a listener which can observe agent1 lost later. // Make a listener which can observe agentWeaker lost later.
val callbackWeaker = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS) val callbackWeaker = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS)
registerNetworkCallback(NetworkRequest.Builder() registerNetworkCallback(NetworkRequest.Builder()
.clearCapabilities() .clearCapabilities()
.addTransportType(TRANSPORT_TEST) .addTransportType(TRANSPORT_TEST)
.setNetworkSpecifier(CompatUtil.makeEthernetNetworkSpecifier(name1)) .setNetworkSpecifier(CompatUtil.makeEthernetNetworkSpecifier(specifierWeaker))
.build(), callbackWeaker) .build(), callbackWeaker)
callbackWeaker.expectAvailableCallbacks(agent1.network!!) callbackWeaker.expectAvailableCallbacks(agentWeaker.network!!)
// Connect the second agent with a score better than agent1. Verify the callback for // Connect the agentStronger with a score better than agentWeaker. Verify the callback for
// agent1 sees the linger expiry while the callback for both sees the winner. // agentWeaker sees the linger expiry while the callback for both sees the winner.
// Record linger start timestamp prior to send score to prevent possible race, the actual // Record linger start timestamp prior to send score to prevent possible race, the actual
// timestamp should be slightly late than this since the service handles update // timestamp should be slightly late than this since the service handles update
// network score asynchronously. // network score asynchronously.
val lingerStart = SystemClock.elapsedRealtime() val lingerStart = SystemClock.elapsedRealtime()
val agent2 = createNetworkAgent(name = name2) val agentStronger = createNetworkAgent(specifier = specifierStronger)
agent2.register() agentStronger.register()
agent2.markConnected() agentStronger.markConnected()
callback.expectAvailableCallbacks(agent2.network!!) commonCallback.expectAvailableCallbacks(agentStronger.network!!)
callbackWeaker.expectCallback<Losing>(agent1.network!!) callbackWeaker.expectCallback<Losing>(agentWeaker.network!!)
val expectedRemainingLingerDuration = lingerStart + val expectedRemainingLingerDuration = lingerStart +
NetworkAgent.MIN_LINGER_TIMER_MS.toLong() - SystemClock.elapsedRealtime() NetworkAgent.MIN_LINGER_TIMER_MS.toLong() - SystemClock.elapsedRealtime()
// If the available callback is too late. The remaining duration will be reduced. // If the available callback is too late. The remaining duration will be reduced.
assertTrue(expectedRemainingLingerDuration > 0, assertTrue(expectedRemainingLingerDuration > 0,
"expected remaining linger duration is $expectedRemainingLingerDuration") "expected remaining linger duration is $expectedRemainingLingerDuration")
callbackWeaker.assertNoCallback(expectedRemainingLingerDuration) callbackWeaker.assertNoCallback(expectedRemainingLingerDuration)
callbackWeaker.expectCallback<Lost>(agent1.network!!) callbackWeaker.expectCallback<Lost>(agentWeaker.network!!)
} }
@Test @Test
@IgnoreUpTo(Build.VERSION_CODES.R) @IgnoreUpTo(Build.VERSION_CODES.R)
fun testSetSubscriberId() { fun testSetSubscriberId() {
val name = "TEST-AGENT"
val imsi = UUID.randomUUID().toString() val imsi = UUID.randomUUID().toString()
val config = NetworkAgentConfig.Builder().setSubscriberId(imsi).build() val config = NetworkAgentConfig.Builder().setSubscriberId(imsi).build()
val request: NetworkRequest = NetworkRequest.Builder() val (agent, _) = createConnectedNetworkAgent(initialConfig = config)
.clearCapabilities()
.addTransportType(TRANSPORT_TEST)
.setNetworkSpecifier(CompatUtil.makeEthernetNetworkSpecifier(name))
.build()
val callback = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS)
requestNetwork(request, callback)
val agent = createNetworkAgent(name = name, initialConfig = config)
agent.register()
agent.markConnected()
callback.expectAvailableThenValidatedCallbacks(agent.network!!)
val snapshots = runWithShellPermissionIdentity(ThrowingSupplier { val snapshots = runWithShellPermissionIdentity(ThrowingSupplier {
mCM!!.allNetworkStateSnapshots }, NETWORK_SETTINGS) mCM!!.allNetworkStateSnapshots }, NETWORK_SETTINGS)
val testNetworkSnapshot = snapshots.findLast { it.network == agent.network } val testNetworkSnapshot = snapshots.findLast { it.network == agent.network }
assertEquals(imsi, testNetworkSnapshot!!.subscriberId) assertEquals(imsi, testNetworkSnapshot!!.subscriberId)
} }
@Test
@IgnoreUpTo(Build.VERSION_CODES.R)
// TODO: Refactor helper functions to util class and move this test case to
// {@link android.net.cts.ConnectivityManagerTest}.
fun testRegisterBestMatchingNetworkCallback() {
// Register best matching network callback with additional condition that will be
// exercised later. This assumes the test network agent has NOT_VCN_MANAGED in it and
// does not have NET_CAPABILITY_TEMPORARILY_NOT_METERED.
val bestMatchingCb = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS)
registerBestMatchingNetworkCallback(NetworkRequest.Builder()
.clearCapabilities()
.addTransportType(TRANSPORT_TEST)
.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
.build(), bestMatchingCb, mHandlerThread.threadHandler)
val (agent1, _) = createConnectedNetworkAgent(specifier = "AGENT-1")
bestMatchingCb.expectAvailableThenValidatedCallbacks(agent1.network!!)
// Make agent1 worse so when agent2 shows up, the callback will see that.
agent1.sendNetworkScore(NetworkScore.Builder().setExiting(true).build())
bestMatchingCb.assertNoCallback(NO_CALLBACK_TIMEOUT)
val (agent2, _) = createConnectedNetworkAgent(specifier = "AGENT-2")
bestMatchingCb.expectAvailableDoubleValidatedCallbacks(agent2.network!!)
// Change something on agent1 to trigger capabilities changed, since the callback
// only cares about the best network, verify it received nothing from agent1.
val ncAgent1 = agent1.nc
ncAgent1.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)
agent1.sendNetworkCapabilities(ncAgent1)
bestMatchingCb.assertNoCallback(NO_CALLBACK_TIMEOUT)
// Make agent1 the best network again, verify the callback now tracks agent1.
agent1.sendNetworkScore(NetworkScore.Builder()
.setExiting(false).setTransportPrimary(true).build())
bestMatchingCb.expectAvailableCallbacks(agent1.network!!)
// Make agent1 temporary vcn managed, which will not satisfying the request.
// Verify the callback switch from/to the other network accordingly.
ncAgent1.removeCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
agent1.sendNetworkCapabilities(ncAgent1)
bestMatchingCb.expectAvailableCallbacks(agent2.network!!)
ncAgent1.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
agent1.sendNetworkCapabilities(ncAgent1)
bestMatchingCb.expectAvailableDoubleValidatedCallbacks(agent1.network!!)
// Verify the callback doesn't care about agent2 disconnect.
agent2.unregister()
agentsToCleanUp.remove(agent2)
bestMatchingCb.assertNoCallback()
agent1.unregister()
agentsToCleanUp.remove(agent1)
bestMatchingCb.expectCallback<Lost>(agent1.network!!)
// tearDown() will unregister the requests and agents
}
} }