diff options
6 files changed, 98 insertions, 22 deletions
diff --git a/service/java/com/android/server/wifi/ClientModeManager.java b/service/java/com/android/server/wifi/ClientModeManager.java index 922d21958..b5300d24c 100644 --- a/service/java/com/android/server/wifi/ClientModeManager.java +++ b/service/java/com/android/server/wifi/ClientModeManager.java @@ -53,6 +53,8 @@ public class ClientModeManager implements ActiveModeManager { private String mClientInterfaceName; private boolean mIfaceIsUp = false; + private boolean mExpectedStop = false; + ClientModeManager(Context context, @NonNull Looper looper, WifiNative wifiNative, Listener listener, WifiMetrics wifiMetrics, ScanRequestProxy scanRequestProxy, WifiStateMachine wifiStateMachine) { @@ -77,6 +79,7 @@ public class ClientModeManager implements ActiveModeManager { */ public void stop() { Log.d(TAG, " currentstate: " + getCurrentStateName()); + mExpectedStop = true; if (mClientInterfaceName != null) { if (mIfaceIsUp) { updateWifiState(WifiManager.WIFI_STATE_DISABLING, @@ -127,7 +130,19 @@ public class ClientModeManager implements ActiveModeManager { * @param currentState current wifi state */ private void updateWifiState(int newState, int currentState) { - mListener.onStateChanged(newState); + if (!mExpectedStop) { + mListener.onStateChanged(newState); + } else { + Log.d(TAG, "expected stop, not triggering callbacks: newState = " + newState); + } + + // Once we report the mode has stopped/failed any other stop signals are redundant + // note: this can happen in failure modes where we get multiple callbacks as underlying + // components/interface stops or the underlying interface is destroyed in cleanup + if (newState == WifiManager.WIFI_STATE_UNKNOWN + || newState == WifiManager.WIFI_STATE_DISABLED) { + mExpectedStop = true; + } if (newState == WifiManager.WIFI_STATE_UNKNOWN) { // do not need to broadcast failure to system @@ -314,6 +329,9 @@ public class ClientModeManager implements ActiveModeManager { updateWifiState(WifiManager.WIFI_STATE_DISABLED, WifiManager.WIFI_STATE_DISABLING); + + // once we leave started, nothing else to do... stop the state machine + mStateMachine.quitNow(); } } diff --git a/service/java/com/android/server/wifi/ScanOnlyModeManager.java b/service/java/com/android/server/wifi/ScanOnlyModeManager.java index a98c6ba66..346d2ca67 100644 --- a/service/java/com/android/server/wifi/ScanOnlyModeManager.java +++ b/service/java/com/android/server/wifi/ScanOnlyModeManager.java @@ -52,6 +52,8 @@ public class ScanOnlyModeManager implements ActiveModeManager { private String mClientInterfaceName; private boolean mIfaceIsUp = false; + private boolean mExpectedStop = false; + ScanOnlyModeManager(@NonNull Context context, @NonNull Looper looper, @NonNull WifiNative wifiNative, @NonNull Listener listener, @NonNull WifiMetrics wifiMetrics, @@ -78,6 +80,7 @@ public class ScanOnlyModeManager implements ActiveModeManager { */ public void stop() { Log.d(TAG, " currentstate: " + getCurrentStateName()); + mExpectedStop = true; mStateMachine.quitNow(); } @@ -118,6 +121,18 @@ public class ScanOnlyModeManager implements ActiveModeManager { * @param state new Wifi state */ private void updateWifiState(int state) { + if (mExpectedStop) { + Log.d(TAG, "expected stop, not triggering callbacks: state = " + state); + return; + } + + // Once we report the mode has stopped/failed any other stop signals are redundant + // note: this can happen in failure modes where we get multiple callbacks as underlying + // components/interface stops or the underlying interface is destroyed in cleanup + if (state == WifiManager.WIFI_STATE_UNKNOWN || state == WifiManager.WIFI_STATE_DISABLED) { + mExpectedStop = true; + } + mListener.onStateChanged(state); } @@ -266,6 +281,9 @@ public class ScanOnlyModeManager implements ActiveModeManager { mClientInterfaceName = null; } updateWifiState(WifiManager.WIFI_STATE_DISABLED); + + // once we leave started, nothing else to do... stop the state machine + mStateMachine.quitNow(); } } } diff --git a/service/java/com/android/server/wifi/SoftApManager.java b/service/java/com/android/server/wifi/SoftApManager.java index 2faf11577..6c52918a5 100644 --- a/service/java/com/android/server/wifi/SoftApManager.java +++ b/service/java/com/android/server/wifi/SoftApManager.java @@ -514,6 +514,7 @@ public class SoftApManager implements ActiveModeManager { WifiManager.WIFI_AP_STATE_DISABLING, 0); mApInterfaceName = null; mIfaceIsUp = false; + mStateMachine.quitNow(); } @Override diff --git a/service/java/com/android/server/wifi/WifiStateMachinePrime.java b/service/java/com/android/server/wifi/WifiStateMachinePrime.java index fcb199eee..85ea001fb 100644 --- a/service/java/com/android/server/wifi/WifiStateMachinePrime.java +++ b/service/java/com/android/server/wifi/WifiStateMachinePrime.java @@ -351,16 +351,24 @@ public class WifiStateMachinePrime { } class ClientModeActiveState extends ModeActiveState { + ClientListener mListener; private class ClientListener implements ClientModeManager.Listener { @Override public void onStateChanged(int state) { - Log.d(TAG, "State changed from client mode."); + // make sure this listener is still active + if (this != mListener) { + Log.d(TAG, "Client mode state change from previous manager"); + return; + } + + Log.d(TAG, "State changed from client mode. state = " + state); + if (state == WifiManager.WIFI_STATE_UNKNOWN) { // error while setting up client mode or an unexpected failure. - mModeStateMachine.sendMessage(CMD_CLIENT_MODE_FAILED); + mModeStateMachine.sendMessage(CMD_CLIENT_MODE_FAILED, this); } else if (state == WifiManager.WIFI_STATE_DISABLED) { // client mode stopped - mModeStateMachine.sendMessage(CMD_CLIENT_MODE_STOPPED); + mModeStateMachine.sendMessage(CMD_CLIENT_MODE_STOPPED, this); } else if (state == WifiManager.WIFI_STATE_ENABLED) { // client mode is ready to go Log.d(TAG, "client mode active"); @@ -374,7 +382,8 @@ public class WifiStateMachinePrime { public void enter() { Log.d(TAG, "Entering ClientModeActiveState"); - mManager = mWifiInjector.makeClientModeManager(new ClientListener()); + mListener = new ClientListener(); + mManager = mWifiInjector.makeClientModeManager(mListener); mManager.start(); mActiveModeManagers.add(mManager); @@ -382,6 +391,12 @@ public class WifiStateMachinePrime { } @Override + public void exit() { + super.exit(); + mListener = null; + } + + @Override public boolean processMessage(Message message) { if (checkForAndHandleModeChange(message)) { return HANDLED; @@ -392,12 +407,21 @@ public class WifiStateMachinePrime { Log.d(TAG, "Received CMD_START_CLIENT_MODE when active - drop"); break; case CMD_CLIENT_MODE_FAILED: + if (mListener != message.obj) { + Log.d(TAG, "Client mode state change from previous manager"); + return HANDLED; + } Log.d(TAG, "ClientMode failed, return to WifiDisabledState."); // notify WifiController that ClientMode failed mClientModeCallback.onStateChanged(WifiManager.WIFI_STATE_UNKNOWN); mModeStateMachine.transitionTo(mWifiDisabledState); break; case CMD_CLIENT_MODE_STOPPED: + if (mListener != message.obj) { + Log.d(TAG, "Client mode state change from previous manager"); + return HANDLED; + } + Log.d(TAG, "ClientMode stopped, return to WifiDisabledState."); // notify WifiController that ClientMode stopped mClientModeCallback.onStateChanged(WifiManager.WIFI_STATE_DISABLED); @@ -411,17 +435,23 @@ public class WifiStateMachinePrime { } class ScanOnlyModeActiveState extends ModeActiveState { + ScanOnlyListener mListener; private class ScanOnlyListener implements ScanOnlyModeManager.Listener { @Override public void onStateChanged(int state) { + if (this != mListener) { + Log.d(TAG, "ScanOnly mode state change from previous manager"); + return; + } + if (state == WifiManager.WIFI_STATE_UNKNOWN) { Log.d(TAG, "ScanOnlyMode mode failed"); // error while setting up scan mode or an unexpected failure. - mModeStateMachine.sendMessage(CMD_SCAN_ONLY_MODE_FAILED); + mModeStateMachine.sendMessage(CMD_SCAN_ONLY_MODE_FAILED, this); } else if (state == WifiManager.WIFI_STATE_DISABLED) { Log.d(TAG, "ScanOnlyMode stopped"); //scan only mode stopped - mModeStateMachine.sendMessage(CMD_SCAN_ONLY_MODE_STOPPED); + mModeStateMachine.sendMessage(CMD_SCAN_ONLY_MODE_STOPPED, this); } else if (state == WifiManager.WIFI_STATE_ENABLED) { // scan mode is ready to go Log.d(TAG, "scan mode active"); @@ -435,7 +465,8 @@ public class WifiStateMachinePrime { public void enter() { Log.d(TAG, "Entering ScanOnlyModeActiveState"); - mManager = mWifiInjector.makeScanOnlyModeManager(new ScanOnlyListener()); + mListener = new ScanOnlyListener(); + mManager = mWifiInjector.makeScanOnlyModeManager(mListener); mManager.start(); mActiveModeManagers.add(mManager); @@ -444,6 +475,12 @@ public class WifiStateMachinePrime { } @Override + public void exit() { + super.exit(); + mListener = null; + } + + @Override public boolean processMessage(Message message) { if (checkForAndHandleModeChange(message)) { return HANDLED; @@ -454,12 +491,22 @@ public class WifiStateMachinePrime { Log.d(TAG, "Received CMD_START_SCAN_ONLY_MODE when active - drop"); break; case CMD_SCAN_ONLY_MODE_FAILED: + if (mListener != message.obj) { + Log.d(TAG, "ScanOnly mode state change from previous manager"); + return HANDLED; + } + Log.d(TAG, "ScanOnlyMode failed, return to WifiDisabledState."); // notify WifiController that ScanOnlyMode failed mScanOnlyCallback.onStateChanged(WifiManager.WIFI_STATE_UNKNOWN); mModeStateMachine.transitionTo(mWifiDisabledState); break; case CMD_SCAN_ONLY_MODE_STOPPED: + if (mListener != message.obj) { + Log.d(TAG, "ScanOnly mode state change from previous manager"); + return HANDLED; + } + Log.d(TAG, "ScanOnlyMode stopped, return to WifiDisabledState."); // notify WifiController that ScanOnlyMode stopped mScanOnlyCallback.onStateChanged(WifiManager.WIFI_STATE_DISABLED); diff --git a/tests/wifitests/src/com/android/server/wifi/ClientModeManagerTest.java b/tests/wifitests/src/com/android/server/wifi/ClientModeManagerTest.java index b04caf54d..ca6ddfd61 100644 --- a/tests/wifitests/src/com/android/server/wifi/ClientModeManagerTest.java +++ b/tests/wifitests/src/com/android/server/wifi/ClientModeManagerTest.java @@ -158,7 +158,7 @@ public class ClientModeManagerTest { assertEquals(2, intents.size()); checkWifiStateChangedBroadcast(intents.get(0), WIFI_STATE_DISABLING, WIFI_STATE_UNKNOWN); checkWifiStateChangedBroadcast(intents.get(1), WIFI_STATE_DISABLED, WIFI_STATE_DISABLING); - checkWifiStateChangeListenerUpdate(WIFI_STATE_DISABLED); + checkWifiStateChangeListenerUpdate(WIFI_STATE_UNKNOWN); } /** @@ -227,11 +227,14 @@ public class ClientModeManagerTest { @Test public void clientModeStopCleansUpState() throws Exception { startClientModeAndVerifyEnabled(); - reset(mContext); + reset(mContext, mListener); mClientModeManager.stop(); mLooper.dispatchAll(); verifyNotificationsForCleanShutdown(WIFI_STATE_ENABLED); + + // on an explicit stop, we should not trigger the callback + verifyNoMoreInteractions(mListener); } /** @@ -309,11 +312,6 @@ public class ClientModeManagerTest { mClientModeManager.stop(); mLooper.dispatchAll(); - verify(mListener).onStateChanged(WIFI_STATE_DISABLING); - verify(mListener).onStateChanged(WIFI_STATE_DISABLED); - - reset(mListener); - // now trigger interface destroyed and make sure callback doesn't get called mInterfaceCallbackCaptor.getValue().onDestroyed(TEST_INTERFACE_NAME); mLooper.dispatchAll(); diff --git a/tests/wifitests/src/com/android/server/wifi/ScanOnlyModeManagerTest.java b/tests/wifitests/src/com/android/server/wifi/ScanOnlyModeManagerTest.java index 3ad57f535..41362eec6 100644 --- a/tests/wifitests/src/com/android/server/wifi/ScanOnlyModeManagerTest.java +++ b/tests/wifitests/src/com/android/server/wifi/ScanOnlyModeManagerTest.java @@ -170,7 +170,7 @@ public class ScanOnlyModeManagerTest { mLooper.dispatchAll(); verify(mWifiNative).teardownInterface(TEST_INTERFACE_NAME); verify(mContext, never()).sendStickyBroadcastAsUser(any(), eq(UserHandle.ALL)); - checkWifiStateChangeListenerUpdate(WIFI_STATE_DISABLED); + verifyNoMoreInteractions(mListener); } /** @@ -214,7 +214,6 @@ public class ScanOnlyModeManagerTest { mLooper.dispatchAll(); verify(mContext, never()).sendStickyBroadcastAsUser(any(), eq(UserHandle.ALL)); checkWifiStateChangeListenerUpdate(WIFI_STATE_UNKNOWN); - checkWifiStateChangeListenerUpdate(WIFI_STATE_DISABLED); verify(mScanRequestProxy).clearScanResults(); } @@ -246,10 +245,6 @@ public class ScanOnlyModeManagerTest { mScanOnlyModeManager.stop(); mLooper.dispatchAll(); - verify(mListener).onStateChanged(WIFI_STATE_DISABLED); - - reset(mListener); - // now trigger interface destroyed and make sure callback doesn't get called mInterfaceCallbackCaptor.getValue().onDestroyed(TEST_INTERFACE_NAME); mLooper.dispatchAll(); @@ -282,6 +277,5 @@ public class ScanOnlyModeManagerTest { inOrder.verify(mWakeupController).start(); inOrder.verify(mWakeupController).stop(); inOrder.verify(mWifiNative).teardownInterface(eq(TEST_INTERFACE_NAME)); - inOrder.verify(mListener).onStateChanged(eq(WIFI_STATE_DISABLED)); } } |