WifiControllerTest.java revision 24750cd1f8148d6a935bda96f3b17f22b0c1d8bd
1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.server.wifi; 18 19import static android.net.wifi.WifiManager.WIFI_MODE_FULL; 20 21import static com.android.server.wifi.WifiController.CMD_AP_STOPPED; 22import static com.android.server.wifi.WifiController.CMD_DEVICE_IDLE; 23import static com.android.server.wifi.WifiController.CMD_EMERGENCY_CALL_STATE_CHANGED; 24import static com.android.server.wifi.WifiController.CMD_EMERGENCY_MODE_CHANGED; 25import static com.android.server.wifi.WifiController.CMD_RESTART_WIFI; 26import static com.android.server.wifi.WifiController.CMD_SET_AP; 27import static com.android.server.wifi.WifiController.CMD_WIFI_TOGGLED; 28 29import static org.junit.Assert.assertEquals; 30import static org.mockito.Matchers.*; 31import static org.mockito.Mockito.*; 32 33import android.content.ContentResolver; 34import android.content.Context; 35import android.os.WorkSource; 36import android.test.suitebuilder.annotation.SmallTest; 37import android.util.Log; 38 39import com.android.internal.util.IState; 40import com.android.internal.util.StateMachine; 41 42import org.junit.After; 43import org.junit.Before; 44import org.junit.Test; 45import org.mockito.InOrder; 46import org.mockito.Mock; 47import org.mockito.MockitoAnnotations; 48 49import java.io.ByteArrayOutputStream; 50import java.io.PrintWriter; 51import java.lang.reflect.Method; 52 53/** 54 * Test WifiController for changes in and out of ECM and SoftAP modes. 55 */ 56@SmallTest 57public class WifiControllerTest { 58 59 private static final String TAG = "WifiControllerTest"; 60 61 private void dumpState() { 62 ByteArrayOutputStream stream = new ByteArrayOutputStream(); 63 PrintWriter writer = new PrintWriter(stream); 64 mWifiController.dump(null, writer, null); 65 writer.flush(); 66 Log.d(TAG, "WifiStateMachine state -" + stream.toString()); 67 } 68 69 private IState getCurrentState() throws Exception { 70 Method method = StateMachine.class.getDeclaredMethod("getCurrentState"); 71 method.setAccessible(true); 72 return (IState) method.invoke(mWifiController); 73 } 74 75 private void initializeSettingsStore() throws Exception { 76 when(mSettingsStore.isAirplaneModeOn()).thenReturn(false); 77 when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false); 78 when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(true); 79 } 80 81 MockLooper mLooper; 82 @Mock Context mContext; 83 @Mock WifiServiceImpl mService; 84 @Mock FrameworkFacade mFacade; 85 @Mock WifiSettingsStore mSettingsStore; 86 @Mock WifiStateMachine mWifiStateMachine; 87 @Mock WifiLockManager mWifiLockManager; 88 89 WifiController mWifiController; 90 91 @Before 92 public void setUp() throws Exception { 93 MockitoAnnotations.initMocks(this); 94 95 mLooper = new MockLooper(); 96 97 initializeSettingsStore(); 98 99 when(mContext.getContentResolver()).thenReturn(mock(ContentResolver.class)); 100 101 mWifiController = new WifiController(mContext, mWifiStateMachine, 102 mSettingsStore, mWifiLockManager, mLooper.getLooper(), mFacade); 103 104 mWifiController.start(); 105 mLooper.dispatchAll(); 106 } 107 108 @After 109 public void cleanUp() { 110 mLooper.dispatchAll(); 111 } 112 113 @Test 114 public void enableWifi() throws Exception { 115 assertEquals("StaDisabledWithScanState", getCurrentState().getName()); 116 117 when(mSettingsStore.isWifiToggleEnabled()).thenReturn(true); 118 mWifiController.sendMessage(CMD_WIFI_TOGGLED); 119 mLooper.dispatchAll(); 120 assertEquals("DeviceActiveState", getCurrentState().getName()); 121 122 when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false); 123 mWifiController.sendMessage(CMD_WIFI_TOGGLED); 124 mLooper.dispatchAll(); 125 assertEquals("StaDisabledWithScanState", getCurrentState().getName()); 126 127 when(mSettingsStore.isWifiToggleEnabled()).thenReturn(true); 128 mWifiController.sendMessage(CMD_WIFI_TOGGLED); 129 mLooper.dispatchAll(); 130 assertEquals("DeviceActiveState", getCurrentState().getName()); 131 } 132 133 @Test 134 public void testEcmOn() throws Exception { 135 enableWifi(); 136 137 // Test with WifiDisableInECBM turned on: 138 when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true); 139 doTestEcm(true); 140 } 141 142 @Test 143 public void testEcmOff() throws Exception { 144 enableWifi(); 145 146 // Test with WifiDisableInECBM turned off 147 when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(false); 148 doTestEcm(false); 149 } 150 151 private void assertInEcm(boolean ecmEnabled) throws Exception { 152 if (ecmEnabled) { 153 assertEquals("EcmState", getCurrentState().getName()); 154 } else { 155 assertEquals("DeviceActiveState", getCurrentState().getName()); 156 } 157 } 158 159 160 private void doTestEcm(boolean ecmEnabled) throws Exception { 161 162 // test ecm changed 163 mWifiController.sendMessage(CMD_EMERGENCY_MODE_CHANGED, 1); 164 mLooper.dispatchAll(); 165 assertInEcm(ecmEnabled); 166 167 mWifiController.sendMessage(CMD_EMERGENCY_MODE_CHANGED, 0); 168 mLooper.dispatchAll(); 169 assertEquals("DeviceActiveState", getCurrentState().getName()); 170 171 // test call state changed 172 mWifiController.sendMessage(CMD_EMERGENCY_CALL_STATE_CHANGED, 1); 173 mLooper.dispatchAll(); 174 assertInEcm(ecmEnabled); 175 176 mWifiController.sendMessage(CMD_EMERGENCY_CALL_STATE_CHANGED, 0); 177 mLooper.dispatchAll(); 178 assertEquals("DeviceActiveState", getCurrentState().getName()); 179 180 181 // test both changed (variation 1 - the good case) 182 mWifiController.sendMessage(CMD_EMERGENCY_CALL_STATE_CHANGED, 1); 183 mLooper.dispatchAll(); 184 assertInEcm(ecmEnabled); 185 186 mWifiController.sendMessage(CMD_EMERGENCY_MODE_CHANGED, 1); 187 mLooper.dispatchAll(); 188 assertInEcm(ecmEnabled); 189 190 mWifiController.sendMessage(CMD_EMERGENCY_CALL_STATE_CHANGED, 0); 191 mLooper.dispatchAll(); 192 assertInEcm(ecmEnabled); 193 194 mWifiController.sendMessage(CMD_EMERGENCY_MODE_CHANGED, 0); 195 mLooper.dispatchAll(); 196 assertEquals("DeviceActiveState", getCurrentState().getName()); 197 198 // test both changed (variation 2 - emergency call in ecm) 199 mWifiController.sendMessage(CMD_EMERGENCY_MODE_CHANGED, 1); 200 mLooper.dispatchAll(); 201 assertInEcm(ecmEnabled); 202 203 mWifiController.sendMessage(CMD_EMERGENCY_CALL_STATE_CHANGED, 1); 204 mLooper.dispatchAll(); 205 assertInEcm(ecmEnabled); 206 207 mWifiController.sendMessage(CMD_EMERGENCY_CALL_STATE_CHANGED, 0); 208 mLooper.dispatchAll(); 209 assertInEcm(ecmEnabled); 210 211 mWifiController.sendMessage(CMD_EMERGENCY_MODE_CHANGED, 0); 212 mLooper.dispatchAll(); 213 assertEquals("DeviceActiveState", getCurrentState().getName()); 214 215 // test both changed (variation 3 - not so good order of events) 216 mWifiController.sendMessage(CMD_EMERGENCY_CALL_STATE_CHANGED, 1); 217 mLooper.dispatchAll(); 218 assertInEcm(ecmEnabled); 219 220 mWifiController.sendMessage(CMD_EMERGENCY_MODE_CHANGED, 1); 221 mLooper.dispatchAll(); 222 assertInEcm(ecmEnabled); 223 224 mWifiController.sendMessage(CMD_EMERGENCY_MODE_CHANGED, 0); 225 mLooper.dispatchAll(); 226 assertInEcm(ecmEnabled); 227 228 mWifiController.sendMessage(CMD_EMERGENCY_CALL_STATE_CHANGED, 0); 229 mLooper.dispatchAll(); 230 assertEquals("DeviceActiveState", getCurrentState().getName()); 231 232 // test that Wifi toggle doesn't exit Ecm 233 mWifiController.sendMessage(CMD_EMERGENCY_CALL_STATE_CHANGED, 1); 234 mLooper.dispatchAll(); 235 assertInEcm(ecmEnabled); 236 237 when(mSettingsStore.isWifiToggleEnabled()).thenReturn(true); 238 mWifiController.sendMessage(CMD_WIFI_TOGGLED); 239 mLooper.dispatchAll(); 240 assertInEcm(ecmEnabled); 241 242 mWifiController.sendMessage(CMD_EMERGENCY_CALL_STATE_CHANGED, 0); 243 mLooper.dispatchAll(); 244 assertEquals("DeviceActiveState", getCurrentState().getName()); 245 } 246 247 /** 248 * When AP mode is enabled and wifi was previously in AP mode, we should return to 249 * DeviceActiveState after the AP is disabled. 250 * Enter DeviceActiveState, activate AP mode, disable AP mode. 251 * <p> 252 * Expected: AP should successfully start and exit, then return to DeviceActiveState. 253 */ 254 @Test 255 public void testReturnToDeviceActiveStateAfterAPModeShutdown() throws Exception { 256 enableWifi(); 257 assertEquals("DeviceActiveState", getCurrentState().getName()); 258 259 mWifiController.obtainMessage(CMD_SET_AP, 1, 0).sendToTarget(); 260 mLooper.dispatchAll(); 261 assertEquals("ApEnabledState", getCurrentState().getName()); 262 263 when(mSettingsStore.getWifiSavedState()).thenReturn(1); 264 mWifiController.obtainMessage(CMD_AP_STOPPED).sendToTarget(); 265 mLooper.dispatchAll(); 266 267 InOrder inOrder = inOrder(mWifiStateMachine); 268 inOrder.verify(mWifiStateMachine).setSupplicantRunning(true); 269 inOrder.verify(mWifiStateMachine).setOperationalMode(WifiStateMachine.CONNECT_MODE); 270 inOrder.verify(mWifiStateMachine).setDriverStart(true); 271 assertEquals("DeviceActiveState", getCurrentState().getName()); 272 } 273 274 /** 275 * When AP mode is enabled and wifi is toggled on, we should transition to 276 * DeviceActiveState after the AP is disabled. 277 * Enter DeviceActiveState, activate AP mode, toggle WiFi. 278 * <p> 279 * Expected: AP should successfully start and exit, then return to DeviceActiveState. 280 */ 281 @Test 282 public void testReturnToDeviceActiveStateAfterWifiEnabledShutdown() throws Exception { 283 enableWifi(); 284 assertEquals("DeviceActiveState", getCurrentState().getName()); 285 286 mWifiController.obtainMessage(CMD_SET_AP, 1, 0).sendToTarget(); 287 mLooper.dispatchAll(); 288 assertEquals("ApEnabledState", getCurrentState().getName()); 289 290 when(mSettingsStore.isWifiToggleEnabled()).thenReturn(true); 291 mWifiController.obtainMessage(CMD_WIFI_TOGGLED).sendToTarget(); 292 mWifiController.obtainMessage(CMD_AP_STOPPED).sendToTarget(); 293 mLooper.dispatchAll(); 294 295 InOrder inOrder = inOrder(mWifiStateMachine); 296 inOrder.verify(mWifiStateMachine).setSupplicantRunning(true); 297 inOrder.verify(mWifiStateMachine).setOperationalMode(WifiStateMachine.CONNECT_MODE); 298 inOrder.verify(mWifiStateMachine).setDriverStart(true); 299 assertEquals("DeviceActiveState", getCurrentState().getName()); 300 } 301 302 /** 303 * When the wifi device is idle, AP mode is enabled and disabled 304 * we should return to the appropriate Idle state. 305 * Enter DeviceActiveState, indicate idle device, activate AP mode, disable AP mode. 306 * <p> 307 * Expected: AP should successfully start and exit, then return to a device idle state. 308 */ 309 @Test 310 public void testReturnToDeviceIdleStateAfterAPModeShutdown() throws Exception { 311 enableWifi(); 312 assertEquals("DeviceActiveState", getCurrentState().getName()); 313 314 // make sure mDeviceIdle is set to true 315 when(mWifiLockManager.getStrongestLockMode()).thenReturn(WIFI_MODE_FULL); 316 when(mWifiLockManager.createMergedWorkSource()).thenReturn(new WorkSource()); 317 mWifiController.sendMessage(CMD_DEVICE_IDLE); 318 mLooper.dispatchAll(); 319 assertEquals("FullLockHeldState", getCurrentState().getName()); 320 321 mWifiController.obtainMessage(CMD_SET_AP, 1, 0).sendToTarget(); 322 mLooper.dispatchAll(); 323 assertEquals("ApEnabledState", getCurrentState().getName()); 324 325 when(mSettingsStore.getWifiSavedState()).thenReturn(1); 326 mWifiController.obtainMessage(CMD_AP_STOPPED).sendToTarget(); 327 mLooper.dispatchAll(); 328 329 InOrder inOrder = inOrder(mWifiStateMachine); 330 inOrder.verify(mWifiStateMachine).setSupplicantRunning(true); 331 inOrder.verify(mWifiStateMachine).setOperationalMode(WifiStateMachine.CONNECT_MODE); 332 inOrder.verify(mWifiStateMachine).setDriverStart(true); 333 assertEquals("FullLockHeldState", getCurrentState().getName()); 334 } 335 336 /** 337 * The command to trigger a WiFi reset should not trigger any action by WifiController if we 338 * are not in STA mode. 339 * WiFi is not in connect mode, so any calls to reset the wifi stack due to connection failures 340 * should be ignored. 341 * Create and start WifiController in ApStaDisabledState, send command to restart WiFi 342 * <p> 343 * Expected: WiFiController should not call WifiStateMachine.setSupplicantRunning(false) 344 */ 345 @Test 346 public void testRestartWifiStackInApStaDisabledState() throws Exception { 347 // Start a new WifiController with wifi disabled 348 when(mSettingsStore.isAirplaneModeOn()).thenReturn(false); 349 when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false); 350 when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(false); 351 352 when(mContext.getContentResolver()).thenReturn(mock(ContentResolver.class)); 353 354 mWifiController = new WifiController(mContext, mWifiStateMachine, 355 mSettingsStore, mWifiLockManager, mLooper.getLooper(), mFacade); 356 357 mWifiController.start(); 358 mLooper.dispatchAll(); 359 360 reset(mWifiStateMachine); 361 assertEquals("ApStaDisabledState", getCurrentState().getName()); 362 mWifiController.sendMessage(CMD_RESTART_WIFI); 363 mLooper.dispatchAll(); 364 verifyZeroInteractions(mWifiStateMachine); 365 } 366 367 /** 368 * The command to trigger a WiFi reset should not trigger any action by WifiController if we 369 * are not in STA mode, even if scans are allowed. 370 * WiFi is not in connect mode, so any calls to reset the wifi stack due to connection failures 371 * should be ignored. 372 * Create and start WifiController in StaDisablediWithScanState, send command to restart WiFi 373 * <p> 374 * Expected: WiFiController should not call WifiStateMachine.setSupplicantRunning(false) 375 */ 376 @Test 377 public void testRestartWifiStackInStaDisabledWithScanState() throws Exception { 378 reset(mWifiStateMachine); 379 assertEquals("StaDisabledWithScanState", getCurrentState().getName()); 380 mWifiController.sendMessage(CMD_RESTART_WIFI); 381 mLooper.dispatchAll(); 382 verifyZeroInteractions(mWifiStateMachine); 383 } 384 385 /** 386 * The command to trigger a WiFi reset should trigger a wifi reset in WifiStateMachine through 387 * the WifiStateMachine.setSupplicantRunning(false) call when in STA mode. 388 * WiFi is in connect mode, calls to reset the wifi stack due to connection failures 389 * should trigger a supplicant stop, and subsequently, a driver reload. 390 * Create and start WifiController in DeviceActiveState, send command to restart WiFi 391 * <p> 392 * Expected: WiFiController should call WifiStateMachine.setSupplicantRunning(false), 393 * WifiStateMachine should enter CONNECT_MODE and the wifi driver should be started. 394 */ 395 @Test 396 public void testRestartWifiStackInStaEnabledState() throws Exception { 397 enableWifi(); 398 399 reset(mWifiStateMachine); 400 assertEquals("DeviceActiveState", getCurrentState().getName()); 401 mWifiController.sendMessage(CMD_RESTART_WIFI); 402 mLooper.dispatchAll(); 403 InOrder inOrder = inOrder(mWifiStateMachine); 404 inOrder.verify(mWifiStateMachine).setSupplicantRunning(false); 405 inOrder.verify(mWifiStateMachine).setSupplicantRunning(true); 406 inOrder.verify(mWifiStateMachine).setOperationalMode(WifiStateMachine.CONNECT_MODE); 407 inOrder.verify(mWifiStateMachine).setDriverStart(true); 408 assertEquals("DeviceActiveState", getCurrentState().getName()); 409 } 410 411 /** 412 * The command to trigger a WiFi reset should not trigger a reset when in ECM mode. 413 * Enable wifi and enter ECM state, send command to restart wifi. 414 * <p> 415 * Expected: The command to trigger a wifi reset should be ignored and we should remain in ECM 416 * mode. 417 */ 418 @Test 419 public void testRestartWifiStackDoesNotExitECMMode() throws Exception { 420 enableWifi(); 421 assertEquals("DeviceActiveState", getCurrentState().getName()); 422 when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true); 423 424 mWifiController.sendMessage(CMD_EMERGENCY_CALL_STATE_CHANGED, 1); 425 mLooper.dispatchAll(); 426 assertInEcm(true); 427 428 reset(mWifiStateMachine); 429 mWifiController.sendMessage(CMD_RESTART_WIFI); 430 mLooper.dispatchAll(); 431 assertInEcm(true); 432 verifyZeroInteractions(mWifiStateMachine); 433 } 434 435 /** 436 * The command to trigger a WiFi reset should not trigger a reset when in AP mode. 437 * Enter AP mode, send command to restart wifi. 438 * <p> 439 * Expected: The command to trigger a wifi reset should be ignored and we should remain in AP 440 * mode. 441 */ 442 @Test 443 public void testRestartWifiStackDoesNotExitAPMode() throws Exception { 444 mWifiController.obtainMessage(CMD_SET_AP, 1).sendToTarget(); 445 mLooper.dispatchAll(); 446 assertEquals("ApEnabledState", getCurrentState().getName()); 447 448 reset(mWifiStateMachine); 449 mWifiController.sendMessage(CMD_RESTART_WIFI); 450 mLooper.dispatchAll(); 451 verifyZeroInteractions(mWifiStateMachine); 452 } 453} 454