SupplicantStaIfaceHalTest.java revision 5a1adfdef3025a595544b3d17e1d5d9afca7673b
1/* 2 * Copyright (C) 2017 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 */ 16package com.android.server.wifi; 17 18import static org.junit.Assert.*; 19import static org.mockito.Matchers.any; 20import static org.mockito.Matchers.anyBoolean; 21import static org.mockito.Matchers.anyInt; 22import static org.mockito.Matchers.anyLong; 23import static org.mockito.Matchers.anyShort; 24import static org.mockito.Matchers.anyString; 25import static org.mockito.Matchers.eq; 26import static org.mockito.Mockito.doAnswer; 27import static org.mockito.Mockito.doThrow; 28import static org.mockito.Mockito.inOrder; 29import static org.mockito.Mockito.mock; 30import static org.mockito.Mockito.never; 31import static org.mockito.Mockito.times; 32import static org.mockito.Mockito.verify; 33import static org.mockito.Mockito.when; 34 35import android.app.test.MockAnswerUtil; 36import android.content.Context; 37import android.hardware.wifi.supplicant.V1_0.ISupplicant; 38import android.hardware.wifi.supplicant.V1_0.ISupplicantIface; 39import android.hardware.wifi.supplicant.V1_0.ISupplicantStaIface; 40import android.hardware.wifi.supplicant.V1_0.ISupplicantStaIfaceCallback; 41import android.hardware.wifi.supplicant.V1_0.ISupplicantStaNetwork; 42import android.hardware.wifi.supplicant.V1_0.IfaceType; 43import android.hardware.wifi.supplicant.V1_0.SupplicantStatus; 44import android.hardware.wifi.supplicant.V1_0.SupplicantStatusCode; 45import android.hardware.wifi.supplicant.V1_0.WpsConfigMethods; 46import android.hidl.manager.V1_0.IServiceManager; 47import android.hidl.manager.V1_0.IServiceNotification; 48import android.net.IpConfiguration; 49import android.net.wifi.WifiConfiguration; 50import android.os.IHwBinder; 51import android.os.RemoteException; 52import android.util.SparseArray; 53 54import com.android.server.wifi.hotspot2.AnqpEvent; 55import com.android.server.wifi.hotspot2.IconEvent; 56import com.android.server.wifi.hotspot2.WnmData; 57import com.android.server.wifi.util.NativeUtil; 58 59import org.junit.Before; 60import org.junit.Test; 61import org.mockito.ArgumentCaptor; 62import org.mockito.InOrder; 63import org.mockito.Mock; 64import org.mockito.MockitoAnnotations; 65 66import java.nio.ByteBuffer; 67import java.nio.ByteOrder; 68import java.util.ArrayList; 69import java.util.Arrays; 70import java.util.HashMap; 71import java.util.Map; 72import java.util.Random; 73 74/** 75 * Unit tests for SupplicantStaIfaceHal 76 */ 77public class SupplicantStaIfaceHalTest { 78 private static final String TAG = "SupplicantStaIfaceHalTest"; 79 private static final Map<Integer, String> NETWORK_ID_TO_SSID = new HashMap<Integer, String>() {{ 80 put(1, "ssid1"); 81 put(2, "ssid2"); 82 put(3, "ssid3"); 83 }}; 84 private static final int EXISTING_SUPPLICANT_NETWORK_ID = 2; 85 private static final int ROAM_NETWORK_ID = 4; 86 private static final String BSSID = "fa:45:23:23:12:12"; 87 private static final String WLAN_IFACE_NAME = "wlan0"; 88 private static final String P2P_IFACE_NAME = "p2p0"; 89 private static final String ICON_FILE_NAME = "blahblah"; 90 private static final int ICON_FILE_SIZE = 72; 91 private static final String HS20_URL = "http://blahblah"; 92 93 @Mock IServiceManager mServiceManagerMock; 94 @Mock ISupplicant mISupplicantMock; 95 @Mock ISupplicantIface mISupplicantIfaceMock; 96 @Mock ISupplicantStaIface mISupplicantStaIfaceMock; 97 @Mock Context mContext; 98 @Mock WifiMonitor mWifiMonitor; 99 @Mock SupplicantStaNetworkHal mSupplicantStaNetworkMock; 100 SupplicantStatus mStatusSuccess; 101 SupplicantStatus mStatusFailure; 102 ISupplicant.IfaceInfo mStaIface; 103 ISupplicant.IfaceInfo mP2pIface; 104 ArrayList<ISupplicant.IfaceInfo> mIfaceInfoList; 105 ISupplicantStaIfaceCallback mISupplicantStaIfaceCallback; 106 private SupplicantStaIfaceHal mDut; 107 private ArgumentCaptor<IHwBinder.DeathRecipient> mDeathRecipientCaptor = 108 ArgumentCaptor.forClass(IHwBinder.DeathRecipient.class); 109 private ArgumentCaptor<IServiceNotification.Stub> mServiceNotificationCaptor = 110 ArgumentCaptor.forClass(IServiceNotification.Stub.class); 111 private InOrder mInOrder; 112 113 private class SupplicantStaIfaceHalSpy extends SupplicantStaIfaceHal { 114 SupplicantStaIfaceHalSpy(Context context, WifiMonitor monitor) { 115 super(context, monitor); 116 } 117 118 @Override 119 protected IServiceManager getServiceManagerMockable() throws RemoteException { 120 return mServiceManagerMock; 121 } 122 123 @Override 124 protected ISupplicant getSupplicantMockable() throws RemoteException { 125 return mISupplicantMock; 126 } 127 128 @Override 129 protected ISupplicantStaIface getStaIfaceMockable(ISupplicantIface iface) { 130 return mISupplicantStaIfaceMock; 131 } 132 133 @Override 134 protected SupplicantStaNetworkHal getStaNetworkMockable( 135 ISupplicantStaNetwork iSupplicantStaNetwork) { 136 return mSupplicantStaNetworkMock; 137 } 138 } 139 140 @Before 141 public void setUp() throws Exception { 142 MockitoAnnotations.initMocks(this); 143 mStatusSuccess = createSupplicantStatus(SupplicantStatusCode.SUCCESS); 144 mStatusFailure = createSupplicantStatus(SupplicantStatusCode.FAILURE_UNKNOWN); 145 mStaIface = createIfaceInfo(IfaceType.STA, WLAN_IFACE_NAME); 146 mP2pIface = createIfaceInfo(IfaceType.P2P, P2P_IFACE_NAME); 147 148 mIfaceInfoList = new ArrayList<>(); 149 mIfaceInfoList.add(mStaIface); 150 mIfaceInfoList.add(mP2pIface); 151 152 when(mServiceManagerMock.linkToDeath(any(IHwBinder.DeathRecipient.class), 153 anyLong())).thenReturn(true); 154 when(mServiceManagerMock.registerForNotifications(anyString(), anyString(), 155 any(IServiceNotification.Stub.class))).thenReturn(true); 156 mDut = new SupplicantStaIfaceHalSpy(mContext, mWifiMonitor); 157 } 158 159 /** 160 * Sunny day scenario for SupplicantStaIfaceHal initialization 161 * Asserts successful initialization 162 */ 163 @Test 164 public void testInitialize_success() throws Exception { 165 executeAndValidateInitializationSequence(false, false, false, false); 166 } 167 168 /** 169 * Tests the initialization flow, with a RemoteException occurring when 'getInterface' is called 170 * Ensures initialization fails. 171 */ 172 @Test 173 public void testInitialize_remoteExceptionFailure() throws Exception { 174 executeAndValidateInitializationSequence(true, false, false, false); 175 } 176 177 /** 178 * Tests the initialization flow, with listInterfaces returning 0 interfaces. 179 * Ensures failure 180 */ 181 @Test 182 public void testInitialize_zeroInterfacesFailure() throws Exception { 183 executeAndValidateInitializationSequence(false, true, false, false); 184 } 185 186 /** 187 * Tests the initialization flow, with a null interface being returned by getInterface. 188 * Ensures initialization fails. 189 */ 190 @Test 191 public void testInitialize_nullInterfaceFailure() throws Exception { 192 executeAndValidateInitializationSequence(false, false, true, false); 193 } 194 195 /** 196 * Tests the initialization flow, with a callback registration failure. 197 * Ensures initialization fails. 198 */ 199 @Test 200 public void testInitialize_callbackRegistrationFailure() throws Exception { 201 executeAndValidateInitializationSequence(false, false, false, true); 202 } 203 204 /** 205 * Tests the loading of networks using {@link SupplicantStaNetworkHal}. 206 * Fills up only the SSID field of configs and uses it as a configKey as well. 207 */ 208 @Test 209 public void testLoadNetworks() throws Exception { 210 executeAndValidateInitializationSequence(); 211 doAnswer(new MockAnswerUtil.AnswerWithArguments() { 212 public void answer(ISupplicantStaIface.listNetworksCallback cb) { 213 cb.onValues(mStatusSuccess, new ArrayList<>(NETWORK_ID_TO_SSID.keySet())); 214 } 215 }).when(mISupplicantStaIfaceMock) 216 .listNetworks(any(ISupplicantStaIface.listNetworksCallback.class)); 217 doAnswer(new MockAnswerUtil.AnswerWithArguments() { 218 public void answer(final int networkId, ISupplicantStaIface.getNetworkCallback cb) { 219 // Reset the |mSupplicantStaNetwork| mock for each network. 220 doAnswer(new MockAnswerUtil.AnswerWithArguments() { 221 public boolean answer( 222 WifiConfiguration config, Map<String, String> networkExtra) { 223 config.SSID = NETWORK_ID_TO_SSID.get(networkId); 224 config.networkId = networkId; 225 networkExtra.put( 226 SupplicantStaNetworkHal.ID_STRING_KEY_CONFIG_KEY, config.SSID); 227 return true; 228 } 229 }).when(mSupplicantStaNetworkMock) 230 .loadWifiConfiguration(any(WifiConfiguration.class), any(Map.class)); 231 cb.onValues(mStatusSuccess, mock(ISupplicantStaNetwork.class)); 232 return; 233 } 234 }).when(mISupplicantStaIfaceMock) 235 .getNetwork(anyInt(), any(ISupplicantStaIface.getNetworkCallback.class)); 236 237 Map<String, WifiConfiguration> configs = new HashMap<>(); 238 SparseArray<Map<String, String>> extras = new SparseArray<>(); 239 assertTrue(mDut.loadNetworks(configs, extras)); 240 241 assertEquals(3, configs.size()); 242 assertEquals(3, extras.size()); 243 for (Map.Entry<Integer, String> network : NETWORK_ID_TO_SSID.entrySet()) { 244 WifiConfiguration config = configs.get(network.getValue()); 245 assertTrue(config != null); 246 assertEquals(network.getKey(), Integer.valueOf(config.networkId)); 247 assertEquals(network.getValue(), config.SSID); 248 assertEquals(IpConfiguration.IpAssignment.DHCP, config.getIpAssignment()); 249 assertEquals(IpConfiguration.ProxySettings.NONE, config.getProxySettings()); 250 } 251 } 252 253 /** 254 * Tests the loading of networks using {@link SupplicantStaNetworkHal} removes any networks 255 * with duplicate config key. 256 * Fills up only the SSID field of configs and uses it as a configKey as well. 257 */ 258 @Test 259 public void testLoadNetworksRemovesDuplicates() throws Exception { 260 // Network ID which will have the same config key as the previous one. 261 final int duplicateNetworkId = 2; 262 final int toRemoveNetworkId = duplicateNetworkId - 1; 263 executeAndValidateInitializationSequence(); 264 doAnswer(new MockAnswerUtil.AnswerWithArguments() { 265 public void answer(ISupplicantStaIface.listNetworksCallback cb) { 266 cb.onValues(mStatusSuccess, new ArrayList<>(NETWORK_ID_TO_SSID.keySet())); 267 } 268 }).when(mISupplicantStaIfaceMock) 269 .listNetworks(any(ISupplicantStaIface.listNetworksCallback.class)); 270 doAnswer(new MockAnswerUtil.AnswerWithArguments() { 271 public SupplicantStatus answer(int id) { 272 return mStatusSuccess; 273 } 274 }).when(mISupplicantStaIfaceMock).removeNetwork(eq(toRemoveNetworkId)); 275 doAnswer(new MockAnswerUtil.AnswerWithArguments() { 276 public void answer(final int networkId, ISupplicantStaIface.getNetworkCallback cb) { 277 // Reset the |mSupplicantStaNetwork| mock for each network. 278 doAnswer(new MockAnswerUtil.AnswerWithArguments() { 279 public boolean answer( 280 WifiConfiguration config, Map<String, String> networkExtra) { 281 config.SSID = NETWORK_ID_TO_SSID.get(networkId); 282 config.networkId = networkId; 283 // Duplicate network gets the same config key as the to removed one. 284 if (networkId == duplicateNetworkId) { 285 networkExtra.put( 286 SupplicantStaNetworkHal.ID_STRING_KEY_CONFIG_KEY, 287 NETWORK_ID_TO_SSID.get(toRemoveNetworkId)); 288 } else { 289 networkExtra.put( 290 SupplicantStaNetworkHal.ID_STRING_KEY_CONFIG_KEY, 291 NETWORK_ID_TO_SSID.get(networkId)); 292 } 293 return true; 294 } 295 }).when(mSupplicantStaNetworkMock) 296 .loadWifiConfiguration(any(WifiConfiguration.class), any(Map.class)); 297 cb.onValues(mStatusSuccess, mock(ISupplicantStaNetwork.class)); 298 return; 299 } 300 }).when(mISupplicantStaIfaceMock) 301 .getNetwork(anyInt(), any(ISupplicantStaIface.getNetworkCallback.class)); 302 303 Map<String, WifiConfiguration> configs = new HashMap<>(); 304 SparseArray<Map<String, String>> extras = new SparseArray<>(); 305 assertTrue(mDut.loadNetworks(configs, extras)); 306 307 assertEquals(2, configs.size()); 308 assertEquals(2, extras.size()); 309 for (Map.Entry<Integer, String> network : NETWORK_ID_TO_SSID.entrySet()) { 310 if (network.getKey() == toRemoveNetworkId) { 311 continue; 312 } 313 WifiConfiguration config; 314 // Duplicate network gets the same config key as the to removed one. So, use that to 315 // lookup the map. 316 if (network.getKey() == duplicateNetworkId) { 317 config = configs.get(NETWORK_ID_TO_SSID.get(toRemoveNetworkId)); 318 } else { 319 config = configs.get(network.getValue()); 320 } 321 assertTrue(config != null); 322 assertEquals(network.getKey(), Integer.valueOf(config.networkId)); 323 assertEquals(network.getValue(), config.SSID); 324 assertEquals(IpConfiguration.IpAssignment.DHCP, config.getIpAssignment()); 325 assertEquals(IpConfiguration.ProxySettings.NONE, config.getProxySettings()); 326 } 327 } 328 329 /** 330 * Tests the failure to load networks because of listNetworks failure. 331 */ 332 @Test 333 public void testLoadNetworksFailedDueToListNetworks() throws Exception { 334 executeAndValidateInitializationSequence(); 335 doAnswer(new MockAnswerUtil.AnswerWithArguments() { 336 public void answer(ISupplicantStaIface.listNetworksCallback cb) { 337 cb.onValues(mStatusFailure, null); 338 } 339 }).when(mISupplicantStaIfaceMock) 340 .listNetworks(any(ISupplicantStaIface.listNetworksCallback.class)); 341 342 Map<String, WifiConfiguration> configs = new HashMap<>(); 343 SparseArray<Map<String, String>> extras = new SparseArray<>(); 344 assertFalse(mDut.loadNetworks(configs, extras)); 345 } 346 347 /** 348 * Tests the failure to load networks because of getNetwork failure. 349 */ 350 @Test 351 public void testLoadNetworksFailedDueToGetNetwork() throws Exception { 352 executeAndValidateInitializationSequence(); 353 doAnswer(new MockAnswerUtil.AnswerWithArguments() { 354 public void answer(ISupplicantStaIface.listNetworksCallback cb) { 355 cb.onValues(mStatusSuccess, new ArrayList<>(NETWORK_ID_TO_SSID.keySet())); 356 } 357 }).when(mISupplicantStaIfaceMock) 358 .listNetworks(any(ISupplicantStaIface.listNetworksCallback.class)); 359 doAnswer(new MockAnswerUtil.AnswerWithArguments() { 360 public void answer(final int networkId, ISupplicantStaIface.getNetworkCallback cb) { 361 cb.onValues(mStatusFailure, mock(ISupplicantStaNetwork.class)); 362 return; 363 } 364 }).when(mISupplicantStaIfaceMock) 365 .getNetwork(anyInt(), any(ISupplicantStaIface.getNetworkCallback.class)); 366 367 Map<String, WifiConfiguration> configs = new HashMap<>(); 368 SparseArray<Map<String, String>> extras = new SparseArray<>(); 369 assertFalse(mDut.loadNetworks(configs, extras)); 370 } 371 372 /** 373 * Tests the failure to load networks because of loadWifiConfiguration failure. 374 */ 375 @Test 376 public void testLoadNetworksFailedDueToLoadWifiConfiguration() throws Exception { 377 executeAndValidateInitializationSequence(); 378 doAnswer(new MockAnswerUtil.AnswerWithArguments() { 379 public void answer(ISupplicantStaIface.listNetworksCallback cb) { 380 cb.onValues(mStatusSuccess, new ArrayList<>(NETWORK_ID_TO_SSID.keySet())); 381 } 382 }).when(mISupplicantStaIfaceMock) 383 .listNetworks(any(ISupplicantStaIface.listNetworksCallback.class)); 384 doAnswer(new MockAnswerUtil.AnswerWithArguments() { 385 public boolean answer(WifiConfiguration config, Map<String, String> networkExtra) { 386 return false; 387 } 388 }).when(mSupplicantStaNetworkMock) 389 .loadWifiConfiguration(any(WifiConfiguration.class), any(Map.class)); 390 391 Map<String, WifiConfiguration> configs = new HashMap<>(); 392 SparseArray<Map<String, String>> extras = new SparseArray<>(); 393 assertFalse(mDut.loadNetworks(configs, extras)); 394 } 395 396 /** 397 * Tests connection to a specified network without triggering disconnect. 398 */ 399 @Test 400 public void testConnectWithNoDisconnectAndEmptyExistingNetworks() throws Exception { 401 executeAndValidateInitializationSequence(); 402 executeAndValidateConnectSequence(0, false, false); 403 } 404 405 /** 406 * Tests connection to a specified network without triggering disconnect. 407 */ 408 @Test 409 public void testConnectWithNoDisconnectAndSingleExistingNetwork() throws Exception { 410 executeAndValidateInitializationSequence(); 411 executeAndValidateConnectSequence(0, true, false); 412 } 413 414 /** 415 * Tests connection to a specified network, with a triggered disconnect. 416 */ 417 @Test 418 public void testConnectWithDisconnectAndSingleExistingNetwork() throws Exception { 419 executeAndValidateInitializationSequence(); 420 executeAndValidateConnectSequence(0, false, true); 421 } 422 423 /** 424 * Tests connection to a specified network failure due to network add. 425 */ 426 @Test 427 public void testConnectFailureDueToNetworkAddFailure() throws Exception { 428 executeAndValidateInitializationSequence(); 429 setupMocksForConnectSequence(false); 430 doAnswer(new MockAnswerUtil.AnswerWithArguments() { 431 public void answer(ISupplicantStaIface.addNetworkCallback cb) throws RemoteException { 432 cb.onValues(mStatusFailure, mock(ISupplicantStaNetwork.class)); 433 return; 434 } 435 }).when(mISupplicantStaIfaceMock).addNetwork( 436 any(ISupplicantStaIface.addNetworkCallback.class)); 437 438 assertFalse(mDut.connectToNetwork(new WifiConfiguration(), false)); 439 } 440 441 /** 442 * Tests connection to a specified network failure due to network save. 443 */ 444 @Test 445 public void testConnectFailureDueToNetworkSaveFailure() throws Exception { 446 executeAndValidateInitializationSequence(); 447 setupMocksForConnectSequence(false); 448 449 when(mSupplicantStaNetworkMock.saveWifiConfiguration(any(WifiConfiguration.class))) 450 .thenReturn(false); 451 452 assertFalse(mDut.connectToNetwork(new WifiConfiguration(), false)); 453 } 454 455 /** 456 * Tests connection to a specified network failure due to network select. 457 */ 458 @Test 459 public void testConnectFailureDueToNetworkSelectFailure() throws Exception { 460 executeAndValidateInitializationSequence(); 461 setupMocksForConnectSequence(false); 462 463 when(mSupplicantStaNetworkMock.select()).thenReturn(false); 464 465 assertFalse(mDut.connectToNetwork(new WifiConfiguration(), false)); 466 } 467 468 /** 469 * Tests roaming to the same network as the currently connected one. 470 */ 471 @Test 472 public void testRoamToSameNetwork() throws Exception { 473 executeAndValidateInitializationSequence(); 474 executeAndValidateRoamSequence(true); 475 } 476 477 /** 478 * Tests roaming to a different network. 479 */ 480 @Test 481 public void testRoamToDifferentNetwork() throws Exception { 482 executeAndValidateInitializationSequence(); 483 executeAndValidateRoamSequence(false); 484 } 485 486 /** 487 * Tests roaming failure because of unable to set bssid. 488 */ 489 @Test 490 public void testRoamFailureDueToBssidSet() throws Exception { 491 executeAndValidateInitializationSequence(); 492 int connectedNetworkId = 5; 493 executeAndValidateConnectSequence(connectedNetworkId, false, false); 494 when(mSupplicantStaNetworkMock.setBssid(anyString())).thenReturn(false); 495 496 WifiConfiguration roamingConfig = new WifiConfiguration(); 497 roamingConfig.networkId = connectedNetworkId; 498 roamingConfig.getNetworkSelectionStatus().setNetworkSelectionBSSID("45:34:23:23:ab:ed"); 499 assertFalse(mDut.roamToNetwork(roamingConfig)); 500 } 501 502 /** 503 * Tests removal of all configured networks from wpa_supplicant. 504 */ 505 @Test 506 public void testRemoveAllNetworks() throws Exception { 507 executeAndValidateInitializationSequence(); 508 doAnswer(new MockAnswerUtil.AnswerWithArguments() { 509 public void answer(ISupplicantStaIface.listNetworksCallback cb) { 510 cb.onValues(mStatusSuccess, new ArrayList<>(NETWORK_ID_TO_SSID.keySet())); 511 } 512 }).when(mISupplicantStaIfaceMock) 513 .listNetworks(any(ISupplicantStaIface.listNetworksCallback.class)); 514 doAnswer(new MockAnswerUtil.AnswerWithArguments() { 515 public SupplicantStatus answer(int id) { 516 assertTrue(NETWORK_ID_TO_SSID.containsKey(id)); 517 return mStatusSuccess; 518 } 519 }).when(mISupplicantStaIfaceMock).removeNetwork(anyInt()); 520 521 assertTrue(mDut.removeAllNetworks()); 522 verify(mISupplicantStaIfaceMock, times(NETWORK_ID_TO_SSID.size())).removeNetwork(anyInt()); 523 } 524 525 /** 526 * Tests roaming failure because of unable to reassociate. 527 */ 528 @Test 529 public void testRoamFailureDueToReassociate() throws Exception { 530 executeAndValidateInitializationSequence(); 531 int connectedNetworkId = 5; 532 executeAndValidateConnectSequence(connectedNetworkId, false, false); 533 534 doAnswer(new MockAnswerUtil.AnswerWithArguments() { 535 public SupplicantStatus answer() throws RemoteException { 536 return mStatusFailure; 537 } 538 }).when(mISupplicantStaIfaceMock).reassociate(); 539 when(mSupplicantStaNetworkMock.setBssid(anyString())).thenReturn(true); 540 541 WifiConfiguration roamingConfig = new WifiConfiguration(); 542 roamingConfig.networkId = connectedNetworkId; 543 roamingConfig.getNetworkSelectionStatus().setNetworkSelectionBSSID("45:34:23:23:ab:ed"); 544 assertFalse(mDut.roamToNetwork(roamingConfig)); 545 } 546 547 /** 548 * Tests the retrieval of WPS NFC token. 549 */ 550 @Test 551 public void testGetCurrentNetworkWpsNfcConfigurationToken() throws Exception { 552 String token = "45adbc1"; 553 when(mSupplicantStaNetworkMock.getWpsNfcConfigurationToken()).thenReturn(token); 554 555 executeAndValidateInitializationSequence(); 556 557 // Return null when not connected to the network. 558 assertTrue(mDut.getCurrentNetworkWpsNfcConfigurationToken() == null); 559 560 executeAndValidateConnectSequence(4, false, false); 561 562 assertEquals(token, mDut.getCurrentNetworkWpsNfcConfigurationToken()); 563 } 564 565 /** 566 * Tests the setting of BSSID. 567 */ 568 @Test 569 public void testSetCurrentNetworkBssid() throws Exception { 570 String bssidStr = "34:34:12:12:12:90"; 571 when(mSupplicantStaNetworkMock.setBssid(eq(bssidStr))).thenReturn(true); 572 573 executeAndValidateInitializationSequence(); 574 575 // Fail when not connected to a network. 576 assertFalse(mDut.setCurrentNetworkBssid(bssidStr)); 577 578 executeAndValidateConnectSequence(4, false, false); 579 580 assertTrue(mDut.setCurrentNetworkBssid(bssidStr)); 581 } 582 583 /** 584 * Tests the setting of WPS device type. 585 */ 586 @Test 587 public void testSetWpsDeviceType() throws Exception { 588 String validDeviceTypeStr = "10-0050F204-5"; 589 byte[] expectedDeviceType = { 0x0, 0xa, 0x0, 0x50, (byte) 0xf2, 0x04, 0x0, 0x05}; 590 String invalidDeviceType1Str = "10-02050F204-5"; 591 String invalidDeviceType2Str = "10-0050F204-534"; 592 when(mISupplicantStaIfaceMock.setWpsDeviceType(any(byte[].class))) 593 .thenReturn(mStatusSuccess); 594 595 executeAndValidateInitializationSequence(); 596 597 // This should work. 598 assertTrue(mDut.setWpsDeviceType(validDeviceTypeStr)); 599 verify(mISupplicantStaIfaceMock).setWpsDeviceType(eq(expectedDeviceType)); 600 601 // This should not work 602 assertFalse(mDut.setWpsDeviceType(invalidDeviceType1Str)); 603 // This should not work 604 assertFalse(mDut.setWpsDeviceType(invalidDeviceType2Str)); 605 } 606 607 /** 608 * Tests the setting of WPS config methods. 609 */ 610 @Test 611 public void testSetWpsConfigMethods() throws Exception { 612 String validConfigMethodsStr = "physical_display virtual_push_button"; 613 Short expectedConfigMethods = 614 WpsConfigMethods.PHY_DISPLAY | WpsConfigMethods.VIRT_PUSHBUTTON; 615 String invalidConfigMethodsStr = "physical_display virtual_push_button test"; 616 when(mISupplicantStaIfaceMock.setWpsConfigMethods(anyShort())).thenReturn(mStatusSuccess); 617 618 executeAndValidateInitializationSequence(); 619 620 // This should work. 621 assertTrue(mDut.setWpsConfigMethods(validConfigMethodsStr)); 622 verify(mISupplicantStaIfaceMock).setWpsConfigMethods(eq(expectedConfigMethods)); 623 624 // This should throw an illegal argument exception. 625 try { 626 assertFalse(mDut.setWpsConfigMethods(invalidConfigMethodsStr)); 627 } catch (IllegalArgumentException e) { 628 return; 629 } 630 assertTrue(false); 631 } 632 633 /** 634 * Tests the handling of ANQP done callback. 635 * Note: Since the ANQP element parsing methods are static, this can only test the negative test 636 * where all the parsing fails because the data is empty. It'll be non-trivial and unnecessary 637 * to test out the parsing logic here. 638 */ 639 @Test 640 public void testAnqpDoneCallback() throws Exception { 641 executeAndValidateInitializationSequence(); 642 assertNotNull(mISupplicantStaIfaceCallback); 643 byte[] bssid = NativeUtil.macAddressToByteArray(BSSID); 644 mISupplicantStaIfaceCallback.onAnqpQueryDone( 645 bssid, new ISupplicantStaIfaceCallback.AnqpData(), 646 new ISupplicantStaIfaceCallback.Hs20AnqpData()); 647 648 ArgumentCaptor<AnqpEvent> anqpEventCaptor = ArgumentCaptor.forClass(AnqpEvent.class); 649 verify(mWifiMonitor).broadcastAnqpDoneEvent(eq(WLAN_IFACE_NAME), anqpEventCaptor.capture()); 650 assertEquals( 651 ByteBufferReader.readInteger( 652 ByteBuffer.wrap(bssid), ByteOrder.BIG_ENDIAN, bssid.length), 653 anqpEventCaptor.getValue().getBssid()); 654 } 655 656 /** 657 * Tests the handling of Icon done callback. 658 */ 659 @Test 660 public void testIconDoneCallback() throws Exception { 661 executeAndValidateInitializationSequence(); 662 assertNotNull(mISupplicantStaIfaceCallback); 663 664 byte[] bssid = NativeUtil.macAddressToByteArray(BSSID); 665 byte[] iconData = new byte[ICON_FILE_SIZE]; 666 new Random().nextBytes(iconData); 667 mISupplicantStaIfaceCallback.onHs20IconQueryDone( 668 bssid, ICON_FILE_NAME, NativeUtil.byteArrayToArrayList(iconData)); 669 670 ArgumentCaptor<IconEvent> iconEventCaptor = ArgumentCaptor.forClass(IconEvent.class); 671 verify(mWifiMonitor).broadcastIconDoneEvent(eq(WLAN_IFACE_NAME), iconEventCaptor.capture()); 672 assertEquals( 673 ByteBufferReader.readInteger( 674 ByteBuffer.wrap(bssid), ByteOrder.BIG_ENDIAN, bssid.length), 675 iconEventCaptor.getValue().getBSSID()); 676 assertEquals(ICON_FILE_NAME, iconEventCaptor.getValue().getFileName()); 677 assertArrayEquals(iconData, iconEventCaptor.getValue().getData()); 678 } 679 680 /** 681 * Tests the handling of HS20 subscription remediation callback. 682 */ 683 @Test 684 public void testHs20SubscriptionRemediationCallback() throws Exception { 685 executeAndValidateInitializationSequence(); 686 assertNotNull(mISupplicantStaIfaceCallback); 687 688 byte[] bssid = NativeUtil.macAddressToByteArray(BSSID); 689 byte osuMethod = ISupplicantStaIfaceCallback.OsuMethod.OMA_DM; 690 mISupplicantStaIfaceCallback.onHs20SubscriptionRemediation( 691 bssid, osuMethod, HS20_URL); 692 693 ArgumentCaptor<WnmData> wnmDataCaptor = ArgumentCaptor.forClass(WnmData.class); 694 verify(mWifiMonitor).broadcastWnmEvent(eq(WLAN_IFACE_NAME), wnmDataCaptor.capture()); 695 assertEquals( 696 ByteBufferReader.readInteger( 697 ByteBuffer.wrap(bssid), ByteOrder.BIG_ENDIAN, bssid.length), 698 wnmDataCaptor.getValue().getBssid()); 699 assertEquals(osuMethod, wnmDataCaptor.getValue().getMethod()); 700 assertEquals(HS20_URL, wnmDataCaptor.getValue().getUrl()); 701 } 702 703 /** 704 * Tests the handling of HS20 deauth imminent callback. 705 */ 706 @Test 707 public void testHs20DeauthImminentCallbackWithEssReasonCode() throws Exception { 708 executeAndValidateHs20DeauthImminentCallback(true); 709 } 710 711 /** 712 * Tests the handling of HS20 deauth imminent callback. 713 */ 714 @Test 715 public void testHs20DeauthImminentCallbackWithNonEssReasonCode() throws Exception { 716 executeAndValidateHs20DeauthImminentCallback(false); 717 718 } 719 720 private void executeAndValidateHs20DeauthImminentCallback(boolean isEss) throws Exception { 721 executeAndValidateInitializationSequence(); 722 assertNotNull(mISupplicantStaIfaceCallback); 723 724 byte[] bssid = NativeUtil.macAddressToByteArray(BSSID); 725 int reasonCode = isEss ? WnmData.ESS : WnmData.ESS + 1; 726 int reauthDelay = 5; 727 mISupplicantStaIfaceCallback.onHs20DeauthImminentNotice( 728 bssid, reasonCode, reauthDelay, HS20_URL); 729 730 ArgumentCaptor<WnmData> wnmDataCaptor = ArgumentCaptor.forClass(WnmData.class); 731 verify(mWifiMonitor).broadcastWnmEvent(eq(WLAN_IFACE_NAME), wnmDataCaptor.capture()); 732 assertEquals( 733 ByteBufferReader.readInteger( 734 ByteBuffer.wrap(bssid), ByteOrder.BIG_ENDIAN, bssid.length), 735 wnmDataCaptor.getValue().getBssid()); 736 assertEquals(isEss, wnmDataCaptor.getValue().isEss()); 737 assertEquals(reauthDelay, wnmDataCaptor.getValue().getDelay()); 738 assertEquals(HS20_URL, wnmDataCaptor.getValue().getUrl()); 739 } 740 741 private void executeAndValidateInitializationSequence() throws Exception { 742 executeAndValidateInitializationSequence(false, false, false, false); 743 } 744 745 /** 746 * Tests the setting of log level. 747 */ 748 @Test 749 public void testSetLogLevel() throws Exception { 750 when(mISupplicantMock.setDebugParams(anyInt(), anyBoolean(), anyBoolean())) 751 .thenReturn(mStatusSuccess); 752 753 // Fail before initialization is performed. 754 assertFalse(mDut.setLogLevel(SupplicantStaIfaceHal.LOG_LEVEL_DEBUG)); 755 756 executeAndValidateInitializationSequence(); 757 758 // This should work. 759 assertTrue(mDut.setLogLevel(SupplicantStaIfaceHal.LOG_LEVEL_DEBUG)); 760 verify(mISupplicantMock) 761 .setDebugParams(eq(ISupplicant.DebugLevel.DEBUG), eq(false), eq(false)); 762 } 763 764 /** 765 * Tests the setting of concurrency priority. 766 */ 767 @Test 768 public void testConcurrencyPriority() throws Exception { 769 when(mISupplicantMock.setConcurrencyPriority(anyInt())).thenReturn(mStatusSuccess); 770 771 // Fail before initialization is performed. 772 assertFalse(mDut.setConcurrencyPriority(false)); 773 774 executeAndValidateInitializationSequence(); 775 776 // This should work. 777 assertTrue(mDut.setConcurrencyPriority(false)); 778 verify(mISupplicantMock).setConcurrencyPriority(eq(IfaceType.P2P)); 779 assertTrue(mDut.setConcurrencyPriority(true)); 780 verify(mISupplicantMock).setConcurrencyPriority(eq(IfaceType.STA)); 781 } 782 783 /** 784 * Calls.initialize(), mocking various call back answers and verifying flow, asserting for the 785 * expected result. Verifies if ISupplicantStaIface manager is initialized or reset. 786 * Each of the arguments will cause a different failure mode when set true. 787 */ 788 private void executeAndValidateInitializationSequence(boolean causeRemoteException, 789 boolean getZeroInterfaces, 790 boolean getNullInterface, 791 boolean causeCallbackRegFailure) 792 throws Exception { 793 boolean shouldSucceed = 794 !causeRemoteException && !getZeroInterfaces && !getNullInterface 795 && !causeCallbackRegFailure; 796 // Setup callback mock answers 797 ArrayList<ISupplicant.IfaceInfo> interfaces; 798 if (getZeroInterfaces) { 799 interfaces = new ArrayList<>(); 800 } else { 801 interfaces = mIfaceInfoList; 802 } 803 doAnswer(new GetListInterfacesAnswer(interfaces)).when(mISupplicantMock) 804 .listInterfaces(any(ISupplicant.listInterfacesCallback.class)); 805 if (causeRemoteException) { 806 doThrow(new RemoteException("Some error!!!")) 807 .when(mISupplicantMock).getInterface(any(ISupplicant.IfaceInfo.class), 808 any(ISupplicant.getInterfaceCallback.class)); 809 } else { 810 doAnswer(new GetGetInterfaceAnswer(getNullInterface)) 811 .when(mISupplicantMock).getInterface(any(ISupplicant.IfaceInfo.class), 812 any(ISupplicant.getInterfaceCallback.class)); 813 } 814 /** Callback registeration */ 815 if (causeCallbackRegFailure) { 816 doAnswer(new MockAnswerUtil.AnswerWithArguments() { 817 public SupplicantStatus answer(ISupplicantStaIfaceCallback cb) 818 throws RemoteException { 819 return mStatusFailure; 820 } 821 }).when(mISupplicantStaIfaceMock) 822 .registerCallback(any(ISupplicantStaIfaceCallback.class)); 823 } else { 824 doAnswer(new MockAnswerUtil.AnswerWithArguments() { 825 public SupplicantStatus answer(ISupplicantStaIfaceCallback cb) 826 throws RemoteException { 827 mISupplicantStaIfaceCallback = cb; 828 return mStatusSuccess; 829 } 830 }).when(mISupplicantStaIfaceMock) 831 .registerCallback(any(ISupplicantStaIfaceCallback.class)); 832 } 833 834 mInOrder = inOrder(mServiceManagerMock, mISupplicantMock, mISupplicantStaIfaceMock); 835 // Initialize SupplicantStaIfaceHal, should call serviceManager.registerForNotifications 836 assertTrue(mDut.initialize()); 837 // verify: service manager initialization sequence 838 mInOrder.verify(mServiceManagerMock).linkToDeath(any(IHwBinder.DeathRecipient.class), 839 anyLong()); 840 mInOrder.verify(mServiceManagerMock).registerForNotifications( 841 eq(ISupplicant.kInterfaceName), eq(""), mServiceNotificationCaptor.capture()); 842 // act: cause the onRegistration(...) callback to execute 843 mServiceNotificationCaptor.getValue().onRegistration(ISupplicant.kInterfaceName, "", true); 844 845 assertTrue(mDut.isInitializationComplete() == shouldSucceed); 846 // verify: listInterfaces is called 847 mInOrder.verify(mISupplicantMock).listInterfaces( 848 any(ISupplicant.listInterfacesCallback.class)); 849 if (!getZeroInterfaces) { 850 mInOrder.verify(mISupplicantMock) 851 .getInterface(any(ISupplicant.IfaceInfo.class), 852 any(ISupplicant.getInterfaceCallback.class)); 853 } 854 if (!causeRemoteException && !getZeroInterfaces && !getNullInterface) { 855 mInOrder.verify(mISupplicantStaIfaceMock) 856 .registerCallback(any(ISupplicantStaIfaceCallback.class)); 857 } 858 } 859 860 private SupplicantStatus createSupplicantStatus(int code) { 861 SupplicantStatus status = new SupplicantStatus(); 862 status.code = code; 863 return status; 864 } 865 866 /** 867 * Create an IfaceInfo with given type and name 868 */ 869 private ISupplicant.IfaceInfo createIfaceInfo(int type, String name) { 870 ISupplicant.IfaceInfo info = new ISupplicant.IfaceInfo(); 871 info.type = type; 872 info.name = name; 873 return info; 874 } 875 876 private class GetListInterfacesAnswer extends MockAnswerUtil.AnswerWithArguments { 877 private ArrayList<ISupplicant.IfaceInfo> mInterfaceList; 878 879 GetListInterfacesAnswer(ArrayList<ISupplicant.IfaceInfo> ifaces) { 880 mInterfaceList = ifaces; 881 } 882 883 public void answer(ISupplicant.listInterfacesCallback cb) { 884 cb.onValues(mStatusSuccess, mInterfaceList); 885 } 886 } 887 888 private class GetGetInterfaceAnswer extends MockAnswerUtil.AnswerWithArguments { 889 boolean mGetNullInterface; 890 891 GetGetInterfaceAnswer(boolean getNullInterface) { 892 mGetNullInterface = getNullInterface; 893 } 894 895 public void answer(ISupplicant.IfaceInfo iface, ISupplicant.getInterfaceCallback cb) { 896 if (mGetNullInterface) { 897 cb.onValues(mStatusSuccess, null); 898 } else { 899 cb.onValues(mStatusSuccess, mISupplicantIfaceMock); 900 } 901 } 902 } 903 904 /** 905 * Setup mocks for connect sequence. 906 */ 907 private void setupMocksForConnectSequence(final boolean haveExistingNetwork) throws Exception { 908 final int existingNetworkId = EXISTING_SUPPLICANT_NETWORK_ID; 909 doAnswer(new MockAnswerUtil.AnswerWithArguments() { 910 public SupplicantStatus answer() throws RemoteException { 911 return mStatusSuccess; 912 } 913 }).when(mISupplicantStaIfaceMock).disconnect(); 914 doAnswer(new MockAnswerUtil.AnswerWithArguments() { 915 public void answer(ISupplicantStaIface.listNetworksCallback cb) throws RemoteException { 916 if (haveExistingNetwork) { 917 cb.onValues(mStatusSuccess, new ArrayList<>(Arrays.asList(existingNetworkId))); 918 } else { 919 cb.onValues(mStatusSuccess, new ArrayList<>()); 920 } 921 } 922 }).when(mISupplicantStaIfaceMock) 923 .listNetworks(any(ISupplicantStaIface.listNetworksCallback.class)); 924 doAnswer(new MockAnswerUtil.AnswerWithArguments() { 925 public SupplicantStatus answer(int id) throws RemoteException { 926 return mStatusSuccess; 927 } 928 }).when(mISupplicantStaIfaceMock).removeNetwork(eq(existingNetworkId)); 929 doAnswer(new MockAnswerUtil.AnswerWithArguments() { 930 public void answer(ISupplicantStaIface.addNetworkCallback cb) throws RemoteException { 931 cb.onValues(mStatusSuccess, mock(ISupplicantStaNetwork.class)); 932 return; 933 } 934 }).when(mISupplicantStaIfaceMock).addNetwork( 935 any(ISupplicantStaIface.addNetworkCallback.class)); 936 when(mSupplicantStaNetworkMock.saveWifiConfiguration(any(WifiConfiguration.class))) 937 .thenReturn(true); 938 when(mSupplicantStaNetworkMock.select()).thenReturn(true); 939 } 940 941 /** 942 * Helper function to validate the connect sequence. 943 */ 944 private void validateConnectSequence( 945 final boolean haveExistingNetwork, boolean shouldDisconnect, int numNetworkAdditions) 946 throws Exception { 947 if (shouldDisconnect) { 948 verify(mISupplicantStaIfaceMock).disconnect(); 949 } 950 if (haveExistingNetwork) { 951 verify(mISupplicantStaIfaceMock).removeNetwork(anyInt()); 952 } 953 verify(mISupplicantStaIfaceMock, times(numNetworkAdditions)) 954 .addNetwork(any(ISupplicantStaIface.addNetworkCallback.class)); 955 verify(mSupplicantStaNetworkMock, times(numNetworkAdditions)) 956 .saveWifiConfiguration(any(WifiConfiguration.class)); 957 verify(mSupplicantStaNetworkMock, times(numNetworkAdditions)).select(); 958 } 959 960 /** 961 * Helper function to execute all the actions to perform connection to the network. 962 * 963 * @param newFrameworkNetworkId Framework Network Id of the new network to connect. 964 * @param haveExistingNetwork Removes the existing network. 965 * @param shouldDisconnect Should trigger disconnect before connecting. 966 */ 967 private void executeAndValidateConnectSequence( 968 final int newFrameworkNetworkId, final boolean haveExistingNetwork, 969 boolean shouldDisconnect) throws Exception { 970 setupMocksForConnectSequence(haveExistingNetwork); 971 WifiConfiguration config = new WifiConfiguration(); 972 config.networkId = newFrameworkNetworkId; 973 assertTrue(mDut.connectToNetwork(config, shouldDisconnect)); 974 validateConnectSequence(haveExistingNetwork, shouldDisconnect, 1); 975 } 976 977 /** 978 * Setup mocks for roam sequence. 979 */ 980 private void setupMocksForRoamSequence(String roamBssid) throws Exception { 981 doAnswer(new MockAnswerUtil.AnswerWithArguments() { 982 public SupplicantStatus answer() throws RemoteException { 983 return mStatusSuccess; 984 } 985 }).when(mISupplicantStaIfaceMock).reassociate(); 986 when(mSupplicantStaNetworkMock.setBssid(eq(roamBssid))).thenReturn(true); 987 } 988 989 /** 990 * Helper function to execute all the actions to perform roaming to the network. 991 * 992 * @param sameNetwork Roam to the same network or not. 993 */ 994 private void executeAndValidateRoamSequence(boolean sameNetwork) throws Exception { 995 int connectedNetworkId = ROAM_NETWORK_ID; 996 String roamBssid = BSSID; 997 int roamNetworkId; 998 if (sameNetwork) { 999 roamNetworkId = connectedNetworkId; 1000 } else { 1001 roamNetworkId = connectedNetworkId + 1; 1002 } 1003 executeAndValidateConnectSequence(connectedNetworkId, false, true); 1004 setupMocksForRoamSequence(roamBssid); 1005 1006 WifiConfiguration roamingConfig = new WifiConfiguration(); 1007 roamingConfig.networkId = roamNetworkId; 1008 roamingConfig.getNetworkSelectionStatus().setNetworkSelectionBSSID(roamBssid); 1009 assertTrue(mDut.roamToNetwork(roamingConfig)); 1010 1011 if (!sameNetwork) { 1012 validateConnectSequence(false, false, 2); 1013 verify(mSupplicantStaNetworkMock, never()).setBssid(anyString()); 1014 verify(mISupplicantStaIfaceMock, never()).reassociate(); 1015 } else { 1016 verify(mSupplicantStaNetworkMock).setBssid(eq(roamBssid)); 1017 verify(mISupplicantStaIfaceMock).reassociate(); 1018 } 1019 } 1020} 1021