diff options
8 files changed, 163 insertions, 4 deletions
diff --git a/service/java/com/android/server/wifi/ActiveModeManager.java b/service/java/com/android/server/wifi/ActiveModeManager.java index aa0bf9f6b..0983e9b93 100644 --- a/service/java/com/android/server/wifi/ActiveModeManager.java +++ b/service/java/com/android/server/wifi/ActiveModeManager.java @@ -59,6 +59,11 @@ public interface ActiveModeManager { */ void stop(); + /** + * Method used to indicate if the mode manager is still stopping. + */ + boolean isStopping(); + /** Roles assigned to each mode manager. */ int ROLE_UNSPECIFIED = -1; // SoftApManager - Tethering, will respond to public APIs. diff --git a/service/java/com/android/server/wifi/ActiveModeWarden.java b/service/java/com/android/server/wifi/ActiveModeWarden.java index 03334584b..e0a0a3d29 100644 --- a/service/java/com/android/server/wifi/ActiveModeWarden.java +++ b/service/java/com/android/server/wifi/ActiveModeWarden.java @@ -282,6 +282,16 @@ public class ActiveModeWarden { } /** + * @return true if any mode manager is stopping + */ + private boolean hasAnyModeManagerStopping() { + for (ActiveModeManager manager : mActiveModeManagers) { + if (manager.isStopping()) return true; + } + return false; + } + + /** * @return true if all the client mode managers are in scan only role, * false if there are no client mode managers present or if any of them are not in scan only * role. @@ -886,8 +896,16 @@ public class ActiveModeWarden { if (mSettingsStore.isAirplaneModeOn()) { return NOT_HANDLED; } else { - // when airplane mode is toggled off, but wifi is on, we can keep it on - log("airplane mode toggled - and airplane mode is off. return handled"); + if (hasAnyModeManagerStopping()) { + // previous airplane mode toggle on is being processed, defer the + // message toggle off until previous processing is completed. + deferMessage(msg); + } else { + // when airplane mode is toggled off, but wifi is on, we can keep it + // on + log("airplane mode toggled - and airplane mode is off. return " + + "handled"); + } return HANDLED; } case CMD_AP_STOPPED: diff --git a/service/java/com/android/server/wifi/ClientModeManager.java b/service/java/com/android/server/wifi/ClientModeManager.java index 61df5191b..abb6f625d 100644 --- a/service/java/com/android/server/wifi/ClientModeManager.java +++ b/service/java/com/android/server/wifi/ClientModeManager.java @@ -76,9 +76,9 @@ public class ClientModeManager implements ActiveModeManager { private String mClientInterfaceName; private boolean mIfaceIsUp = false; - private @Role int mRole = ROLE_UNSPECIFIED; private DeferStopHandler mDeferStopHandler; - private int mTargetRole = ROLE_UNSPECIFIED; + private @Role int mRole = ROLE_UNSPECIFIED; + private @Role int mTargetRole = ROLE_UNSPECIFIED; private int mActiveSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; ClientModeManager(Context context, @NonNull Looper looper, Clock clock, WifiNative wifiNative, @@ -122,6 +122,11 @@ public class ClientModeManager implements ActiveModeManager { mDeferStopHandler.start(getWifiOffDeferringTimeMs()); } + @Override + public boolean isStopping() { + return mTargetRole == ROLE_UNSPECIFIED && mRole != ROLE_UNSPECIFIED; + } + private class DeferStopHandler extends WifiHandler { private boolean mIsDeferring = false; private ImsMmTelManager mImsMmTelManager = null; diff --git a/service/java/com/android/server/wifi/DefaultModeManager.java b/service/java/com/android/server/wifi/DefaultModeManager.java index cda4978b8..00b2117a8 100644 --- a/service/java/com/android/server/wifi/DefaultModeManager.java +++ b/service/java/com/android/server/wifi/DefaultModeManager.java @@ -45,6 +45,11 @@ public class DefaultModeManager implements ActiveModeManager { @Override public void stop() { }; + @Override + public boolean isStopping() { + return false; + } + /** * No role specified in default mode. */ diff --git a/service/java/com/android/server/wifi/SoftApManager.java b/service/java/com/android/server/wifi/SoftApManager.java index 3bf12ca34..f9720477b 100644 --- a/service/java/com/android/server/wifi/SoftApManager.java +++ b/service/java/com/android/server/wifi/SoftApManager.java @@ -122,6 +122,7 @@ public class SoftApManager implements ActiveModeManager { private BaseWifiDiagnostics mWifiDiagnostics; private @Role int mRole = ROLE_UNSPECIFIED; + private @Role int mTargetRole = ROLE_UNSPECIFIED; private boolean mEverReportMetricsForMaxClient = false; @@ -219,6 +220,7 @@ public class SoftApManager implements ActiveModeManager { @Override public void stop() { Log.d(TAG, " currentstate: " + getCurrentStateName()); + mTargetRole = ROLE_UNSPECIFIED; if (mApInterfaceName != null) { if (mIfaceIsUp) { updateApState(WifiManager.WIFI_AP_STATE_DISABLING, @@ -232,6 +234,11 @@ public class SoftApManager implements ActiveModeManager { } @Override + public boolean isStopping() { + return mTargetRole == ROLE_UNSPECIFIED && mRole != ROLE_UNSPECIFIED; + } + + @Override public @Role int getRole() { return mRole; } @@ -241,6 +248,7 @@ public class SoftApManager implements ActiveModeManager { // softap does not allow in-place switching of roles. Preconditions.checkState(mRole == ROLE_UNSPECIFIED); Preconditions.checkState(SOFTAP_ROLES.contains(role)); + mTargetRole = role; mRole = role; } diff --git a/tests/wifitests/src/com/android/server/wifi/ActiveModeWardenTest.java b/tests/wifitests/src/com/android/server/wifi/ActiveModeWardenTest.java index db7b4e22f..ceaf76dc8 100644 --- a/tests/wifitests/src/com/android/server/wifi/ActiveModeWardenTest.java +++ b/tests/wifitests/src/com/android/server/wifi/ActiveModeWardenTest.java @@ -2172,4 +2172,112 @@ public class ActiveModeWardenTest extends WifiBaseTest { when(mWifiNative.isStaApConcurrencySupported()).thenReturn(true); assertTrue(mActiveModeWarden.isStaApConcurrencySupported()); } + + @Test + public void airplaneModeToggleOnDisablesWifi() throws Exception { + enterClientModeActiveState(); + assertInEnabledState(); + + assertWifiShutDown(() -> { + when(mSettingsStore.isAirplaneModeOn()).thenReturn(true); + mActiveModeWarden.airplaneModeToggled(); + mLooper.dispatchAll(); + }); + + mClientListener.onStopped(); + mLooper.dispatchAll(); + assertInDisabledState(); + } + + @Test + public void airplaneModeToggleOnDisablesSoftAp() throws Exception { + enterSoftApActiveMode(); + assertInEnabledState(); + + assertWifiShutDown(() -> { + when(mSettingsStore.isAirplaneModeOn()).thenReturn(true); + mActiveModeWarden.airplaneModeToggled(); + mLooper.dispatchAll(); + }); + + mSoftApListener.onStopped(); + mLooper.dispatchAll(); + assertInDisabledState(); + } + + @Test + public void airplaneModeToggleOffIsDeferredWhileProcessingToggleOnWithOneModeManager() + throws Exception { + enterClientModeActiveState(); + assertInEnabledState(); + + // APM toggle on + assertWifiShutDown(() -> { + when(mSettingsStore.isAirplaneModeOn()).thenReturn(true); + mActiveModeWarden.airplaneModeToggled(); + mLooper.dispatchAll(); + }); + + + // APM toggle off before the stop is complete. + assertInEnabledState(); + when(mClientModeManager.isStopping()).thenReturn(true); + when(mSettingsStore.isAirplaneModeOn()).thenReturn(false); + mActiveModeWarden.airplaneModeToggled(); + mLooper.dispatchAll(); + + mClientListener.onStopped(); + mLooper.dispatchAll(); + + verify(mClientModeManager, times(2)).start(); + verify(mClientModeManager, times(2)).setRole(ROLE_CLIENT_PRIMARY); + + mClientListener.onStarted(); + mLooper.dispatchAll(); + + // We should be back to enabled state. + assertInEnabledState(); + } + + @Test + public void airplaneModeToggleOffIsDeferredWhileProcessingToggleOnWithTwoModeManager() + throws Exception { + enterClientModeActiveState(); + enterSoftApActiveMode(); + assertInEnabledState(); + + // APM toggle on + assertWifiShutDown(() -> { + when(mSettingsStore.isAirplaneModeOn()).thenReturn(true); + mActiveModeWarden.airplaneModeToggled(); + mLooper.dispatchAll(); + }); + + + // APM toggle off before the stop is complete. + assertInEnabledState(); + when(mClientModeManager.isStopping()).thenReturn(true); + when(mSoftApManager.isStopping()).thenReturn(true); + when(mSettingsStore.isAirplaneModeOn()).thenReturn(false); + mActiveModeWarden.airplaneModeToggled(); + mLooper.dispatchAll(); + + // AP stopped, should not process APM toggle. + mSoftApListener.onStopped(); + mLooper.dispatchAll(); + verify(mClientModeManager, times(1)).start(); + verify(mClientModeManager, times(1)).setRole(ROLE_CLIENT_PRIMARY); + + // STA also stopped, should process APM toggle. + mClientListener.onStopped(); + mLooper.dispatchAll(); + verify(mClientModeManager, times(2)).start(); + verify(mClientModeManager, times(2)).setRole(ROLE_CLIENT_PRIMARY); + + mClientListener.onStarted(); + mLooper.dispatchAll(); + + // We should be back to enabled state. + assertInEnabledState(); + } } diff --git a/tests/wifitests/src/com/android/server/wifi/ClientModeManagerTest.java b/tests/wifitests/src/com/android/server/wifi/ClientModeManagerTest.java index b733ec0ac..1102d1f26 100644 --- a/tests/wifitests/src/com/android/server/wifi/ClientModeManagerTest.java +++ b/tests/wifitests/src/com/android/server/wifi/ClientModeManagerTest.java @@ -28,6 +28,7 @@ import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -469,8 +470,10 @@ public class ClientModeManagerTest extends WifiBaseTest { reset(mContext, mListener); setUpSystemServiceForContext(); mClientModeManager.stop(); + assertTrue(mClientModeManager.isStopping()); mLooper.dispatchAll(); verify(mListener).onStopped(); + assertFalse(mClientModeManager.isStopping()); verify(mImsMmTelManager, never()).registerImsRegistrationCallback(any(), any()); verify(mImsMmTelManager, never()).unregisterImsRegistrationCallback(any()); diff --git a/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java b/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java index ca7bc627c..99cd2db82 100644 --- a/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java +++ b/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java @@ -36,6 +36,8 @@ import static com.android.server.wifi.util.ApConfigUtil.DEFAULT_AP_CHANNEL; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.anyLong; @@ -676,6 +678,7 @@ public class SoftApManagerTest extends WifiBaseTest { InOrder order = inOrder(mCallback, mListener, mContext); mSoftApManager.stop(); + assertTrue(mSoftApManager.isStopping()); mLooper.dispatchAll(); ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); @@ -694,6 +697,8 @@ public class SoftApManagerTest extends WifiBaseTest { checkApStateChangedBroadcast(intentCaptor.getValue(), WIFI_AP_STATE_DISABLED, WIFI_AP_STATE_DISABLING, HOTSPOT_NO_ERROR, TEST_INTERFACE_NAME, softApModeConfig.getTargetMode()); + order.verify(mListener).onStopped(); + assertFalse(mSoftApManager.isStopping()); } /** @@ -729,6 +734,7 @@ public class SoftApManagerTest extends WifiBaseTest { WIFI_AP_STATE_DISABLING, HOTSPOT_NO_ERROR, TEST_INTERFACE_NAME, softApModeConfig.getTargetMode()); order.verify(mListener).onStopped(); + assertFalse(mSoftApManager.isStopping()); } /** @@ -1784,6 +1790,7 @@ public class SoftApManagerTest extends WifiBaseTest { mSoftApManager.start(); + mSoftApManager.setRole(ActiveModeManager.ROLE_SOFTAP_TETHERED); mLooper.dispatchAll(); verify(mFakeSoftApNotifier).dismissSoftApShutDownTimeoutExpiredNotification(); order.verify(mWifiNative).setupInterfaceForSoftApMode( |