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