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