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