From 3abe36567c8afd63f116e7fe736584d80cb63165 Mon Sep 17 00:00:00 2001 From: Treehugger Robot Date: Mon, 15 Jun 2020 10:18:21 +0000 Subject: [PATCH] Fix CtsTetheringTest on devices without permanent softAp interfaces. Normally stop wifi tethering flow would be: Tethering#stopTethering -> WifiManager#stopSoftAp -> softAp disabled, then have WIIF_AP_STATE_CHANGED intent -> stop IpServer and broadcast TETHER_STATE_CHANGED intent. SoftAp is disabled before tethering stop. Because tethering would shutdown the corresponding IpServer if it observed the interface is removed. For those devices that softAp interface would be removed when stop tethering, the flow may be Tethering#stopTethering -> WifiManager#stopSoftAp -> softAp disabing, softAp interface is removed -> tethering trigger stop IpServer and broadcast TETHER_STATE_CHANGED intent -> -> softAp disabled, then wifi broadcast WIIF_AP_STATE_CHANGED intent. In this case, tethering is stopped ready before softap is disabled. For this case, CtsTeteringTest would have race between two test cases. If two case need to start wifi tethering for testing and stop wifi tethering after finish testing. The second test may suffer from startTethering fail problem due to softAP is not disabled yet. E WifiService: Tethering is already active. Bug: 157806780 Test: atest CtsTetheringTest Original-Change: https://android-review.googlesource.com/1331096 Merged-In: I0ba6bc9dcbf7829dcad5561c707d5f5c5540f10b Change-Id: I0ba6bc9dcbf7829dcad5561c707d5f5c5540f10b --- .../tethering/cts/TetheringManagerTest.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java index f7160dd502..5e2f62787c 100644 --- a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java +++ b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java @@ -57,8 +57,11 @@ import android.net.TetheringManager.TetheringInterfaceRegexps; import android.net.TetheringManager.TetheringRequest; import android.net.cts.util.CtsNetUtils; import android.net.cts.util.CtsNetUtils.TestNetworkCallback; +import android.net.wifi.WifiClient; import android.net.wifi.WifiManager; +import android.net.wifi.WifiManager.SoftApCallback; import android.os.Bundle; +import android.os.ConditionVariable; import android.os.PersistableBundle; import android.os.ResultReceiver; import android.telephony.CarrierConfigManager; @@ -135,6 +138,40 @@ public class TetheringManagerTest { dropShellPermissionIdentity(); } + private static class StopSoftApCallback implements SoftApCallback { + private final ConditionVariable mWaiting = new ConditionVariable(); + @Override + public void onStateChanged(int state, int failureReason) { + if (state == WifiManager.WIFI_AP_STATE_DISABLED) mWaiting.open(); + } + + @Override + public void onConnectedClientsChanged(List clients) { } + + public void waitForSoftApStopped() { + if (!mWaiting.block(DEFAULT_TIMEOUT_MS)) { + fail("stopSoftAp Timeout"); + } + } + } + + // Wait for softAp to be disabled. This is necessary on devices where stopping softAp + // deletes the interface. On these devices, tethering immediately stops when the softAp + // interface is removed, but softAp is not yet fully disabled. Wait for softAp to be + // fully disabled, because otherwise the next test might fail because it attempts to + // start softAp before it's fully stopped. + private void expectSoftApDisabled() { + final StopSoftApCallback callback = new StopSoftApCallback(); + try { + mWm.registerSoftApCallback(c -> c.run(), callback); + // registerSoftApCallback will immediately call the callback with the current state, so + // this callback will fire even if softAp is already disabled. + callback.waitForSoftApStopped(); + } finally { + mWm.unregisterSoftApCallback(callback); + } + } + private class TetherChangeReceiver extends BroadcastReceiver { private class TetherState { final ArrayList mAvailable; @@ -294,6 +331,7 @@ public class TetheringManagerTest { mTetherChangeReceiver.expectTethering(true /* active */, wifiRegexs); mTM.stopTethering(TETHERING_WIFI); + expectSoftApDisabled(); mTetherChangeReceiver.expectTethering(false /* active */, wifiRegexs); } @@ -544,6 +582,7 @@ public class TetheringManagerTest { private void stopWifiTethering(final TestTetheringEventCallback callback) { mTM.stopTethering(TETHERING_WIFI); + expectSoftApDisabled(); callback.expectTetheredInterfacesChanged(null); callback.expectOneOfOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED); }