WifiStateMachineTest.java revision f91a96259d1fbdfb9af907dd20cf905a8da3a119
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 startSupplicantAndDispatchMessages(); 457 458 assertEquals("DisconnectedState", getCurrentState().getName()); 459 } 460 461 @Test 462 public void loadComponentsInApMode() throws Exception { 463 mWsm.setHostApRunning(new WifiConfiguration(), true); 464 mLooper.dispatchAll(); 465 466 assertEquals("SoftApState", getCurrentState().getName()); 467 468 verify(mSoftApManager).start(); 469 } 470 471 @Test 472 public void shouldRequireSupplicantStartupToLeaveInitialState() throws Exception { 473 when(mWifiNative.enableSupplicant()).thenReturn(false); 474 mWsm.setSupplicantRunning(true); 475 mLooper.dispatchAll(); 476 assertEquals("InitialState", getCurrentState().getName()); 477 } 478 479 @Test 480 public void shouldRequireWificondToLeaveInitialState() throws Exception { 481 // We start out with valid default values, break them going backwards so that 482 // we test all the bailout cases. 483 484 // ClientInterface dies after creation. 485 doThrow(new RemoteException()).when(mClientInterfaceBinder).linkToDeath(any(), anyInt()); 486 mWsm.setSupplicantRunning(true); 487 mLooper.dispatchAll(); 488 assertEquals("InitialState", getCurrentState().getName()); 489 490 // Failed to even create the client interface. 491 when(mWificond.createClientInterface()).thenReturn(null); 492 mWsm.setSupplicantRunning(true); 493 mLooper.dispatchAll(); 494 assertEquals("InitialState", getCurrentState().getName()); 495 496 // Failed to get wificond proxy. 497 when(mWifiInjector.makeWificond()).thenReturn(null); 498 mWsm.setSupplicantRunning(true); 499 mLooper.dispatchAll(); 500 assertEquals("InitialState", getCurrentState().getName()); 501 } 502 503 @Test 504 public void loadComponentsFailure() throws Exception { 505 when(mWifiNative.startHal(anyBoolean())).thenReturn(false); 506 when(mWifiNative.enableSupplicant()).thenReturn(false); 507 508 mWsm.setSupplicantRunning(true); 509 mLooper.dispatchAll(); 510 assertEquals("InitialState", getCurrentState().getName()); 511 512 when(mWifiNative.startHal(anyBoolean())).thenReturn(true); 513 mWsm.setSupplicantRunning(true); 514 mLooper.dispatchAll(); 515 assertEquals("InitialState", getCurrentState().getName()); 516 } 517 518 @Test 519 public void checkInitialStateStickyWhenDisabledMode() throws Exception { 520 mLooper.dispatchAll(); 521 assertEquals("InitialState", getCurrentState().getName()); 522 assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest()); 523 524 mWsm.setOperationalMode(WifiStateMachine.DISABLED_MODE); 525 mLooper.dispatchAll(); 526 assertEquals(WifiStateMachine.DISABLED_MODE, mWsm.getOperationalModeForTest()); 527 assertEquals("InitialState", getCurrentState().getName()); 528 } 529 530 @Test 531 public void shouldStartSupplicantWhenConnectModeRequested() throws Exception { 532 when(mWifiNative.startHal(anyBoolean())).thenReturn(true); 533 534 // The first time we start out in InitialState, we sit around here. 535 mLooper.dispatchAll(); 536 assertEquals("InitialState", getCurrentState().getName()); 537 assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest()); 538 539 // But if someone tells us to enter connect mode, we start up supplicant 540 mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE); 541 mLooper.dispatchAll(); 542 assertEquals("SupplicantStartingState", getCurrentState().getName()); 543 } 544 545 /** 546 * Test that mode changes accurately reflect the value for isWifiEnabled. 547 */ 548 @Test 549 public void checkIsWifiEnabledForModeChanges() throws Exception { 550 when(mWifiNative.startHal(anyBoolean())).thenReturn(true); 551 552 // Check initial state 553 mLooper.dispatchAll(); 554 assertEquals("InitialState", getCurrentState().getName()); 555 assertEquals(WifiManager.WIFI_STATE_DISABLED, mWsm.syncGetWifiState()); 556 557 mWsm.setOperationalMode(WifiStateMachine.SCAN_ONLY_MODE); 558 startSupplicantAndDispatchMessages(); 559 mWsm.setSupplicantRunning(true); 560 mLooper.dispatchAll(); 561 assertEquals(WifiStateMachine.SCAN_ONLY_MODE, mWsm.getOperationalModeForTest()); 562 assertEquals("ScanModeState", getCurrentState().getName()); 563 assertEquals(WifiManager.WIFI_STATE_DISABLED, mWsm.syncGetWifiState()); 564 565 // switch to connect mode and verify wifi is reported as enabled 566 mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE); 567 mLooper.dispatchAll(); 568 assertEquals("DisconnectedState", getCurrentState().getName()); 569 assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest()); 570 assertEquals(WifiManager.WIFI_STATE_ENABLED, mWsm.syncGetWifiState()); 571 572 // now go back to scan mode with "wifi disabled" to verify the reported wifi state. 573 mWsm.setOperationalMode(WifiStateMachine.SCAN_ONLY_WITH_WIFI_OFF_MODE); 574 mLooper.dispatchAll(); 575 assertEquals(WifiStateMachine.SCAN_ONLY_WITH_WIFI_OFF_MODE, 576 mWsm.getOperationalModeForTest()); 577 assertEquals("ScanModeState", getCurrentState().getName()); 578 assertEquals(WifiManager.WIFI_STATE_DISABLED, mWsm.syncGetWifiState()); 579 580 // now go to AP mode 581 mWsm.setSupplicantRunning(false); 582 mWsm.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_RSP); 583 mWsm.sendMessage(WifiMonitor.SUP_DISCONNECTION_EVENT); 584 mWsm.setHostApRunning(new WifiConfiguration(), true); 585 mLooper.dispatchAll(); 586 assertEquals("SoftApState", getCurrentState().getName()); 587 assertEquals(WifiManager.WIFI_STATE_DISABLED, mWsm.syncGetWifiState()); 588 } 589 590 591 /** 592 * Test that mode changes for WifiStateMachine in the InitialState are realized when supplicant 593 * is started. 594 */ 595 @Test 596 public void checkStartInCorrectStateAfterChangingInitialState() throws Exception { 597 when(mWifiNative.startHal(anyBoolean())).thenReturn(true); 598 599 // Check initial state 600 mLooper.dispatchAll(); 601 assertEquals("InitialState", getCurrentState().getName()); 602 assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest()); 603 604 // Update the mode 605 mWsm.setOperationalMode(WifiStateMachine.SCAN_ONLY_MODE); 606 mLooper.dispatchAll(); 607 assertEquals(WifiStateMachine.SCAN_ONLY_MODE, mWsm.getOperationalModeForTest()); 608 609 // Start supplicant so we move to the next state 610 startSupplicantAndDispatchMessages(); 611 612 assertEquals("ScanModeState", getCurrentState().getName()); 613 } 614 615 /** 616 * Verifies that configs can be removed when in client mode. 617 */ 618 @Test 619 public void canRemoveNetworkConfigInClientMode() throws Exception { 620 boolean result; 621 when(mWifiConfigManager.removeNetwork(eq(0), anyInt())).thenReturn(true); 622 addNetworkAndVerifySuccess(); 623 mLooper.startAutoDispatch(); 624 result = mWsm.syncRemoveNetwork(mWsmAsyncChannel, 0); 625 mLooper.stopAutoDispatch(); 626 assertTrue(result); 627 } 628 629 /** 630 * Verifies that configs can be removed when not in client mode. 631 */ 632 @Test 633 public void canRemoveNetworkConfigWhenWifiDisabled() { 634 boolean result; 635 when(mWifiConfigManager.removeNetwork(eq(0), anyInt())).thenReturn(true); 636 mLooper.startAutoDispatch(); 637 result = mWsm.syncRemoveNetwork(mWsmAsyncChannel, 0); 638 mLooper.stopAutoDispatch(); 639 640 assertTrue(result); 641 verify(mWifiConfigManager).removeNetwork(anyInt(), anyInt()); 642 } 643 644 /** 645 * Verifies that configs can be forgotten when in client mode. 646 */ 647 @Test 648 public void canForgetNetworkConfigInClientMode() throws Exception { 649 when(mWifiConfigManager.removeNetwork(eq(0), anyInt())).thenReturn(true); 650 addNetworkAndVerifySuccess(); 651 mWsm.sendMessage(WifiManager.FORGET_NETWORK, 0, MANAGED_PROFILE_UID); 652 mLooper.dispatchAll(); 653 verify(mWifiConfigManager).removeNetwork(anyInt(), anyInt()); 654 } 655 656 /** 657 * Verifies that configs can be removed when not in client mode. 658 */ 659 @Test 660 public void canForgetNetworkConfigWhenWifiDisabled() throws Exception { 661 when(mWifiConfigManager.removeNetwork(eq(0), anyInt())).thenReturn(true); 662 mWsm.sendMessage(WifiManager.FORGET_NETWORK, 0, MANAGED_PROFILE_UID); 663 mLooper.dispatchAll(); 664 verify(mWifiConfigManager).removeNetwork(anyInt(), anyInt()); 665 } 666 667 /** 668 * Helper method to move through SupplicantStarting and SupplicantStarted states. 669 */ 670 private void startSupplicantAndDispatchMessages() throws Exception { 671 mWsm.setSupplicantRunning(true); 672 mLooper.dispatchAll(); 673 674 assertEquals("SupplicantStartingState", getCurrentState().getName()); 675 676 when(mWifiNative.setDeviceName(anyString())).thenReturn(true); 677 when(mWifiNative.setManufacturer(anyString())).thenReturn(true); 678 when(mWifiNative.setModelName(anyString())).thenReturn(true); 679 when(mWifiNative.setModelNumber(anyString())).thenReturn(true); 680 when(mWifiNative.setSerialNumber(anyString())).thenReturn(true); 681 when(mWifiNative.setConfigMethods(anyString())).thenReturn(true); 682 when(mWifiNative.setDeviceType(anyString())).thenReturn(true); 683 when(mWifiNative.setSerialNumber(anyString())).thenReturn(true); 684 when(mWifiNative.setScanningMacOui(any(byte[].class))).thenReturn(true); 685 686 mWsm.sendMessage(WifiMonitor.SUP_CONNECTION_EVENT); 687 mLooper.dispatchAll(); 688 } 689 690 private void addNetworkAndVerifySuccess() throws Exception { 691 addNetworkAndVerifySuccess(false); 692 } 693 694 private void addNetworkAndVerifySuccess(boolean isHidden) throws Exception { 695 loadComponentsInStaMode(); 696 697 WifiConfiguration config = new WifiConfiguration(); 698 config.SSID = sSSID; 699 config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); 700 config.hiddenSSID = isHidden; 701 702 when(mWifiConfigManager.addOrUpdateNetwork(any(WifiConfiguration.class), anyInt())) 703 .thenReturn(new NetworkUpdateResult(0)); 704 when(mWifiConfigManager.getSavedNetworks()).thenReturn(Arrays.asList(config)); 705 when(mWifiConfigManager.getConfiguredNetwork(0)).thenReturn(config); 706 707 mLooper.startAutoDispatch(); 708 mWsm.syncAddOrUpdateNetwork(mWsmAsyncChannel, config); 709 mLooper.stopAutoDispatch(); 710 711 verify(mWifiConfigManager).addOrUpdateNetwork(eq(config), anyInt()); 712 713 mLooper.startAutoDispatch(); 714 List<WifiConfiguration> configs = mWsm.syncGetConfiguredNetworks(-1, mWsmAsyncChannel); 715 mLooper.stopAutoDispatch(); 716 assertEquals(1, configs.size()); 717 718 WifiConfiguration config2 = configs.get(0); 719 assertEquals("\"GoogleGuest\"", config2.SSID); 720 assertTrue(config2.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.NONE)); 721 } 722 723 /** 724 * Helper method to retrieve WifiConfiguration by SSID. 725 * 726 * Returns the associated WifiConfiguration if it is found, null otherwise. 727 */ 728 private WifiConfiguration getWifiConfigurationForNetwork(String ssid) { 729 mLooper.startAutoDispatch(); 730 List<WifiConfiguration> configs = mWsm.syncGetConfiguredNetworks(-1, mWsmAsyncChannel); 731 mLooper.stopAutoDispatch(); 732 733 for (WifiConfiguration checkConfig : configs) { 734 if (checkConfig.SSID.equals(ssid)) { 735 return checkConfig; 736 } 737 } 738 return null; 739 } 740 741 private void verifyScan(int band, int reportEvents, Set<String> hiddenNetworkSSIDSet) { 742 ArgumentCaptor<WifiScanner.ScanSettings> scanSettingsCaptor = 743 ArgumentCaptor.forClass(WifiScanner.ScanSettings.class); 744 ArgumentCaptor<WifiScanner.ScanListener> scanListenerCaptor = 745 ArgumentCaptor.forClass(WifiScanner.ScanListener.class); 746 verify(mWifiScanner).startScan(scanSettingsCaptor.capture(), scanListenerCaptor.capture(), 747 eq(null)); 748 WifiScanner.ScanSettings actualSettings = scanSettingsCaptor.getValue(); 749 assertEquals("band", band, actualSettings.band); 750 assertEquals("reportEvents", reportEvents, actualSettings.reportEvents); 751 752 if (hiddenNetworkSSIDSet == null) { 753 hiddenNetworkSSIDSet = new HashSet<>(); 754 } 755 Set<String> actualHiddenNetworkSSIDSet = new HashSet<>(); 756 if (actualSettings.hiddenNetworks != null) { 757 for (int i = 0; i < actualSettings.hiddenNetworks.length; ++i) { 758 actualHiddenNetworkSSIDSet.add(actualSettings.hiddenNetworks[i].ssid); 759 } 760 } 761 assertEquals("hidden networks", hiddenNetworkSSIDSet, actualHiddenNetworkSSIDSet); 762 763 when(mWifiNative.getScanResults()).thenReturn(getMockScanResults()); 764 mWsm.sendMessage(WifiMonitor.SCAN_RESULTS_EVENT); 765 766 mLooper.dispatchAll(); 767 768 List<ScanResult> reportedResults = mWsm.syncGetScanResultsList(); 769 assertEquals(8, reportedResults.size()); 770 } 771 772 @Test 773 public void scan() throws Exception { 774 addNetworkAndVerifySuccess(); 775 776 mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE); 777 mWsm.startScan(-1, 0, null, null); 778 mLooper.dispatchAll(); 779 780 verifyScan(WifiScanner.WIFI_BAND_BOTH_WITH_DFS, 781 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN 782 | WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT, null); 783 } 784 785 @Test 786 public void scanWithHiddenNetwork() throws Exception { 787 addNetworkAndVerifySuccess(true); 788 789 Set<String> hiddenNetworkSet = new HashSet<>(); 790 hiddenNetworkSet.add(sSSID); 791 List<WifiScanner.ScanSettings.HiddenNetwork> hiddenNetworkList = new ArrayList<>(); 792 hiddenNetworkList.add(new WifiScanner.ScanSettings.HiddenNetwork(sSSID)); 793 when(mWifiConfigManager.retrieveHiddenNetworkList()).thenReturn(hiddenNetworkList); 794 795 mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE); 796 mWsm.startScan(-1, 0, null, null); 797 mLooper.dispatchAll(); 798 799 verifyScan(WifiScanner.WIFI_BAND_BOTH_WITH_DFS, 800 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN 801 | WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT, 802 hiddenNetworkSet); 803 } 804 805 @Test 806 public void connect() throws Exception { 807 addNetworkAndVerifySuccess(); 808 809 mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE); 810 mLooper.dispatchAll(); 811 812 mLooper.startAutoDispatch(); 813 mWsm.syncEnableNetwork(mWsmAsyncChannel, 0, true); 814 mLooper.stopAutoDispatch(); 815 816 verify(mWifiConfigManager).enableNetwork(eq(0), eq(true), anyInt()); 817 818 mWsm.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, sBSSID); 819 mLooper.dispatchAll(); 820 821 mWsm.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0, 822 new StateChangeResult(0, sWifiSsid, sBSSID, SupplicantState.COMPLETED)); 823 mLooper.dispatchAll(); 824 825 assertEquals("ObtainingIpState", getCurrentState().getName()); 826 827 DhcpResults dhcpResults = new DhcpResults(); 828 dhcpResults.setGateway("1.2.3.4"); 829 dhcpResults.setIpAddress("192.168.1.100", 0); 830 dhcpResults.addDns("8.8.8.8"); 831 dhcpResults.setLeaseDuration(3600); 832 833 mTestIpManager.injectDhcpSuccess(dhcpResults); 834 mLooper.dispatchAll(); 835 836 assertEquals("ConnectedState", getCurrentState().getName()); 837 } 838 839 /** 840 * If caller tries to connect to a network that is already connected, the connection request 841 * should succeed. 842 * 843 * Test: Create and connect to a network, then try to reconnect to the same network. Verify 844 * that connection request returns with CONNECT_NETWORK_SUCCEEDED. 845 */ 846 @Test 847 public void reconnectToConnectedNetwork() throws Exception { 848 addNetworkAndVerifySuccess(); 849 850 mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE); 851 mLooper.dispatchAll(); 852 853 mLooper.startAutoDispatch(); 854 mWsm.syncEnableNetwork(mWsmAsyncChannel, 0, true); 855 mLooper.stopAutoDispatch(); 856 857 verify(mWifiConfigManager).enableNetwork(eq(0), eq(true), anyInt()); 858 859 mWsm.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, sBSSID); 860 mLooper.dispatchAll(); 861 862 mWsm.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0, 863 new StateChangeResult(0, sWifiSsid, sBSSID, SupplicantState.COMPLETED)); 864 mLooper.dispatchAll(); 865 866 assertEquals("ObtainingIpState", getCurrentState().getName()); 867 868 // try to reconnect 869 mLooper.startAutoDispatch(); 870 Message reply = mWsmAsyncChannel.sendMessageSynchronously(WifiManager.CONNECT_NETWORK, 0); 871 mLooper.stopAutoDispatch(); 872 873 assertEquals(WifiManager.CONNECT_NETWORK_SUCCEEDED, reply.what); 874 } 875 876 @Test 877 public void testDhcpFailure() throws Exception { 878 addNetworkAndVerifySuccess(); 879 880 mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE); 881 mLooper.dispatchAll(); 882 883 mLooper.startAutoDispatch(); 884 mWsm.syncEnableNetwork(mWsmAsyncChannel, 0, true); 885 mLooper.stopAutoDispatch(); 886 887 verify(mWifiConfigManager).enableNetwork(eq(0), eq(true), anyInt()); 888 889 mWsm.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, sBSSID); 890 mLooper.dispatchAll(); 891 892 mWsm.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0, 893 new StateChangeResult(0, sWifiSsid, sBSSID, SupplicantState.COMPLETED)); 894 mLooper.dispatchAll(); 895 896 assertEquals("ObtainingIpState", getCurrentState().getName()); 897 898 mTestIpManager.injectDhcpFailure(); 899 mLooper.dispatchAll(); 900 901 assertEquals("DisconnectingState", getCurrentState().getName()); 902 } 903 904 @Test 905 public void testBadNetworkEvent() throws Exception { 906 addNetworkAndVerifySuccess(); 907 908 mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE); 909 mLooper.dispatchAll(); 910 911 mLooper.startAutoDispatch(); 912 mWsm.syncEnableNetwork(mWsmAsyncChannel, 0, true); 913 mLooper.stopAutoDispatch(); 914 915 verify(mWifiConfigManager).enableNetwork(eq(0), eq(true), anyInt()); 916 917 mWsm.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, 0, 0, sBSSID); 918 mLooper.dispatchAll(); 919 920 mWsm.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0, 921 new StateChangeResult(0, sWifiSsid, sBSSID, SupplicantState.COMPLETED)); 922 mLooper.dispatchAll(); 923 924 assertEquals("DisconnectedState", getCurrentState().getName()); 925 } 926 927 928 @Test 929 public void smToString() throws Exception { 930 assertEquals("CMD_CHANNEL_HALF_CONNECTED", mWsm.smToString( 931 AsyncChannel.CMD_CHANNEL_HALF_CONNECTED)); 932 assertEquals("CMD_PRE_DHCP_ACTION", mWsm.smToString( 933 DhcpClient.CMD_PRE_DHCP_ACTION)); 934 assertEquals("CMD_IP_REACHABILITY_LOST", mWsm.smToString( 935 WifiStateMachine.CMD_IP_REACHABILITY_LOST)); 936 } 937 938 @Test 939 public void disconnect() throws Exception { 940 connect(); 941 942 mWsm.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, -1, 3, "01:02:03:04:05:06"); 943 mLooper.dispatchAll(); 944 mWsm.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0, 945 new StateChangeResult(0, sWifiSsid, sBSSID, SupplicantState.DISCONNECTED)); 946 mLooper.dispatchAll(); 947 948 assertEquals("DisconnectedState", getCurrentState().getName()); 949 } 950 951 /** 952 * Successfully connecting to a network will set WifiConfiguration's value of HasEverConnected 953 * to true. 954 * 955 * Test: Successfully create and connect to a network. Check the config and verify 956 * WifiConfiguration.getHasEverConnected() is true. 957 */ 958 @Test 959 public void setHasEverConnectedTrueOnConnect() throws Exception { 960 connect(); 961 verify(mWifiConfigManager, atLeastOnce()).updateNetworkAfterConnect(0); 962 } 963 964 /** 965 * Fail network connection attempt and verify HasEverConnected remains false. 966 * 967 * Test: Successfully create a network but fail when connecting. Check the config and verify 968 * WifiConfiguration.getHasEverConnected() is false. 969 */ 970 @Test 971 public void connectionFailureDoesNotSetHasEverConnectedTrue() throws Exception { 972 testDhcpFailure(); 973 verify(mWifiConfigManager, never()).updateNetworkAfterConnect(0); 974 } 975 976 @Test 977 public void iconQueryTest() throws Exception { 978 // TODO(b/31065385): Passpoint config management. 979 } 980 981 @Test 982 public void verboseLogRecSizeIsGreaterThanNormalSize() { 983 assertTrue(LOG_REC_LIMIT_IN_VERBOSE_MODE > WifiStateMachine.NUM_LOG_RECS_NORMAL); 984 } 985 986 /** 987 * Verifies that, by default, we allow only the "normal" number of log records. 988 */ 989 @Test 990 public void normalLogRecSizeIsUsedByDefault() { 991 assertEquals(WifiStateMachine.NUM_LOG_RECS_NORMAL, mWsm.getLogRecMaxSize()); 992 } 993 994 /** 995 * Verifies that, in verbose mode, we allow a larger number of log records. 996 */ 997 @Test 998 public void enablingVerboseLoggingUpdatesLogRecSize() { 999 mWsm.enableVerboseLogging(1); 1000 assertEquals(LOG_REC_LIMIT_IN_VERBOSE_MODE, mWsm.getLogRecMaxSize()); 1001 } 1002 1003 @Test 1004 public void disablingVerboseLoggingClearsRecords() { 1005 mWsm.sendMessage(WifiStateMachine.CMD_DISCONNECT); 1006 mLooper.dispatchAll(); 1007 assertTrue(mWsm.getLogRecSize() >= 1); 1008 1009 mWsm.enableVerboseLogging(0); 1010 assertEquals(0, mWsm.getLogRecSize()); 1011 } 1012 1013 @Test 1014 public void disablingVerboseLoggingUpdatesLogRecSize() { 1015 mWsm.enableVerboseLogging(1); 1016 mWsm.enableVerboseLogging(0); 1017 assertEquals(WifiStateMachine.NUM_LOG_RECS_NORMAL, mWsm.getLogRecMaxSize()); 1018 } 1019 1020 /** Verifies that enabling verbose logging sets the hal log property in eng builds. */ 1021 @Test 1022 public void enablingVerboseLoggingSetsHalLogPropertyInEngBuilds() { 1023 reset(mPropertyService); // Ignore calls made in setUp() 1024 when(mBuildProperties.isEngBuild()).thenReturn(true); 1025 when(mBuildProperties.isUserdebugBuild()).thenReturn(false); 1026 when(mBuildProperties.isUserBuild()).thenReturn(false); 1027 mWsm.enableVerboseLogging(1); 1028 verify(mPropertyService).set("log.tag.WifiHAL", "V"); 1029 } 1030 1031 /** Verifies that enabling verbose logging sets the hal log property in userdebug builds. */ 1032 @Test 1033 public void enablingVerboseLoggingSetsHalLogPropertyInUserdebugBuilds() { 1034 reset(mPropertyService); // Ignore calls made in setUp() 1035 when(mBuildProperties.isUserdebugBuild()).thenReturn(true); 1036 when(mBuildProperties.isEngBuild()).thenReturn(false); 1037 when(mBuildProperties.isUserBuild()).thenReturn(false); 1038 mWsm.enableVerboseLogging(1); 1039 verify(mPropertyService).set("log.tag.WifiHAL", "V"); 1040 } 1041 1042 /** Verifies that enabling verbose logging does NOT set the hal log property in user builds. */ 1043 @Test 1044 public void enablingVerboseLoggingDoeNotSetHalLogPropertyInUserBuilds() { 1045 reset(mPropertyService); // Ignore calls made in setUp() 1046 when(mBuildProperties.isUserBuild()).thenReturn(true); 1047 when(mBuildProperties.isEngBuild()).thenReturn(false); 1048 when(mBuildProperties.isUserdebugBuild()).thenReturn(false); 1049 mWsm.enableVerboseLogging(1); 1050 verify(mPropertyService, never()).set(anyString(), anyString()); 1051 } 1052 1053 private int testGetSupportedFeaturesCase(int supportedFeatures, boolean rttConfigured) { 1054 AsyncChannel channel = mock(AsyncChannel.class); 1055 Message reply = Message.obtain(); 1056 reply.arg1 = supportedFeatures; 1057 reset(mPropertyService); // Ignore calls made in setUp() 1058 when(channel.sendMessageSynchronously(WifiStateMachine.CMD_GET_SUPPORTED_FEATURES)) 1059 .thenReturn(reply); 1060 when(mPropertyService.getBoolean("config.disable_rtt", false)) 1061 .thenReturn(rttConfigured); 1062 return mWsm.syncGetSupportedFeatures(channel); 1063 } 1064 1065 /** Verifies that syncGetSupportedFeatures() masks out capabilities based on system flags. */ 1066 @Test 1067 public void syncGetSupportedFeatures() { 1068 final int featureAware = WifiManager.WIFI_FEATURE_AWARE; 1069 final int featureInfra = WifiManager.WIFI_FEATURE_INFRA; 1070 final int featureD2dRtt = WifiManager.WIFI_FEATURE_D2D_RTT; 1071 final int featureD2apRtt = WifiManager.WIFI_FEATURE_D2AP_RTT; 1072 1073 assertEquals(0, testGetSupportedFeaturesCase(0, false)); 1074 assertEquals(0, testGetSupportedFeaturesCase(0, true)); 1075 assertEquals(featureAware | featureInfra, 1076 testGetSupportedFeaturesCase(featureAware | featureInfra, false)); 1077 assertEquals(featureAware | featureInfra, 1078 testGetSupportedFeaturesCase(featureAware | featureInfra, true)); 1079 assertEquals(featureInfra | featureD2dRtt, 1080 testGetSupportedFeaturesCase(featureInfra | featureD2dRtt, false)); 1081 assertEquals(featureInfra, 1082 testGetSupportedFeaturesCase(featureInfra | featureD2dRtt, true)); 1083 assertEquals(featureInfra | featureD2apRtt, 1084 testGetSupportedFeaturesCase(featureInfra | featureD2apRtt, false)); 1085 assertEquals(featureInfra, 1086 testGetSupportedFeaturesCase(featureInfra | featureD2apRtt, true)); 1087 assertEquals(featureInfra | featureD2dRtt | featureD2apRtt, 1088 testGetSupportedFeaturesCase(featureInfra | featureD2dRtt | featureD2apRtt, false)); 1089 assertEquals(featureInfra, 1090 testGetSupportedFeaturesCase(featureInfra | featureD2dRtt | featureD2apRtt, true)); 1091 } 1092} 1093