summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRebecca Silberstein <silberst@google.com>2016-11-21 19:22:19 +0000
committerandroid-build-merger <android-build-merger@google.com>2016-11-21 19:22:19 +0000
commit8cc7a77953dca3ec2d6c8bdc62ca789c508b1efb (patch)
treed1e685f148d2ec30b052dbd37fbeb473db2ee063
parent9dee6afa78e114fb6405746d3f40502a34978002 (diff)
parentfa528234cf518fda63435cf9c4956576d64e8860 (diff)
WifiStateMachinePrime: allow for configs in softap
am: fa528234cf Change-Id: I5c44ca0c80956d65a8c35429c9b4aa5a57927645
-rw-r--r--service/java/com/android/server/wifi/WifiStateMachinePrime.java91
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiStateMachinePrimeTest.java152
2 files changed, 176 insertions, 67 deletions
diff --git a/service/java/com/android/server/wifi/WifiStateMachinePrime.java b/service/java/com/android/server/wifi/WifiStateMachinePrime.java
index dbb826293..200688494 100644
--- a/service/java/com/android/server/wifi/WifiStateMachinePrime.java
+++ b/service/java/com/android/server/wifi/WifiStateMachinePrime.java
@@ -30,6 +30,9 @@ import com.android.internal.util.Protocol;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
/**
* This class provides the implementation for different WiFi operating modes.
*
@@ -47,6 +50,8 @@ public class WifiStateMachinePrime {
private IWificond mWificond;
+ private Queue<WifiConfiguration> mApConfigQueue = new ConcurrentLinkedQueue<>();
+
/* The base for wifi message types */
static final int BASE = Protocol.BASE_WIFI;
@@ -100,8 +105,19 @@ public class WifiStateMachinePrime {
/**
* Method to enable soft ap for wifi hotspot.
+ *
+ * The WifiConfiguration is generally going to be null to indicate that the
+ * currently saved config in WifiApConfigManager should be used. When the config is
+ * not null, it will be saved in the WifiApConfigManager. This save is performed in the
+ * constructor of SoftApManager.
+ *
+ * @param wifiConfig WifiConfiguration for the hostapd softap
*/
- public void enterSoftAPMode() {
+ public void enterSoftAPMode(WifiConfiguration wifiConfig) {
+ if (wifiConfig == null) {
+ wifiConfig = new WifiConfiguration();
+ }
+ mApConfigQueue.offer(wifiConfig);
changeMode(ModeStateMachine.CMD_START_SOFT_AP_MODE);
}
@@ -128,12 +144,10 @@ public class WifiStateMachinePrime {
Log.e(TAG, "Received call to disable wifi when it is already disabled.");
return;
}
- // state machine was not initialized yet, we must be starting up
- mModeStateMachine = new ModeStateMachine(newMode);
- } else {
- // we have a current state, go ahead and prep for the new state
- mModeStateMachine.sendMessage(newMode);
+ // state machine was not initialized yet, we must be starting up.
+ mModeStateMachine = new ModeStateMachine();
}
+ mModeStateMachine.sendMessage(newMode);
}
private class ModeStateMachine extends StateMachine {
@@ -154,7 +168,7 @@ public class WifiStateMachinePrime {
private final State mScanOnlyModeActiveState = new ScanOnlyModeActiveState();
private final State mSoftAPModeActiveState = new SoftAPModeActiveState();
- ModeStateMachine(int initialMode) {
+ ModeStateMachine() {
super(TAG, mLooper);
// CHECKSTYLE:OFF IndentationCheck
@@ -167,24 +181,8 @@ public class WifiStateMachinePrime {
addState(mWifiDisabledState);
// CHECKSTYLE:ON IndentationCheck
- State startingState;
- switch(initialMode) {
- case CMD_START_CLIENT_MODE:
- startingState = mClientModeState;
- break;
- case CMD_START_SCAN_ONLY_MODE:
- startingState = mScanOnlyModeState;
- break;
- case CMD_START_SOFT_AP_MODE:
- startingState = mSoftAPModeState;
- break;
- default:
- Log.e(TAG, "Attempting to start WifiStateMachinePrime "
- + "in an invalid operating mode: " + initialMode);
- throw new IllegalArgumentException("Invalid wifi operating mode");
- }
- Log.d(TAG, "Switching from WifiDisabled to " + startingState.getName());
- setInitialState(startingState);
+ Log.d(TAG, "Starting Wifi in WifiDisabledState");
+ setInitialState(mWifiDisabledState);
start();
}
@@ -275,10 +273,18 @@ public class WifiStateMachinePrime {
@Override
public void enter() {
+ final Message message = mModeStateMachine.getCurrentMessage();
+ if (message.what != ModeStateMachine.CMD_START_SOFT_AP_MODE) {
+ Log.d(TAG, "Entering SoftAPMode (idle)");
+ return;
+ }
+
+ // Continue with setup since we are changing modes
mApInterface = null;
mWificond = mWifiInjector.makeWificond();
if (mWificond == null) {
Log.e(TAG, "Failed to get reference to wificond");
+ writeApConfigDueToStartFailure();
mModeStateMachine.sendMessage(CMD_START_AP_FAILURE);
return;
}
@@ -289,10 +295,11 @@ public class WifiStateMachinePrime {
if (mApInterface == null) {
Log.e(TAG, "Could not get IApInterface instance from wificond");
+ writeApConfigDueToStartFailure();
mModeStateMachine.sendMessage(CMD_START_AP_FAILURE);
return;
}
- mModeStateMachine.sendMessage(CMD_START_AP);
+ mModeStateMachine.transitionTo(mSoftAPModeActiveState);
}
@Override
@@ -303,8 +310,7 @@ public class WifiStateMachinePrime {
switch(message.what) {
case CMD_START_AP:
- Log.d(TAG, "Transitioning to softapmodeactivestate");
- mModeStateMachine.transitionTo(mSoftAPModeActiveState);
+ Log.d(TAG, "Received CMD_START_AP (now invalid message) - dropping");
break;
case CMD_STOP_AP:
// not in active state, nothing to stop.
@@ -329,16 +335,29 @@ public class WifiStateMachinePrime {
protected IApInterface getInterface() {
return mApInterface;
}
+
+ private void writeApConfigDueToStartFailure() {
+ WifiConfiguration config = mApConfigQueue.poll();
+ if (config != null && config.SSID != null) {
+ // Save valid configs for future calls.
+ mWifiInjector.getWifiApConfigStore().setApConfiguration(config);
+ }
+ }
}
class WifiDisabledState extends State {
@Override
public void enter() {
// make sure everything is torn down
+ Log.d(TAG, "Entering WifiDisabledState");
}
@Override
public boolean processMessage(Message message) {
+ Log.d(TAG, "received a message in WifiDisabledState: " + message);
+ if (checkForAndHandleModeChange(message)) {
+ return HANDLED;
+ }
return NOT_HANDLED;
}
@@ -390,15 +409,13 @@ public class WifiStateMachinePrime {
@Override
public void enter() {
Log.d(TAG, "Entering SoftApModeActiveState");
- final Message message = mModeStateMachine.getCurrentMessage();
- if (message.what != CMD_START_AP) {
- throw new RuntimeException("Illegal transition to SoftApState: " + message);
+ WifiConfiguration config = mApConfigQueue.poll();
+ if (config != null && config.SSID != null) {
+ Log.d(TAG, "Passing config to SoftApManager! " + config);
+ } else {
+ config = null;
}
- // The WifiConfiguration is generally going to be null to indicate that the
- // currently saved config in WifiApConfigManager should be used. When the config is
- // not null, it will be saved in the WifiApConfigManager. This save is performed in
- // the constructor of SoftApManager.
- WifiConfiguration config = (WifiConfiguration) message.obj;
+
this.mActiveModeManager = mWifiInjector.makeSoftApManager(mNMService,
new SoftApListener(), ((SoftAPModeState) mSoftAPModeState).getInterface(),
config);
@@ -409,7 +426,7 @@ public class WifiStateMachinePrime {
public boolean processMessage(Message message) {
switch(message.what) {
case CMD_START_AP:
- Log.d(TAG, "Received CMD_START_AP with SoftApMode already active. drop");
+ Log.d(TAG, "Received CMD_START_AP when active - invalid message - drop");
break;
case CMD_STOP_AP:
mActiveModeManager.stop();
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiStateMachinePrimeTest.java b/tests/wifitests/src/com/android/server/wifi/WifiStateMachinePrimeTest.java
index cf20ecc56..879862bf9 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiStateMachinePrimeTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiStateMachinePrimeTest.java
@@ -52,13 +52,13 @@ public class WifiStateMachinePrimeTest {
private static final String SOFT_AP_MODE_ACTIVE_STATE_STRING = "SoftAPModeActiveState";
@Mock WifiInjector mWifiInjector;
+ @Mock WifiApConfigStore mWifiApConfigStore;
TestLooper mLooper;
@Mock IWificond mWificond;
@Mock IApInterface mApInterface;
@Mock INetworkManagementService mNMService;
@Mock SoftApManager mSoftApManager;
SoftApManager.Listener mSoftApListener;
- @Mock WifiConfiguration mApConfig;
WifiStateMachinePrime mWifiStateMachinePrime;
/**
@@ -88,33 +88,39 @@ public class WifiStateMachinePrimeTest {
mWifiStateMachinePrime = null;
}
+ private void enterSoftApActiveMode() throws Exception {
+ enterSoftApActiveMode(null);
+ }
+
/**
* Helper method to enter the SoftApActiveMode for WifiStateMachinePrime.
*
* This method puts the test object into the correct state and verifies steps along the way.
*/
- private void enterSoftApActiveMode() throws Exception {
+ private void enterSoftApActiveMode(WifiConfiguration wifiConfig) throws Exception {
String fromState = mWifiStateMachinePrime.getCurrentMode();
when(mWifiInjector.makeWificond()).thenReturn(mWificond);
when(mWificond.createApInterface()).thenReturn(mApInterface);
doAnswer(
new Answer<Object>() {
public SoftApManager answer(InvocationOnMock invocation) {
- mSoftApListener = (SoftApManager.Listener) invocation.getArguments()[1];
+ Object[] args = invocation.getArguments();
+ assertEquals(mNMService, (INetworkManagementService) args[0]);
+ mSoftApListener = (SoftApManager.Listener) args[1];
+ assertEquals(mApInterface, (IApInterface) args[2]);
+ assertEquals(wifiConfig, (WifiConfiguration) args[3]);
return mSoftApManager;
}
}).when(mWifiInjector).makeSoftApManager(any(INetworkManagementService.class),
any(SoftApManager.Listener.class),
any(IApInterface.class),
any(WifiConfiguration.class));
- mWifiStateMachinePrime.enterSoftAPMode();
- mLooper.dispatchNext();
- assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
+ mWifiStateMachinePrime.enterSoftAPMode(wifiConfig);
+ mLooper.dispatchAll();
Log.e("WifiStateMachinePrimeTest", "check fromState: " + fromState);
if (!fromState.equals(WIFI_DISABLED_STATE_STRING)) {
verify(mWificond).tearDownInterfaces();
}
- mLooper.dispatchNext();
assertEquals(SOFT_AP_MODE_ACTIVE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
verify(mSoftApManager).start();
}
@@ -151,7 +157,7 @@ public class WifiStateMachinePrimeTest {
public void testEnterSoftApModeFromDifferentState() throws Exception {
when(mWifiInjector.makeWificond()).thenReturn(mWificond);
mWifiStateMachinePrime.enterClientMode();
- mLooper.dispatchNext();
+ mLooper.dispatchAll();
assertEquals(CLIENT_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
enterSoftApActiveMode();
}
@@ -164,7 +170,7 @@ public class WifiStateMachinePrimeTest {
enterSoftApActiveMode();
mWifiStateMachinePrime.disableWifi();
- mLooper.dispatchNext();
+ mLooper.dispatchAll();
verify(mSoftApManager).stop();
verify(mWificond).tearDownInterfaces();
assertEquals(WIFI_DISABLED_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
@@ -177,14 +183,12 @@ public class WifiStateMachinePrimeTest {
public void testDisableWifiFromSoftApModeState() throws Exception {
// Use a failure getting wificond to stay in the SoftAPModeState
when(mWifiInjector.makeWificond()).thenReturn(null);
- mWifiStateMachinePrime.enterSoftAPMode();
- mLooper.dispatchNext();
- assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
- mLooper.dispatchNext();
+ mWifiStateMachinePrime.enterSoftAPMode(null);
+ mLooper.dispatchAll();
assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
mWifiStateMachinePrime.disableWifi();
- mLooper.dispatchNext();
+ mLooper.dispatchAll();
// mWificond will be null due to this test, no call to tearDownInterfaces here.
assertEquals(WIFI_DISABLED_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
}
@@ -199,7 +203,7 @@ public class WifiStateMachinePrimeTest {
enterSoftApActiveMode();
mWifiStateMachinePrime.enterClientMode();
- mLooper.dispatchNext();
+ mLooper.dispatchAll();
verify(mSoftApManager).stop();
verify(mWificond).tearDownInterfaces();
assertEquals(CLIENT_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
@@ -214,10 +218,8 @@ public class WifiStateMachinePrimeTest {
@Test
public void testWificondNullWhenSwitchingToApMode() throws Exception {
when(mWifiInjector.makeWificond()).thenReturn(null);
- mWifiStateMachinePrime.enterSoftAPMode();
- mLooper.dispatchNext();
- assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
- mLooper.dispatchNext();
+ mWifiStateMachinePrime.enterSoftAPMode(null);
+ mLooper.dispatchAll();
assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
}
@@ -231,10 +233,8 @@ public class WifiStateMachinePrimeTest {
public void testAPInterfaceFailedWhenSwitchingToApMode() throws Exception {
when(mWifiInjector.makeWificond()).thenReturn(mWificond);
when(mWificond.createApInterface()).thenReturn(null);
- mWifiStateMachinePrime.enterSoftAPMode();
- mLooper.dispatchNext();
- assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
- mLooper.dispatchNext();
+ mWifiStateMachinePrime.enterSoftAPMode(null);
+ mLooper.dispatchAll();
assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
}
@@ -247,14 +247,11 @@ public class WifiStateMachinePrimeTest {
public void testEnterSoftApModeActiveWhenAlreadyInSoftApMode() throws Exception {
when(mWifiInjector.makeWificond()).thenReturn(mWificond);
when(mWificond.createApInterface()).thenReturn(null);
- mWifiStateMachinePrime.enterSoftAPMode();
- mLooper.dispatchNext();
- assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
- mLooper.dispatchNext();
+ mWifiStateMachinePrime.enterSoftAPMode(null);
+ mLooper.dispatchAll();
assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
enterSoftApActiveMode();
- verify(mWificond).tearDownInterfaces();
}
/**
@@ -267,7 +264,7 @@ public class WifiStateMachinePrimeTest {
enterSoftApActiveMode();
// now inject failure through the SoftApManager.Listener
mSoftApListener.onStateChanged(WifiManager.WIFI_AP_STATE_FAILED, 0);
- mLooper.dispatchNext();
+ mLooper.dispatchAll();
assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
verify(mSoftApManager).stop();
}
@@ -282,12 +279,107 @@ public class WifiStateMachinePrimeTest {
enterSoftApActiveMode();
// now inject failure through the SoftApManager.Listener
mSoftApListener.onStateChanged(WifiManager.WIFI_AP_STATE_FAILED, 0);
- mLooper.dispatchNext();
+ mLooper.dispatchAll();
assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
verify(mSoftApManager).stop();
}
/**
+ * Test that a config passed in to the call to enterSoftApMode is used to create the new
+ * SoftApManager.
+ * Expectations: We should create a SoftApManager in WifiInjector with the config passed in to
+ * WifiStateMachinePrime to switch to SoftApMode.
+ */
+ @Test
+ public void testConfigIsPassedToWifiInjector() throws Exception {
+ WifiConfiguration config = new WifiConfiguration();
+ config.SSID = "ThisIsAConfig";
+ enterSoftApActiveMode(config);
+ }
+
+ /**
+ * Test that when enterSoftAPMode is called with a null config, we pass a null config to
+ * WifiInjector.makeSoftApManager.
+ *
+ * Passing a null config to SoftApManager indicates that the default config should be used.
+ *
+ * Expectations: WifiInjector should be called with a null config.
+ */
+ @Test
+ public void testNullConfigIsPassedToWifiInjector() throws Exception {
+ enterSoftApActiveMode(null);
+ }
+
+ /**
+ * Test that the proper config is used if a prior attempt fails without using the config.
+ * Expectations: A call to start softap with a null config fails, but a second call has a set
+ * config - this second call should use the correct config.
+ */
+ @Test
+ public void testNullConfigFailsSecondCallWithConfigSuccessful() throws Exception {
+ when(mWifiInjector.makeWificond()).thenReturn(mWificond);
+ when(mWificond.createApInterface()).thenReturn(null);
+ mWifiStateMachinePrime.enterSoftAPMode(null);
+ mLooper.dispatchAll();
+ assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
+ WifiConfiguration config = new WifiConfiguration();
+ config.SSID = "ThisIsAConfig";
+ enterSoftApActiveMode(config);
+ }
+
+ /**
+ * Test that a failed call to start softap with a valid config has the config saved for future
+ * calls to enable softap.
+ *
+ * Expectations: A call to start SoftAPMode with a config should write out the config if we
+ * did not create a SoftApManager.
+ */
+ @Test
+ public void testValidConfigIsSavedOnFailureToStart() throws Exception {
+ when(mWifiInjector.makeWificond()).thenReturn(null);
+ when(mWifiInjector.getWifiApConfigStore()).thenReturn(mWifiApConfigStore);
+ WifiConfiguration config = new WifiConfiguration();
+ config.SSID = "ThisIsAConfig";
+ mWifiStateMachinePrime.enterSoftAPMode(config);
+ mLooper.dispatchAll();
+ assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
+ verify(mWifiApConfigStore).setApConfiguration(eq(config));
+ }
+
+ /**
+ * Thest that two calls to switch to SoftAPMode in succession ends up with the correct config.
+ *
+ * Expectation: we should end up in SoftAPMode state configured with the second config.
+ */
+ @Test
+ public void testStartSoftApModeTwiceWithTwoConfigs() throws Exception {
+ when(mWifiInjector.makeWificond()).thenReturn(mWificond);
+ when(mWificond.createApInterface()).thenReturn(mApInterface);
+ when(mWifiInjector.getWifiApConfigStore()).thenReturn(mWifiApConfigStore);
+ WifiConfiguration config1 = new WifiConfiguration();
+ config1.SSID = "ThisIsAConfig";
+ WifiConfiguration config2 = new WifiConfiguration();
+ config2.SSID = "ThisIsASecondConfig";
+
+ when(mWifiInjector.makeSoftApManager(any(INetworkManagementService.class),
+ any(SoftApManager.Listener.class),
+ any(IApInterface.class),
+ eq(config1)))
+ .thenReturn(mSoftApManager);
+ when(mWifiInjector.makeSoftApManager(any(INetworkManagementService.class),
+ any(SoftApManager.Listener.class),
+ any(IApInterface.class),
+ eq(config2)))
+ .thenReturn(mSoftApManager);
+
+
+ mWifiStateMachinePrime.enterSoftAPMode(config1);
+ mWifiStateMachinePrime.enterSoftAPMode(config2);
+ mLooper.dispatchAll();
+ assertEquals(SOFT_AP_MODE_ACTIVE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
+ }
+
+ /**
* Test that we safely disable wifi if it is already disabled.
* Expectations: We should not interact with wificond since we should have already cleaned up
* everything.