From 82350ea26961bd9ee5530ae467b58c164b42a9c5 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 16 Sep 2022 19:53:03 +0900 Subject: [PATCH] Make unregisterAfterReplacement tear down CONNECTING networks. Bug: 245823767 Test: new test coverage Change-Id: Icb47e8375f3f8bff4ac8d0833c9efd8d0ba7cda0 --- .../android/server/ConnectivityService.java | 14 ++++- .../src/android/net/cts/NetworkAgentTest.kt | 56 ++++++++++++++++++- 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java index afb3ca23e9..8fd1db09e2 100755 --- a/service/src/com/android/server/ConnectivityService.java +++ b/service/src/com/android/server/ConnectivityService.java @@ -3639,8 +3639,18 @@ public class ConnectivityService extends IConnectivityManager.Stub break; } case NetworkAgent.EVENT_UNREGISTER_AFTER_REPLACEMENT: { - // If nai is not yet created, or is already destroyed, ignore. - if (!shouldDestroyNativeNetwork(nai)) break; + if (!nai.isCreated()) { + Log.d(TAG, "unregisterAfterReplacement on uncreated " + nai.toShortString() + + ", tearing down instead"); + teardownUnneededNetwork(nai); + break; + } + + if (nai.isDestroyed()) { + Log.d(TAG, "unregisterAfterReplacement on destroyed " + nai.toShortString() + + ", ignoring"); + break; + } final int timeoutMs = (int) arg.second; if (timeoutMs < 0 || timeoutMs > NetworkAgent.MAX_TEARDOWN_DELAY_MS) { diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt index d4f3d579a6..b9627dbd0a 100644 --- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt @@ -332,6 +332,28 @@ class NetworkAgentTest { mFakeConnectivityService.connect(it.registerForTest(Network(FAKE_NET_ID))) } + fun assertLinkPropertiesEventually( + n: Network, + description: String, + condition: (LinkProperties?) -> Boolean + ): LinkProperties? { + val deadline = SystemClock.elapsedRealtime() + DEFAULT_TIMEOUT_MS + do { + val lp = mCM.getLinkProperties(n) + if (condition(lp)) return lp + SystemClock.sleep(10 /* ms */) + } while (SystemClock.elapsedRealtime() < deadline) + fail("Network $n LinkProperties did not $description after $DEFAULT_TIMEOUT_MS ms") + } + + fun assertLinkPropertiesEventuallyNotNull(n: Network) { + assertLinkPropertiesEventually(n, "become non-null") { it != null } + } + + fun assertLinkPropertiesEventuallyNull(n: Network) { + assertLinkPropertiesEventually(n, "become null") { it == null } + } + @Test fun testSetSubtypeNameAndExtraInfoByAgentConfig() { val subtypeLTE = TelephonyManager.NETWORK_TYPE_LTE @@ -1232,8 +1254,40 @@ class NetworkAgentTest { agent5.expectCallback() agent5.expectCallback() + // If unregisterAfterReplacement is called before markConnected, the network disconnects. + val specifier6 = UUID.randomUUID().toString() + val callback = TestableNetworkCallback() + requestNetwork(makeTestNetworkRequest(specifier = specifier6), callback) + val agent6 = createNetworkAgent(specifier = specifier6) + val network6 = agent6.register() + // No callbacks are sent, so check the LinkProperties to see if the network has connected. + assertLinkPropertiesEventuallyNotNull(agent6.network!!) + + // unregisterAfterReplacement tears down the network immediately. + // Approximately check that this is the case by picking an unregister timeout that's longer + // than the timeout of the expectCallback below. + // TODO: consider adding configurable timeouts to TestableNetworkAgent expectations. + val timeoutMs = agent6.DEFAULT_TIMEOUT_MS.toInt() + 1_000 + agent6.unregisterAfterReplacement(timeoutMs) + agent6.expectCallback() + if (!SdkLevel.isAtLeastT()) { + // Before T, onNetworkDestroyed is called even if the network was never created. + agent6.expectCallback() + } + // Poll for LinkProperties becoming null, because when onNetworkUnwanted is called, the + // network has not yet been removed from the CS data structures. + assertLinkPropertiesEventuallyNull(agent6.network!!) + assertFalse(mCM.getAllNetworks().contains(agent6.network!!)) + + // After unregisterAfterReplacement is called, the network is no longer usable and + // markConnected has no effect. + agent6.markConnected() + agent6.assertNoCallback() + assertNull(mCM.getLinkProperties(agent6.network!!)) + matchAllCallback.assertNoCallback(200 /* timeoutMs */) + // If wifi is replaced within the timeout, the device does not switch to cellular. - val (cellAgent, cellNetwork) = connectNetwork(TRANSPORT_CELLULAR) + val (_, cellNetwork) = connectNetwork(TRANSPORT_CELLULAR) testCallback.expectAvailableThenValidatedCallbacks(cellNetwork) matchAllCallback.expectAvailableThenValidatedCallbacks(cellNetwork)