WifiStateMachineTest.java revision 6259b630ddb59b642729a2d2113d81ed8e33a0e3
1/* 2 * Copyright (C) 2015 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 org.junit.Assert.assertEquals; 20import static org.junit.Assert.assertTrue; 21import static org.mockito.Mockito.*; 22 23import android.app.ActivityManager; 24import android.app.test.MockAnswerUtil.AnswerWithArguments; 25import android.app.test.TestAlarmManager; 26import android.content.ContentResolver; 27import android.content.Context; 28import android.content.pm.PackageManager; 29import android.content.pm.UserInfo; 30import android.content.res.Resources; 31import android.net.ConnectivityManager; 32import android.net.DhcpResults; 33import android.net.LinkProperties; 34import android.net.dhcp.DhcpClient; 35import android.net.ip.IpManager; 36import android.net.wifi.IClientInterface; 37import android.net.wifi.IWificond; 38import android.net.wifi.ScanResult; 39import android.net.wifi.SupplicantState; 40import android.net.wifi.WifiConfiguration; 41import android.net.wifi.WifiManager; 42import android.net.wifi.WifiScanner; 43import android.net.wifi.WifiSsid; 44import android.net.wifi.p2p.IWifiP2pManager; 45import android.os.BatteryStats; 46import android.os.Binder; 47import android.os.Handler; 48import android.os.HandlerThread; 49import android.os.IBinder; 50import android.os.IInterface; 51import android.os.INetworkManagementService; 52import android.os.IPowerManager; 53import android.os.Looper; 54import android.os.Message; 55import android.os.Messenger; 56import android.os.PowerManager; 57import android.os.RemoteException; 58import android.os.UserHandle; 59import android.os.UserManager; 60import android.os.test.TestLooper; 61import android.provider.Settings; 62import android.security.KeyStore; 63import android.test.suitebuilder.annotation.SmallTest; 64import android.util.Log; 65 66import com.android.internal.R; 67import com.android.internal.app.IBatteryStats; 68import com.android.internal.util.AsyncChannel; 69import com.android.internal.util.IState; 70import com.android.internal.util.StateMachine; 71import com.android.server.wifi.hotspot2.NetworkDetail; 72import com.android.server.wifi.p2p.WifiP2pServiceImpl; 73 74import org.junit.After; 75import org.junit.Before; 76import org.junit.Test; 77import org.mockito.ArgumentCaptor; 78import org.mockito.Mock; 79import org.mockito.MockitoAnnotations; 80 81import java.io.ByteArrayOutputStream; 82import java.io.PrintWriter; 83import java.lang.reflect.Field; 84import java.lang.reflect.InvocationTargetException; 85import java.lang.reflect.Method; 86import java.util.ArrayList; 87import java.util.Arrays; 88import java.util.HashSet; 89import java.util.List; 90import java.util.Set; 91import java.util.concurrent.CountDownLatch; 92 93/** 94 * Unit tests for {@link com.android.server.wifi.WifiStateMachine}. 95 */ 96@SmallTest 97public class WifiStateMachineTest { 98 public static final String TAG = "WifiStateMachineTest"; 99 100 private static final int MANAGED_PROFILE_UID = 1100000; 101 private static final int OTHER_USER_UID = 1200000; 102 private static final int LOG_REC_LIMIT_IN_VERBOSE_MODE = 103 (ActivityManager.isLowRamDeviceStatic() 104 ? WifiStateMachine.NUM_LOG_RECS_VERBOSE_LOW_MEMORY 105 : WifiStateMachine.NUM_LOG_RECS_VERBOSE); 106 private static final String DEFAULT_TEST_SSID = "\"GoogleGuest\""; 107 108 private long mBinderToken; 109 110 private static <T> T mockWithInterfaces(Class<T> class1, Class<?>... interfaces) { 111 return mock(class1, withSettings().extraInterfaces(interfaces)); 112 } 113 114 private static <T, I> IBinder mockService(Class<T> class1, Class<I> iface) { 115 T tImpl = mockWithInterfaces(class1, iface); 116 IBinder binder = mock(IBinder.class); 117 when(((IInterface) tImpl).asBinder()).thenReturn(binder); 118 when(binder.queryLocalInterface(iface.getCanonicalName())) 119 .thenReturn((IInterface) tImpl); 120 return binder; 121 } 122 123 private void enableDebugLogs() { 124 mWsm.enableVerboseLogging(1); 125 } 126 127 private class TestIpManager extends IpManager { 128 TestIpManager(Context context, String ifname, IpManager.Callback callback) { 129 // Call dependency-injection superclass constructor. 130 super(context, ifname, callback, mock(INetworkManagementService.class)); 131 } 132 133 @Override 134 public void startProvisioning(IpManager.ProvisioningConfiguration config) {} 135 136 @Override 137 public void stop() {} 138 139 @Override 140 public void confirmConfiguration() {} 141 142 void injectDhcpSuccess(DhcpResults dhcpResults) { 143 mCallback.onNewDhcpResults(dhcpResults); 144 mCallback.onProvisioningSuccess(new LinkProperties()); 145 } 146 147 void injectDhcpFailure() { 148 mCallback.onNewDhcpResults(null); 149 mCallback.onProvisioningFailure(new LinkProperties()); 150 } 151 } 152 153 private FrameworkFacade getFrameworkFacade() throws Exception { 154 FrameworkFacade facade = mock(FrameworkFacade.class); 155 156 when(facade.getService(Context.NETWORKMANAGEMENT_SERVICE)).thenReturn( 157 mockWithInterfaces(IBinder.class, INetworkManagementService.class)); 158 159 IBinder p2pBinder = mockService(WifiP2pServiceImpl.class, IWifiP2pManager.class); 160 when(facade.getService(Context.WIFI_P2P_SERVICE)).thenReturn(p2pBinder); 161 162 WifiP2pServiceImpl p2pm = (WifiP2pServiceImpl) p2pBinder.queryLocalInterface( 163 IWifiP2pManager.class.getCanonicalName()); 164 165 final CountDownLatch untilDone = new CountDownLatch(1); 166 mP2pThread = new HandlerThread("WifiP2pMockThread") { 167 @Override 168 protected void onLooperPrepared() { 169 untilDone.countDown(); 170 } 171 }; 172 173 mP2pThread.start(); 174 untilDone.await(); 175 176 Handler handler = new Handler(mP2pThread.getLooper()); 177 when(p2pm.getP2pStateMachineMessenger()).thenReturn(new Messenger(handler)); 178 179 IBinder batteryStatsBinder = mockService(BatteryStats.class, IBatteryStats.class); 180 when(facade.getService(BatteryStats.SERVICE_NAME)).thenReturn(batteryStatsBinder); 181 182 when(facade.makeIpManager(any(Context.class), anyString(), any(IpManager.Callback.class))) 183 .then(new AnswerWithArguments() { 184 public IpManager answer( 185 Context context, String ifname, IpManager.Callback callback) { 186 mTestIpManager = new TestIpManager(context, ifname, callback); 187 return mTestIpManager; 188 } 189 }); 190 191 when(facade.checkUidPermission(eq(android.Manifest.permission.OVERRIDE_WIFI_CONFIG), 192 anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); 193 return facade; 194 } 195 196 private Context getContext() throws Exception { 197 PackageManager pkgMgr = mock(PackageManager.class); 198 when(pkgMgr.hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT)).thenReturn(true); 199 200 Context context = mock(Context.class); 201 when(context.getPackageManager()).thenReturn(pkgMgr); 202 when(context.getContentResolver()).thenReturn(mock(ContentResolver.class)); 203 204 MockResources resources = new com.android.server.wifi.MockResources(); 205 when(context.getResources()).thenReturn(resources); 206 207 ContentResolver cr = mock(ContentResolver.class); 208 when(context.getContentResolver()).thenReturn(cr); 209 210 when(context.getSystemService(Context.POWER_SERVICE)).thenReturn( 211 new PowerManager(context, mock(IPowerManager.class), new Handler())); 212 213 mAlarmManager = new TestAlarmManager(); 214 when(context.getSystemService(Context.ALARM_SERVICE)).thenReturn( 215 mAlarmManager.getAlarmManager()); 216 217 when(context.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn( 218 mock(ConnectivityManager.class)); 219 220 return context; 221 } 222 223 private Resources getMockResources() { 224 MockResources resources = new MockResources(); 225 resources.setBoolean(R.bool.config_wifi_enable_wifi_firmware_debugging, false); 226 return resources; 227 } 228 229 private IState getCurrentState() throws 230 NoSuchMethodException, InvocationTargetException, IllegalAccessException { 231 Method method = StateMachine.class.getDeclaredMethod("getCurrentState"); 232 method.setAccessible(true); 233 return (IState) method.invoke(mWsm); 234 } 235 236 private static HandlerThread getWsmHandlerThread(WifiStateMachine wsm) throws 237 NoSuchFieldException, InvocationTargetException, IllegalAccessException { 238 Field field = StateMachine.class.getDeclaredField("mSmThread"); 239 field.setAccessible(true); 240 return (HandlerThread) field.get(wsm); 241 } 242 243 private static void stopLooper(final Looper looper) throws Exception { 244 new Handler(looper).post(new Runnable() { 245 @Override 246 public void run() { 247 looper.quitSafely(); 248 } 249 }); 250 } 251 252 private void dumpState() { 253 ByteArrayOutputStream stream = new ByteArrayOutputStream(); 254 PrintWriter writer = new PrintWriter(stream); 255 mWsm.dump(null, writer, null); 256 writer.flush(); 257 Log.d(TAG, "WifiStateMachine state -" + stream.toString()); 258 } 259 260 private static ScanDetail getGoogleGuestScanDetail(int rssi) { 261 ScanResult.InformationElement ie[] = new ScanResult.InformationElement[1]; 262 ie[0] = ScanResults.generateSsidIe(sSSID); 263 NetworkDetail nd = new NetworkDetail(sBSSID, ie, new ArrayList<String>(), sFreq); 264 ScanDetail detail = new ScanDetail(nd, sWifiSsid, sBSSID, "", rssi, sFreq, 265 Long.MAX_VALUE, /* needed so that scan results aren't rejected because 266 there older than scan start */ 267 ie, new ArrayList<String>()); 268 return detail; 269 } 270 271 private ArrayList<ScanDetail> getMockScanResults() { 272 ScanResults sr = ScanResults.create(0, 2412, 2437, 2462, 5180, 5220, 5745, 5825); 273 ArrayList<ScanDetail> list = sr.getScanDetailArrayList(); 274 275 int rssi = -65; 276 list.add(getGoogleGuestScanDetail(rssi)); 277 return list; 278 } 279 280 static final String sSSID = "\"GoogleGuest\""; 281 static final WifiSsid sWifiSsid = WifiSsid.createFromAsciiEncoded(sSSID); 282 static final String sHexSSID = sWifiSsid.getHexString().replace("0x", "").replace("22", ""); 283 static final String sBSSID = "01:02:03:04:05:06"; 284 static final int sFreq = 2437; 285 286 WifiStateMachine mWsm; 287 HandlerThread mWsmThread; 288 HandlerThread mP2pThread; 289 HandlerThread mSyncThread; 290 AsyncChannel mWsmAsyncChannel; 291 TestAlarmManager mAlarmManager; 292 MockWifiMonitor mWifiMonitor; 293 TestIpManager mTestIpManager; 294 TestLooper mLooper; 295 296 @Mock WifiNative mWifiNative; 297 @Mock WifiScanner mWifiScanner; 298 @Mock SupplicantStateTracker mSupplicantStateTracker; 299 @Mock WifiMetrics mWifiMetrics; 300 @Mock UserManager mUserManager; 301 @Mock WifiApConfigStore mApConfigStore; 302 @Mock BackupManagerProxy mBackupManagerProxy; 303 @Mock WifiCountryCode mCountryCode; 304 @Mock WifiInjector mWifiInjector; 305 @Mock WifiLastResortWatchdog mWifiLastResortWatchdog; 306 @Mock PropertyService mPropertyService; 307 @Mock BuildProperties mBuildProperties; 308 @Mock IWificond mWificond; 309 @Mock IClientInterface mClientInterface; 310 @Mock IBinder mClientInterfaceBinder; 311 @Mock WifiConfigManager mWifiConfigManager; 312 @Mock WifiSupplicantControl mWifiSupplicantControl; 313 314 public WifiStateMachineTest() throws Exception { 315 } 316 317 @Before 318 public void setUp() throws Exception { 319 Log.d(TAG, "Setting up ..."); 320 321 // Ensure looper exists 322 mLooper = new TestLooper(); 323 324 MockitoAnnotations.initMocks(this); 325 326 /** uncomment this to enable logs from WifiStateMachines */ 327 // enableDebugLogs(); 328 329 mWifiMonitor = new MockWifiMonitor(); 330 when(mWifiInjector.getWifiMetrics()).thenReturn(mWifiMetrics); 331 when(mWifiInjector.getClock()).thenReturn(mock(Clock.class)); 332 when(mWifiInjector.getWifiLastResortWatchdog()).thenReturn(mWifiLastResortWatchdog); 333 when(mWifiInjector.getPropertyService()).thenReturn(mPropertyService); 334 when(mWifiInjector.getBuildProperties()).thenReturn(mBuildProperties); 335 when(mWifiInjector.getKeyStore()).thenReturn(mock(KeyStore.class)); 336 when(mWifiInjector.getWifiBackupRestore()).thenReturn(mock(WifiBackupRestore.class)); 337 when(mWifiInjector.makeWifiDiagnostics(anyObject())).thenReturn( 338 mock(BaseWifiDiagnostics.class)); 339 when(mWifiInjector.makeWificond()).thenReturn(mWificond); 340 when(mWifiInjector.getWifiConfigManager()).thenReturn(mWifiConfigManager); 341 when(mWifiInjector.getWifiSupplicantControl()).thenReturn(mWifiSupplicantControl); 342 when(mWifiInjector.getWifiScanner()).thenReturn(mWifiScanner); 343 344 when(mWifiNative.getInterfaceName()).thenReturn("mockWlan"); 345 when(mWifiSupplicantControl.getFrameworkNetworkId(anyInt())).thenReturn(0); 346 347 348 FrameworkFacade factory = getFrameworkFacade(); 349 Context context = getContext(); 350 351 Resources resources = getMockResources(); 352 when(context.getResources()).thenReturn(resources); 353 354 when(factory.getIntegerSetting(context, 355 Settings.Global.WIFI_FREQUENCY_BAND, 356 WifiManager.WIFI_FREQUENCY_BAND_AUTO)).thenReturn( 357 WifiManager.WIFI_FREQUENCY_BAND_AUTO); 358 359 when(factory.makeApConfigStore(eq(context), eq(mBackupManagerProxy))) 360 .thenReturn(mApConfigStore); 361 362 when(factory.makeSupplicantStateTracker( 363 any(Context.class), any(WifiConfigManager.class), 364 any(Handler.class))).thenReturn(mSupplicantStateTracker); 365 366 when(mUserManager.getProfileParent(11)) 367 .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "owner", 0)); 368 when(mUserManager.getProfiles(UserHandle.USER_SYSTEM)).thenReturn(Arrays.asList( 369 new UserInfo(UserHandle.USER_SYSTEM, "owner", 0), 370 new UserInfo(11, "managed profile", 0))); 371 372 when(mWificond.createClientInterface()).thenReturn(mClientInterface); 373 when(mClientInterface.asBinder()).thenReturn(mClientInterfaceBinder); 374 when(mClientInterface.enableSupplicant()).thenReturn(true); 375 when(mClientInterface.disableSupplicant()).thenReturn(true); 376 377 mWsm = new WifiStateMachine(context, factory, mLooper.getLooper(), 378 mUserManager, mWifiInjector, mBackupManagerProxy, mCountryCode, mWifiNative); 379 mWsmThread = getWsmHandlerThread(mWsm); 380 381 final AsyncChannel channel = new AsyncChannel(); 382 Handler handler = new Handler(mLooper.getLooper()) { 383 @Override 384 public void handleMessage(Message msg) { 385 switch (msg.what) { 386 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: 387 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { 388 mWsmAsyncChannel = channel; 389 } else { 390 Log.d(TAG, "Failed to connect Command channel " + this); 391 } 392 break; 393 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: 394 Log.d(TAG, "Command channel disconnected" + this); 395 break; 396 } 397 } 398 }; 399 400 channel.connect(context, handler, mWsm.getMessenger()); 401 mLooper.dispatchAll(); 402 /* Now channel is supposed to be connected */ 403 404 mBinderToken = Binder.clearCallingIdentity(); 405 } 406 407 @After 408 public void cleanUp() throws Exception { 409 Binder.restoreCallingIdentity(mBinderToken); 410 411 if (mSyncThread != null) stopLooper(mSyncThread.getLooper()); 412 if (mWsmThread != null) stopLooper(mWsmThread.getLooper()); 413 if (mP2pThread != null) stopLooper(mP2pThread.getLooper()); 414 415 mWsmThread = null; 416 mP2pThread = null; 417 mSyncThread = null; 418 mWsmAsyncChannel = null; 419 mWsm = null; 420 } 421 422 @Test 423 public void createNew() throws Exception { 424 assertEquals("InitialState", getCurrentState().getName()); 425 426 mWsm.sendMessage(WifiStateMachine.CMD_BOOT_COMPLETED); 427 mLooper.dispatchAll(); 428 assertEquals("InitialState", getCurrentState().getName()); 429 } 430 431 @Test 432 public void loadComponents() throws Exception { 433 when(mWifiNative.startHal()).thenReturn(true); 434 mWsm.setSupplicantRunning(true); 435 mLooper.dispatchAll(); 436 437 assertEquals("SupplicantStartingState", getCurrentState().getName()); 438 439 when(mWifiNative.setBand(anyInt())).thenReturn(true); 440 when(mWifiNative.setDeviceName(anyString())).thenReturn(true); 441 when(mWifiNative.setManufacturer(anyString())).thenReturn(true); 442 when(mWifiNative.setModelName(anyString())).thenReturn(true); 443 when(mWifiNative.setModelNumber(anyString())).thenReturn(true); 444 when(mWifiNative.setSerialNumber(anyString())).thenReturn(true); 445 when(mWifiNative.setConfigMethods(anyString())).thenReturn(true); 446 when(mWifiNative.setDeviceType(anyString())).thenReturn(true); 447 when(mWifiNative.setSerialNumber(anyString())).thenReturn(true); 448 when(mWifiNative.setScanningMacOui(any(byte[].class))).thenReturn(true); 449 450 mWsm.sendMessage(WifiMonitor.SUP_CONNECTION_EVENT); 451 mLooper.dispatchAll(); 452 453 assertEquals("DisconnectedState", getCurrentState().getName()); 454 } 455 456 @Test 457 public void shouldRequireSupplicantStartupToLeaveInitialState() throws Exception { 458 when(mClientInterface.enableSupplicant()).thenReturn(false); 459 mWsm.setSupplicantRunning(true); 460 mLooper.dispatchAll(); 461 assertEquals("InitialState", getCurrentState().getName()); 462 } 463 464 @Test 465 public void shouldRequireWificondToLeaveInitialState() throws Exception { 466 // We start out with valid default values, break them going backwards so that 467 // we test all the bailout cases. 468 469 // ClientInterface dies after creation. 470 doThrow(new RemoteException()).when(mClientInterfaceBinder).linkToDeath(any(), anyInt()); 471 mWsm.setSupplicantRunning(true); 472 mLooper.dispatchAll(); 473 assertEquals("InitialState", getCurrentState().getName()); 474 475 // Failed to even create the client interface. 476 when(mWificond.createClientInterface()).thenReturn(null); 477 mWsm.setSupplicantRunning(true); 478 mLooper.dispatchAll(); 479 assertEquals("InitialState", getCurrentState().getName()); 480 481 // Failed to get wificond proxy. 482 when(mWifiInjector.makeWificond()).thenReturn(null); 483 mWsm.setSupplicantRunning(true); 484 mLooper.dispatchAll(); 485 assertEquals("InitialState", getCurrentState().getName()); 486 } 487 488 @Test 489 public void loadComponentsFailure() throws Exception { 490 when(mWifiNative.startHal()).thenReturn(false); 491 when(mClientInterface.enableSupplicant()).thenReturn(false); 492 493 mWsm.setSupplicantRunning(true); 494 mLooper.dispatchAll(); 495 assertEquals("InitialState", getCurrentState().getName()); 496 497 when(mWifiNative.startHal()).thenReturn(true); 498 mWsm.setSupplicantRunning(true); 499 mLooper.dispatchAll(); 500 assertEquals("InitialState", getCurrentState().getName()); 501 } 502 503 @Test 504 public void checkInitialStateStickyWhenDisabledMode() throws Exception { 505 mLooper.dispatchAll(); 506 assertEquals("InitialState", getCurrentState().getName()); 507 assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest()); 508 509 mWsm.setOperationalMode(WifiStateMachine.DISABLED_MODE); 510 mLooper.dispatchAll(); 511 assertEquals(WifiStateMachine.DISABLED_MODE, mWsm.getOperationalModeForTest()); 512 assertEquals("InitialState", getCurrentState().getName()); 513 } 514 515 @Test 516 public void shouldStartSupplicantWhenConnectModeRequested() throws Exception { 517 when(mWifiNative.startHal()).thenReturn(true); 518 519 // The first time we start out in InitialState, we sit around here. 520 mLooper.dispatchAll(); 521 assertEquals("InitialState", getCurrentState().getName()); 522 assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest()); 523 524 // But if someone tells us to enter connect mode, we start up supplicant 525 mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE); 526 mLooper.dispatchAll(); 527 assertEquals("SupplicantStartingState", getCurrentState().getName()); 528 } 529 530 /** 531 * Test that mode changes for WifiStateMachine in the InitialState are realized when supplicant 532 * is started. 533 */ 534 @Test 535 public void checkStartInCorrectStateAfterChangingInitialState() throws Exception { 536 when(mWifiNative.startHal()).thenReturn(true); 537 538 // Check initial state 539 mLooper.dispatchAll(); 540 assertEquals("InitialState", getCurrentState().getName()); 541 assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest()); 542 543 // Update the mode 544 mWsm.setOperationalMode(WifiStateMachine.SCAN_ONLY_MODE); 545 mLooper.dispatchAll(); 546 assertEquals(WifiStateMachine.SCAN_ONLY_MODE, mWsm.getOperationalModeForTest()); 547 548 // Start supplicant so we move to the next state 549 mWsm.setSupplicantRunning(true); 550 mLooper.dispatchAll(); 551 assertEquals("SupplicantStartingState", getCurrentState().getName()); 552 when(mWifiNative.setBand(anyInt())).thenReturn(true); 553 when(mWifiNative.setDeviceName(anyString())).thenReturn(true); 554 when(mWifiNative.setManufacturer(anyString())).thenReturn(true); 555 when(mWifiNative.setModelName(anyString())).thenReturn(true); 556 when(mWifiNative.setModelNumber(anyString())).thenReturn(true); 557 when(mWifiNative.setSerialNumber(anyString())).thenReturn(true); 558 when(mWifiNative.setConfigMethods(anyString())).thenReturn(true); 559 when(mWifiNative.setDeviceType(anyString())).thenReturn(true); 560 when(mWifiNative.setSerialNumber(anyString())).thenReturn(true); 561 when(mWifiNative.setScanningMacOui(any(byte[].class))).thenReturn(true); 562 563 mWsm.sendMessage(WifiMonitor.SUP_CONNECTION_EVENT); 564 mLooper.dispatchAll(); 565 566 assertEquals("ScanModeState", getCurrentState().getName()); 567 } 568 569 private void addNetworkAndVerifySuccess() throws Exception { 570 addNetworkAndVerifySuccess(false); 571 } 572 573 private void addNetworkAndVerifySuccess(boolean isHidden) throws Exception { 574 loadComponents(); 575 576 WifiConfiguration config = new WifiConfiguration(); 577 config.SSID = sSSID; 578 config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); 579 config.hiddenSSID = isHidden; 580 581 when(mWifiConfigManager.addOrUpdateNetwork(any(WifiConfiguration.class), anyInt())) 582 .thenReturn(new NetworkUpdateResult(0)); 583 when(mWifiConfigManager.getSavedNetworks()).thenReturn(Arrays.asList(config)); 584 when(mWifiConfigManager.getConfiguredNetwork(0)).thenReturn(config); 585 586 mLooper.startAutoDispatch(); 587 mWsm.syncAddOrUpdateNetwork(mWsmAsyncChannel, config); 588 mLooper.stopAutoDispatch(); 589 590 verify(mWifiConfigManager).addOrUpdateNetwork(eq(config), anyInt()); 591 592 mLooper.startAutoDispatch(); 593 List<WifiConfiguration> configs = mWsm.syncGetConfiguredNetworks(-1, mWsmAsyncChannel); 594 mLooper.stopAutoDispatch(); 595 assertEquals(1, configs.size()); 596 597 WifiConfiguration config2 = configs.get(0); 598 assertEquals("\"GoogleGuest\"", config2.SSID); 599 assertTrue(config2.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.NONE)); 600 } 601 602 /** 603 * Helper method to retrieve WifiConfiguration by SSID. 604 * 605 * Returns the associated WifiConfiguration if it is found, null otherwise. 606 */ 607 private WifiConfiguration getWifiConfigurationForNetwork(String ssid) { 608 mLooper.startAutoDispatch(); 609 List<WifiConfiguration> configs = mWsm.syncGetConfiguredNetworks(-1, mWsmAsyncChannel); 610 mLooper.stopAutoDispatch(); 611 612 for (WifiConfiguration checkConfig : configs) { 613 if (checkConfig.SSID.equals(ssid)) { 614 return checkConfig; 615 } 616 } 617 return null; 618 } 619 620 private void verifyScan(int band, int reportEvents, Set<String> hiddenNetworkSSIDSet) { 621 ArgumentCaptor<WifiScanner.ScanSettings> scanSettingsCaptor = 622 ArgumentCaptor.forClass(WifiScanner.ScanSettings.class); 623 ArgumentCaptor<WifiScanner.ScanListener> scanListenerCaptor = 624 ArgumentCaptor.forClass(WifiScanner.ScanListener.class); 625 verify(mWifiScanner).startScan(scanSettingsCaptor.capture(), scanListenerCaptor.capture(), 626 eq(null)); 627 WifiScanner.ScanSettings actualSettings = scanSettingsCaptor.getValue(); 628 assertEquals("band", band, actualSettings.band); 629 assertEquals("reportEvents", reportEvents, actualSettings.reportEvents); 630 631 if (hiddenNetworkSSIDSet == null) { 632 hiddenNetworkSSIDSet = new HashSet<>(); 633 } 634 Set<String> actualHiddenNetworkSSIDSet = new HashSet<>(); 635 if (actualSettings.hiddenNetworks != null) { 636 for (int i = 0; i < actualSettings.hiddenNetworks.length; ++i) { 637 actualHiddenNetworkSSIDSet.add(actualSettings.hiddenNetworks[i].ssid); 638 } 639 } 640 assertEquals("hidden networks", hiddenNetworkSSIDSet, actualHiddenNetworkSSIDSet); 641 642 when(mWifiNative.getScanResults()).thenReturn(getMockScanResults()); 643 mWsm.sendMessage(WifiMonitor.SCAN_RESULTS_EVENT); 644 645 mLooper.dispatchAll(); 646 647 List<ScanResult> reportedResults = mWsm.syncGetScanResultsList(); 648 assertEquals(8, reportedResults.size()); 649 } 650 651 @Test 652 public void scan() throws Exception { 653 addNetworkAndVerifySuccess(); 654 655 mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE); 656 mWsm.startScan(-1, 0, null, null); 657 mLooper.dispatchAll(); 658 659 verifyScan(WifiScanner.WIFI_BAND_BOTH_WITH_DFS, 660 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN 661 | WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT, null); 662 } 663 664 @Test 665 public void scanWithHiddenNetwork() throws Exception { 666 addNetworkAndVerifySuccess(true); 667 668 Set<String> hiddenNetworkSet = new HashSet<>(); 669 hiddenNetworkSet.add(sSSID); 670 List<WifiScanner.ScanSettings.HiddenNetwork> hiddenNetworkList = new ArrayList<>(); 671 hiddenNetworkList.add(new WifiScanner.ScanSettings.HiddenNetwork(sSSID)); 672 when(mWifiConfigManager.retrieveHiddenNetworkList()).thenReturn(hiddenNetworkList); 673 674 mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE); 675 mWsm.startScan(-1, 0, null, null); 676 mLooper.dispatchAll(); 677 678 verifyScan(WifiScanner.WIFI_BAND_BOTH_WITH_DFS, 679 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN 680 | WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT, 681 hiddenNetworkSet); 682 } 683 684 @Test 685 public void connect() throws Exception { 686 addNetworkAndVerifySuccess(); 687 688 mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE); 689 mLooper.dispatchAll(); 690 691 mLooper.startAutoDispatch(); 692 mWsm.syncEnableNetwork(mWsmAsyncChannel, 0, true); 693 mLooper.stopAutoDispatch(); 694 695 verify(mWifiConfigManager).enableNetwork(eq(0), eq(true), anyInt()); 696 697 mWsm.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, sBSSID); 698 mLooper.dispatchAll(); 699 700 mWsm.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0, 701 new StateChangeResult(0, sWifiSsid, sBSSID, SupplicantState.COMPLETED)); 702 mLooper.dispatchAll(); 703 704 assertEquals("ObtainingIpState", getCurrentState().getName()); 705 706 DhcpResults dhcpResults = new DhcpResults(); 707 dhcpResults.setGateway("1.2.3.4"); 708 dhcpResults.setIpAddress("192.168.1.100", 0); 709 dhcpResults.addDns("8.8.8.8"); 710 dhcpResults.setLeaseDuration(3600); 711 712 mTestIpManager.injectDhcpSuccess(dhcpResults); 713 mLooper.dispatchAll(); 714 715 assertEquals("ConnectedState", getCurrentState().getName()); 716 } 717 718 @Test 719 public void testDhcpFailure() throws Exception { 720 addNetworkAndVerifySuccess(); 721 722 mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE); 723 mLooper.dispatchAll(); 724 725 mLooper.startAutoDispatch(); 726 mWsm.syncEnableNetwork(mWsmAsyncChannel, 0, true); 727 mLooper.stopAutoDispatch(); 728 729 verify(mWifiConfigManager).enableNetwork(eq(0), eq(true), anyInt()); 730 731 mWsm.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, sBSSID); 732 mLooper.dispatchAll(); 733 734 mWsm.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0, 735 new StateChangeResult(0, sWifiSsid, sBSSID, SupplicantState.COMPLETED)); 736 mLooper.dispatchAll(); 737 738 assertEquals("ObtainingIpState", getCurrentState().getName()); 739 740 mTestIpManager.injectDhcpFailure(); 741 mLooper.dispatchAll(); 742 743 assertEquals("DisconnectingState", getCurrentState().getName()); 744 } 745 746 @Test 747 public void testBadNetworkEvent() throws Exception { 748 addNetworkAndVerifySuccess(); 749 750 mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE); 751 mLooper.dispatchAll(); 752 753 mLooper.startAutoDispatch(); 754 mWsm.syncEnableNetwork(mWsmAsyncChannel, 0, true); 755 mLooper.stopAutoDispatch(); 756 757 verify(mWifiConfigManager).enableNetwork(eq(0), eq(true), anyInt()); 758 759 mWsm.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, 0, 0, sBSSID); 760 mLooper.dispatchAll(); 761 762 mWsm.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0, 763 new StateChangeResult(0, sWifiSsid, sBSSID, SupplicantState.COMPLETED)); 764 mLooper.dispatchAll(); 765 766 assertEquals("DisconnectedState", getCurrentState().getName()); 767 } 768 769 770 @Test 771 public void smToString() throws Exception { 772 assertEquals("CMD_CHANNEL_HALF_CONNECTED", mWsm.smToString( 773 AsyncChannel.CMD_CHANNEL_HALF_CONNECTED)); 774 assertEquals("CMD_PRE_DHCP_ACTION", mWsm.smToString( 775 DhcpClient.CMD_PRE_DHCP_ACTION)); 776 assertEquals("CMD_IP_REACHABILITY_LOST", mWsm.smToString( 777 WifiStateMachine.CMD_IP_REACHABILITY_LOST)); 778 } 779 780 @Test 781 public void disconnect() throws Exception { 782 connect(); 783 784 mWsm.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, -1, 3, "01:02:03:04:05:06"); 785 mLooper.dispatchAll(); 786 mWsm.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0, 787 new StateChangeResult(0, sWifiSsid, sBSSID, SupplicantState.DISCONNECTED)); 788 mLooper.dispatchAll(); 789 790 assertEquals("DisconnectedState", getCurrentState().getName()); 791 } 792 793 /** 794 * Successfully connecting to a network will set WifiConfiguration's value of HasEverConnected 795 * to true. 796 * 797 * Test: Successfully create and connect to a network. Check the config and verify 798 * WifiConfiguration.getHasEverConnected() is true. 799 */ 800 @Test 801 public void setHasEverConnectedTrueOnConnect() throws Exception { 802 connect(); 803 verify(mWifiConfigManager, atLeastOnce()).updateNetworkAfterConnect(0); 804 } 805 806 /** 807 * Fail network connection attempt and verify HasEverConnected remains false. 808 * 809 * Test: Successfully create a network but fail when connecting. Check the config and verify 810 * WifiConfiguration.getHasEverConnected() is false. 811 */ 812 @Test 813 public void connectionFailureDoesNotSetHasEverConnectedTrue() throws Exception { 814 testDhcpFailure(); 815 verify(mWifiConfigManager, never()).updateNetworkAfterConnect(0); 816 } 817 818 @Test 819 public void iconQueryTest() throws Exception { 820 // TODO(b/31065385): Passpoint config management. 821 } 822 823 /** 824 * Verifies that, by default, we allow only the "normal" number of log records. 825 */ 826 @Test 827 public void normalLogRecSizeIsUsedByDefault() { 828 for (int i = 0; i < WifiStateMachine.NUM_LOG_RECS_NORMAL * 2; i++) { 829 mWsm.sendMessage(WifiStateMachine.CMD_BOOT_COMPLETED); 830 } 831 mLooper.dispatchAll(); 832 assertEquals(WifiStateMachine.NUM_LOG_RECS_NORMAL, mWsm.getLogRecSize()); 833 } 834 835 /** 836 * Verifies that, in verbose mode, we allow a larger number of log records. 837 */ 838 @Test 839 public void enablingVerboseLoggingIncreasesLogRecSize() { 840 assertTrue(LOG_REC_LIMIT_IN_VERBOSE_MODE > WifiStateMachine.NUM_LOG_RECS_NORMAL); 841 mWsm.enableVerboseLogging(1); 842 for (int i = 0; i < LOG_REC_LIMIT_IN_VERBOSE_MODE * 2; i++) { 843 mWsm.sendMessage(WifiStateMachine.CMD_BOOT_COMPLETED); 844 } 845 mLooper.dispatchAll(); 846 assertEquals(LOG_REC_LIMIT_IN_VERBOSE_MODE, mWsm.getLogRecSize()); 847 } 848 849 /** 850 * Verifies that moving from verbose mode to normal mode resets the buffer, and limits new 851 * records to a small number of entries. 852 */ 853 @Test 854 public void disablingVerboseLoggingClearsRecordsAndDecreasesLogRecSize() { 855 mWsm.enableVerboseLogging(1); 856 for (int i = 0; i < LOG_REC_LIMIT_IN_VERBOSE_MODE; i++) { 857 mWsm.sendMessage(WifiStateMachine.CMD_BOOT_COMPLETED); 858 } 859 mLooper.dispatchAll(); 860 assertEquals(LOG_REC_LIMIT_IN_VERBOSE_MODE, mWsm.getLogRecSize()); 861 862 mWsm.enableVerboseLogging(0); 863 assertEquals(0, mWsm.getLogRecSize()); 864 for (int i = 0; i < LOG_REC_LIMIT_IN_VERBOSE_MODE; i++) { 865 mWsm.sendMessage(WifiStateMachine.CMD_BOOT_COMPLETED); 866 } 867 mLooper.dispatchAll(); 868 assertEquals(WifiStateMachine.NUM_LOG_RECS_NORMAL, mWsm.getLogRecSize()); 869 } 870 871 /** Verifies that enabling verbose logging sets the hal log property in eng builds. */ 872 @Test 873 public void enablingVerboseLoggingSetsHalLogPropertyInEngBuilds() { 874 reset(mPropertyService); // Ignore calls made in setUp() 875 when(mBuildProperties.isEngBuild()).thenReturn(true); 876 when(mBuildProperties.isUserdebugBuild()).thenReturn(false); 877 when(mBuildProperties.isUserBuild()).thenReturn(false); 878 mWsm.enableVerboseLogging(1); 879 verify(mPropertyService).set("log.tag.WifiHAL", "V"); 880 } 881 882 /** Verifies that enabling verbose logging sets the hal log property in userdebug builds. */ 883 @Test 884 public void enablingVerboseLoggingSetsHalLogPropertyInUserdebugBuilds() { 885 reset(mPropertyService); // Ignore calls made in setUp() 886 when(mBuildProperties.isUserdebugBuild()).thenReturn(true); 887 when(mBuildProperties.isEngBuild()).thenReturn(false); 888 when(mBuildProperties.isUserBuild()).thenReturn(false); 889 mWsm.enableVerboseLogging(1); 890 verify(mPropertyService).set("log.tag.WifiHAL", "V"); 891 } 892 893 /** Verifies that enabling verbose logging does NOT set the hal log property in user builds. */ 894 @Test 895 public void enablingVerboseLoggingDoeNotSetHalLogPropertyInUserBuilds() { 896 reset(mPropertyService); // Ignore calls made in setUp() 897 when(mBuildProperties.isUserBuild()).thenReturn(true); 898 when(mBuildProperties.isEngBuild()).thenReturn(false); 899 when(mBuildProperties.isUserdebugBuild()).thenReturn(false); 900 mWsm.enableVerboseLogging(1); 901 verify(mPropertyService, never()).set(anyString(), anyString()); 902 } 903} 904