WifiStateMachineTest.java revision a59f7d1ab2b9e912a9918eef96a29676c1725824
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 when(mWifiInjector.getWifiNetworkSelector()).thenReturn(mock(WifiNetworkSelector.class)); 352 353 when(mWifiNative.getInterfaceName()).thenReturn("mockWlan"); 354 when(mWifiSupplicantControl.getFrameworkNetworkId(anyInt())).thenReturn(0); 355 356 357 FrameworkFacade factory = getFrameworkFacade(); 358 Context context = getContext(); 359 360 Resources resources = getMockResources(); 361 when(context.getResources()).thenReturn(resources); 362 363 when(factory.getIntegerSetting(context, 364 Settings.Global.WIFI_FREQUENCY_BAND, 365 WifiManager.WIFI_FREQUENCY_BAND_AUTO)).thenReturn( 366 WifiManager.WIFI_FREQUENCY_BAND_AUTO); 367 368 when(factory.makeApConfigStore(eq(context), eq(mBackupManagerProxy))) 369 .thenReturn(mApConfigStore); 370 371 when(factory.makeSupplicantStateTracker( 372 any(Context.class), any(WifiConfigManager.class), 373 any(Handler.class))).thenReturn(mSupplicantStateTracker); 374 375 when(mUserManager.getProfileParent(11)) 376 .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "owner", 0)); 377 when(mUserManager.getProfiles(UserHandle.USER_SYSTEM)).thenReturn(Arrays.asList( 378 new UserInfo(UserHandle.USER_SYSTEM, "owner", 0), 379 new UserInfo(11, "managed profile", 0))); 380 381 when(mWificond.createClientInterface()).thenReturn(mClientInterface); 382 when(mClientInterface.asBinder()).thenReturn(mClientInterfaceBinder); 383 when(mClientInterface.enableSupplicant()).thenReturn(true); 384 when(mClientInterface.disableSupplicant()).thenReturn(true); 385 386 mWsm = new WifiStateMachine(context, factory, mLooper.getLooper(), 387 mUserManager, mWifiInjector, mBackupManagerProxy, mCountryCode, mWifiNative); 388 mWsmThread = getWsmHandlerThread(mWsm); 389 390 final AsyncChannel channel = new AsyncChannel(); 391 Handler handler = new Handler(mLooper.getLooper()) { 392 @Override 393 public void handleMessage(Message msg) { 394 switch (msg.what) { 395 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: 396 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { 397 mWsmAsyncChannel = channel; 398 } else { 399 Log.d(TAG, "Failed to connect Command channel " + this); 400 } 401 break; 402 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: 403 Log.d(TAG, "Command channel disconnected" + this); 404 break; 405 } 406 } 407 }; 408 409 channel.connect(context, handler, mWsm.getMessenger()); 410 mLooper.dispatchAll(); 411 /* Now channel is supposed to be connected */ 412 413 mBinderToken = Binder.clearCallingIdentity(); 414 } 415 416 @After 417 public void cleanUp() throws Exception { 418 Binder.restoreCallingIdentity(mBinderToken); 419 420 if (mSyncThread != null) stopLooper(mSyncThread.getLooper()); 421 if (mWsmThread != null) stopLooper(mWsmThread.getLooper()); 422 if (mP2pThread != null) stopLooper(mP2pThread.getLooper()); 423 424 mWsmThread = null; 425 mP2pThread = null; 426 mSyncThread = null; 427 mWsmAsyncChannel = null; 428 mWsm = null; 429 } 430 431 @Test 432 public void createNew() throws Exception { 433 assertEquals("InitialState", getCurrentState().getName()); 434 435 mWsm.sendMessage(WifiStateMachine.CMD_BOOT_COMPLETED); 436 mLooper.dispatchAll(); 437 assertEquals("InitialState", getCurrentState().getName()); 438 } 439 440 @Test 441 public void loadComponents() throws Exception { 442 when(mWifiNative.startHal()).thenReturn(true); 443 mWsm.setSupplicantRunning(true); 444 mLooper.dispatchAll(); 445 446 assertEquals("SupplicantStartingState", getCurrentState().getName()); 447 448 when(mWifiNative.setDeviceName(anyString())).thenReturn(true); 449 when(mWifiNative.setManufacturer(anyString())).thenReturn(true); 450 when(mWifiNative.setModelName(anyString())).thenReturn(true); 451 when(mWifiNative.setModelNumber(anyString())).thenReturn(true); 452 when(mWifiNative.setSerialNumber(anyString())).thenReturn(true); 453 when(mWifiNative.setConfigMethods(anyString())).thenReturn(true); 454 when(mWifiNative.setDeviceType(anyString())).thenReturn(true); 455 when(mWifiNative.setSerialNumber(anyString())).thenReturn(true); 456 when(mWifiNative.setScanningMacOui(any(byte[].class))).thenReturn(true); 457 458 mWsm.sendMessage(WifiMonitor.SUP_CONNECTION_EVENT); 459 mLooper.dispatchAll(); 460 461 assertEquals("DisconnectedState", getCurrentState().getName()); 462 } 463 464 @Test 465 public void shouldRequireSupplicantStartupToLeaveInitialState() throws Exception { 466 when(mClientInterface.enableSupplicant()).thenReturn(false); 467 mWsm.setSupplicantRunning(true); 468 mLooper.dispatchAll(); 469 assertEquals("InitialState", getCurrentState().getName()); 470 } 471 472 @Test 473 public void shouldRequireWificondToLeaveInitialState() throws Exception { 474 // We start out with valid default values, break them going backwards so that 475 // we test all the bailout cases. 476 477 // ClientInterface dies after creation. 478 doThrow(new RemoteException()).when(mClientInterfaceBinder).linkToDeath(any(), anyInt()); 479 mWsm.setSupplicantRunning(true); 480 mLooper.dispatchAll(); 481 assertEquals("InitialState", getCurrentState().getName()); 482 483 // Failed to even create the client interface. 484 when(mWificond.createClientInterface()).thenReturn(null); 485 mWsm.setSupplicantRunning(true); 486 mLooper.dispatchAll(); 487 assertEquals("InitialState", getCurrentState().getName()); 488 489 // Failed to get wificond proxy. 490 when(mWifiInjector.makeWificond()).thenReturn(null); 491 mWsm.setSupplicantRunning(true); 492 mLooper.dispatchAll(); 493 assertEquals("InitialState", getCurrentState().getName()); 494 } 495 496 @Test 497 public void loadComponentsFailure() throws Exception { 498 when(mWifiNative.startHal()).thenReturn(false); 499 when(mClientInterface.enableSupplicant()).thenReturn(false); 500 501 mWsm.setSupplicantRunning(true); 502 mLooper.dispatchAll(); 503 assertEquals("InitialState", getCurrentState().getName()); 504 505 when(mWifiNative.startHal()).thenReturn(true); 506 mWsm.setSupplicantRunning(true); 507 mLooper.dispatchAll(); 508 assertEquals("InitialState", getCurrentState().getName()); 509 } 510 511 @Test 512 public void checkInitialStateStickyWhenDisabledMode() throws Exception { 513 mLooper.dispatchAll(); 514 assertEquals("InitialState", getCurrentState().getName()); 515 assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest()); 516 517 mWsm.setOperationalMode(WifiStateMachine.DISABLED_MODE); 518 mLooper.dispatchAll(); 519 assertEquals(WifiStateMachine.DISABLED_MODE, mWsm.getOperationalModeForTest()); 520 assertEquals("InitialState", getCurrentState().getName()); 521 } 522 523 @Test 524 public void shouldStartSupplicantWhenConnectModeRequested() throws Exception { 525 when(mWifiNative.startHal()).thenReturn(true); 526 527 // The first time we start out in InitialState, we sit around here. 528 mLooper.dispatchAll(); 529 assertEquals("InitialState", getCurrentState().getName()); 530 assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest()); 531 532 // But if someone tells us to enter connect mode, we start up supplicant 533 mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE); 534 mLooper.dispatchAll(); 535 assertEquals("SupplicantStartingState", getCurrentState().getName()); 536 } 537 538 /** 539 * Test that mode changes for WifiStateMachine in the InitialState are realized when supplicant 540 * is started. 541 */ 542 @Test 543 public void checkStartInCorrectStateAfterChangingInitialState() throws Exception { 544 when(mWifiNative.startHal()).thenReturn(true); 545 546 // Check initial state 547 mLooper.dispatchAll(); 548 assertEquals("InitialState", getCurrentState().getName()); 549 assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest()); 550 551 // Update the mode 552 mWsm.setOperationalMode(WifiStateMachine.SCAN_ONLY_MODE); 553 mLooper.dispatchAll(); 554 assertEquals(WifiStateMachine.SCAN_ONLY_MODE, mWsm.getOperationalModeForTest()); 555 556 // Start supplicant so we move to the next state 557 mWsm.setSupplicantRunning(true); 558 mLooper.dispatchAll(); 559 assertEquals("SupplicantStartingState", getCurrentState().getName()); 560 when(mWifiNative.setDeviceName(anyString())).thenReturn(true); 561 when(mWifiNative.setManufacturer(anyString())).thenReturn(true); 562 when(mWifiNative.setModelName(anyString())).thenReturn(true); 563 when(mWifiNative.setModelNumber(anyString())).thenReturn(true); 564 when(mWifiNative.setSerialNumber(anyString())).thenReturn(true); 565 when(mWifiNative.setConfigMethods(anyString())).thenReturn(true); 566 when(mWifiNative.setDeviceType(anyString())).thenReturn(true); 567 when(mWifiNative.setSerialNumber(anyString())).thenReturn(true); 568 when(mWifiNative.setScanningMacOui(any(byte[].class))).thenReturn(true); 569 570 mWsm.sendMessage(WifiMonitor.SUP_CONNECTION_EVENT); 571 mLooper.dispatchAll(); 572 573 assertEquals("ScanModeState", getCurrentState().getName()); 574 } 575 576 private void addNetworkAndVerifySuccess() throws Exception { 577 addNetworkAndVerifySuccess(false); 578 } 579 580 private void addNetworkAndVerifySuccess(boolean isHidden) throws Exception { 581 loadComponents(); 582 583 WifiConfiguration config = new WifiConfiguration(); 584 config.SSID = sSSID; 585 config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); 586 config.hiddenSSID = isHidden; 587 588 when(mWifiConfigManager.addOrUpdateNetwork(any(WifiConfiguration.class), anyInt())) 589 .thenReturn(new NetworkUpdateResult(0)); 590 when(mWifiConfigManager.getSavedNetworks()).thenReturn(Arrays.asList(config)); 591 when(mWifiConfigManager.getConfiguredNetwork(0)).thenReturn(config); 592 593 mLooper.startAutoDispatch(); 594 mWsm.syncAddOrUpdateNetwork(mWsmAsyncChannel, config); 595 mLooper.stopAutoDispatch(); 596 597 verify(mWifiConfigManager).addOrUpdateNetwork(eq(config), anyInt()); 598 599 mLooper.startAutoDispatch(); 600 List<WifiConfiguration> configs = mWsm.syncGetConfiguredNetworks(-1, mWsmAsyncChannel); 601 mLooper.stopAutoDispatch(); 602 assertEquals(1, configs.size()); 603 604 WifiConfiguration config2 = configs.get(0); 605 assertEquals("\"GoogleGuest\"", config2.SSID); 606 assertTrue(config2.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.NONE)); 607 } 608 609 /** 610 * Helper method to retrieve WifiConfiguration by SSID. 611 * 612 * Returns the associated WifiConfiguration if it is found, null otherwise. 613 */ 614 private WifiConfiguration getWifiConfigurationForNetwork(String ssid) { 615 mLooper.startAutoDispatch(); 616 List<WifiConfiguration> configs = mWsm.syncGetConfiguredNetworks(-1, mWsmAsyncChannel); 617 mLooper.stopAutoDispatch(); 618 619 for (WifiConfiguration checkConfig : configs) { 620 if (checkConfig.SSID.equals(ssid)) { 621 return checkConfig; 622 } 623 } 624 return null; 625 } 626 627 private void verifyScan(int band, int reportEvents, Set<String> hiddenNetworkSSIDSet) { 628 ArgumentCaptor<WifiScanner.ScanSettings> scanSettingsCaptor = 629 ArgumentCaptor.forClass(WifiScanner.ScanSettings.class); 630 ArgumentCaptor<WifiScanner.ScanListener> scanListenerCaptor = 631 ArgumentCaptor.forClass(WifiScanner.ScanListener.class); 632 verify(mWifiScanner).startScan(scanSettingsCaptor.capture(), scanListenerCaptor.capture(), 633 eq(null)); 634 WifiScanner.ScanSettings actualSettings = scanSettingsCaptor.getValue(); 635 assertEquals("band", band, actualSettings.band); 636 assertEquals("reportEvents", reportEvents, actualSettings.reportEvents); 637 638 if (hiddenNetworkSSIDSet == null) { 639 hiddenNetworkSSIDSet = new HashSet<>(); 640 } 641 Set<String> actualHiddenNetworkSSIDSet = new HashSet<>(); 642 if (actualSettings.hiddenNetworks != null) { 643 for (int i = 0; i < actualSettings.hiddenNetworks.length; ++i) { 644 actualHiddenNetworkSSIDSet.add(actualSettings.hiddenNetworks[i].ssid); 645 } 646 } 647 assertEquals("hidden networks", hiddenNetworkSSIDSet, actualHiddenNetworkSSIDSet); 648 649 when(mWifiNative.getScanResults()).thenReturn(getMockScanResults()); 650 mWsm.sendMessage(WifiMonitor.SCAN_RESULTS_EVENT); 651 652 mLooper.dispatchAll(); 653 654 List<ScanResult> reportedResults = mWsm.syncGetScanResultsList(); 655 assertEquals(8, reportedResults.size()); 656 } 657 658 @Test 659 public void scan() throws Exception { 660 addNetworkAndVerifySuccess(); 661 662 mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE); 663 mWsm.startScan(-1, 0, null, null); 664 mLooper.dispatchAll(); 665 666 verifyScan(WifiScanner.WIFI_BAND_BOTH_WITH_DFS, 667 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN 668 | WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT, null); 669 } 670 671 @Test 672 public void scanWithHiddenNetwork() throws Exception { 673 addNetworkAndVerifySuccess(true); 674 675 Set<String> hiddenNetworkSet = new HashSet<>(); 676 hiddenNetworkSet.add(sSSID); 677 List<WifiScanner.ScanSettings.HiddenNetwork> hiddenNetworkList = new ArrayList<>(); 678 hiddenNetworkList.add(new WifiScanner.ScanSettings.HiddenNetwork(sSSID)); 679 when(mWifiConfigManager.retrieveHiddenNetworkList()).thenReturn(hiddenNetworkList); 680 681 mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE); 682 mWsm.startScan(-1, 0, null, null); 683 mLooper.dispatchAll(); 684 685 verifyScan(WifiScanner.WIFI_BAND_BOTH_WITH_DFS, 686 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN 687 | WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT, 688 hiddenNetworkSet); 689 } 690 691 @Test 692 public void connect() throws Exception { 693 addNetworkAndVerifySuccess(); 694 695 mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE); 696 mLooper.dispatchAll(); 697 698 mLooper.startAutoDispatch(); 699 mWsm.syncEnableNetwork(mWsmAsyncChannel, 0, true); 700 mLooper.stopAutoDispatch(); 701 702 verify(mWifiConfigManager).enableNetwork(eq(0), eq(true), anyInt()); 703 704 mWsm.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, sBSSID); 705 mLooper.dispatchAll(); 706 707 mWsm.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0, 708 new StateChangeResult(0, sWifiSsid, sBSSID, SupplicantState.COMPLETED)); 709 mLooper.dispatchAll(); 710 711 assertEquals("ObtainingIpState", getCurrentState().getName()); 712 713 DhcpResults dhcpResults = new DhcpResults(); 714 dhcpResults.setGateway("1.2.3.4"); 715 dhcpResults.setIpAddress("192.168.1.100", 0); 716 dhcpResults.addDns("8.8.8.8"); 717 dhcpResults.setLeaseDuration(3600); 718 719 mTestIpManager.injectDhcpSuccess(dhcpResults); 720 mLooper.dispatchAll(); 721 722 assertEquals("ConnectedState", getCurrentState().getName()); 723 } 724 725 @Test 726 public void testDhcpFailure() throws Exception { 727 addNetworkAndVerifySuccess(); 728 729 mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE); 730 mLooper.dispatchAll(); 731 732 mLooper.startAutoDispatch(); 733 mWsm.syncEnableNetwork(mWsmAsyncChannel, 0, true); 734 mLooper.stopAutoDispatch(); 735 736 verify(mWifiConfigManager).enableNetwork(eq(0), eq(true), anyInt()); 737 738 mWsm.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, sBSSID); 739 mLooper.dispatchAll(); 740 741 mWsm.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0, 742 new StateChangeResult(0, sWifiSsid, sBSSID, SupplicantState.COMPLETED)); 743 mLooper.dispatchAll(); 744 745 assertEquals("ObtainingIpState", getCurrentState().getName()); 746 747 mTestIpManager.injectDhcpFailure(); 748 mLooper.dispatchAll(); 749 750 assertEquals("DisconnectingState", getCurrentState().getName()); 751 } 752 753 @Test 754 public void testBadNetworkEvent() throws Exception { 755 addNetworkAndVerifySuccess(); 756 757 mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE); 758 mLooper.dispatchAll(); 759 760 mLooper.startAutoDispatch(); 761 mWsm.syncEnableNetwork(mWsmAsyncChannel, 0, true); 762 mLooper.stopAutoDispatch(); 763 764 verify(mWifiConfigManager).enableNetwork(eq(0), eq(true), anyInt()); 765 766 mWsm.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, 0, 0, sBSSID); 767 mLooper.dispatchAll(); 768 769 mWsm.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0, 770 new StateChangeResult(0, sWifiSsid, sBSSID, SupplicantState.COMPLETED)); 771 mLooper.dispatchAll(); 772 773 assertEquals("DisconnectedState", getCurrentState().getName()); 774 } 775 776 777 @Test 778 public void smToString() throws Exception { 779 assertEquals("CMD_CHANNEL_HALF_CONNECTED", mWsm.smToString( 780 AsyncChannel.CMD_CHANNEL_HALF_CONNECTED)); 781 assertEquals("CMD_PRE_DHCP_ACTION", mWsm.smToString( 782 DhcpClient.CMD_PRE_DHCP_ACTION)); 783 assertEquals("CMD_IP_REACHABILITY_LOST", mWsm.smToString( 784 WifiStateMachine.CMD_IP_REACHABILITY_LOST)); 785 } 786 787 @Test 788 public void disconnect() throws Exception { 789 connect(); 790 791 mWsm.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, -1, 3, "01:02:03:04:05:06"); 792 mLooper.dispatchAll(); 793 mWsm.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0, 794 new StateChangeResult(0, sWifiSsid, sBSSID, SupplicantState.DISCONNECTED)); 795 mLooper.dispatchAll(); 796 797 assertEquals("DisconnectedState", getCurrentState().getName()); 798 } 799 800 /** 801 * Successfully connecting to a network will set WifiConfiguration's value of HasEverConnected 802 * to true. 803 * 804 * Test: Successfully create and connect to a network. Check the config and verify 805 * WifiConfiguration.getHasEverConnected() is true. 806 */ 807 @Test 808 public void setHasEverConnectedTrueOnConnect() throws Exception { 809 connect(); 810 verify(mWifiConfigManager, atLeastOnce()).updateNetworkAfterConnect(0); 811 } 812 813 /** 814 * Fail network connection attempt and verify HasEverConnected remains false. 815 * 816 * Test: Successfully create a network but fail when connecting. Check the config and verify 817 * WifiConfiguration.getHasEverConnected() is false. 818 */ 819 @Test 820 public void connectionFailureDoesNotSetHasEverConnectedTrue() throws Exception { 821 testDhcpFailure(); 822 verify(mWifiConfigManager, never()).updateNetworkAfterConnect(0); 823 } 824 825 @Test 826 public void iconQueryTest() throws Exception { 827 // TODO(b/31065385): Passpoint config management. 828 } 829 830 /** 831 * Verifies that, by default, we allow only the "normal" number of log records. 832 */ 833 @Test 834 public void normalLogRecSizeIsUsedByDefault() { 835 for (int i = 0; i < WifiStateMachine.NUM_LOG_RECS_NORMAL * 2; i++) { 836 mWsm.sendMessage(WifiStateMachine.CMD_BOOT_COMPLETED); 837 } 838 mLooper.dispatchAll(); 839 assertEquals(WifiStateMachine.NUM_LOG_RECS_NORMAL, mWsm.getLogRecSize()); 840 } 841 842 /** 843 * Verifies that, in verbose mode, we allow a larger number of log records. 844 */ 845 @Test 846 public void enablingVerboseLoggingIncreasesLogRecSize() { 847 assertTrue(LOG_REC_LIMIT_IN_VERBOSE_MODE > WifiStateMachine.NUM_LOG_RECS_NORMAL); 848 mWsm.enableVerboseLogging(1); 849 for (int i = 0; i < LOG_REC_LIMIT_IN_VERBOSE_MODE * 2; i++) { 850 mWsm.sendMessage(WifiStateMachine.CMD_BOOT_COMPLETED); 851 } 852 mLooper.dispatchAll(); 853 assertEquals(LOG_REC_LIMIT_IN_VERBOSE_MODE, mWsm.getLogRecSize()); 854 } 855 856 /** 857 * Verifies that moving from verbose mode to normal mode resets the buffer, and limits new 858 * records to a small number of entries. 859 */ 860 @Test 861 public void disablingVerboseLoggingClearsRecordsAndDecreasesLogRecSize() { 862 mWsm.enableVerboseLogging(1); 863 for (int i = 0; i < LOG_REC_LIMIT_IN_VERBOSE_MODE; i++) { 864 mWsm.sendMessage(WifiStateMachine.CMD_BOOT_COMPLETED); 865 } 866 mLooper.dispatchAll(); 867 assertEquals(LOG_REC_LIMIT_IN_VERBOSE_MODE, mWsm.getLogRecSize()); 868 869 mWsm.enableVerboseLogging(0); 870 assertEquals(0, mWsm.getLogRecSize()); 871 for (int i = 0; i < LOG_REC_LIMIT_IN_VERBOSE_MODE; i++) { 872 mWsm.sendMessage(WifiStateMachine.CMD_BOOT_COMPLETED); 873 } 874 mLooper.dispatchAll(); 875 assertEquals(WifiStateMachine.NUM_LOG_RECS_NORMAL, mWsm.getLogRecSize()); 876 } 877 878 /** Verifies that enabling verbose logging sets the hal log property in eng builds. */ 879 @Test 880 public void enablingVerboseLoggingSetsHalLogPropertyInEngBuilds() { 881 reset(mPropertyService); // Ignore calls made in setUp() 882 when(mBuildProperties.isEngBuild()).thenReturn(true); 883 when(mBuildProperties.isUserdebugBuild()).thenReturn(false); 884 when(mBuildProperties.isUserBuild()).thenReturn(false); 885 mWsm.enableVerboseLogging(1); 886 verify(mPropertyService).set("log.tag.WifiHAL", "V"); 887 } 888 889 /** Verifies that enabling verbose logging sets the hal log property in userdebug builds. */ 890 @Test 891 public void enablingVerboseLoggingSetsHalLogPropertyInUserdebugBuilds() { 892 reset(mPropertyService); // Ignore calls made in setUp() 893 when(mBuildProperties.isUserdebugBuild()).thenReturn(true); 894 when(mBuildProperties.isEngBuild()).thenReturn(false); 895 when(mBuildProperties.isUserBuild()).thenReturn(false); 896 mWsm.enableVerboseLogging(1); 897 verify(mPropertyService).set("log.tag.WifiHAL", "V"); 898 } 899 900 /** Verifies that enabling verbose logging does NOT set the hal log property in user builds. */ 901 @Test 902 public void enablingVerboseLoggingDoeNotSetHalLogPropertyInUserBuilds() { 903 reset(mPropertyService); // Ignore calls made in setUp() 904 when(mBuildProperties.isUserBuild()).thenReturn(true); 905 when(mBuildProperties.isEngBuild()).thenReturn(false); 906 when(mBuildProperties.isUserdebugBuild()).thenReturn(false); 907 mWsm.enableVerboseLogging(1); 908 verify(mPropertyService, never()).set(anyString(), anyString()); 909 } 910 911 private int testGetSupportedFeaturesCase(int supportedFeatures, boolean rttConfigured) { 912 AsyncChannel channel = mock(AsyncChannel.class); 913 Message reply = Message.obtain(); 914 reply.arg1 = supportedFeatures; 915 reset(mPropertyService); // Ignore calls made in setUp() 916 when(channel.sendMessageSynchronously(WifiStateMachine.CMD_GET_SUPPORTED_FEATURES)) 917 .thenReturn(reply); 918 when(mPropertyService.getBoolean("config.disable_rtt", false)) 919 .thenReturn(rttConfigured); 920 return mWsm.syncGetSupportedFeatures(channel); 921 } 922 923 /** Verifies that syncGetSupportedFeatures() masks out capabilities based on system flags. */ 924 @Test 925 public void syncGetSupportedFeatures() { 926 final int featureAware = WifiManager.WIFI_FEATURE_AWARE; 927 final int featureInfra = WifiManager.WIFI_FEATURE_INFRA; 928 final int featureD2dRtt = WifiManager.WIFI_FEATURE_D2D_RTT; 929 final int featureD2apRtt = WifiManager.WIFI_FEATURE_D2AP_RTT; 930 931 assertEquals(0, testGetSupportedFeaturesCase(0, false)); 932 assertEquals(0, testGetSupportedFeaturesCase(0, true)); 933 assertEquals(featureAware | featureInfra, 934 testGetSupportedFeaturesCase(featureAware | featureInfra, false)); 935 assertEquals(featureAware | featureInfra, 936 testGetSupportedFeaturesCase(featureAware | featureInfra, true)); 937 assertEquals(featureInfra | featureD2dRtt, 938 testGetSupportedFeaturesCase(featureInfra | featureD2dRtt, false)); 939 assertEquals(featureInfra, 940 testGetSupportedFeaturesCase(featureInfra | featureD2dRtt, true)); 941 assertEquals(featureInfra | featureD2apRtt, 942 testGetSupportedFeaturesCase(featureInfra | featureD2apRtt, false)); 943 assertEquals(featureInfra, 944 testGetSupportedFeaturesCase(featureInfra | featureD2apRtt, true)); 945 assertEquals(featureInfra | featureD2dRtt | featureD2apRtt, 946 testGetSupportedFeaturesCase(featureInfra | featureD2dRtt | featureD2apRtt, false)); 947 assertEquals(featureInfra, 948 testGetSupportedFeaturesCase(featureInfra | featureD2dRtt | featureD2apRtt, true)); 949 } 950} 951