1 /* 2 * Copyright (C) 2016 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 17 package com.android.server.wifi.aware; 18 19 import static android.hardware.wifi.V1_0.NanRangingIndication.EGRESS_MET_MASK; 20 21 import static org.hamcrest.core.IsEqual.equalTo; 22 import static org.hamcrest.core.IsNull.notNullValue; 23 import static org.hamcrest.core.IsNull.nullValue; 24 import static org.junit.Assert.assertEquals; 25 import static org.junit.Assert.assertNotEquals; 26 import static org.junit.Assert.assertTrue; 27 import static org.mockito.ArgumentMatchers.any; 28 import static org.mockito.ArgumentMatchers.anyBoolean; 29 import static org.mockito.ArgumentMatchers.anyByte; 30 import static org.mockito.ArgumentMatchers.anyInt; 31 import static org.mockito.ArgumentMatchers.anyLong; 32 import static org.mockito.ArgumentMatchers.anyShort; 33 import static org.mockito.ArgumentMatchers.eq; 34 import static org.mockito.ArgumentMatchers.isNull; 35 import static org.mockito.Mockito.inOrder; 36 import static org.mockito.Mockito.mock; 37 import static org.mockito.Mockito.times; 38 import static org.mockito.Mockito.verify; 39 import static org.mockito.Mockito.verifyNoMoreInteractions; 40 import static org.mockito.Mockito.when; 41 42 import android.Manifest; 43 import android.app.AppOpsManager; 44 import android.app.test.MockAnswerUtil; 45 import android.app.test.TestAlarmManager; 46 import android.content.BroadcastReceiver; 47 import android.content.Context; 48 import android.content.Intent; 49 import android.content.IntentFilter; 50 import android.content.pm.PackageManager; 51 import android.hardware.wifi.V1_0.NanRangingIndication; 52 import android.hardware.wifi.V1_0.NanStatusType; 53 import android.location.LocationManager; 54 import android.net.ConnectivityManager; 55 import android.net.wifi.WifiManager; 56 import android.net.wifi.aware.ConfigRequest; 57 import android.net.wifi.aware.IWifiAwareDiscoverySessionCallback; 58 import android.net.wifi.aware.IWifiAwareEventCallback; 59 import android.net.wifi.aware.IWifiAwareMacAddressProvider; 60 import android.net.wifi.aware.PublishConfig; 61 import android.net.wifi.aware.SubscribeConfig; 62 import android.net.wifi.aware.WifiAwareManager; 63 import android.os.Handler; 64 import android.os.IBinder; 65 import android.os.IPowerManager; 66 import android.os.Message; 67 import android.os.PowerManager; 68 import android.os.RemoteException; 69 import android.os.UserHandle; 70 import android.os.test.TestLooper; 71 import android.support.test.filters.SmallTest; 72 import android.util.Log; 73 import android.util.SparseArray; 74 75 import com.android.server.wifi.util.WifiPermissionsUtil; 76 import com.android.server.wifi.util.WifiPermissionsWrapper; 77 78 import libcore.util.HexEncoding; 79 80 import org.junit.After; 81 import org.junit.Before; 82 import org.junit.Rule; 83 import org.junit.Test; 84 import org.junit.rules.ErrorCollector; 85 import org.mockito.ArgumentCaptor; 86 import org.mockito.InOrder; 87 import org.mockito.Mock; 88 import org.mockito.MockitoAnnotations; 89 import org.mockito.Spy; 90 91 import java.io.PrintWriter; 92 import java.io.StringWriter; 93 import java.lang.reflect.Field; 94 import java.util.ArrayList; 95 import java.util.HashMap; 96 import java.util.HashSet; 97 import java.util.LinkedList; 98 import java.util.List; 99 import java.util.Map; 100 import java.util.Random; 101 import java.util.Set; 102 103 /** 104 * Unit test harness for WifiAwareStateManager. 105 */ 106 @SmallTest 107 public class WifiAwareStateManagerTest { 108 private TestLooper mMockLooper; 109 private Random mRandomNg = new Random(15687); 110 private WifiAwareStateManager mDut; 111 @Mock private WifiAwareNativeManager mMockNativeManager; 112 @Spy private TestUtils.MonitoredWifiAwareNativeApi mMockNative = 113 new TestUtils.MonitoredWifiAwareNativeApi(); 114 @Mock private Context mMockContext; 115 @Mock private AppOpsManager mMockAppOpsManager; 116 @Mock private WifiAwareMetrics mAwareMetricsMock; 117 @Mock private WifiPermissionsUtil mWifiPermissionsUtil; 118 @Mock private WifiPermissionsWrapper mPermissionsWrapperMock; 119 @Mock private LocationManager mLocationManagerMock; 120 TestAlarmManager mAlarmManager; 121 private PowerManager mMockPowerManager; 122 @Mock private WifiManager mMockWifiManager; 123 private BroadcastReceiver mPowerBcastReceiver; 124 private BroadcastReceiver mLocationModeReceiver; 125 private BroadcastReceiver mWifiStateChangedReceiver; 126 @Mock private WifiAwareDataPathStateManager mMockAwareDataPathStatemanager; 127 128 @Rule 129 public ErrorCollector collector = new ErrorCollector(); 130 131 private static final byte[] ALL_ZERO_MAC = new byte[] {0, 0, 0, 0, 0, 0}; 132 133 /** 134 * Pre-test configuration. Initialize and install mocks. 135 */ 136 @Before 137 public void setUp() throws Exception { 138 MockitoAnnotations.initMocks(this); 139 140 mAlarmManager = new TestAlarmManager(); 141 when(mMockContext.getSystemService(Context.ALARM_SERVICE)) 142 .thenReturn(mAlarmManager.getAlarmManager()); 143 144 when(mMockContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager); 145 when(mMockWifiManager.getWifiState()).thenReturn(WifiManager.WIFI_STATE_ENABLED); 146 147 mMockLooper = new TestLooper(); 148 149 IPowerManager powerManagerService = mock(IPowerManager.class); 150 mMockPowerManager = new PowerManager(mMockContext, powerManagerService, 151 new Handler(mMockLooper.getLooper())); 152 153 when(mMockContext.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn( 154 mock(ConnectivityManager.class)); 155 when(mMockContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mMockAppOpsManager); 156 when(mMockContext.getSystemServiceName(PowerManager.class)).thenReturn( 157 Context.POWER_SERVICE); 158 when(mMockContext.getSystemService(PowerManager.class)).thenReturn(mMockPowerManager); 159 when(mMockContext.getSystemService(Context.LOCATION_SERVICE)).thenReturn( 160 mLocationManagerMock); 161 when(mMockContext.checkPermission(eq(android.Manifest.permission.ACCESS_FINE_LOCATION), 162 anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_DENIED); 163 when(mMockContext.checkPermission(eq(Manifest.permission.ACCESS_COARSE_LOCATION), 164 anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_DENIED); 165 when(mMockAppOpsManager.noteOp(eq(AppOpsManager.OP_FINE_LOCATION), anyInt(), 166 any())).thenReturn(AppOpsManager.MODE_ERRORED); 167 when(mMockAppOpsManager.noteOp(eq(AppOpsManager.OP_COARSE_LOCATION), anyInt(), 168 any())).thenReturn(AppOpsManager.MODE_ERRORED); 169 when(mMockPowerManager.isDeviceIdleMode()).thenReturn(false); 170 when(mMockPowerManager.isInteractive()).thenReturn(true); 171 when(mLocationManagerMock.isLocationEnabled()).thenReturn(true); 172 173 ArgumentCaptor<BroadcastReceiver> bcastRxCaptor = ArgumentCaptor.forClass( 174 BroadcastReceiver.class); 175 mDut = new WifiAwareStateManager(); 176 mDut.setNative(mMockNativeManager, mMockNative); 177 mDut.start(mMockContext, mMockLooper.getLooper(), mAwareMetricsMock, 178 mWifiPermissionsUtil, mPermissionsWrapperMock); 179 mDut.startLate(); 180 mMockLooper.dispatchAll(); 181 verify(mMockContext, times(3)).registerReceiver(bcastRxCaptor.capture(), 182 any(IntentFilter.class)); 183 mPowerBcastReceiver = bcastRxCaptor.getAllValues().get(0); 184 mLocationModeReceiver = bcastRxCaptor.getAllValues().get(1); 185 mWifiStateChangedReceiver = bcastRxCaptor.getAllValues().get(2); 186 installMocksInStateManager(mDut, mMockAwareDataPathStatemanager); 187 } 188 189 /** 190 * Post-test validation. 191 */ 192 @After 193 public void tearDown() throws Exception { 194 mMockNative.validateUniqueTransactionIds(); 195 } 196 197 /** 198 * Test that the set parameter shell command executor works when parameters are valid. 199 */ 200 @Test 201 public void testSetParameterShellCommandSuccess() { 202 setSettableParam(WifiAwareStateManager.PARAM_ON_IDLE_DISABLE_AWARE, Integer.toString(1), 203 true); 204 } 205 206 /** 207 * Test that the set parameter shell command executor fails on incorrect name. 208 */ 209 @Test 210 public void testSetParameterShellCommandInvalidParameterName() { 211 setSettableParam("XXX", Integer.toString(1), false); 212 } 213 214 /** 215 * Test that the set parameter shell command executor fails on invalid value (not convertible 216 * to an int). 217 */ 218 @Test 219 public void testSetParameterShellCommandInvalidValue() { 220 setSettableParam(WifiAwareStateManager.PARAM_ON_IDLE_DISABLE_AWARE, "garbage", false); 221 } 222 223 /** 224 * Test the PeerHandle -> MAC address API: 225 * - Start up discovery of 2 sessions 226 * - Get multiple matches (PeerHandles) 227 * - Request translation as UID of sesssion #1 for PeerHandles of the same UID + of the other 228 * discovery session (to which we shouldn't have access) + invalid PeerHandle. 229 * -> validate results 230 */ 231 @Test 232 public void testRequestMacAddresses() throws Exception { 233 final int clientId1 = 1005; 234 final int clientId2 = 1006; 235 final int uid1 = 1000; 236 final int uid2 = 1001; 237 final int pid1 = 2000; 238 final int pid2 = 2001; 239 final String callingPackage = "com.google.somePackage"; 240 final String serviceName = "some-service-name"; 241 final byte subscribeId1 = 15; 242 final byte subscribeId2 = 16; 243 final int requestorIdBase = 22; 244 final byte[] peerMac1 = HexEncoding.decode("060708090A0B".toCharArray(), false); 245 final byte[] peerMac2 = HexEncoding.decode("010203040506".toCharArray(), false); 246 final byte[] peerMac3 = HexEncoding.decode("AABBCCDDEEFF".toCharArray(), false); 247 final int distance = 10; 248 249 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 250 SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().setServiceName(serviceName) 251 .build(); 252 253 IWifiAwareEventCallback mockCallback1 = mock(IWifiAwareEventCallback.class); 254 IWifiAwareEventCallback mockCallback2 = mock(IWifiAwareEventCallback.class); 255 IWifiAwareDiscoverySessionCallback mockSessionCallback1 = mock( 256 IWifiAwareDiscoverySessionCallback.class); 257 IWifiAwareDiscoverySessionCallback mockSessionCallback2 = mock( 258 IWifiAwareDiscoverySessionCallback.class); 259 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 260 ArgumentCaptor<Integer> sessionId = ArgumentCaptor.forClass(Integer.class); 261 ArgumentCaptor<Integer> peerIdCaptor = ArgumentCaptor.forClass(Integer.class); 262 InOrder inOrder = inOrder(mockCallback1, mockCallback2, mockSessionCallback1, 263 mockSessionCallback2, mMockNative); 264 265 // (0) enable 266 mDut.enableUsage(); 267 mMockLooper.dispatchAll(); 268 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 269 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 270 mMockLooper.dispatchAll(); 271 272 // (1) connect 2 clients 273 mDut.connect(clientId1, uid1, pid1, callingPackage, mockCallback1, configRequest, false); 274 mMockLooper.dispatchAll(); 275 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), 276 eq(configRequest), eq(false), eq(true), eq(true), eq(false)); 277 mDut.onConfigSuccessResponse(transactionId.getValue()); 278 mMockLooper.dispatchAll(); 279 inOrder.verify(mockCallback1).onConnectSuccess(clientId1); 280 281 mDut.connect(clientId2, uid2, pid2, callingPackage, mockCallback2, configRequest, false); 282 mMockLooper.dispatchAll(); 283 inOrder.verify(mockCallback2).onConnectSuccess(clientId2); 284 285 // (2) subscribe both clients 286 mDut.subscribe(clientId1, subscribeConfig, mockSessionCallback1); 287 mMockLooper.dispatchAll(); 288 inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq((byte) 0), 289 eq(subscribeConfig)); 290 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), false, subscribeId1); 291 mMockLooper.dispatchAll(); 292 inOrder.verify(mockSessionCallback1).onSessionStarted(sessionId.capture()); 293 294 mDut.subscribe(clientId2, subscribeConfig, mockSessionCallback2); 295 mMockLooper.dispatchAll(); 296 inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq((byte) 0), 297 eq(subscribeConfig)); 298 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), false, subscribeId2); 299 mMockLooper.dispatchAll(); 300 inOrder.verify(mockSessionCallback2).onSessionStarted(sessionId.capture()); 301 302 // (3) 2 matches on session 1 (second one with distance), 1 match on session 2 303 mDut.onMatchNotification(subscribeId1, requestorIdBase, peerMac1, null, null, 0, 0); 304 mDut.onMatchNotification(subscribeId1, requestorIdBase + 1, peerMac2, null, null, 305 NanRangingIndication.INGRESS_MET_MASK, distance); 306 mMockLooper.dispatchAll(); 307 inOrder.verify(mockSessionCallback1).onMatch(peerIdCaptor.capture(), isNull(), 308 isNull()); 309 inOrder.verify(mockSessionCallback1).onMatchWithDistance(peerIdCaptor.capture(), isNull(), 310 isNull(), eq(distance)); 311 int peerId1 = peerIdCaptor.getAllValues().get(0); 312 int peerId2 = peerIdCaptor.getAllValues().get(1); 313 314 mDut.onMatchNotification(subscribeId2, requestorIdBase + 2, peerMac3, null, null, 0, 0); 315 mMockLooper.dispatchAll(); 316 inOrder.verify(mockSessionCallback2).onMatch(peerIdCaptor.capture(), isNull(), isNull()); 317 int peerId3 = peerIdCaptor.getAllValues().get(0); 318 319 // request MAC addresses 320 List<Integer> request = new ArrayList<>(); 321 request.add(peerId1); 322 request.add(peerId2); 323 request.add(peerId3); // for uid2: so should not be in results 324 request.add(peerId1 * 20 + peerId2 + peerId3); // garbage values != to any 325 Mutable<Map> response = new Mutable<>(); 326 mDut.requestMacAddresses(uid1, request, new IWifiAwareMacAddressProvider() { 327 @Override 328 public void macAddress(Map peerIdToMacMap) throws RemoteException { 329 response.value = peerIdToMacMap; 330 } 331 332 @Override 333 public IBinder asBinder() { 334 return null; 335 } 336 }); 337 mMockLooper.dispatchAll(); 338 339 assertNotEquals("Non-null result", null, response.value); 340 assertEquals("Number of results", 2, response.value.size()); 341 assertEquals("Results[peerId1]", peerMac1, response.value.get(peerId1)); 342 assertEquals("Results[peerId2]", peerMac2, response.value.get(peerId2)); 343 } 344 345 /** 346 * Validate that Aware data-path interfaces are brought up and down correctly. 347 */ 348 @Test 349 public void testAwareDataPathInterfaceUpDown() throws Exception { 350 final int clientId = 12341; 351 final int uid = 1000; 352 final int pid = 2000; 353 final String callingPackage = "com.google.somePackage"; 354 final ConfigRequest configRequest = new ConfigRequest.Builder().build(); 355 356 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 357 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 358 InOrder inOrder = inOrder(mMockContext, mMockNative, mMockAwareDataPathStatemanager, 359 mockCallback); 360 361 // (1) enable usage 362 mDut.enableUsage(); 363 mMockLooper.dispatchAll(); 364 validateCorrectAwareStatusChangeBroadcast(inOrder, true); 365 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 366 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 367 mMockLooper.dispatchAll(); 368 collector.checkThat("usage enabled", mDut.isUsageEnabled(), equalTo(true)); 369 370 // (2) connect (enable Aware) 371 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 372 mMockLooper.dispatchAll(); 373 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 374 eq(false), eq(true), eq(true), eq(false)); 375 mDut.onConfigSuccessResponse(transactionId.getValue()); 376 mMockLooper.dispatchAll(); 377 inOrder.verify(mockCallback).onConnectSuccess(clientId); 378 inOrder.verify(mMockAwareDataPathStatemanager).createAllInterfaces(); 379 380 // (3) disconnect (disable Aware) 381 mDut.disconnect(clientId); 382 mMockLooper.dispatchAll(); 383 inOrder.verify(mMockNative).disable(transactionId.capture()); 384 mDut.onDisableResponse(transactionId.getValue(), NanStatusType.SUCCESS); 385 mMockLooper.dispatchAll(); 386 inOrder.verify(mMockAwareDataPathStatemanager).deleteAllInterfaces(); 387 388 verifyNoMoreInteractions(mMockNative, mMockAwareDataPathStatemanager); 389 } 390 391 /** 392 * Validate that APIs aren't functional when usage is disabled. 393 */ 394 @Test 395 public void testDisableUsageDisablesApis() throws Exception { 396 final int clientId = 12314; 397 final int uid = 1000; 398 final int pid = 2000; 399 final String callingPackage = "com.google.somePackage"; 400 final ConfigRequest configRequest = new ConfigRequest.Builder().build(); 401 402 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 403 InOrder inOrder = inOrder(mMockContext, mMockNative, mockCallback); 404 405 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 406 407 // (1) check initial state 408 mDut.enableUsage(); 409 mMockLooper.dispatchAll(); 410 validateCorrectAwareStatusChangeBroadcast(inOrder, true); 411 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 412 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 413 mMockLooper.dispatchAll(); 414 collector.checkThat("usage enabled", mDut.isUsageEnabled(), equalTo(true)); 415 416 // (2) disable usage and validate state 417 mDut.disableUsage(); 418 mMockLooper.dispatchAll(); 419 collector.checkThat("usage disabled", mDut.isUsageEnabled(), equalTo(false)); 420 inOrder.verify(mMockNative).disable(transactionId.capture()); 421 mDut.onDisableResponse(transactionId.getValue(), NanStatusType.SUCCESS); 422 validateCorrectAwareStatusChangeBroadcast(inOrder, false); 423 424 // (3) try connecting and validate that get failure callback (though app should be aware of 425 // non-availability through state change broadcast and/or query API) 426 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 427 mMockLooper.dispatchAll(); 428 inOrder.verify(mockCallback).onConnectFail(anyInt()); 429 430 verifyNoMoreInteractions(mMockNative, mockCallback); 431 } 432 433 /** 434 * Validate that when API usage is disabled while in the middle of a connection that internal 435 * state is cleaned-up, and that all subsequent operations are NOP. Then enable usage again and 436 * validate that operates correctly. 437 */ 438 @Test 439 public void testDisableUsageFlow() throws Exception { 440 final int clientId = 12341; 441 final int uid = 1000; 442 final int pid = 2000; 443 final String callingPackage = "com.google.somePackage"; 444 final ConfigRequest configRequest = new ConfigRequest.Builder().build(); 445 446 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 447 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 448 ArgumentCaptor<SparseArray> sparseArrayCaptor = ArgumentCaptor.forClass(SparseArray.class); 449 InOrder inOrder = inOrder(mMockContext, mMockNative, mockCallback); 450 InOrder inOrderM = inOrder(mAwareMetricsMock); 451 452 // (1) check initial state 453 mDut.enableUsage(); 454 mMockLooper.dispatchAll(); 455 validateCorrectAwareStatusChangeBroadcast(inOrder, true); 456 inOrderM.verify(mAwareMetricsMock).recordEnableUsage(); 457 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 458 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 459 mMockLooper.dispatchAll(); 460 461 collector.checkThat("usage enabled", mDut.isUsageEnabled(), equalTo(true)); 462 463 // (2) connect (successfully) 464 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 465 mMockLooper.dispatchAll(); 466 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 467 eq(false), eq(true), eq(true), eq(false)); 468 mDut.onConfigSuccessResponse(transactionId.getValue()); 469 mMockLooper.dispatchAll(); 470 inOrder.verify(mockCallback).onConnectSuccess(clientId); 471 inOrderM.verify(mAwareMetricsMock).recordAttachSession(eq(uid), eq(false), 472 sparseArrayCaptor.capture()); 473 collector.checkThat("num of clients", sparseArrayCaptor.getValue().size(), equalTo(1)); 474 475 // (3) disable usage & verify callbacks 476 mDut.disableUsage(); 477 mMockLooper.dispatchAll(); 478 collector.checkThat("usage disabled", mDut.isUsageEnabled(), equalTo(false)); 479 inOrder.verify(mMockNative).disable(transactionId.capture()); 480 inOrderM.verify(mAwareMetricsMock).recordAttachSessionDuration(anyLong()); 481 inOrderM.verify(mAwareMetricsMock).recordDisableAware(); 482 inOrderM.verify(mAwareMetricsMock).recordDisableUsage(); 483 validateCorrectAwareStatusChangeBroadcast(inOrder, false); 484 validateInternalClientInfoCleanedUp(clientId); 485 mDut.onDisableResponse(transactionId.getValue(), NanStatusType.SUCCESS); 486 mMockLooper.dispatchAll(); 487 inOrderM.verify(mAwareMetricsMock).recordDisableAware(); 488 489 // (4) try connecting again and validate that get a failure 490 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 491 mMockLooper.dispatchAll(); 492 inOrder.verify(mockCallback).onConnectFail(anyInt()); 493 inOrderM.verify(mAwareMetricsMock).recordAttachStatus(NanStatusType.INTERNAL_FAILURE); 494 495 // (5) disable usage again and validate that not much happens 496 mDut.disableUsage(); 497 mMockLooper.dispatchAll(); 498 collector.checkThat("usage disabled", mDut.isUsageEnabled(), equalTo(false)); 499 500 // (6) enable usage 501 mDut.enableUsage(); 502 mMockLooper.dispatchAll(); 503 inOrderM.verify(mAwareMetricsMock).recordEnableUsage(); 504 collector.checkThat("usage enabled", mDut.isUsageEnabled(), equalTo(true)); 505 validateCorrectAwareStatusChangeBroadcast(inOrder, true); 506 507 // (7) connect (should be successful) 508 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 509 mMockLooper.dispatchAll(); 510 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 511 eq(false), eq(true), eq(true), eq(false)); 512 mDut.onConfigSuccessResponse(transactionId.getValue()); 513 mMockLooper.dispatchAll(); 514 inOrder.verify(mockCallback).onConnectSuccess(clientId); 515 inOrderM.verify(mAwareMetricsMock).recordAttachSession(eq(uid), eq(false), 516 sparseArrayCaptor.capture()); 517 collector.checkThat("num of clients", sparseArrayCaptor.getValue().size(), equalTo(1)); 518 519 verifyNoMoreInteractions(mMockNative, mockCallback, mAwareMetricsMock); 520 } 521 522 /** 523 * Validates that a HAL failure on enable and configure results in failed callback. 524 */ 525 @Test 526 public void testHalFailureEnableAndConfigure() throws Exception { 527 final int clientId = 12341; 528 final int uid = 1000; 529 final int pid = 2000; 530 final String callingPackage = "com.google.somePackage"; 531 final ConfigRequest configRequest = new ConfigRequest.Builder().build(); 532 533 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 534 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 535 InOrder inOrder = inOrder(mMockContext, mMockNative, mockCallback); 536 537 when(mMockNative.enableAndConfigure(anyShort(), any(), anyBoolean(), 538 anyBoolean(), eq(true), eq(false))).thenReturn(false); 539 540 // (1) check initial state 541 mDut.enableUsage(); 542 mMockLooper.dispatchAll(); 543 validateCorrectAwareStatusChangeBroadcast(inOrder, true); 544 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 545 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 546 mMockLooper.dispatchAll(); 547 548 // (2) connect with HAL failure 549 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 550 mMockLooper.dispatchAll(); 551 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 552 eq(false), eq(true), eq(true), eq(false)); 553 inOrder.verify(mockCallback).onConnectFail(NanStatusType.INTERNAL_FAILURE); 554 555 validateInternalClientInfoCleanedUp(clientId); 556 verifyNoMoreInteractions(mMockNative, mockCallback); 557 } 558 559 /** 560 * Validates that all events are delivered with correct arguments. Validates 561 * that IdentityChanged not delivered if configuration disables delivery. 562 */ 563 @Test 564 public void testAwareEventsDelivery() throws Exception { 565 final int clientId1 = 1005; 566 final int clientId2 = 1007; 567 final int clusterLow = 5; 568 final int clusterHigh = 100; 569 final int masterPref = 111; 570 final int uid = 1000; 571 final int pid = 2000; 572 final String callingPackage = "com.google.somePackage"; 573 final int reason = NanStatusType.INTERNAL_FAILURE; 574 final byte[] someMac = HexEncoding.decode("000102030405".toCharArray(), false); 575 final byte[] someMac2 = HexEncoding.decode("060708090A0B".toCharArray(), false); 576 577 ConfigRequest configRequest = new ConfigRequest.Builder().setClusterLow(clusterLow) 578 .setClusterHigh(clusterHigh).setMasterPreference(masterPref) 579 .build(); 580 581 IWifiAwareEventCallback mockCallback1 = mock(IWifiAwareEventCallback.class); 582 IWifiAwareEventCallback mockCallback2 = mock(IWifiAwareEventCallback.class); 583 ArgumentCaptor<Short> transactionIdCapture = ArgumentCaptor.forClass(Short.class); 584 InOrder inOrder = inOrder(mockCallback1, mockCallback2, mMockNative); 585 586 mDut.enableUsage(); 587 mMockLooper.dispatchAll(); 588 inOrder.verify(mMockNative).getCapabilities(transactionIdCapture.capture()); 589 mDut.onCapabilitiesUpdateResponse(transactionIdCapture.getValue(), getCapabilities()); 590 mMockLooper.dispatchAll(); 591 592 // (1) connect 1st and 2nd clients 593 mDut.connect(clientId1, uid, pid, callingPackage, mockCallback1, configRequest, false); 594 mMockLooper.dispatchAll(); 595 inOrder.verify(mMockNative).enableAndConfigure(transactionIdCapture.capture(), 596 eq(configRequest), eq(false), eq(true), eq(true), eq(false)); 597 short transactionId = transactionIdCapture.getValue(); 598 mDut.onConfigSuccessResponse(transactionId); 599 mMockLooper.dispatchAll(); 600 inOrder.verify(mockCallback1).onConnectSuccess(clientId1); 601 602 mDut.connect(clientId2, uid, pid, callingPackage, mockCallback2, configRequest, true); 603 mMockLooper.dispatchAll(); 604 inOrder.verify(mMockNative).enableAndConfigure(transactionIdCapture.capture(), 605 eq(configRequest), eq(true), eq(false), eq(true), eq(false)); 606 transactionId = transactionIdCapture.getValue(); 607 mDut.onConfigSuccessResponse(transactionId); 608 mMockLooper.dispatchAll(); 609 inOrder.verify(mockCallback2).onConnectSuccess(clientId2); 610 611 // (2) deliver Aware events - without LOCATIONING permission 612 mDut.onClusterChangeNotification(WifiAwareClientState.CLUSTER_CHANGE_EVENT_STARTED, 613 someMac); 614 mDut.onInterfaceAddressChangeNotification(someMac); 615 mMockLooper.dispatchAll(); 616 617 inOrder.verify(mockCallback2).onIdentityChanged(ALL_ZERO_MAC); 618 619 // (3) deliver new identity - still without LOCATIONING permission (should get an event) 620 mDut.onInterfaceAddressChangeNotification(someMac2); 621 mMockLooper.dispatchAll(); 622 623 inOrder.verify(mockCallback2).onIdentityChanged(ALL_ZERO_MAC); 624 625 // (4) deliver same identity - still without LOCATIONING permission (should 626 // not get an event) 627 mDut.onInterfaceAddressChangeNotification(someMac2); 628 mMockLooper.dispatchAll(); 629 630 // (5) deliver new identity - with LOCATIONING permission 631 when(mMockContext.checkPermission(eq(Manifest.permission.ACCESS_COARSE_LOCATION), 632 anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); 633 when(mMockAppOpsManager.noteOp(eq(AppOpsManager.OP_COARSE_LOCATION), anyInt(), 634 any())).thenReturn(AppOpsManager.MODE_ALLOWED); 635 mDut.onInterfaceAddressChangeNotification(someMac); 636 mMockLooper.dispatchAll(); 637 638 inOrder.verify(mockCallback2).onIdentityChanged(someMac); 639 640 // (6) Aware down (no feedback) 641 mDut.onAwareDownNotification(reason); 642 mMockLooper.dispatchAll(); 643 644 validateInternalClientInfoCleanedUp(clientId1); 645 validateInternalClientInfoCleanedUp(clientId2); 646 647 verifyNoMoreInteractions(mockCallback1, mockCallback2, mMockNative); 648 } 649 650 /** 651 * Validate that when the HAL doesn't respond we get a TIMEOUT (which 652 * results in a failure response) at which point we can process additional 653 * commands. Steps: (1) connect, (2) publish - timeout, (3) publish + 654 * success. 655 */ 656 @Test 657 public void testHalNoResponseTimeout() throws Exception { 658 final int clientId = 12341; 659 final int uid = 1000; 660 final int pid = 2000; 661 final String callingPackage = "com.google.somePackage"; 662 final ConfigRequest configRequest = new ConfigRequest.Builder().build(); 663 final PublishConfig publishConfig = new PublishConfig.Builder().build(); 664 665 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 666 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 667 IWifiAwareDiscoverySessionCallback.class); 668 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 669 InOrder inOrder = inOrder(mMockNative, mockCallback, mockSessionCallback); 670 InOrder inOrderM = inOrder(mAwareMetricsMock); 671 672 mDut.enableUsage(); 673 mMockLooper.dispatchAll(); 674 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 675 inOrderM.verify(mAwareMetricsMock).recordEnableUsage(); 676 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 677 mMockLooper.dispatchAll(); 678 679 // (1) connect (successfully) 680 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 681 mMockLooper.dispatchAll(); 682 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 683 eq(false), eq(true), eq(true), eq(false)); 684 mDut.onConfigSuccessResponse(transactionId.getValue()); 685 mMockLooper.dispatchAll(); 686 inOrder.verify(mockCallback).onConnectSuccess(clientId); 687 inOrderM.verify(mAwareMetricsMock).recordAttachSession(eq(uid), eq(false), any()); 688 689 // (2) publish + timeout 690 mDut.publish(clientId, publishConfig, mockSessionCallback); 691 mMockLooper.dispatchAll(); 692 inOrder.verify(mMockNative).publish(anyShort(), eq((byte) 0), eq(publishConfig)); 693 assertTrue(mAlarmManager.dispatch(WifiAwareStateManager.HAL_COMMAND_TIMEOUT_TAG)); 694 mMockLooper.dispatchAll(); 695 inOrder.verify(mockSessionCallback).onSessionConfigFail(NanStatusType.INTERNAL_FAILURE); 696 inOrderM.verify(mAwareMetricsMock).recordDiscoveryStatus(uid, 697 NanStatusType.INTERNAL_FAILURE, true); 698 validateInternalNoSessions(clientId); 699 700 // (3) publish + success 701 mDut.publish(clientId, publishConfig, mockSessionCallback); 702 mMockLooper.dispatchAll(); 703 inOrder.verify(mMockNative).publish(transactionId.capture(), eq((byte) 0), 704 eq(publishConfig)); 705 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), true, (byte) 99); 706 mMockLooper.dispatchAll(); 707 inOrder.verify(mockSessionCallback).onSessionStarted(anyInt()); 708 inOrderM.verify(mAwareMetricsMock).recordDiscoverySession(eq(uid), any()); 709 inOrderM.verify(mAwareMetricsMock).recordDiscoveryStatus(uid, NanStatusType.SUCCESS, true); 710 711 verifyNoMoreInteractions(mMockNative, mockCallback, mockSessionCallback, mAwareMetricsMock); 712 } 713 714 /** 715 * Validates publish flow: (1) initial publish (2) fail informed by notification, (3) fail due 716 * to immediate HAL failure. Expected: get a failure callback. 717 */ 718 @Test 719 public void testPublishFail() throws Exception { 720 final int clientId = 1005; 721 final int uid = 1000; 722 final int pid = 2000; 723 final String callingPackage = "com.google.somePackage"; 724 final int reasonFail = NanStatusType.INTERNAL_FAILURE; 725 726 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 727 PublishConfig publishConfig = new PublishConfig.Builder().build(); 728 729 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 730 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 731 IWifiAwareDiscoverySessionCallback.class); 732 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 733 InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mMockNative); 734 InOrder inOrderM = inOrder(mAwareMetricsMock); 735 736 mDut.enableUsage(); 737 mMockLooper.dispatchAll(); 738 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 739 inOrderM.verify(mAwareMetricsMock).recordEnableUsage(); 740 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 741 mMockLooper.dispatchAll(); 742 743 // (0) connect 744 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 745 mMockLooper.dispatchAll(); 746 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), 747 eq(configRequest), eq(false), eq(true), eq(true), eq(false)); 748 mDut.onConfigSuccessResponse(transactionId.getValue()); 749 mMockLooper.dispatchAll(); 750 inOrder.verify(mockCallback).onConnectSuccess(clientId); 751 inOrderM.verify(mAwareMetricsMock).recordAttachSession(eq(uid), eq(false), any()); 752 753 // (1) initial publish 754 mDut.publish(clientId, publishConfig, mockSessionCallback); 755 mMockLooper.dispatchAll(); 756 inOrder.verify(mMockNative).publish(transactionId.capture(), eq((byte) 0), 757 eq(publishConfig)); 758 759 // (2) publish failure callback (i.e. firmware tried and failed) 760 mDut.onSessionConfigFailResponse(transactionId.getValue(), true, reasonFail); 761 mMockLooper.dispatchAll(); 762 inOrder.verify(mockSessionCallback).onSessionConfigFail(reasonFail); 763 inOrderM.verify(mAwareMetricsMock).recordDiscoveryStatus(uid, reasonFail, true); 764 validateInternalNoSessions(clientId); 765 766 // (3) publish and get immediate failure (i.e. HAL failed) 767 when(mMockNative.publish(anyShort(), anyByte(), any())).thenReturn(false); 768 769 mDut.publish(clientId, publishConfig, mockSessionCallback); 770 mMockLooper.dispatchAll(); 771 inOrder.verify(mMockNative).publish(transactionId.capture(), eq((byte) 0), 772 eq(publishConfig)); 773 774 inOrder.verify(mockSessionCallback).onSessionConfigFail(reasonFail); 775 inOrderM.verify(mAwareMetricsMock).recordDiscoveryStatus(uid, reasonFail, true); 776 validateInternalNoSessions(clientId); 777 778 verifyNoMoreInteractions(mockCallback, mockSessionCallback, mMockNative, mAwareMetricsMock); 779 } 780 781 /** 782 * Validates the publish flow: (1) initial publish (2) success (3) 783 * termination (e.g. DONE) (4) update session attempt (5) terminateSession 784 * (6) update session attempt. Expected: session ID callback + session 785 * cleaned-up. 786 */ 787 @Test 788 public void testPublishSuccessTerminated() throws Exception { 789 final int clientId = 2005; 790 final int uid = 1000; 791 final int pid = 2000; 792 final String callingPackage = "com.google.somePackage"; 793 final int reasonTerminate = NanStatusType.SUCCESS; 794 final byte publishId = 15; 795 796 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 797 PublishConfig publishConfig = new PublishConfig.Builder().build(); 798 799 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 800 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 801 IWifiAwareDiscoverySessionCallback.class); 802 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 803 ArgumentCaptor<Integer> sessionId = ArgumentCaptor.forClass(Integer.class); 804 InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mMockNative); 805 InOrder inOrderM = inOrder(mAwareMetricsMock); 806 807 mDut.enableUsage(); 808 mMockLooper.dispatchAll(); 809 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 810 inOrderM.verify(mAwareMetricsMock).recordEnableUsage(); 811 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 812 mMockLooper.dispatchAll(); 813 814 // (0) connect 815 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 816 mMockLooper.dispatchAll(); 817 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), 818 eq(configRequest), eq(false), eq(true), eq(true), eq(false)); 819 mDut.onConfigSuccessResponse(transactionId.getValue()); 820 mMockLooper.dispatchAll(); 821 inOrder.verify(mockCallback).onConnectSuccess(clientId); 822 inOrderM.verify(mAwareMetricsMock).recordAttachSession(eq(uid), eq(false), any()); 823 824 // (1) initial publish 825 mDut.publish(clientId, publishConfig, mockSessionCallback); 826 mMockLooper.dispatchAll(); 827 inOrder.verify(mMockNative).publish(transactionId.capture(), eq((byte) 0), 828 eq(publishConfig)); 829 830 // (2) publish success 831 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), true, publishId); 832 mMockLooper.dispatchAll(); 833 inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture()); 834 inOrderM.verify(mAwareMetricsMock).recordDiscoverySession(eq(uid), any()); 835 inOrderM.verify(mAwareMetricsMock).recordDiscoveryStatus(uid, NanStatusType.SUCCESS, true); 836 837 // (3) publish termination (from firmware - not app!) 838 mDut.onSessionTerminatedNotification(publishId, reasonTerminate, true); 839 mMockLooper.dispatchAll(); 840 inOrder.verify(mockSessionCallback).onSessionTerminated(reasonTerminate); 841 inOrderM.verify(mAwareMetricsMock).recordDiscoverySessionDuration(anyLong(), eq(true)); 842 843 // (4) app update session (race condition: app didn't get termination 844 // yet) 845 mDut.updatePublish(clientId, sessionId.getValue(), publishConfig); 846 mMockLooper.dispatchAll(); 847 848 // (5) app terminates session 849 mDut.terminateSession(clientId, sessionId.getValue()); 850 mMockLooper.dispatchAll(); 851 852 // (6) app updates session (app already knows that terminated - will get 853 // a local FAIL). 854 mDut.updatePublish(clientId, sessionId.getValue(), publishConfig); 855 mMockLooper.dispatchAll(); 856 857 validateInternalSessionInfoCleanedUp(clientId, sessionId.getValue()); 858 859 verifyNoMoreInteractions(mockSessionCallback, mMockNative, mAwareMetricsMock); 860 } 861 862 /** 863 * Validate the publish flow: (1) initial publish + (2) success + (3) update + (4) update 864 * fails (callback from firmware) + (5) update + (6). Expected: session is still alive after 865 * update failure so second update succeeds (no callbacks) + (7) update + immediate failure from 866 * HAL + (8) update + failure for invalid ID (which should clean-up state) + (9) another update 867 * - should get no response. 868 */ 869 @Test 870 public void testPublishUpdateFail() throws Exception { 871 final int clientId = 2005; 872 final int uid = 1000; 873 final int pid = 2000; 874 final String callingPackage = "com.google.somePackage"; 875 final byte publishId = 15; 876 final int reasonFail = NanStatusType.INTERNAL_FAILURE; 877 878 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 879 PublishConfig publishConfig = new PublishConfig.Builder().setRangingEnabled(true).build(); 880 881 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 882 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 883 IWifiAwareDiscoverySessionCallback.class); 884 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 885 ArgumentCaptor<Integer> sessionId = ArgumentCaptor.forClass(Integer.class); 886 InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mMockNative); 887 InOrder inOrderM = inOrder(mAwareMetricsMock); 888 889 mDut.enableUsage(); 890 mMockLooper.dispatchAll(); 891 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 892 inOrderM.verify(mAwareMetricsMock).recordEnableUsage(); 893 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 894 mMockLooper.dispatchAll(); 895 896 // (0) connect 897 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 898 mMockLooper.dispatchAll(); 899 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 900 eq(false), eq(true), eq(true), eq(false)); 901 mDut.onConfigSuccessResponse(transactionId.getValue()); 902 mMockLooper.dispatchAll(); 903 inOrder.verify(mockCallback).onConnectSuccess(clientId); 904 inOrderM.verify(mAwareMetricsMock).recordAttachSession(eq(uid), eq(false), any()); 905 906 // (1) initial publish 907 mDut.publish(clientId, publishConfig, mockSessionCallback); 908 mMockLooper.dispatchAll(); 909 inOrder.verify(mMockNative).publish(transactionId.capture(), eq((byte) 0), 910 eq(publishConfig)); 911 912 // (2) publish success 913 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), true, publishId); 914 mMockLooper.dispatchAll(); 915 inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture()); 916 inOrderM.verify(mAwareMetricsMock).recordDiscoverySessionWithRanging(eq(uid), eq(false), 917 eq(-1), eq(-1), any()); 918 inOrderM.verify(mAwareMetricsMock).recordDiscoveryStatus(uid, NanStatusType.SUCCESS, true); 919 920 // (3) update publish 921 mDut.updatePublish(clientId, sessionId.getValue(), publishConfig); 922 mMockLooper.dispatchAll(); 923 inOrder.verify(mMockNative).publish(transactionId.capture(), eq(publishId), 924 eq(publishConfig)); 925 926 // (4) update fails 927 mDut.onSessionConfigFailResponse(transactionId.getValue(), true, reasonFail); 928 mMockLooper.dispatchAll(); 929 inOrder.verify(mockSessionCallback).onSessionConfigFail(reasonFail); 930 inOrderM.verify(mAwareMetricsMock).recordDiscoveryStatus(uid, reasonFail, true); 931 932 // (5) another update publish 933 mDut.updatePublish(clientId, sessionId.getValue(), publishConfig); 934 mMockLooper.dispatchAll(); 935 inOrder.verify(mMockNative).publish(transactionId.capture(), eq(publishId), 936 eq(publishConfig)); 937 938 // (6) update succeeds 939 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), true, publishId); 940 mMockLooper.dispatchAll(); 941 inOrder.verify(mockSessionCallback).onSessionConfigSuccess(); 942 inOrderM.verify(mAwareMetricsMock).recordDiscoveryStatus(uid, NanStatusType.SUCCESS, true); 943 944 // (7) another update + immediate failure 945 when(mMockNative.publish(anyShort(), anyByte(), any())).thenReturn(false); 946 947 mDut.updatePublish(clientId, sessionId.getValue(), publishConfig); 948 mMockLooper.dispatchAll(); 949 inOrder.verify(mMockNative).publish(transactionId.capture(), eq(publishId), 950 eq(publishConfig)); 951 inOrder.verify(mockSessionCallback).onSessionConfigFail(reasonFail); 952 inOrderM.verify(mAwareMetricsMock).recordDiscoveryStatus(uid, reasonFail, true); 953 954 // (8) an update with bad ID failure 955 when(mMockNative.publish(anyShort(), anyByte(), any())).thenReturn(true); 956 957 mDut.updatePublish(clientId, sessionId.getValue(), publishConfig); 958 mMockLooper.dispatchAll(); 959 inOrder.verify(mMockNative).publish(transactionId.capture(), eq(publishId), 960 eq(publishConfig)); 961 mDut.onSessionConfigFailResponse(transactionId.getValue(), true, 962 NanStatusType.INVALID_SESSION_ID); 963 mMockLooper.dispatchAll(); 964 inOrder.verify(mockSessionCallback).onSessionConfigFail(NanStatusType.INVALID_SESSION_ID); 965 inOrderM.verify(mAwareMetricsMock).recordDiscoveryStatus(uid, 966 NanStatusType.INVALID_SESSION_ID, true); 967 968 // (9) try updating again - do nothing/get nothing 969 mDut.updatePublish(clientId, sessionId.getValue(), publishConfig); 970 mMockLooper.dispatchAll(); 971 972 verifyNoMoreInteractions(mockCallback, mockSessionCallback, mMockNative, mAwareMetricsMock); 973 } 974 975 /** 976 * Validate race condition: publish pending but session terminated (due to 977 * disconnect - can't terminate such a session directly from app). Need to 978 * make sure that once publish succeeds (failure isn't a problem) the 979 * session is immediately terminated since no-one is listening for it. 980 */ 981 @Test 982 public void testDisconnectWhilePublishPending() throws Exception { 983 final int clientId = 2005; 984 final int uid = 1000; 985 final int pid = 2000; 986 final String callingPackage = "com.google.somePackage"; 987 final byte publishId = 15; 988 989 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 990 PublishConfig publishConfig = new PublishConfig.Builder().build(); 991 992 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 993 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 994 IWifiAwareDiscoverySessionCallback.class); 995 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 996 InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mMockNative); 997 InOrder inOrderM = inOrder(mAwareMetricsMock); 998 999 mDut.enableUsage(); 1000 mMockLooper.dispatchAll(); 1001 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 1002 inOrderM.verify(mAwareMetricsMock).recordEnableUsage(); 1003 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 1004 mMockLooper.dispatchAll(); 1005 1006 // (0) connect 1007 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 1008 mMockLooper.dispatchAll(); 1009 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 1010 eq(false), eq(true), eq(true), eq(false)); 1011 mDut.onConfigSuccessResponse(transactionId.getValue()); 1012 mMockLooper.dispatchAll(); 1013 inOrder.verify(mockCallback).onConnectSuccess(clientId); 1014 inOrderM.verify(mAwareMetricsMock).recordAttachSession(eq(uid), eq(false), any()); 1015 1016 // (1) initial publish 1017 mDut.publish(clientId, publishConfig, mockSessionCallback); 1018 mMockLooper.dispatchAll(); 1019 inOrder.verify(mMockNative).publish(transactionId.capture(), eq((byte) 0), 1020 eq(publishConfig)); 1021 1022 // (2) disconnect (but doesn't get executed until get response for 1023 // publish command) 1024 mDut.disconnect(clientId); 1025 mMockLooper.dispatchAll(); 1026 1027 // (3) publish success 1028 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), true, publishId); 1029 mMockLooper.dispatchAll(); 1030 inOrder.verify(mockSessionCallback).onSessionStarted(anyInt()); 1031 inOrder.verify(mMockNative).stopPublish(transactionId.capture(), eq(publishId)); 1032 inOrder.verify(mMockNative).disable(anyShort()); 1033 inOrderM.verify(mAwareMetricsMock).recordDiscoverySession(eq(uid), any()); 1034 inOrderM.verify(mAwareMetricsMock).recordDiscoveryStatus(uid, NanStatusType.SUCCESS, true); 1035 inOrderM.verify(mAwareMetricsMock).recordAttachSessionDuration(anyLong()); 1036 inOrderM.verify(mAwareMetricsMock).recordDiscoverySessionDuration(anyLong(), eq(true)); 1037 1038 validateInternalClientInfoCleanedUp(clientId); 1039 1040 verifyNoMoreInteractions(mockCallback, mockSessionCallback, mMockNative, mAwareMetricsMock); 1041 } 1042 1043 /** 1044 * Validates subscribe flow: (1) initial subscribe (2) fail (callback from firmware), (3) fail 1045 * due to immeidate HAL failure. Expected: get a failure callback. 1046 */ 1047 @Test 1048 public void testSubscribeFail() throws Exception { 1049 final int clientId = 1005; 1050 final int uid = 1000; 1051 final int pid = 2000; 1052 final String callingPackage = "com.google.somePackage"; 1053 final int reasonFail = NanStatusType.INTERNAL_FAILURE; 1054 1055 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 1056 SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build(); 1057 1058 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 1059 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 1060 IWifiAwareDiscoverySessionCallback.class); 1061 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 1062 InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mMockNative); 1063 InOrder inOrderM = inOrder(mAwareMetricsMock); 1064 1065 mDut.enableUsage(); 1066 mMockLooper.dispatchAll(); 1067 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 1068 inOrderM.verify(mAwareMetricsMock).recordEnableUsage(); 1069 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 1070 mMockLooper.dispatchAll(); 1071 1072 // (0) connect 1073 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 1074 mMockLooper.dispatchAll(); 1075 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 1076 eq(false), eq(true), eq(true), eq(false)); 1077 mDut.onConfigSuccessResponse(transactionId.getValue()); 1078 mMockLooper.dispatchAll(); 1079 inOrder.verify(mockCallback).onConnectSuccess(clientId); 1080 inOrderM.verify(mAwareMetricsMock).recordAttachSession(eq(uid), eq(false), any()); 1081 1082 // (1) initial subscribe 1083 mDut.subscribe(clientId, subscribeConfig, mockSessionCallback); 1084 mMockLooper.dispatchAll(); 1085 inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq((byte) 0), 1086 eq(subscribeConfig)); 1087 1088 // (2) subscribe failure 1089 mDut.onSessionConfigFailResponse(transactionId.getValue(), false, reasonFail); 1090 mMockLooper.dispatchAll(); 1091 inOrder.verify(mockSessionCallback).onSessionConfigFail(reasonFail); 1092 inOrderM.verify(mAwareMetricsMock).recordDiscoveryStatus(uid, reasonFail, false); 1093 validateInternalNoSessions(clientId); 1094 1095 // (3) subscribe and get immediate failure (i.e. HAL failed) 1096 when(mMockNative.subscribe(anyShort(), anyByte(), any())) 1097 .thenReturn(false); 1098 1099 mDut.subscribe(clientId, subscribeConfig, mockSessionCallback); 1100 mMockLooper.dispatchAll(); 1101 inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq((byte) 0), 1102 eq(subscribeConfig)); 1103 1104 inOrder.verify(mockSessionCallback).onSessionConfigFail(reasonFail); 1105 inOrderM.verify(mAwareMetricsMock).recordDiscoveryStatus(uid, reasonFail, false); 1106 validateInternalNoSessions(clientId); 1107 1108 verifyNoMoreInteractions(mockCallback, mockSessionCallback, mMockNative, mAwareMetricsMock); 1109 } 1110 1111 /** 1112 * Validates the subscribe flow: (1) initial subscribe (2) success (3) 1113 * termination (e.g. DONE) (4) update session attempt (5) terminateSession 1114 * (6) update session attempt. Expected: session ID callback + session 1115 * cleaned-up 1116 */ 1117 @Test 1118 public void testSubscribeSuccessTerminated() throws Exception { 1119 final int clientId = 2005; 1120 final int uid = 1000; 1121 final int pid = 2000; 1122 final String callingPackage = "com.google.somePackage"; 1123 final int reasonTerminate = NanStatusType.SUCCESS; 1124 final byte subscribeId = 15; 1125 1126 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 1127 SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build(); 1128 1129 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 1130 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 1131 IWifiAwareDiscoverySessionCallback.class); 1132 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 1133 ArgumentCaptor<Integer> sessionId = ArgumentCaptor.forClass(Integer.class); 1134 InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mMockNative); 1135 InOrder inOrderM = inOrder(mAwareMetricsMock); 1136 1137 mDut.enableUsage(); 1138 mMockLooper.dispatchAll(); 1139 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 1140 inOrderM.verify(mAwareMetricsMock).recordEnableUsage(); 1141 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 1142 mMockLooper.dispatchAll(); 1143 1144 // (0) connect 1145 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 1146 mMockLooper.dispatchAll(); 1147 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 1148 eq(false), eq(true), eq(true), eq(false)); 1149 mDut.onConfigSuccessResponse(transactionId.getValue()); 1150 mMockLooper.dispatchAll(); 1151 inOrder.verify(mockCallback).onConnectSuccess(clientId); 1152 inOrderM.verify(mAwareMetricsMock).recordAttachSession(eq(uid), eq(false), any()); 1153 1154 // (1) initial subscribe 1155 mDut.subscribe(clientId, subscribeConfig, mockSessionCallback); 1156 mMockLooper.dispatchAll(); 1157 inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq((byte) 0), 1158 eq(subscribeConfig)); 1159 1160 // (2) subscribe success 1161 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), false, subscribeId); 1162 mMockLooper.dispatchAll(); 1163 inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture()); 1164 inOrderM.verify(mAwareMetricsMock).recordDiscoverySession(eq(uid), any()); 1165 inOrderM.verify(mAwareMetricsMock).recordDiscoveryStatus(uid, NanStatusType.SUCCESS, false); 1166 1167 // (3) subscribe termination (from firmware - not app!) 1168 mDut.onSessionTerminatedNotification(subscribeId, reasonTerminate, false); 1169 mMockLooper.dispatchAll(); 1170 inOrder.verify(mockSessionCallback).onSessionTerminated(reasonTerminate); 1171 inOrderM.verify(mAwareMetricsMock).recordDiscoverySessionDuration(anyLong(), eq(false)); 1172 1173 // (4) app update session (race condition: app didn't get termination 1174 // yet) 1175 mDut.updateSubscribe(clientId, sessionId.getValue(), subscribeConfig); 1176 mMockLooper.dispatchAll(); 1177 1178 // (5) app terminates session 1179 mDut.terminateSession(clientId, sessionId.getValue()); 1180 mMockLooper.dispatchAll(); 1181 1182 // (6) app updates session 1183 mDut.updateSubscribe(clientId, sessionId.getValue(), subscribeConfig); 1184 mMockLooper.dispatchAll(); 1185 1186 validateInternalSessionInfoCleanedUp(clientId, sessionId.getValue()); 1187 1188 verifyNoMoreInteractions(mockSessionCallback, mMockNative, mAwareMetricsMock); 1189 } 1190 1191 /** 1192 * Validate the subscribe flow: (1) initial subscribe + (2) success + (3) update + (4) update 1193 * fails (callback from firmware) + (5) update + (6). Expected: session is still alive after 1194 * update failure so second update succeeds (no callbacks). + (7) update + immediate failure 1195 * from HAL. 1196 */ 1197 @Test 1198 public void testSubscribeUpdateFail() throws Exception { 1199 final int clientId = 2005; 1200 final int uid = 1000; 1201 final int pid = 2000; 1202 final String callingPackage = "com.google.somePackage"; 1203 final byte subscribeId = 15; 1204 final int reasonFail = NanStatusType.INTERNAL_FAILURE; 1205 final int rangeMax = 10; 1206 1207 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 1208 SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().setMaxDistanceMm( 1209 rangeMax).build(); 1210 1211 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 1212 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 1213 IWifiAwareDiscoverySessionCallback.class); 1214 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 1215 ArgumentCaptor<Integer> sessionId = ArgumentCaptor.forClass(Integer.class); 1216 InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mMockNative); 1217 InOrder inOrderM = inOrder(mAwareMetricsMock); 1218 1219 mDut.enableUsage(); 1220 mMockLooper.dispatchAll(); 1221 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 1222 inOrderM.verify(mAwareMetricsMock).recordEnableUsage(); 1223 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 1224 mMockLooper.dispatchAll(); 1225 1226 // (0) connect 1227 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 1228 mMockLooper.dispatchAll(); 1229 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 1230 eq(false), eq(true), eq(true), eq(false)); 1231 mDut.onConfigSuccessResponse(transactionId.getValue()); 1232 mMockLooper.dispatchAll(); 1233 inOrder.verify(mockCallback).onConnectSuccess(clientId); 1234 inOrderM.verify(mAwareMetricsMock).recordAttachSession(eq(uid), eq(false), any()); 1235 1236 // (1) initial subscribe 1237 mDut.subscribe(clientId, subscribeConfig, mockSessionCallback); 1238 mMockLooper.dispatchAll(); 1239 inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq((byte) 0), 1240 eq(subscribeConfig)); 1241 1242 // (2) subscribe success 1243 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), false, subscribeId); 1244 mMockLooper.dispatchAll(); 1245 inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture()); 1246 inOrderM.verify(mAwareMetricsMock).recordDiscoverySessionWithRanging(eq(uid), eq(true), 1247 eq(-1), eq(rangeMax), any()); 1248 inOrderM.verify(mAwareMetricsMock).recordDiscoveryStatus(uid, NanStatusType.SUCCESS, false); 1249 1250 // (3) update subscribe 1251 mDut.updateSubscribe(clientId, sessionId.getValue(), subscribeConfig); 1252 mMockLooper.dispatchAll(); 1253 inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq(subscribeId), 1254 eq(subscribeConfig)); 1255 1256 // (4) update fails 1257 mDut.onSessionConfigFailResponse(transactionId.getValue(), false, reasonFail); 1258 mMockLooper.dispatchAll(); 1259 inOrder.verify(mockSessionCallback).onSessionConfigFail(reasonFail); 1260 inOrderM.verify(mAwareMetricsMock).recordDiscoveryStatus(uid, reasonFail, false); 1261 1262 // (5) another update subscribe 1263 mDut.updateSubscribe(clientId, sessionId.getValue(), subscribeConfig); 1264 mMockLooper.dispatchAll(); 1265 inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq(subscribeId), 1266 eq(subscribeConfig)); 1267 1268 // (6) update succeeds 1269 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), false, subscribeId); 1270 mMockLooper.dispatchAll(); 1271 inOrder.verify(mockSessionCallback).onSessionConfigSuccess(); 1272 inOrderM.verify(mAwareMetricsMock).recordDiscoveryStatus(uid, NanStatusType.SUCCESS, false); 1273 1274 // (7) another update + immediate failure 1275 when(mMockNative.subscribe(anyShort(), anyByte(), any())) 1276 .thenReturn(false); 1277 1278 mDut.updateSubscribe(clientId, sessionId.getValue(), subscribeConfig); 1279 mMockLooper.dispatchAll(); 1280 inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq(subscribeId), 1281 eq(subscribeConfig)); 1282 inOrder.verify(mockSessionCallback).onSessionConfigFail(reasonFail); 1283 inOrderM.verify(mAwareMetricsMock).recordDiscoveryStatus(uid, reasonFail, false); 1284 1285 verifyNoMoreInteractions(mockCallback, mockSessionCallback, mMockNative, mAwareMetricsMock); 1286 } 1287 1288 /** 1289 * Validate race condition: subscribe pending but session terminated (due to 1290 * disconnect - can't terminate such a session directly from app). Need to 1291 * make sure that once subscribe succeeds (failure isn't a problem) the 1292 * session is immediately terminated since no-one is listening for it. 1293 */ 1294 @Test 1295 public void testDisconnectWhileSubscribePending() throws Exception { 1296 final int clientId = 2005; 1297 final int uid = 1000; 1298 final int pid = 2000; 1299 final String callingPackage = "com.google.somePackage"; 1300 final byte subscribeId = 15; 1301 1302 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 1303 SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build(); 1304 1305 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 1306 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 1307 IWifiAwareDiscoverySessionCallback.class); 1308 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 1309 InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mMockNative); 1310 1311 mDut.enableUsage(); 1312 mMockLooper.dispatchAll(); 1313 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 1314 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 1315 mMockLooper.dispatchAll(); 1316 1317 // (0) connect 1318 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 1319 mMockLooper.dispatchAll(); 1320 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 1321 eq(false), eq(true), eq(true), eq(false)); 1322 mDut.onConfigSuccessResponse(transactionId.getValue()); 1323 mMockLooper.dispatchAll(); 1324 inOrder.verify(mockCallback).onConnectSuccess(clientId); 1325 1326 // (1) initial subscribe 1327 mDut.subscribe(clientId, subscribeConfig, mockSessionCallback); 1328 mMockLooper.dispatchAll(); 1329 inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq((byte) 0), 1330 eq(subscribeConfig)); 1331 1332 // (2) disconnect (but doesn't get executed until get response for 1333 // subscribe command) 1334 mDut.disconnect(clientId); 1335 mMockLooper.dispatchAll(); 1336 1337 // (3) subscribe success 1338 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), false, subscribeId); 1339 mMockLooper.dispatchAll(); 1340 inOrder.verify(mockSessionCallback).onSessionStarted(anyInt()); 1341 inOrder.verify(mMockNative).stopSubscribe((short) 0, subscribeId); 1342 inOrder.verify(mMockNative).disable(anyShort()); 1343 1344 validateInternalClientInfoCleanedUp(clientId); 1345 1346 verifyNoMoreInteractions(mockCallback, mockSessionCallback, mMockNative); 1347 } 1348 1349 /** 1350 * Validate (1) subscribe (success), (2) match (i.e. discovery), (3) message reception, 1351 * (4) message transmission failed (after ok queuing), (5) message transmission success. 1352 */ 1353 @Test 1354 public void testMatchAndMessages() throws Exception { 1355 final int clientId = 1005; 1356 final int uid = 1000; 1357 final int pid = 2000; 1358 final String callingPackage = "com.google.somePackage"; 1359 final String serviceName = "some-service-name"; 1360 final String ssi = "some much longer and more arbitrary data"; 1361 final int reasonFail = NanStatusType.INTERNAL_FAILURE; 1362 final byte subscribeId = 15; 1363 final int requestorId = 22; 1364 final byte[] peerMac = HexEncoding.decode("060708090A0B".toCharArray(), false); 1365 final String peerSsi = "some peer ssi data"; 1366 final String peerMatchFilter = "filter binary array represented as string"; 1367 final String peerMsg = "some message from peer"; 1368 final int messageId = 6948; 1369 final int messageId2 = 6949; 1370 final int rangeMin = 0; 1371 final int rangeMax = 55; 1372 final int rangedDistance = 30; 1373 1374 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 1375 SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().setServiceName(serviceName) 1376 .setServiceSpecificInfo(ssi.getBytes()) 1377 .setSubscribeType(SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE) 1378 .setMinDistanceMm(rangeMin) 1379 .setMaxDistanceMm(rangeMax) 1380 .build(); 1381 1382 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 1383 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 1384 IWifiAwareDiscoverySessionCallback.class); 1385 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 1386 ArgumentCaptor<Integer> sessionId = ArgumentCaptor.forClass(Integer.class); 1387 ArgumentCaptor<Integer> peerIdCaptor = ArgumentCaptor.forClass(Integer.class); 1388 InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mMockNative); 1389 InOrder inOrderM = inOrder(mAwareMetricsMock); 1390 1391 mDut.enableUsage(); 1392 mMockLooper.dispatchAll(); 1393 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 1394 inOrderM.verify(mAwareMetricsMock).recordEnableUsage(); 1395 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 1396 mMockLooper.dispatchAll(); 1397 1398 // (0) connect 1399 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 1400 mMockLooper.dispatchAll(); 1401 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), 1402 eq(configRequest), eq(false), eq(true), eq(true), eq(false)); 1403 mDut.onConfigSuccessResponse(transactionId.getValue()); 1404 mMockLooper.dispatchAll(); 1405 inOrder.verify(mockCallback).onConnectSuccess(clientId); 1406 inOrderM.verify(mAwareMetricsMock).recordAttachSession(eq(uid), eq(false), any()); 1407 1408 // (1) subscribe 1409 mDut.subscribe(clientId, subscribeConfig, mockSessionCallback); 1410 mMockLooper.dispatchAll(); 1411 inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq((byte) 0), 1412 eq(subscribeConfig)); 1413 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), false, subscribeId); 1414 mMockLooper.dispatchAll(); 1415 inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture()); 1416 inOrderM.verify(mAwareMetricsMock).recordDiscoverySessionWithRanging(eq(uid), eq(true), 1417 eq(rangeMin), eq(rangeMax), any()); 1418 inOrderM.verify(mAwareMetricsMock).recordDiscoveryStatus(uid, NanStatusType.SUCCESS, false); 1419 1420 // (2) 2 matches : with and w/o range 1421 mDut.onMatchNotification(subscribeId, requestorId, peerMac, peerSsi.getBytes(), 1422 peerMatchFilter.getBytes(), 0, 0); 1423 mMockLooper.dispatchAll(); 1424 inOrder.verify(mockSessionCallback).onMatch(peerIdCaptor.capture(), eq(peerSsi.getBytes()), 1425 eq(peerMatchFilter.getBytes())); 1426 inOrderM.verify(mAwareMetricsMock).recordMatchIndicationForRangeEnabledSubscribe(false); 1427 1428 mDut.onMatchNotification(subscribeId, requestorId, peerMac, peerSsi.getBytes(), 1429 peerMatchFilter.getBytes(), EGRESS_MET_MASK, rangedDistance); 1430 mMockLooper.dispatchAll(); 1431 inOrder.verify(mockSessionCallback).onMatchWithDistance(peerIdCaptor.capture(), 1432 eq(peerSsi.getBytes()), eq(peerMatchFilter.getBytes()), eq(rangedDistance)); 1433 inOrderM.verify(mAwareMetricsMock).recordMatchIndicationForRangeEnabledSubscribe(true); 1434 1435 // (3) message Rx 1436 mDut.onMessageReceivedNotification(subscribeId, requestorId, peerMac, peerMsg.getBytes()); 1437 mMockLooper.dispatchAll(); 1438 inOrder.verify(mockSessionCallback).onMessageReceived(peerIdCaptor.getValue(), 1439 peerMsg.getBytes()); 1440 1441 // (4) message Tx successful queuing 1442 mDut.sendMessage(clientId, sessionId.getValue(), peerIdCaptor.getValue(), ssi.getBytes(), 1443 messageId, 0); 1444 mMockLooper.dispatchAll(); 1445 inOrder.verify(mMockNative).sendMessage(transactionId.capture(), eq(subscribeId), 1446 eq(requestorId), eq(peerMac), eq(ssi.getBytes()), eq(messageId)); 1447 short tid1 = transactionId.getValue(); 1448 mDut.onMessageSendQueuedSuccessResponse(tid1); 1449 mMockLooper.dispatchAll(); 1450 1451 // (5) message Tx successful queuing 1452 mDut.sendMessage(clientId, sessionId.getValue(), peerIdCaptor.getValue(), ssi.getBytes(), 1453 messageId2, 0); 1454 mMockLooper.dispatchAll(); 1455 inOrder.verify(mMockNative).sendMessage(transactionId.capture(), eq(subscribeId), 1456 eq(requestorId), eq(peerMac), eq(ssi.getBytes()), eq(messageId2)); 1457 short tid2 = transactionId.getValue(); 1458 mDut.onMessageSendQueuedSuccessResponse(tid2); 1459 mMockLooper.dispatchAll(); 1460 1461 // (4) and (5) final Tx results (on-air results) 1462 mDut.onMessageSendFailNotification(tid1, reasonFail); 1463 mDut.onMessageSendSuccessNotification(tid2); 1464 mMockLooper.dispatchAll(); 1465 inOrder.verify(mockSessionCallback).onMessageSendFail(messageId, reasonFail); 1466 inOrder.verify(mockSessionCallback).onMessageSendSuccess(messageId2); 1467 validateInternalSendMessageQueuesCleanedUp(messageId); 1468 validateInternalSendMessageQueuesCleanedUp(messageId2); 1469 1470 verifyNoMoreInteractions(mockCallback, mockSessionCallback, mMockNative, mAwareMetricsMock); 1471 } 1472 1473 /** 1474 * Summary: in a single publish session interact with multiple peers 1475 * (different MAC addresses). 1476 */ 1477 @Test 1478 public void testMultipleMessageSources() throws Exception { 1479 final int clientId = 300; 1480 final int uid = 1000; 1481 final int pid = 2000; 1482 final String callingPackage = "com.google.somePackage"; 1483 final int clusterLow = 7; 1484 final int clusterHigh = 7; 1485 final int masterPref = 0; 1486 final String serviceName = "some-service-name"; 1487 final byte publishId = 88; 1488 final int requestorId1 = 568; 1489 final int requestorId2 = 873; 1490 final byte[] peerMac1 = HexEncoding.decode("000102030405".toCharArray(), false); 1491 final byte[] peerMac2 = HexEncoding.decode("060708090A0B".toCharArray(), false); 1492 final String msgFromPeer1 = "hey from 000102..."; 1493 final String msgFromPeer2 = "hey from 0607..."; 1494 final String msgToPeer1 = "hey there 000102..."; 1495 final String msgToPeer2 = "hey there 0506..."; 1496 final int msgToPeerId1 = 546; 1497 final int msgToPeerId2 = 9654; 1498 final int reason = NanStatusType.INTERNAL_FAILURE; 1499 1500 ConfigRequest configRequest = new ConfigRequest.Builder().setClusterLow(clusterLow) 1501 .setClusterHigh(clusterHigh).setMasterPreference(masterPref).build(); 1502 1503 PublishConfig publishConfig = new PublishConfig.Builder().setServiceName(serviceName) 1504 .setPublishType(PublishConfig.PUBLISH_TYPE_UNSOLICITED).build(); 1505 1506 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 1507 ArgumentCaptor<Integer> sessionId = ArgumentCaptor.forClass(Integer.class); 1508 ArgumentCaptor<Integer> peerIdCaptor = ArgumentCaptor.forClass(Integer.class); 1509 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 1510 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 1511 IWifiAwareDiscoverySessionCallback.class); 1512 InOrder inOrder = inOrder(mMockNative, mockCallback, mockSessionCallback); 1513 1514 mDut.enableUsage(); 1515 mMockLooper.dispatchAll(); 1516 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 1517 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 1518 mMockLooper.dispatchAll(); 1519 1520 // (1) connect 1521 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 1522 mMockLooper.dispatchAll(); 1523 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 1524 eq(false), eq(true), eq(true), eq(false)); 1525 mDut.onConfigSuccessResponse(transactionId.getValue()); 1526 mMockLooper.dispatchAll(); 1527 inOrder.verify(mockCallback).onConnectSuccess(clientId); 1528 1529 // (2) publish 1530 mDut.publish(clientId, publishConfig, mockSessionCallback); 1531 mMockLooper.dispatchAll(); 1532 inOrder.verify(mMockNative).publish(transactionId.capture(), eq((byte) 0), 1533 eq(publishConfig)); 1534 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), true, publishId); 1535 mMockLooper.dispatchAll(); 1536 inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture()); 1537 1538 // (3) message received from peers 1 & 2 1539 mDut.onMessageReceivedNotification(publishId, requestorId1, peerMac1, 1540 msgFromPeer1.getBytes()); 1541 mDut.onMessageReceivedNotification(publishId, requestorId2, peerMac2, 1542 msgFromPeer2.getBytes()); 1543 mMockLooper.dispatchAll(); 1544 inOrder.verify(mockSessionCallback).onMessageReceived(peerIdCaptor.capture(), 1545 eq(msgFromPeer1.getBytes())); 1546 int peerId1 = peerIdCaptor.getValue(); 1547 inOrder.verify(mockSessionCallback).onMessageReceived(peerIdCaptor.capture(), 1548 eq(msgFromPeer2.getBytes())); 1549 int peerId2 = peerIdCaptor.getValue(); 1550 1551 // (4) sending messages back to same peers: one Tx fails, other succeeds 1552 mDut.sendMessage(clientId, sessionId.getValue(), peerId2, msgToPeer2.getBytes(), 1553 msgToPeerId2, 0); 1554 mMockLooper.dispatchAll(); 1555 inOrder.verify(mMockNative).sendMessage(transactionId.capture(), eq(publishId), 1556 eq(requestorId2), eq(peerMac2), eq(msgToPeer2.getBytes()), eq(msgToPeerId2)); 1557 short transactionIdVal = transactionId.getValue(); 1558 mDut.onMessageSendQueuedSuccessResponse(transactionIdVal); 1559 mDut.onMessageSendSuccessNotification(transactionIdVal); 1560 1561 mDut.sendMessage(clientId, sessionId.getValue(), peerId1, msgToPeer1.getBytes(), 1562 msgToPeerId1, 0); 1563 mMockLooper.dispatchAll(); 1564 inOrder.verify(mockSessionCallback).onMessageSendSuccess(msgToPeerId2); 1565 inOrder.verify(mMockNative).sendMessage(transactionId.capture(), eq(publishId), 1566 eq(requestorId1), eq(peerMac1), eq(msgToPeer1.getBytes()), eq(msgToPeerId1)); 1567 transactionIdVal = transactionId.getValue(); 1568 mDut.onMessageSendQueuedSuccessResponse(transactionIdVal); 1569 mDut.onMessageSendFailNotification(transactionIdVal, reason); 1570 mMockLooper.dispatchAll(); 1571 inOrder.verify(mockSessionCallback).onMessageSendFail(msgToPeerId1, reason); 1572 validateInternalSendMessageQueuesCleanedUp(msgToPeerId1); 1573 validateInternalSendMessageQueuesCleanedUp(msgToPeerId2); 1574 1575 verifyNoMoreInteractions(mMockNative, mockCallback, mockSessionCallback); 1576 } 1577 1578 /** 1579 * Summary: interact with a peer which changed its identity (MAC address) 1580 * but which keeps its requestor instance ID. Should be transparent. 1581 */ 1582 @Test 1583 public void testMessageWhilePeerChangesIdentity() throws Exception { 1584 final int clientId = 300; 1585 final int uid = 1000; 1586 final int pid = 2000; 1587 final String callingPackage = "com.google.somePackage"; 1588 final int clusterLow = 7; 1589 final int clusterHigh = 7; 1590 final int masterPref = 0; 1591 final String serviceName = "some-service-name"; 1592 final byte publishId = 88; 1593 final int requestorId = 568; 1594 final byte[] peerMacOrig = HexEncoding.decode("000102030405".toCharArray(), false); 1595 final byte[] peerMacLater = HexEncoding.decode("060708090A0B".toCharArray(), false); 1596 final String msgFromPeer1 = "hey from 000102..."; 1597 final String msgFromPeer2 = "hey from 0607..."; 1598 final String msgToPeer1 = "hey there 000102..."; 1599 final String msgToPeer2 = "hey there 0506..."; 1600 final int msgToPeerId1 = 546; 1601 final int msgToPeerId2 = 9654; 1602 ConfigRequest configRequest = new ConfigRequest.Builder().setClusterLow(clusterLow) 1603 .setClusterHigh(clusterHigh).setMasterPreference(masterPref).build(); 1604 1605 PublishConfig publishConfig = new PublishConfig.Builder().setServiceName(serviceName) 1606 .setPublishType(PublishConfig.PUBLISH_TYPE_UNSOLICITED).build(); 1607 1608 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 1609 ArgumentCaptor<Integer> sessionId = ArgumentCaptor.forClass(Integer.class); 1610 ArgumentCaptor<Integer> peerId = ArgumentCaptor.forClass(Integer.class); 1611 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 1612 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 1613 IWifiAwareDiscoverySessionCallback.class); 1614 InOrder inOrder = inOrder(mMockNative, mockCallback, mockSessionCallback); 1615 1616 mDut.enableUsage(); 1617 mMockLooper.dispatchAll(); 1618 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 1619 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 1620 mMockLooper.dispatchAll(); 1621 1622 // (1) connect 1623 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 1624 mMockLooper.dispatchAll(); 1625 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 1626 eq(false), eq(true), eq(true), eq(false)); 1627 mDut.onConfigSuccessResponse(transactionId.getValue()); 1628 mMockLooper.dispatchAll(); 1629 inOrder.verify(mockCallback).onConnectSuccess(clientId); 1630 1631 // (2) publish 1632 mDut.publish(clientId, publishConfig, mockSessionCallback); 1633 mMockLooper.dispatchAll(); 1634 inOrder.verify(mMockNative).publish(transactionId.capture(), eq((byte) 0), 1635 eq(publishConfig)); 1636 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), true, publishId); 1637 mMockLooper.dispatchAll(); 1638 inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture()); 1639 1640 // (3) message received & responded to 1641 mDut.onMessageReceivedNotification(publishId, requestorId, peerMacOrig, 1642 msgFromPeer1.getBytes()); 1643 mMockLooper.dispatchAll(); 1644 inOrder.verify(mockSessionCallback).onMessageReceived(peerId.capture(), 1645 eq(msgFromPeer1.getBytes())); 1646 mDut.sendMessage(clientId, sessionId.getValue(), peerId.getValue(), msgToPeer1.getBytes(), 1647 msgToPeerId1, 0); 1648 mMockLooper.dispatchAll(); 1649 inOrder.verify(mMockNative).sendMessage(transactionId.capture(), eq(publishId), 1650 eq(requestorId), eq(peerMacOrig), eq(msgToPeer1.getBytes()), 1651 eq(msgToPeerId1)); 1652 mDut.onMessageSendQueuedSuccessResponse(transactionId.getValue()); 1653 mDut.onMessageSendSuccessNotification(transactionId.getValue()); 1654 mMockLooper.dispatchAll(); 1655 inOrder.verify(mockSessionCallback).onMessageSendSuccess(msgToPeerId1); 1656 validateInternalSendMessageQueuesCleanedUp(msgToPeerId1); 1657 1658 // (4) message received with same peer ID but different MAC 1659 mDut.onMessageReceivedNotification(publishId, requestorId, peerMacLater, 1660 msgFromPeer2.getBytes()); 1661 mMockLooper.dispatchAll(); 1662 inOrder.verify(mockSessionCallback).onMessageReceived(peerId.capture(), 1663 eq(msgFromPeer2.getBytes())); 1664 mDut.sendMessage(clientId, sessionId.getValue(), peerId.getValue(), msgToPeer2.getBytes(), 1665 msgToPeerId2, 0); 1666 mMockLooper.dispatchAll(); 1667 inOrder.verify(mMockNative).sendMessage(transactionId.capture(), eq(publishId), 1668 eq(requestorId), eq(peerMacLater), eq(msgToPeer2.getBytes()), 1669 eq(msgToPeerId2)); 1670 mDut.onMessageSendQueuedSuccessResponse(transactionId.getValue()); 1671 mDut.onMessageSendSuccessNotification(transactionId.getValue()); 1672 mMockLooper.dispatchAll(); 1673 inOrder.verify(mockSessionCallback).onMessageSendSuccess(msgToPeerId2); 1674 validateInternalSendMessageQueuesCleanedUp(msgToPeerId2); 1675 1676 verifyNoMoreInteractions(mMockNative, mockCallback, mockSessionCallback); 1677 } 1678 1679 /** 1680 * Validate that get failure (with correct code) when trying to send a 1681 * message to an invalid peer ID. 1682 */ 1683 @Test 1684 public void testSendMessageToInvalidPeerId() throws Exception { 1685 final int clientId = 1005; 1686 final int uid = 1000; 1687 final int pid = 2000; 1688 final String callingPackage = "com.google.somePackage"; 1689 final String ssi = "some much longer and more arbitrary data"; 1690 final byte subscribeId = 15; 1691 final int requestorId = 22; 1692 final byte[] peerMac = HexEncoding.decode("060708090A0B".toCharArray(), false); 1693 final String peerSsi = "some peer ssi data"; 1694 final String peerMatchFilter = "filter binary array represented as string"; 1695 final int messageId = 6948; 1696 1697 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 1698 SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build(); 1699 1700 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 1701 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 1702 IWifiAwareDiscoverySessionCallback.class); 1703 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 1704 ArgumentCaptor<Integer> sessionId = ArgumentCaptor.forClass(Integer.class); 1705 ArgumentCaptor<Integer> peerIdCaptor = ArgumentCaptor.forClass(Integer.class); 1706 InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mMockNative); 1707 1708 mDut.enableUsage(); 1709 mMockLooper.dispatchAll(); 1710 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 1711 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 1712 mMockLooper.dispatchAll(); 1713 1714 // (1) connect 1715 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 1716 mMockLooper.dispatchAll(); 1717 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 1718 eq(false), eq(true), eq(true), eq(false)); 1719 mDut.onConfigSuccessResponse(transactionId.getValue()); 1720 mMockLooper.dispatchAll(); 1721 inOrder.verify(mockCallback).onConnectSuccess(clientId); 1722 1723 // (2) subscribe & match 1724 mDut.subscribe(clientId, subscribeConfig, mockSessionCallback); 1725 mMockLooper.dispatchAll(); 1726 inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq((byte) 0), 1727 eq(subscribeConfig)); 1728 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), false, subscribeId); 1729 mDut.onMatchNotification(subscribeId, requestorId, peerMac, peerSsi.getBytes(), 1730 peerMatchFilter.getBytes(), 0, 0); 1731 mMockLooper.dispatchAll(); 1732 inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture()); 1733 inOrder.verify(mockSessionCallback).onMatch(peerIdCaptor.capture(), eq(peerSsi.getBytes()), 1734 eq(peerMatchFilter.getBytes())); 1735 1736 // (3) send message to invalid peer ID 1737 mDut.sendMessage(clientId, sessionId.getValue(), peerIdCaptor.getValue() + 5, 1738 ssi.getBytes(), messageId, 0); 1739 mMockLooper.dispatchAll(); 1740 inOrder.verify(mockSessionCallback).onMessageSendFail(messageId, 1741 NanStatusType.INTERNAL_FAILURE); 1742 validateInternalSendMessageQueuesCleanedUp(messageId); 1743 1744 verifyNoMoreInteractions(mockCallback, mockSessionCallback, mMockNative); 1745 } 1746 1747 /** 1748 * Validate that on send message errors are handled correctly: immediate send error, queue fail 1749 * error (not queue full), and timeout. Behavior: correct callback is dispatched and a later 1750 * firmware notification is ignored. Intersperse with one successfull transmission. 1751 */ 1752 @Test 1753 public void testSendMessageErrorsImmediateQueueTimeout() throws Exception { 1754 final int clientId = 1005; 1755 final int uid = 1000; 1756 final int pid = 2000; 1757 final String callingPackage = "com.google.somePackage"; 1758 final String ssi = "some much longer and more arbitrary data"; 1759 final byte subscribeId = 15; 1760 final int requestorId = 22; 1761 final byte[] peerMac = HexEncoding.decode("060708090A0B".toCharArray(), false); 1762 final String peerSsi = "some peer ssi data"; 1763 final String peerMatchFilter = "filter binary array represented as string"; 1764 final int messageId = 6948; 1765 1766 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 1767 SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build(); 1768 1769 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 1770 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 1771 IWifiAwareDiscoverySessionCallback.class); 1772 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 1773 ArgumentCaptor<Integer> sessionId = ArgumentCaptor.forClass(Integer.class); 1774 ArgumentCaptor<Integer> peerIdCaptor = ArgumentCaptor.forClass(Integer.class); 1775 InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mMockNative); 1776 1777 mDut.enableUsage(); 1778 mMockLooper.dispatchAll(); 1779 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 1780 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 1781 mMockLooper.dispatchAll(); 1782 1783 // (1) connect 1784 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 1785 mMockLooper.dispatchAll(); 1786 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 1787 eq(false), eq(true), eq(true), eq(false)); 1788 mDut.onConfigSuccessResponse(transactionId.getValue()); 1789 mMockLooper.dispatchAll(); 1790 inOrder.verify(mockCallback).onConnectSuccess(clientId); 1791 1792 // (2) subscribe & match 1793 mDut.subscribe(clientId, subscribeConfig, mockSessionCallback); 1794 mMockLooper.dispatchAll(); 1795 inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq((byte) 0), 1796 eq(subscribeConfig)); 1797 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), false, subscribeId); 1798 mDut.onMatchNotification(subscribeId, requestorId, peerMac, peerSsi.getBytes(), 1799 peerMatchFilter.getBytes(), 0, 0); 1800 mMockLooper.dispatchAll(); 1801 inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture()); 1802 inOrder.verify(mockSessionCallback).onMatch(peerIdCaptor.capture(), eq(peerSsi.getBytes()), 1803 eq(peerMatchFilter.getBytes())); 1804 1805 // (3) send 2 messages and enqueue successfully 1806 mDut.sendMessage(clientId, sessionId.getValue(), peerIdCaptor.getValue(), ssi.getBytes(), 1807 messageId, 0); 1808 mMockLooper.dispatchAll(); 1809 inOrder.verify(mMockNative).sendMessage(transactionId.capture(), eq(subscribeId), 1810 eq(requestorId), eq(peerMac), eq(ssi.getBytes()), eq(messageId)); 1811 short transactionId1 = transactionId.getValue(); 1812 mDut.onMessageSendQueuedSuccessResponse(transactionId1); 1813 mMockLooper.dispatchAll(); 1814 1815 mDut.sendMessage(clientId, sessionId.getValue(), peerIdCaptor.getValue(), ssi.getBytes(), 1816 messageId + 1, 0); 1817 mMockLooper.dispatchAll(); 1818 inOrder.verify(mMockNative).sendMessage(transactionId.capture(), eq(subscribeId), 1819 eq(requestorId), eq(peerMac), eq(ssi.getBytes()), eq(messageId + 1)); 1820 short transactionId2 = transactionId.getValue(); 1821 mDut.onMessageSendQueuedSuccessResponse(transactionId2); 1822 mMockLooper.dispatchAll(); 1823 1824 // (4) send a message and get a queueing failure (not queue full) 1825 mDut.sendMessage(clientId, sessionId.getValue(), peerIdCaptor.getValue(), ssi.getBytes(), 1826 messageId + 2, 0); 1827 mMockLooper.dispatchAll(); 1828 inOrder.verify(mMockNative).sendMessage(transactionId.capture(), eq(subscribeId), 1829 eq(requestorId), eq(peerMac), eq(ssi.getBytes()), eq(messageId + 2)); 1830 short transactionId3 = transactionId.getValue(); 1831 mDut.onMessageSendQueuedFailResponse(transactionId3, NanStatusType.INTERNAL_FAILURE); 1832 mMockLooper.dispatchAll(); 1833 inOrder.verify(mockSessionCallback).onMessageSendFail(messageId + 2, 1834 NanStatusType.INTERNAL_FAILURE); 1835 validateInternalSendMessageQueuesCleanedUp(messageId + 2); 1836 1837 // (5) send a message and get an immediate failure (configure first) 1838 when(mMockNative.sendMessage(anyShort(), anyByte(), anyInt(), any(), 1839 any(), anyInt())).thenReturn(false); 1840 1841 mDut.sendMessage(clientId, sessionId.getValue(), peerIdCaptor.getValue(), ssi.getBytes(), 1842 messageId + 3, 0); 1843 mMockLooper.dispatchAll(); 1844 inOrder.verify(mMockNative).sendMessage(transactionId.capture(), eq(subscribeId), 1845 eq(requestorId), eq(peerMac), eq(ssi.getBytes()), eq(messageId + 3)); 1846 short transactionId4 = transactionId.getValue(); 1847 inOrder.verify(mockSessionCallback).onMessageSendFail(messageId + 3, 1848 NanStatusType.INTERNAL_FAILURE); 1849 validateInternalSendMessageQueuesCleanedUp(messageId + 3); 1850 1851 // (6) message send timeout 1852 assertTrue(mAlarmManager.dispatch(WifiAwareStateManager.HAL_SEND_MESSAGE_TIMEOUT_TAG)); 1853 mMockLooper.dispatchAll(); 1854 inOrder.verify(mockSessionCallback).onMessageSendFail(messageId, 1855 NanStatusType.INTERNAL_FAILURE); 1856 validateInternalSendMessageQueuesCleanedUp(messageId); 1857 1858 // (7) firmware response (unlikely - but good to check) 1859 mDut.onMessageSendSuccessNotification(transactionId1); 1860 mDut.onMessageSendSuccessNotification(transactionId2); 1861 1862 // bogus: these didn't even go to firmware or weren't queued 1863 mDut.onMessageSendSuccessNotification(transactionId3); 1864 mDut.onMessageSendFailNotification(transactionId4, NanStatusType.INTERNAL_FAILURE); 1865 mMockLooper.dispatchAll(); 1866 inOrder.verify(mockSessionCallback).onMessageSendSuccess(messageId + 1); 1867 1868 validateInternalSendMessageQueuesCleanedUp(messageId + 1); 1869 1870 verifyNoMoreInteractions(mockCallback, mockSessionCallback, mMockNative); 1871 } 1872 1873 /** 1874 * Validate that when sending a message with a retry count the message is retried the specified 1875 * number of times. Scenario ending with success. 1876 */ 1877 @Test 1878 public void testSendMessageRetransmitSuccess() throws Exception { 1879 final int clientId = 1005; 1880 final int uid = 1000; 1881 final int pid = 2000; 1882 final String callingPackage = "com.google.somePackage"; 1883 final String ssi = "some much longer and more arbitrary data"; 1884 final byte subscribeId = 15; 1885 final int requestorId = 22; 1886 final byte[] peerMac = HexEncoding.decode("060708090A0B".toCharArray(), false); 1887 final String peerSsi = "some peer ssi data"; 1888 final String peerMatchFilter = "filter binary array represented as string"; 1889 final int messageId = 6948; 1890 final int retryCount = 3; 1891 1892 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 1893 SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build(); 1894 1895 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 1896 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 1897 IWifiAwareDiscoverySessionCallback.class); 1898 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 1899 ArgumentCaptor<Integer> sessionId = ArgumentCaptor.forClass(Integer.class); 1900 ArgumentCaptor<Integer> peerIdCaptor = ArgumentCaptor.forClass(Integer.class); 1901 InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mMockNative); 1902 1903 mDut.enableUsage(); 1904 mMockLooper.dispatchAll(); 1905 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 1906 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 1907 mMockLooper.dispatchAll(); 1908 1909 // (1) connect 1910 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 1911 mMockLooper.dispatchAll(); 1912 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 1913 eq(false), eq(true), eq(true), eq(false)); 1914 mDut.onConfigSuccessResponse(transactionId.getValue()); 1915 mMockLooper.dispatchAll(); 1916 inOrder.verify(mockCallback).onConnectSuccess(clientId); 1917 1918 // (2) subscribe & match 1919 mDut.subscribe(clientId, subscribeConfig, mockSessionCallback); 1920 mMockLooper.dispatchAll(); 1921 inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq((byte) 0), 1922 eq(subscribeConfig)); 1923 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), false, subscribeId); 1924 mDut.onMatchNotification(subscribeId, requestorId, peerMac, peerSsi.getBytes(), 1925 peerMatchFilter.getBytes(), 0, 0); 1926 mMockLooper.dispatchAll(); 1927 inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture()); 1928 inOrder.verify(mockSessionCallback).onMatch(peerIdCaptor.capture(), eq(peerSsi.getBytes()), 1929 eq(peerMatchFilter.getBytes())); 1930 1931 // (3) send message and enqueue successfully 1932 mDut.sendMessage(clientId, sessionId.getValue(), peerIdCaptor.getValue(), ssi.getBytes(), 1933 messageId, retryCount); 1934 mMockLooper.dispatchAll(); 1935 inOrder.verify(mMockNative).sendMessage(transactionId.capture(), eq(subscribeId), 1936 eq(requestorId), eq(peerMac), eq(ssi.getBytes()), eq(messageId)); 1937 mDut.onMessageSendQueuedSuccessResponse(transactionId.getValue()); 1938 mMockLooper.dispatchAll(); 1939 1940 // (4) loop and fail until reach retryCount 1941 for (int i = 0; i < retryCount; ++i) { 1942 mDut.onMessageSendFailNotification(transactionId.getValue(), NanStatusType.NO_OTA_ACK); 1943 mMockLooper.dispatchAll(); 1944 inOrder.verify(mMockNative).sendMessage(transactionId.capture(), eq(subscribeId), 1945 eq(requestorId), eq(peerMac), eq(ssi.getBytes()), eq(messageId)); 1946 mDut.onMessageSendQueuedSuccessResponse(transactionId.getValue()); 1947 mMockLooper.dispatchAll(); 1948 } 1949 1950 // (5) succeed on last retry 1951 mDut.onMessageSendSuccessNotification(transactionId.getValue()); 1952 mMockLooper.dispatchAll(); 1953 1954 inOrder.verify(mockSessionCallback).onMessageSendSuccess(messageId); 1955 validateInternalSendMessageQueuesCleanedUp(messageId); 1956 1957 verifyNoMoreInteractions(mockCallback, mockSessionCallback, mMockNative); 1958 } 1959 1960 /** 1961 * Validate that when sending a message with a retry count the message is retried the specified 1962 * number of times. Scenario ending with failure. 1963 */ 1964 @Test 1965 public void testSendMessageRetransmitFail() throws Exception { 1966 final int clientId = 1005; 1967 final int uid = 1000; 1968 final int pid = 2000; 1969 final String callingPackage = "com.google.somePackage"; 1970 final String ssi = "some much longer and more arbitrary data"; 1971 final byte subscribeId = 15; 1972 final int requestorId = 22; 1973 final byte[] peerMac = HexEncoding.decode("060708090A0B".toCharArray(), false); 1974 final String peerSsi = "some peer ssi data"; 1975 final String peerMatchFilter = "filter binary array represented as string"; 1976 final int messageId = 6948; 1977 final int retryCount = 3; 1978 1979 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 1980 SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build(); 1981 1982 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 1983 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 1984 IWifiAwareDiscoverySessionCallback.class); 1985 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 1986 ArgumentCaptor<Integer> sessionId = ArgumentCaptor.forClass(Integer.class); 1987 ArgumentCaptor<Integer> peerIdCaptor = ArgumentCaptor.forClass(Integer.class); 1988 InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mMockNative); 1989 1990 mDut.enableUsage(); 1991 mMockLooper.dispatchAll(); 1992 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 1993 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 1994 mMockLooper.dispatchAll(); 1995 1996 // (1) connect 1997 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 1998 mMockLooper.dispatchAll(); 1999 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 2000 eq(false), eq(true), eq(true), eq(false)); 2001 mDut.onConfigSuccessResponse(transactionId.getValue()); 2002 mMockLooper.dispatchAll(); 2003 inOrder.verify(mockCallback).onConnectSuccess(clientId); 2004 2005 // (2) subscribe & match 2006 mDut.subscribe(clientId, subscribeConfig, mockSessionCallback); 2007 mMockLooper.dispatchAll(); 2008 inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq((byte) 0), 2009 eq(subscribeConfig)); 2010 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), false, subscribeId); 2011 mDut.onMatchNotification(subscribeId, requestorId, peerMac, peerSsi.getBytes(), 2012 peerMatchFilter.getBytes(), 0, 0); 2013 mMockLooper.dispatchAll(); 2014 inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture()); 2015 inOrder.verify(mockSessionCallback).onMatch(peerIdCaptor.capture(), eq(peerSsi.getBytes()), 2016 eq(peerMatchFilter.getBytes())); 2017 2018 // (3) send message and enqueue successfully 2019 mDut.sendMessage(clientId, sessionId.getValue(), peerIdCaptor.getValue(), ssi.getBytes(), 2020 messageId, retryCount); 2021 mMockLooper.dispatchAll(); 2022 inOrder.verify(mMockNative).sendMessage(transactionId.capture(), eq(subscribeId), 2023 eq(requestorId), eq(peerMac), eq(ssi.getBytes()), eq(messageId)); 2024 mDut.onMessageSendQueuedSuccessResponse(transactionId.getValue()); 2025 mMockLooper.dispatchAll(); 2026 2027 // (4) loop and fail until reach retryCount+1 2028 for (int i = 0; i < retryCount + 1; ++i) { 2029 mDut.onMessageSendFailNotification(transactionId.getValue(), NanStatusType.NO_OTA_ACK); 2030 mMockLooper.dispatchAll(); 2031 2032 if (i != retryCount) { 2033 inOrder.verify(mMockNative).sendMessage(transactionId.capture(), eq(subscribeId), 2034 eq(requestorId), eq(peerMac), eq(ssi.getBytes()), eq(messageId)); 2035 mDut.onMessageSendQueuedSuccessResponse(transactionId.getValue()); 2036 mMockLooper.dispatchAll(); 2037 } 2038 } 2039 2040 inOrder.verify(mockSessionCallback).onMessageSendFail(messageId, 2041 NanStatusType.NO_OTA_ACK); 2042 validateInternalSendMessageQueuesCleanedUp(messageId); 2043 2044 verifyNoMoreInteractions(mockCallback, mockSessionCallback, mMockNative); 2045 } 2046 2047 /** 2048 * Validate that the host-side message queue functions. Tests the perfect case of queue always 2049 * succeeds and all messages are received on first attempt. 2050 */ 2051 @Test 2052 public void testSendMessageQueueSequence() throws Exception { 2053 final int clientId = 1005; 2054 final int uid = 1000; 2055 final int pid = 2000; 2056 final String callingPackage = "com.google.somePackage"; 2057 final String serviceName = "some-service-name"; 2058 final byte subscribeId = 15; 2059 final int requestorId = 22; 2060 final byte[] peerMac = HexEncoding.decode("060708090A0B".toCharArray(), false); 2061 final int messageIdBase = 6948; 2062 final int numberOfMessages = 30; 2063 final int queueDepth = 6; 2064 2065 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 2066 SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().setServiceName(serviceName) 2067 .build(); 2068 2069 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 2070 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 2071 IWifiAwareDiscoverySessionCallback.class); 2072 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 2073 ArgumentCaptor<Integer> sessionId = ArgumentCaptor.forClass(Integer.class); 2074 ArgumentCaptor<Integer> messageIdCaptor = ArgumentCaptor.forClass(Integer.class); 2075 ArgumentCaptor<Integer> peerIdCaptor = ArgumentCaptor.forClass(Integer.class); 2076 InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mMockNative); 2077 2078 mDut.enableUsage(); 2079 mMockLooper.dispatchAll(); 2080 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 2081 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 2082 mMockLooper.dispatchAll(); 2083 2084 // (0) connect 2085 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 2086 mMockLooper.dispatchAll(); 2087 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), 2088 eq(configRequest), eq(false), eq(true), eq(true), eq(false)); 2089 mDut.onConfigSuccessResponse(transactionId.getValue()); 2090 mMockLooper.dispatchAll(); 2091 inOrder.verify(mockCallback).onConnectSuccess(clientId); 2092 2093 // (1) subscribe 2094 mDut.subscribe(clientId, subscribeConfig, mockSessionCallback); 2095 mMockLooper.dispatchAll(); 2096 inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq((byte) 0), 2097 eq(subscribeConfig)); 2098 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), false, subscribeId); 2099 mMockLooper.dispatchAll(); 2100 inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture()); 2101 2102 // (2) match 2103 mDut.onMatchNotification(subscribeId, requestorId, peerMac, null, null, 0, 0); 2104 mMockLooper.dispatchAll(); 2105 inOrder.verify(mockSessionCallback).onMatch(peerIdCaptor.capture(), isNull(), isNull()); 2106 2107 // (3) transmit messages 2108 SendMessageQueueModelAnswer answerObj = new SendMessageQueueModelAnswer(queueDepth, 2109 null, null, null); 2110 when(mMockNative.sendMessage(anyShort(), anyByte(), anyInt(), any(), 2111 any(), anyInt())).thenAnswer(answerObj); 2112 2113 int remainingMessages = numberOfMessages; 2114 for (int i = 0; i < numberOfMessages; ++i) { 2115 mDut.sendMessage(clientId, sessionId.getValue(), peerIdCaptor.getValue(), null, 2116 messageIdBase + i, 0); 2117 mMockLooper.dispatchAll(); 2118 // at 1/2 interval have the system simulate transmitting a queued message over-the-air 2119 if (i % 2 == 1) { 2120 assertTrue(answerObj.process()); 2121 remainingMessages--; 2122 mMockLooper.dispatchAll(); 2123 } 2124 } 2125 for (int i = 0; i < remainingMessages; ++i) { 2126 assertTrue(answerObj.process()); 2127 mMockLooper.dispatchAll(); 2128 } 2129 assertEquals("queue empty", 0, answerObj.queueSize()); 2130 2131 inOrder.verify(mockSessionCallback, times(numberOfMessages)).onMessageSendSuccess( 2132 messageIdCaptor.capture()); 2133 for (int i = 0; i < numberOfMessages; ++i) { 2134 assertEquals("message ID: " + i, (long) messageIdBase + i, 2135 (long) messageIdCaptor.getAllValues().get(i)); 2136 } 2137 2138 verifyNoMoreInteractions(mockCallback, mockSessionCallback); 2139 } 2140 2141 /** 2142 * Validate that the host-side message queue functions. A combination of imperfect conditions: 2143 * - Failure to queue: synchronous firmware error 2144 * - Failure to queue: asyncronous firmware error 2145 * - Failure to transmit: OTA (which will be retried) 2146 * - Failure to transmit: other 2147 */ 2148 @Test 2149 public void testSendMessageQueueSequenceImperfect() throws Exception { 2150 final int clientId = 1005; 2151 final int uid = 1000; 2152 final int pid = 2000; 2153 final String callingPackage = "com.google.somePackage"; 2154 final String serviceName = "some-service-name"; 2155 final byte subscribeId = 15; 2156 final int requestorId = 22; 2157 final byte[] peerMac = HexEncoding.decode("060708090A0B".toCharArray(), false); 2158 final int messageIdBase = 6948; 2159 final int numberOfMessages = 300; 2160 final int queueDepth = 6; 2161 final int retransmitCount = 3; // not the maximum 2162 2163 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 2164 SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().setServiceName(serviceName) 2165 .build(); 2166 2167 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 2168 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 2169 IWifiAwareDiscoverySessionCallback.class); 2170 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 2171 ArgumentCaptor<Integer> sessionId = ArgumentCaptor.forClass(Integer.class); 2172 ArgumentCaptor<Integer> peerIdCaptor = ArgumentCaptor.forClass(Integer.class); 2173 InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mMockNative); 2174 2175 mDut.enableUsage(); 2176 mMockLooper.dispatchAll(); 2177 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 2178 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 2179 mMockLooper.dispatchAll(); 2180 2181 // (0) connect 2182 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 2183 mMockLooper.dispatchAll(); 2184 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), 2185 eq(configRequest), eq(false), eq(true), eq(true), eq(false)); 2186 mDut.onConfigSuccessResponse(transactionId.getValue()); 2187 mMockLooper.dispatchAll(); 2188 inOrder.verify(mockCallback).onConnectSuccess(clientId); 2189 2190 // (1) subscribe 2191 mDut.subscribe(clientId, subscribeConfig, mockSessionCallback); 2192 mMockLooper.dispatchAll(); 2193 inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq((byte) 0), 2194 eq(subscribeConfig)); 2195 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), false, subscribeId); 2196 mMockLooper.dispatchAll(); 2197 inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture()); 2198 2199 // (2) match 2200 mDut.onMatchNotification(subscribeId, requestorId, peerMac, null, null, 0, 0); 2201 mMockLooper.dispatchAll(); 2202 inOrder.verify(mockSessionCallback).onMatch(peerIdCaptor.capture(), isNull(), isNull()); 2203 2204 // (3) transmit messages: configure a mix of failures/success 2205 Set<Integer> failQueueCommandImmediately = new HashSet<>(); 2206 Set<Integer> failQueueCommandLater = new HashSet<>(); 2207 Map<Integer, Integer> numberOfRetries = new HashMap<>(); 2208 2209 int numOfSuccesses = 0; 2210 int numOfFailuresInternalFailure = 0; 2211 int numOfFailuresNoOta = 0; 2212 for (int i = 0; i < numberOfMessages; ++i) { 2213 // random results: 2214 // - 0-50: success 2215 // - 51-60: retransmit value (which will fail for >5) 2216 // - 61-70: fail queue later 2217 // - 71-80: fail queue immediately 2218 // - 81-90: fail retransmit with non-OTA failure 2219 int random = mRandomNg.nextInt(90); 2220 if (random <= 50) { 2221 numberOfRetries.put(messageIdBase + i, 0); 2222 numOfSuccesses++; 2223 } else if (random <= 60) { 2224 numberOfRetries.put(messageIdBase + i, random - 51); 2225 if (random - 51 > retransmitCount) { 2226 numOfFailuresNoOta++; 2227 } else { 2228 numOfSuccesses++; 2229 } 2230 } else if (random <= 70) { 2231 failQueueCommandLater.add(messageIdBase + i); 2232 numOfFailuresInternalFailure++; 2233 } else if (random <= 80) { 2234 failQueueCommandImmediately.add(messageIdBase + i); 2235 numOfFailuresInternalFailure++; 2236 } else { 2237 numberOfRetries.put(messageIdBase + i, -1); 2238 numOfFailuresInternalFailure++; 2239 } 2240 } 2241 2242 Log.v("WifiAwareStateManagerTest", 2243 "failQueueCommandImmediately=" + failQueueCommandImmediately 2244 + ", failQueueCommandLater=" + failQueueCommandLater + ", numberOfRetries=" 2245 + numberOfRetries + ", numOfSuccesses=" + numOfSuccesses 2246 + ", numOfFailuresInternalFailure=" + numOfFailuresInternalFailure 2247 + ", numOfFailuresNoOta=" + numOfFailuresNoOta); 2248 2249 SendMessageQueueModelAnswer answerObj = new SendMessageQueueModelAnswer(queueDepth, 2250 failQueueCommandImmediately, failQueueCommandLater, numberOfRetries); 2251 when(mMockNative.sendMessage(anyShort(), anyByte(), anyInt(), any(), 2252 any(), anyInt())).thenAnswer(answerObj); 2253 2254 for (int i = 0; i < numberOfMessages; ++i) { 2255 mDut.sendMessage(clientId, sessionId.getValue(), peerIdCaptor.getValue(), null, 2256 messageIdBase + i, retransmitCount); 2257 mMockLooper.dispatchAll(); 2258 } 2259 2260 while (answerObj.queueSize() != 0) { 2261 assertTrue(answerObj.process()); 2262 mMockLooper.dispatchAll(); 2263 } 2264 2265 verify(mockSessionCallback, times(numOfSuccesses)).onMessageSendSuccess(anyInt()); 2266 verify(mockSessionCallback, times(numOfFailuresInternalFailure)).onMessageSendFail(anyInt(), 2267 eq(NanStatusType.INTERNAL_FAILURE)); 2268 verify(mockSessionCallback, times(numOfFailuresNoOta)).onMessageSendFail(anyInt(), 2269 eq(NanStatusType.NO_OTA_ACK)); 2270 2271 verifyNoMoreInteractions(mockCallback, mockSessionCallback); 2272 } 2273 2274 /** 2275 * Validate that can send empty message successfully: null, byte[0], "" 2276 */ 2277 @Test 2278 public void testSendEmptyMessages() throws Exception { 2279 final int clientId = 1005; 2280 final int uid = 1000; 2281 final int pid = 2000; 2282 final String callingPackage = "com.google.somePackage"; 2283 final String serviceName = "some-service-name"; 2284 final String ssi = "some much longer and more arbitrary data"; 2285 final byte subscribeId = 15; 2286 final int requestorId = 22; 2287 final byte[] peerMac = HexEncoding.decode("060708090A0B".toCharArray(), false); 2288 final String peerSsi = "some peer ssi data"; 2289 final String peerMatchFilter = "filter binary array represented as string"; 2290 final int messageId = 6948; 2291 2292 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 2293 SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().setServiceName(serviceName) 2294 .setServiceSpecificInfo(ssi.getBytes()) 2295 .setSubscribeType(SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE) 2296 .build(); 2297 2298 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 2299 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 2300 IWifiAwareDiscoverySessionCallback.class); 2301 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 2302 ArgumentCaptor<Integer> sessionId = ArgumentCaptor.forClass(Integer.class); 2303 ArgumentCaptor<Integer> peerIdCaptor = ArgumentCaptor.forClass(Integer.class); 2304 ArgumentCaptor<byte[]> byteArrayCaptor = ArgumentCaptor.forClass(byte[].class); 2305 InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mMockNative); 2306 2307 mDut.enableUsage(); 2308 mMockLooper.dispatchAll(); 2309 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 2310 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 2311 mMockLooper.dispatchAll(); 2312 2313 // (0) connect 2314 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 2315 mMockLooper.dispatchAll(); 2316 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), 2317 eq(configRequest), eq(false), eq(true), eq(true), eq(false)); 2318 mDut.onConfigSuccessResponse(transactionId.getValue()); 2319 mMockLooper.dispatchAll(); 2320 inOrder.verify(mockCallback).onConnectSuccess(clientId); 2321 2322 // (1) subscribe 2323 mDut.subscribe(clientId, subscribeConfig, mockSessionCallback); 2324 mMockLooper.dispatchAll(); 2325 inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq((byte) 0), 2326 eq(subscribeConfig)); 2327 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), false, subscribeId); 2328 mMockLooper.dispatchAll(); 2329 inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture()); 2330 2331 // (2) match 2332 mDut.onMatchNotification(subscribeId, requestorId, peerMac, peerSsi.getBytes(), 2333 peerMatchFilter.getBytes(), 0, 0); 2334 mMockLooper.dispatchAll(); 2335 inOrder.verify(mockSessionCallback).onMatch(peerIdCaptor.capture(), eq(peerSsi.getBytes()), 2336 eq(peerMatchFilter.getBytes())); 2337 2338 // (3) message null Tx successful queuing 2339 mDut.sendMessage(clientId, sessionId.getValue(), peerIdCaptor.getValue(), null, messageId, 2340 0); 2341 mMockLooper.dispatchAll(); 2342 inOrder.verify(mMockNative).sendMessage(transactionId.capture(), eq(subscribeId), 2343 eq(requestorId), eq(peerMac), isNull(byte[].class), eq(messageId)); 2344 short tid = transactionId.getValue(); 2345 mDut.onMessageSendQueuedSuccessResponse(tid); 2346 mMockLooper.dispatchAll(); 2347 2348 // (4) final Tx results (on-air results) 2349 mDut.onMessageSendSuccessNotification(tid); 2350 mMockLooper.dispatchAll(); 2351 inOrder.verify(mockSessionCallback).onMessageSendSuccess(messageId); 2352 validateInternalSendMessageQueuesCleanedUp(messageId); 2353 2354 // (5) message byte[0] Tx successful queuing 2355 mDut.sendMessage(clientId, sessionId.getValue(), peerIdCaptor.getValue(), new byte[0], 2356 messageId, 0); 2357 mMockLooper.dispatchAll(); 2358 inOrder.verify(mMockNative).sendMessage(transactionId.capture(), eq(subscribeId), 2359 eq(requestorId), eq(peerMac), eq(new byte[0]), eq(messageId)); 2360 tid = transactionId.getValue(); 2361 mDut.onMessageSendQueuedSuccessResponse(tid); 2362 mMockLooper.dispatchAll(); 2363 2364 // (6) final Tx results (on-air results) 2365 mDut.onMessageSendSuccessNotification(tid); 2366 mMockLooper.dispatchAll(); 2367 inOrder.verify(mockSessionCallback).onMessageSendSuccess(messageId); 2368 validateInternalSendMessageQueuesCleanedUp(messageId); 2369 2370 // (7) message "" Tx successful queuing 2371 mDut.sendMessage(clientId, sessionId.getValue(), peerIdCaptor.getValue(), "".getBytes(), 2372 messageId, 0); 2373 mMockLooper.dispatchAll(); 2374 inOrder.verify(mMockNative).sendMessage(transactionId.capture(), eq(subscribeId), 2375 eq(requestorId), eq(peerMac), byteArrayCaptor.capture(), eq(messageId)); 2376 collector.checkThat("Empty message contents", "", 2377 equalTo(new String(byteArrayCaptor.getValue()))); 2378 tid = transactionId.getValue(); 2379 mDut.onMessageSendQueuedSuccessResponse(tid); 2380 mMockLooper.dispatchAll(); 2381 2382 // (8) final Tx results (on-air results) 2383 mDut.onMessageSendSuccessNotification(tid); 2384 mMockLooper.dispatchAll(); 2385 inOrder.verify(mockSessionCallback).onMessageSendSuccess(messageId); 2386 validateInternalSendMessageQueuesCleanedUp(messageId); 2387 2388 verifyNoMoreInteractions(mockCallback, mockSessionCallback, mMockNative); 2389 } 2390 2391 private class SendMessageQueueModelAnswer extends MockAnswerUtil.AnswerWithArguments { 2392 private final int mMaxQueueDepth; 2393 2394 // keyed by message ID 2395 private final Set<Integer> mFailQueueCommandImmediately; // return a false 2396 private final Set<Integer> mFailQueueCommandLater; // return an error != TX_QUEUE_FULL 2397 2398 // # of times to return NO_OTA_ACK before returning SUCCESS. So a 0 means success on first 2399 // try, a very large number means - never succeed (since max retry is 5). 2400 // a -1 impiles a non-OTA failure: on first attempt 2401 private final Map<Integer, Integer> mRetryLimit; 2402 2403 private final LinkedList<Short> mQueue = new LinkedList<>(); // transaction ID (tid) 2404 private final Map<Short, Integer> mMessageIdsByTid = new HashMap<>(); // tid -> message ID 2405 private final Map<Integer, Integer> mTriesUsedByMid = new HashMap<>(); // mid -> # of retx 2406 2407 SendMessageQueueModelAnswer(int maxQueueDepth, Set<Integer> failQueueCommandImmediately, 2408 Set<Integer> failQueueCommandLater, Map<Integer, Integer> numberOfRetries) { 2409 mMaxQueueDepth = maxQueueDepth; 2410 mFailQueueCommandImmediately = failQueueCommandImmediately; 2411 mFailQueueCommandLater = failQueueCommandLater; 2412 mRetryLimit = numberOfRetries; 2413 2414 if (mRetryLimit != null) { 2415 for (int mid : mRetryLimit.keySet()) { 2416 mTriesUsedByMid.put(mid, 0); 2417 } 2418 } 2419 } 2420 2421 public boolean answer(short transactionId, byte pubSubId, int requestorInstanceId, 2422 byte[] dest, byte[] message, int messageId) throws Exception { 2423 if (mFailQueueCommandImmediately != null && mFailQueueCommandImmediately.contains( 2424 messageId)) { 2425 return false; 2426 } 2427 2428 if (mFailQueueCommandLater != null && mFailQueueCommandLater.contains(messageId)) { 2429 mDut.onMessageSendQueuedFailResponse(transactionId, NanStatusType.INTERNAL_FAILURE); 2430 } else { 2431 if (mQueue.size() <= mMaxQueueDepth) { 2432 mQueue.addLast(transactionId); 2433 mMessageIdsByTid.put(transactionId, messageId); 2434 mDut.onMessageSendQueuedSuccessResponse(transactionId); 2435 } else { 2436 mDut.onMessageSendQueuedFailResponse(transactionId, 2437 NanStatusType.FOLLOWUP_TX_QUEUE_FULL); 2438 } 2439 } 2440 2441 return true; 2442 } 2443 2444 /** 2445 * Processes the first message in the queue: i.e. responds as if sent over-the-air 2446 * (successfully or failed) 2447 */ 2448 boolean process() { 2449 if (mQueue.size() == 0) { 2450 return false; 2451 } 2452 short tid = mQueue.poll(); 2453 int mid = mMessageIdsByTid.get(tid); 2454 2455 if (mRetryLimit != null && mRetryLimit.containsKey(mid)) { 2456 int numRetries = mRetryLimit.get(mid); 2457 if (numRetries == -1) { 2458 mDut.onMessageSendFailNotification(tid, NanStatusType.INTERNAL_FAILURE); 2459 } else { 2460 int currentRetries = mTriesUsedByMid.get(mid); 2461 if (currentRetries > numRetries) { 2462 return false; // shouldn't be retrying!? 2463 } else if (currentRetries == numRetries) { 2464 mDut.onMessageSendSuccessNotification(tid); 2465 } else { 2466 mDut.onMessageSendFailNotification(tid, NanStatusType.NO_OTA_ACK); 2467 } 2468 mTriesUsedByMid.put(mid, currentRetries + 1); 2469 } 2470 } else { 2471 mDut.onMessageSendSuccessNotification(tid); 2472 } 2473 2474 return true; 2475 } 2476 2477 /** 2478 * Returns the number of elements in the queue. 2479 */ 2480 int queueSize() { 2481 return mQueue.size(); 2482 } 2483 } 2484 2485 /** 2486 * Test sequence of configuration: (1) config1, (2) config2 - incompatible, 2487 * (3) config3 - compatible with config1 (requiring upgrade), (4) disconnect 2488 * config3 (should get a downgrade), (5) disconnect config1 (should get a 2489 * disable). 2490 */ 2491 @Test 2492 public void testConfigs() throws Exception { 2493 final int clientId1 = 9999; 2494 final int clientId2 = 1001; 2495 final int clientId3 = 1005; 2496 final int uid = 1000; 2497 final int pid = 2000; 2498 final String callingPackage = "com.google.somePackage"; 2499 final int masterPref1 = 111; 2500 final int masterPref3 = 115; 2501 final int dwInterval1Band24 = 2; 2502 final int dwInterval3Band24 = 1; 2503 final int dwInterval3Band5 = 0; 2504 2505 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 2506 ArgumentCaptor<ConfigRequest> crCapture = ArgumentCaptor.forClass(ConfigRequest.class); 2507 2508 ConfigRequest configRequest1 = new ConfigRequest.Builder() 2509 .setClusterLow(5).setClusterHigh(100) 2510 .setMasterPreference(masterPref1) 2511 .setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_24GHZ, dwInterval1Band24) 2512 .build(); 2513 2514 ConfigRequest configRequest2 = new ConfigRequest.Builder() 2515 .setSupport5gBand(true) // compatible 2516 .setClusterLow(7).setClusterHigh(155) // incompatible! 2517 .setMasterPreference(0) // compatible 2518 .build(); 2519 2520 ConfigRequest configRequest3 = new ConfigRequest.Builder() 2521 .setSupport5gBand(true) // compatible (will use true) 2522 .setClusterLow(5).setClusterHigh(100) // identical (hence compatible) 2523 .setMasterPreference(masterPref3) // compatible (will use max) 2524 // compatible: will use min 2525 .setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_24GHZ, dwInterval3Band24) 2526 // compatible: will use interval3 since interval1 not init 2527 .setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_5GHZ, dwInterval3Band5) 2528 .build(); 2529 2530 IWifiAwareEventCallback mockCallback1 = mock(IWifiAwareEventCallback.class); 2531 IWifiAwareEventCallback mockCallback2 = mock(IWifiAwareEventCallback.class); 2532 IWifiAwareEventCallback mockCallback3 = mock(IWifiAwareEventCallback.class); 2533 2534 InOrder inOrder = inOrder(mMockNative, mockCallback1, mockCallback2, mockCallback3); 2535 2536 mDut.enableUsage(); 2537 mMockLooper.dispatchAll(); 2538 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 2539 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 2540 mMockLooper.dispatchAll(); 2541 2542 // (1) config1 (valid) 2543 mDut.connect(clientId1, uid, pid, callingPackage, mockCallback1, configRequest1, false); 2544 mMockLooper.dispatchAll(); 2545 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), 2546 crCapture.capture(), eq(false), eq(true), eq(true), eq(false)); 2547 collector.checkThat("merge: stage 1", crCapture.getValue(), equalTo(configRequest1)); 2548 mDut.onConfigSuccessResponse(transactionId.getValue()); 2549 mMockLooper.dispatchAll(); 2550 inOrder.verify(mockCallback1).onConnectSuccess(clientId1); 2551 2552 // (2) config2 (incompatible with config1) 2553 mDut.connect(clientId2, uid, pid, callingPackage, mockCallback2, configRequest2, false); 2554 mMockLooper.dispatchAll(); 2555 inOrder.verify(mockCallback2).onConnectFail(NanStatusType.INTERNAL_FAILURE); 2556 validateInternalClientInfoCleanedUp(clientId2); 2557 2558 // (3) config3 (compatible with config1) 2559 mDut.connect(clientId3, uid, pid, callingPackage, mockCallback3, configRequest3, true); 2560 mMockLooper.dispatchAll(); 2561 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), 2562 crCapture.capture(), eq(true), eq(false), eq(true), eq(false)); 2563 mDut.onConfigSuccessResponse(transactionId.getValue()); 2564 mMockLooper.dispatchAll(); 2565 inOrder.verify(mockCallback3).onConnectSuccess(clientId3); 2566 2567 collector.checkThat("support 5g: or", true, equalTo(crCapture.getValue().mSupport5gBand)); 2568 collector.checkThat("master preference: max", Math.max(masterPref1, masterPref3), 2569 equalTo(crCapture.getValue().mMasterPreference)); 2570 collector.checkThat("dw interval on 2.4: ~min", 2571 Math.min(dwInterval1Band24, dwInterval3Band24), 2572 equalTo(crCapture.getValue().mDiscoveryWindowInterval[ConfigRequest 2573 .NAN_BAND_24GHZ])); 2574 collector.checkThat("dw interval on 5: ~min", dwInterval3Band5, 2575 equalTo(crCapture.getValue().mDiscoveryWindowInterval[ConfigRequest 2576 .NAN_BAND_5GHZ])); 2577 2578 // (4) disconnect config3: downgrade to config1 2579 mDut.disconnect(clientId3); 2580 mMockLooper.dispatchAll(); 2581 validateInternalClientInfoCleanedUp(clientId3); 2582 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), 2583 crCapture.capture(), eq(false), eq(false), eq(true), eq(false)); 2584 2585 collector.checkThat("configRequest1", configRequest1, equalTo(crCapture.getValue())); 2586 2587 mDut.onConfigSuccessResponse(transactionId.getValue()); 2588 mMockLooper.dispatchAll(); 2589 2590 // (5) disconnect config1: disable 2591 mDut.disconnect(clientId1); 2592 mMockLooper.dispatchAll(); 2593 validateInternalClientInfoCleanedUp(clientId1); 2594 inOrder.verify(mMockNative).disable(anyShort()); 2595 2596 verifyNoMoreInteractions(mMockNative, mockCallback1, mockCallback2, mockCallback3); 2597 } 2598 2599 /** 2600 * Validate that identical configuration but with different identity callback requirements 2601 * trigger the correct HAL sequence. 2602 * 1. Attach w/o identity -> enable 2603 * 2. Attach w/o identity -> nop 2604 * 3. Attach w/ identity -> re-configure 2605 * 4. Attach w/o identity -> nop 2606 * 5. Attach w/ identity -> nop 2607 */ 2608 @Test 2609 public void testConfigsIdentityCallback() throws Exception { 2610 int clientId = 9999; 2611 final int uid = 1000; 2612 final int pid = 2000; 2613 final String callingPackage = "com.google.somePackage"; 2614 2615 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 2616 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 2617 2618 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 2619 2620 InOrder inOrder = inOrder(mMockNative, mockCallback); 2621 2622 mDut.enableUsage(); 2623 mMockLooper.dispatchAll(); 2624 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 2625 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 2626 mMockLooper.dispatchAll(); 2627 2628 // (1) attach w/o identity 2629 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 2630 mMockLooper.dispatchAll(); 2631 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), 2632 any(ConfigRequest.class), eq(false), eq(true), eq(true), eq(false)); 2633 mDut.onConfigSuccessResponse(transactionId.getValue()); 2634 mMockLooper.dispatchAll(); 2635 inOrder.verify(mockCallback).onConnectSuccess(clientId); 2636 2637 // (2) attach w/o identity 2638 ++clientId; 2639 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 2640 mMockLooper.dispatchAll(); 2641 inOrder.verify(mockCallback).onConnectSuccess(clientId); 2642 2643 // (3) attach w/ identity 2644 ++clientId; 2645 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, true); 2646 mMockLooper.dispatchAll(); 2647 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), 2648 any(ConfigRequest.class), eq(true), eq(false), eq(true), eq(false)); 2649 mDut.onConfigSuccessResponse(transactionId.getValue()); 2650 mMockLooper.dispatchAll(); 2651 inOrder.verify(mockCallback).onConnectSuccess(clientId); 2652 2653 // (4) attach w/o identity 2654 ++clientId; 2655 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 2656 mMockLooper.dispatchAll(); 2657 inOrder.verify(mockCallback).onConnectSuccess(clientId); 2658 2659 // (5) attach w/ identity 2660 ++clientId; 2661 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, true); 2662 mMockLooper.dispatchAll(); 2663 inOrder.verify(mockCallback).onConnectSuccess(clientId); 2664 2665 verifyNoMoreInteractions(mMockNative, mockCallback); 2666 } 2667 2668 /** 2669 * Summary: disconnect a client while there are pending transactions. 2670 */ 2671 @Test 2672 public void testDisconnectWithPendingTransactions() throws Exception { 2673 final int clientId = 125; 2674 final int uid = 1000; 2675 final int pid = 2000; 2676 final String callingPackage = "com.google.somePackage"; 2677 final int clusterLow = 5; 2678 final int clusterHigh = 100; 2679 final int masterPref = 111; 2680 final String serviceName = "some-service-name"; 2681 final String ssi = "some much longer and more arbitrary data"; 2682 final byte publishId = 22; 2683 2684 ConfigRequest configRequest = new ConfigRequest.Builder().setClusterLow(clusterLow) 2685 .setClusterHigh(clusterHigh).setMasterPreference(masterPref).build(); 2686 2687 PublishConfig publishConfig = new PublishConfig.Builder().setServiceName( 2688 serviceName).setServiceSpecificInfo(ssi.getBytes()).setPublishType( 2689 PublishConfig.PUBLISH_TYPE_UNSOLICITED).build(); 2690 2691 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 2692 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 2693 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 2694 IWifiAwareDiscoverySessionCallback.class); 2695 InOrder inOrder = inOrder(mMockNative, mockCallback, mockSessionCallback); 2696 2697 mDut.enableUsage(); 2698 mMockLooper.dispatchAll(); 2699 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 2700 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 2701 mMockLooper.dispatchAll(); 2702 2703 // (1) connect 2704 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 2705 mMockLooper.dispatchAll(); 2706 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 2707 eq(false), eq(true), eq(true), eq(false)); 2708 mDut.onConfigSuccessResponse(transactionId.getValue()); 2709 mMockLooper.dispatchAll(); 2710 inOrder.verify(mockCallback).onConnectSuccess(clientId); 2711 2712 // (2) publish (no response yet) 2713 mDut.publish(clientId, publishConfig, mockSessionCallback); 2714 mMockLooper.dispatchAll(); 2715 inOrder.verify(mMockNative).publish(transactionId.capture(), eq((byte) 0), 2716 eq(publishConfig)); 2717 2718 // (3) disconnect (but doesn't get executed until get a RESPONSE to the 2719 // previous publish) 2720 mDut.disconnect(clientId); 2721 mMockLooper.dispatchAll(); 2722 2723 // (4) get successful response to the publish 2724 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), true, publishId); 2725 mMockLooper.dispatchAll(); 2726 inOrder.verify(mockSessionCallback).onSessionStarted(anyInt()); 2727 inOrder.verify(mMockNative).stopPublish((short) 0, publishId); 2728 inOrder.verify(mMockNative).disable(anyShort()); 2729 2730 validateInternalClientInfoCleanedUp(clientId); 2731 2732 // (5) trying to publish on the same client: NOP 2733 mDut.publish(clientId, publishConfig, mockSessionCallback); 2734 mMockLooper.dispatchAll(); 2735 2736 // (6) got some callback on original publishId - should be ignored 2737 mDut.onSessionTerminatedNotification(publishId, 0, true); 2738 mMockLooper.dispatchAll(); 2739 2740 verifyNoMoreInteractions(mMockNative, mockCallback, mockSessionCallback); 2741 } 2742 2743 /** 2744 * Validate that an unknown transaction (i.e. a callback from HAL with an 2745 * unknown type) is simply ignored - but also cleans up its state. 2746 */ 2747 @Test 2748 public void testUnknownTransactionType() throws Exception { 2749 final int clientId = 129; 2750 final int uid = 1000; 2751 final int pid = 2000; 2752 final String callingPackage = "com.google.somePackage"; 2753 final int clusterLow = 15; 2754 final int clusterHigh = 192; 2755 final int masterPref = 234; 2756 final String serviceName = "some-service-name"; 2757 final String ssi = "some much longer and more arbitrary data"; 2758 2759 ConfigRequest configRequest = new ConfigRequest.Builder().setClusterLow(clusterLow) 2760 .setClusterHigh(clusterHigh).setMasterPreference(masterPref).build(); 2761 2762 PublishConfig publishConfig = new PublishConfig.Builder().setServiceName( 2763 serviceName).setServiceSpecificInfo(ssi.getBytes()).setPublishType( 2764 PublishConfig.PUBLISH_TYPE_UNSOLICITED).build(); 2765 2766 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 2767 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 2768 IWifiAwareDiscoverySessionCallback mockPublishSessionCallback = mock( 2769 IWifiAwareDiscoverySessionCallback.class); 2770 InOrder inOrder = inOrder(mMockNative, mockCallback, mockPublishSessionCallback); 2771 2772 mDut.enableUsage(); 2773 mMockLooper.dispatchAll(); 2774 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 2775 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 2776 mMockLooper.dispatchAll(); 2777 2778 // (1) connect 2779 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 2780 mMockLooper.dispatchAll(); 2781 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 2782 eq(false), eq(true), eq(true), eq(false)); 2783 mDut.onConfigSuccessResponse(transactionId.getValue()); 2784 mMockLooper.dispatchAll(); 2785 inOrder.verify(mockCallback).onConnectSuccess(clientId); 2786 2787 // (2) publish - no response 2788 mDut.publish(clientId, publishConfig, mockPublishSessionCallback); 2789 mMockLooper.dispatchAll(); 2790 inOrder.verify(mMockNative).publish(transactionId.capture(), eq((byte) 0), 2791 eq(publishConfig)); 2792 2793 verifyNoMoreInteractions(mMockNative, mockCallback, mockPublishSessionCallback); 2794 } 2795 2796 /** 2797 * Validate that a NoOp transaction (i.e. a callback from HAL which doesn't 2798 * require any action except clearing up state) actually cleans up its state 2799 * (and does nothing else). 2800 */ 2801 @Test 2802 public void testNoOpTransaction() throws Exception { 2803 final int clientId = 1294; 2804 final int uid = 1000; 2805 final int pid = 2000; 2806 final String callingPackage = "com.google.somePackage"; 2807 2808 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 2809 2810 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 2811 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 2812 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 2813 IWifiAwareDiscoverySessionCallback.class); 2814 InOrder inOrder = inOrder(mMockNative, mockCallback, mockSessionCallback); 2815 2816 mDut.enableUsage(); 2817 mMockLooper.dispatchAll(); 2818 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 2819 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 2820 mMockLooper.dispatchAll(); 2821 2822 // (1) connect (no response) 2823 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 2824 mMockLooper.dispatchAll(); 2825 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 2826 eq(false), eq(true), eq(true), eq(false)); 2827 2828 verifyNoMoreInteractions(mMockNative, mockCallback, mockSessionCallback); 2829 } 2830 2831 /** 2832 * Validate that getting callbacks from HAL with unknown (expired) 2833 * transaction ID or invalid publish/subscribe ID session doesn't have any 2834 * impact. 2835 */ 2836 @Test 2837 public void testInvalidCallbackIdParameters() throws Exception { 2838 final byte pubSubId = 125; 2839 final int clientId = 132; 2840 final int uid = 1000; 2841 final int pid = 2000; 2842 final String callingPackage = "com.google.somePackage"; 2843 2844 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 2845 2846 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 2847 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 2848 InOrder inOrder = inOrder(mMockNative, mockCallback); 2849 2850 mDut.enableUsage(); 2851 mMockLooper.dispatchAll(); 2852 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 2853 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 2854 mMockLooper.dispatchAll(); 2855 2856 // (1) connect and succeed 2857 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 2858 mMockLooper.dispatchAll(); 2859 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 2860 eq(false), eq(true), eq(true), eq(false)); 2861 short transactionIdConfig = transactionId.getValue(); 2862 mDut.onConfigSuccessResponse(transactionIdConfig); 2863 mMockLooper.dispatchAll(); 2864 inOrder.verify(mockCallback).onConnectSuccess(clientId); 2865 2866 // (2) use the same transaction ID to send a bunch of other responses 2867 mDut.onConfigSuccessResponse(transactionIdConfig); 2868 mDut.onConfigFailedResponse(transactionIdConfig, -1); 2869 mDut.onSessionConfigFailResponse(transactionIdConfig, true, -1); 2870 mDut.onMessageSendQueuedSuccessResponse(transactionIdConfig); 2871 mDut.onMessageSendQueuedFailResponse(transactionIdConfig, -1); 2872 mDut.onSessionConfigFailResponse(transactionIdConfig, false, -1); 2873 mDut.onMatchNotification(-1, -1, new byte[0], new byte[0], new byte[0], 0, 0); 2874 mDut.onSessionTerminatedNotification(-1, -1, true); 2875 mDut.onSessionTerminatedNotification(-1, -1, false); 2876 mDut.onMessageReceivedNotification(-1, -1, new byte[0], new byte[0]); 2877 mDut.onSessionConfigSuccessResponse(transactionIdConfig, true, pubSubId); 2878 mDut.onSessionConfigSuccessResponse(transactionIdConfig, false, pubSubId); 2879 mMockLooper.dispatchAll(); 2880 2881 verifyNoMoreInteractions(mMockNative, mockCallback); 2882 } 2883 2884 /** 2885 * Validate that trying to update-subscribe on a publish session fails. 2886 */ 2887 @Test 2888 public void testSubscribeOnPublishSessionType() throws Exception { 2889 final int clientId = 188; 2890 final int uid = 1000; 2891 final int pid = 2000; 2892 final String callingPackage = "com.google.somePackage"; 2893 final byte publishId = 25; 2894 2895 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 2896 PublishConfig publishConfig = new PublishConfig.Builder().build(); 2897 SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build(); 2898 2899 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 2900 ArgumentCaptor<Integer> sessionId = ArgumentCaptor.forClass(Integer.class); 2901 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 2902 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 2903 IWifiAwareDiscoverySessionCallback.class); 2904 InOrder inOrder = inOrder(mMockNative, mockCallback, mockSessionCallback); 2905 2906 mDut.enableUsage(); 2907 mMockLooper.dispatchAll(); 2908 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 2909 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 2910 mMockLooper.dispatchAll(); 2911 2912 // (1) connect 2913 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 2914 mMockLooper.dispatchAll(); 2915 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 2916 eq(false), eq(true), eq(true), eq(false)); 2917 mDut.onConfigSuccessResponse(transactionId.getValue()); 2918 mMockLooper.dispatchAll(); 2919 inOrder.verify(mockCallback).onConnectSuccess(clientId); 2920 2921 // (2) publish 2922 mDut.publish(clientId, publishConfig, mockSessionCallback); 2923 mMockLooper.dispatchAll(); 2924 inOrder.verify(mMockNative).publish(transactionId.capture(), eq((byte) 0), 2925 eq(publishConfig)); 2926 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), true, publishId); 2927 mMockLooper.dispatchAll(); 2928 inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture()); 2929 2930 // (3) update-subscribe -> failure 2931 mDut.updateSubscribe(clientId, sessionId.getValue(), subscribeConfig); 2932 mMockLooper.dispatchAll(); 2933 inOrder.verify(mockSessionCallback).onSessionConfigFail(NanStatusType.INTERNAL_FAILURE); 2934 2935 verifyNoMoreInteractions(mMockNative, mockCallback, mockSessionCallback); 2936 } 2937 2938 /** 2939 * Validate that trying to (re)subscribe on a publish session or (re)publish 2940 * on a subscribe session fails. 2941 */ 2942 @Test 2943 public void testPublishOnSubscribeSessionType() throws Exception { 2944 final int clientId = 188; 2945 final int uid = 1000; 2946 final int pid = 2000; 2947 final String callingPackage = "com.google.somePackage"; 2948 final byte subscribeId = 25; 2949 2950 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 2951 PublishConfig publishConfig = new PublishConfig.Builder().build(); 2952 SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build(); 2953 2954 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 2955 ArgumentCaptor<Integer> sessionId = ArgumentCaptor.forClass(Integer.class); 2956 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 2957 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 2958 IWifiAwareDiscoverySessionCallback.class); 2959 InOrder inOrder = inOrder(mMockNative, mockCallback, mockSessionCallback); 2960 2961 mDut.enableUsage(); 2962 mMockLooper.dispatchAll(); 2963 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 2964 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 2965 mMockLooper.dispatchAll(); 2966 2967 // (1) connect 2968 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 2969 mMockLooper.dispatchAll(); 2970 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), 2971 eq(configRequest), eq(false), eq(true), eq(true), eq(false)); 2972 mDut.onConfigSuccessResponse(transactionId.getValue()); 2973 mMockLooper.dispatchAll(); 2974 inOrder.verify(mockCallback).onConnectSuccess(clientId); 2975 2976 // (2) subscribe 2977 mDut.subscribe(clientId, subscribeConfig, mockSessionCallback); 2978 mMockLooper.dispatchAll(); 2979 inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq((byte) 0), 2980 eq(subscribeConfig)); 2981 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), false, subscribeId); 2982 mMockLooper.dispatchAll(); 2983 inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture()); 2984 2985 // (3) update-publish -> error 2986 mDut.updatePublish(clientId, sessionId.getValue(), publishConfig); 2987 mMockLooper.dispatchAll(); 2988 inOrder.verify(mockSessionCallback).onSessionConfigFail(NanStatusType.INTERNAL_FAILURE); 2989 2990 verifyNoMoreInteractions(mMockNative, mockCallback, mockSessionCallback); 2991 } 2992 2993 /** 2994 * Validate that the session ID increments monotonically 2995 */ 2996 @Test 2997 public void testSessionIdIncrement() throws Exception { 2998 final int clientId = 188; 2999 final int uid = 1000; 3000 final int pid = 2000; 3001 final String callingPackage = "com.google.somePackage"; 3002 int loopCount = 100; 3003 3004 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 3005 PublishConfig publishConfig = new PublishConfig.Builder().build(); 3006 3007 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 3008 ArgumentCaptor<Integer> sessionId = ArgumentCaptor.forClass(Integer.class); 3009 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 3010 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 3011 IWifiAwareDiscoverySessionCallback.class); 3012 InOrder inOrder = inOrder(mMockNative, mockCallback, mockSessionCallback); 3013 3014 mDut.enableUsage(); 3015 mMockLooper.dispatchAll(); 3016 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 3017 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 3018 mMockLooper.dispatchAll(); 3019 3020 // (1) connect 3021 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 3022 mMockLooper.dispatchAll(); 3023 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), 3024 eq(configRequest), eq(false), eq(true), eq(true), eq(false)); 3025 mDut.onConfigSuccessResponse(transactionId.getValue()); 3026 mMockLooper.dispatchAll(); 3027 inOrder.verify(mockCallback).onConnectSuccess(clientId); 3028 3029 int prevId = 0; 3030 for (int i = 0; i < loopCount; ++i) { 3031 // (2) publish 3032 mDut.publish(clientId, publishConfig, mockSessionCallback); 3033 mMockLooper.dispatchAll(); 3034 inOrder.verify(mMockNative).publish(transactionId.capture(), eq((byte) 0), 3035 eq(publishConfig)); 3036 3037 // (3) publish-success 3038 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), true, (byte) (i + 1)); 3039 mMockLooper.dispatchAll(); 3040 inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture()); 3041 3042 if (i != 0) { 3043 assertTrue("Session ID incrementing", sessionId.getValue() > prevId); 3044 } 3045 prevId = sessionId.getValue(); 3046 } 3047 } 3048 3049 /** 3050 * Validate configuration changes on power state changes when Aware is not disabled on doze. 3051 */ 3052 @Test 3053 public void testConfigOnPowerStateChanges() throws Exception { 3054 final int clientId = 188; 3055 final int uid = 1000; 3056 final int pid = 2000; 3057 final String callingPackage = "com.google.somePackage"; 3058 3059 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 3060 3061 setSettableParam(WifiAwareStateManager.PARAM_ON_IDLE_DISABLE_AWARE, Integer.toString(0), 3062 true); 3063 3064 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 3065 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 3066 InOrder inOrder = inOrder(mMockNative, mockCallback); 3067 3068 mDut.enableUsage(); 3069 mMockLooper.dispatchAll(); 3070 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 3071 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 3072 mMockLooper.dispatchAll(); 3073 3074 // (1) connect 3075 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 3076 mMockLooper.dispatchAll(); 3077 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), 3078 eq(configRequest), eq(false), eq(true), eq(true), eq(false)); 3079 mDut.onConfigSuccessResponse(transactionId.getValue()); 3080 mMockLooper.dispatchAll(); 3081 inOrder.verify(mockCallback).onConnectSuccess(clientId); 3082 3083 // (2) power state change: SCREEN OFF 3084 simulatePowerStateChangeInteractive(false); 3085 mMockLooper.dispatchAll(); 3086 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), 3087 eq(configRequest), eq(false), eq(false), eq(false), eq(false)); 3088 mDut.onConfigSuccessResponse(transactionId.getValue()); 3089 mMockLooper.dispatchAll(); 3090 3091 // (3) power state change: DOZE 3092 simulatePowerStateChangeDoze(true); 3093 mMockLooper.dispatchAll(); 3094 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), 3095 eq(configRequest), eq(false), eq(false), eq(false), eq(true)); 3096 mDut.onConfigSuccessResponse(transactionId.getValue()); 3097 mMockLooper.dispatchAll(); 3098 3099 // (4) restore power state to default 3100 simulatePowerStateChangeInteractive(true); // effectively treated as no-doze 3101 mMockLooper.dispatchAll(); 3102 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), 3103 eq(configRequest), eq(false), eq(false), eq(true), eq(true)); 3104 mDut.onConfigSuccessResponse(transactionId.getValue()); 3105 mMockLooper.dispatchAll(); 3106 3107 verifyNoMoreInteractions(mMockNative, mockCallback); 3108 } 3109 3110 /** 3111 * Validate aware enable/disable during doze transitions. 3112 */ 3113 @Test 3114 public void testEnableDisableOnDoze() throws Exception { 3115 final int clientId = 188; 3116 final int uid = 1000; 3117 final int pid = 2000; 3118 final String callingPackage = "com.google.somePackage"; 3119 3120 setSettableParam(WifiAwareStateManager.PARAM_ON_IDLE_DISABLE_AWARE, Integer.toString(1), 3121 true); 3122 3123 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 3124 3125 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 3126 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 3127 InOrder inOrder = inOrder(mMockContext, mMockNativeManager, mMockNative, mockCallback); 3128 inOrder.verify(mMockNativeManager).start(any(Handler.class)); 3129 3130 mDut.enableUsage(); 3131 mMockLooper.dispatchAll(); 3132 inOrder.verify(mMockNativeManager).tryToGetAware(); 3133 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 3134 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 3135 mMockLooper.dispatchAll(); 3136 inOrder.verify(mMockNativeManager).releaseAware(); 3137 3138 // (1) connect 3139 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 3140 mMockLooper.dispatchAll(); 3141 inOrder.verify(mMockNativeManager).tryToGetAware(); 3142 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), 3143 eq(configRequest), eq(false), eq(true), eq(true), eq(false)); 3144 mDut.onConfigSuccessResponse(transactionId.getValue()); 3145 mMockLooper.dispatchAll(); 3146 inOrder.verify(mockCallback).onConnectSuccess(clientId); 3147 3148 // (3) power state change: DOZE 3149 simulatePowerStateChangeDoze(true); 3150 mMockLooper.dispatchAll(); 3151 inOrder.verify(mMockNative).disable(transactionId.capture()); 3152 mDut.onDisableResponse(transactionId.getValue(), NanStatusType.SUCCESS); 3153 validateCorrectAwareStatusChangeBroadcast(inOrder, false); 3154 3155 // (4) power state change: SCREEN ON (but DOZE still on - fakish but expect no changes) 3156 simulatePowerStateChangeInteractive(false); 3157 mMockLooper.dispatchAll(); 3158 3159 // and same for other gating changes -> no changes 3160 simulateLocationModeChange(false); 3161 simulateWifiStateChange(false); 3162 mMockLooper.dispatchAll(); 3163 3164 // and same for other gating changes -> no changes 3165 simulateLocationModeChange(true); 3166 simulateWifiStateChange(true); 3167 mMockLooper.dispatchAll(); 3168 3169 // (5) power state change: DOZE OFF 3170 simulatePowerStateChangeDoze(false); 3171 mMockLooper.dispatchAll(); 3172 validateCorrectAwareStatusChangeBroadcast(inOrder, true); 3173 3174 verifyNoMoreInteractions(mMockNativeManager, mMockNative, mockCallback); 3175 } 3176 3177 /** 3178 * Validate aware enable/disable during LOCATION MODE transitions. 3179 */ 3180 @Test 3181 public void testEnableDisableOnLocationModeChanges() throws Exception { 3182 final int clientId = 188; 3183 final int uid = 1000; 3184 final int pid = 2000; 3185 final String callingPackage = "com.google.somePackage"; 3186 3187 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 3188 3189 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 3190 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 3191 InOrder inOrder = inOrder(mMockContext, mMockNativeManager, mMockNative, mockCallback); 3192 inOrder.verify(mMockNativeManager).start(any(Handler.class)); 3193 3194 mDut.enableUsage(); 3195 mMockLooper.dispatchAll(); 3196 inOrder.verify(mMockNativeManager).tryToGetAware(); 3197 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 3198 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 3199 mMockLooper.dispatchAll(); 3200 inOrder.verify(mMockNativeManager).releaseAware(); 3201 3202 // (1) connect 3203 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 3204 mMockLooper.dispatchAll(); 3205 inOrder.verify(mMockNativeManager).tryToGetAware(); 3206 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), 3207 eq(configRequest), eq(false), eq(true), eq(true), eq(false)); 3208 mDut.onConfigSuccessResponse(transactionId.getValue()); 3209 mMockLooper.dispatchAll(); 3210 inOrder.verify(mockCallback).onConnectSuccess(clientId); 3211 3212 // (3) location mode change: disable 3213 simulateLocationModeChange(false); 3214 mMockLooper.dispatchAll(); 3215 inOrder.verify(mMockNative).disable(transactionId.capture()); 3216 mDut.onDisableResponse(transactionId.getValue(), NanStatusType.SUCCESS); 3217 validateCorrectAwareStatusChangeBroadcast(inOrder, false); 3218 3219 // disable other gating feature -> no change 3220 simulatePowerStateChangeDoze(true); 3221 simulateWifiStateChange(false); 3222 mMockLooper.dispatchAll(); 3223 3224 // enable other gating feature -> no change 3225 simulatePowerStateChangeDoze(false); 3226 simulateWifiStateChange(true); 3227 mMockLooper.dispatchAll(); 3228 3229 // (4) location mode change: enable 3230 simulateLocationModeChange(true); 3231 mMockLooper.dispatchAll(); 3232 validateCorrectAwareStatusChangeBroadcast(inOrder, true); 3233 3234 verifyNoMoreInteractions(mMockNativeManager, mMockNative, mockCallback); 3235 } 3236 3237 /** 3238 * Validate aware enable/disable during Wi-Fi State transitions. 3239 */ 3240 @Test 3241 public void testEnableDisableOnWifiStateChanges() throws Exception { 3242 final int clientId = 188; 3243 final int uid = 1000; 3244 final int pid = 2000; 3245 final String callingPackage = "com.google.somePackage"; 3246 3247 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 3248 3249 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 3250 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 3251 InOrder inOrder = inOrder(mMockContext, mMockNativeManager, mMockNative, mockCallback); 3252 inOrder.verify(mMockNativeManager).start(any(Handler.class)); 3253 3254 mDut.enableUsage(); 3255 mMockLooper.dispatchAll(); 3256 inOrder.verify(mMockNativeManager).tryToGetAware(); 3257 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 3258 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 3259 mMockLooper.dispatchAll(); 3260 inOrder.verify(mMockNativeManager).releaseAware(); 3261 3262 // (1) connect 3263 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 3264 mMockLooper.dispatchAll(); 3265 inOrder.verify(mMockNativeManager).tryToGetAware(); 3266 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), 3267 eq(configRequest), eq(false), eq(true), eq(true), eq(false)); 3268 mDut.onConfigSuccessResponse(transactionId.getValue()); 3269 mMockLooper.dispatchAll(); 3270 inOrder.verify(mockCallback).onConnectSuccess(clientId); 3271 3272 // (3) wifi state change: disable 3273 simulateWifiStateChange(false); 3274 mMockLooper.dispatchAll(); 3275 inOrder.verify(mMockNative).disable(transactionId.capture()); 3276 mDut.onDisableResponse(transactionId.getValue(), NanStatusType.SUCCESS); 3277 validateCorrectAwareStatusChangeBroadcast(inOrder, false); 3278 3279 // disable other gating feature -> no change 3280 simulatePowerStateChangeDoze(true); 3281 simulateLocationModeChange(false); 3282 mMockLooper.dispatchAll(); 3283 3284 // enable other gating feature -> no change 3285 simulatePowerStateChangeDoze(false); 3286 simulateLocationModeChange(true); 3287 mMockLooper.dispatchAll(); 3288 3289 // (4) wifi state change: enable 3290 simulateWifiStateChange(true); 3291 mMockLooper.dispatchAll(); 3292 validateCorrectAwareStatusChangeBroadcast(inOrder, true); 3293 3294 verifyNoMoreInteractions(mMockNativeManager, mMockNative, mockCallback); 3295 } 3296 3297 /* 3298 * Tests of internal state of WifiAwareStateManager: very limited (not usually 3299 * a good idea). However, these test that the internal state is cleaned-up 3300 * appropriately. Alternatively would cause issues with memory leaks or 3301 * information leak between sessions. 3302 */ 3303 3304 /** 3305 * Utility routine used to validate that the internal state is cleaned-up 3306 * after a client is disconnected. To be used in every test which terminates 3307 * a client. 3308 * 3309 * @param clientId The ID of the client which should be deleted. 3310 */ 3311 private void validateInternalClientInfoCleanedUp(int clientId) throws Exception { 3312 WifiAwareClientState client = getInternalClientState(mDut, clientId); 3313 collector.checkThat("Client record not cleared up for clientId=" + clientId, client, 3314 nullValue()); 3315 } 3316 3317 /** 3318 * Utility routine used to validate that the internal state is cleaned-up 3319 * (deleted) after a session is terminated through API (not callback!). To 3320 * be used in every test which terminates a session. 3321 * 3322 * @param clientId The ID of the client containing the session. 3323 * @param sessionId The ID of the terminated session. 3324 */ 3325 private void validateInternalSessionInfoCleanedUp(int clientId, int sessionId) 3326 throws Exception { 3327 WifiAwareClientState client = getInternalClientState(mDut, clientId); 3328 collector.checkThat("Client record exists clientId=" + clientId, client, notNullValue()); 3329 WifiAwareDiscoverySessionState session = getInternalSessionState(client, sessionId); 3330 collector.checkThat("Client record not cleaned-up for sessionId=" + sessionId, session, 3331 nullValue()); 3332 } 3333 3334 /** 3335 * Utility routine used to validate that the internal state is cleaned-up 3336 * (deleted) correctly. Checks that a specific client has no sessions 3337 * attached to it. 3338 * 3339 * @param clientId The ID of the client which we want to check. 3340 */ 3341 private void validateInternalNoSessions(int clientId) throws Exception { 3342 WifiAwareClientState client = getInternalClientState(mDut, clientId); 3343 collector.checkThat("Client record exists clientId=" + clientId, client, notNullValue()); 3344 3345 Field field = WifiAwareClientState.class.getDeclaredField("mSessions"); 3346 field.setAccessible(true); 3347 @SuppressWarnings("unchecked") 3348 SparseArray<WifiAwareDiscoverySessionState> sessions = 3349 (SparseArray<WifiAwareDiscoverySessionState>) field.get(client); 3350 3351 collector.checkThat("No sessions exist for clientId=" + clientId, sessions.size(), 3352 equalTo(0)); 3353 } 3354 3355 /** 3356 * Validates that the broadcast sent on Aware status change is correct. 3357 * 3358 * @param expectedEnabled The expected change status - i.e. are we expected 3359 * to announce that Aware is enabled (true) or disabled (false). 3360 */ 3361 private void validateCorrectAwareStatusChangeBroadcast(InOrder inOrder, 3362 boolean expectedEnabled) { 3363 ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class); 3364 3365 inOrder.verify(mMockContext).sendBroadcastAsUser(intent.capture(), eq(UserHandle.ALL)); 3366 3367 collector.checkThat("intent action", intent.getValue().getAction(), 3368 equalTo(WifiAwareManager.ACTION_WIFI_AWARE_STATE_CHANGED)); 3369 } 3370 3371 /* 3372 * Utilities 3373 */ 3374 private void setSettableParam(String name, String value, boolean expectSuccess) { 3375 PrintWriter pwMock = mock(PrintWriter.class); 3376 WifiAwareShellCommand parentShellMock = mock(WifiAwareShellCommand.class); 3377 when(parentShellMock.getNextArgRequired()).thenReturn("set").thenReturn(name).thenReturn( 3378 value); 3379 when(parentShellMock.getErrPrintWriter()).thenReturn(pwMock); 3380 3381 collector.checkThat(mDut.onCommand(parentShellMock), equalTo(expectSuccess ? 0 : -1)); 3382 } 3383 3384 private void dumpDut(String prefix) { 3385 StringWriter sw = new StringWriter(); 3386 mDut.dump(null, new PrintWriter(sw), null); 3387 Log.e("WifiAwareStateManagerTest", prefix + sw.toString()); 3388 } 3389 3390 private static void installMocksInStateManager(WifiAwareStateManager awareStateManager, 3391 WifiAwareDataPathStateManager mockDpMgr) 3392 throws Exception { 3393 Field field = WifiAwareStateManager.class.getDeclaredField("mDataPathMgr"); 3394 field.setAccessible(true); 3395 field.set(awareStateManager, mockDpMgr); 3396 } 3397 3398 private static WifiAwareClientState getInternalClientState(WifiAwareStateManager dut, 3399 int clientId) throws Exception { 3400 Field field = WifiAwareStateManager.class.getDeclaredField("mClients"); 3401 field.setAccessible(true); 3402 @SuppressWarnings("unchecked") 3403 SparseArray<WifiAwareClientState> clients = (SparseArray<WifiAwareClientState>) field.get( 3404 dut); 3405 3406 return clients.get(clientId); 3407 } 3408 3409 private static WifiAwareDiscoverySessionState getInternalSessionState( 3410 WifiAwareClientState client, int sessionId) throws Exception { 3411 Field field = WifiAwareClientState.class.getDeclaredField("mSessions"); 3412 field.setAccessible(true); 3413 @SuppressWarnings("unchecked") 3414 SparseArray<WifiAwareDiscoverySessionState> sessions = 3415 (SparseArray<WifiAwareDiscoverySessionState>) field.get(client); 3416 3417 return sessions.get(sessionId); 3418 } 3419 3420 private void validateInternalSendMessageQueuesCleanedUp(int messageId) throws Exception { 3421 Field field = WifiAwareStateManager.class.getDeclaredField("mSm"); 3422 field.setAccessible(true); 3423 WifiAwareStateManager.WifiAwareStateMachine sm = 3424 (WifiAwareStateManager.WifiAwareStateMachine) field.get(mDut); 3425 3426 field = WifiAwareStateManager.WifiAwareStateMachine.class.getDeclaredField( 3427 "mHostQueuedSendMessages"); 3428 field.setAccessible(true); 3429 SparseArray<Message> hostQueuedSendMessages = (SparseArray<Message>) field.get(sm); 3430 3431 field = WifiAwareStateManager.WifiAwareStateMachine.class.getDeclaredField( 3432 "mFwQueuedSendMessages"); 3433 field.setAccessible(true); 3434 Map<Short, Message> fwQueuedSendMessages = (Map<Short, Message>) field.get(sm); 3435 3436 for (int i = 0; i < hostQueuedSendMessages.size(); ++i) { 3437 Message msg = hostQueuedSendMessages.valueAt(i); 3438 if (msg.getData().getInt("message_id") == messageId) { 3439 collector.checkThat( 3440 "Message not cleared-up from host queue. Message ID=" + messageId, msg, 3441 nullValue()); 3442 } 3443 } 3444 3445 for (Message msg: fwQueuedSendMessages.values()) { 3446 if (msg.getData().getInt("message_id") == messageId) { 3447 collector.checkThat( 3448 "Message not cleared-up from firmware queue. Message ID=" + messageId, msg, 3449 nullValue()); 3450 } 3451 } 3452 } 3453 3454 /** 3455 * Simulate power state change due to doze. Changes the power manager return values and 3456 * dispatches a broadcast. 3457 */ 3458 private void simulatePowerStateChangeDoze(boolean isDozeOn) { 3459 when(mMockPowerManager.isDeviceIdleMode()).thenReturn(isDozeOn); 3460 3461 Intent intent = new Intent(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED); 3462 mPowerBcastReceiver.onReceive(mMockContext, intent); 3463 } 3464 3465 /** 3466 * Simulate power state change due to interactive mode change (screen on/off). Changes the power 3467 * manager return values and dispatches a broadcast. 3468 */ 3469 private void simulatePowerStateChangeInteractive(boolean isInteractive) { 3470 when(mMockPowerManager.isInteractive()).thenReturn(isInteractive); 3471 3472 Intent intent = new Intent( 3473 isInteractive ? Intent.ACTION_SCREEN_ON : Intent.ACTION_SCREEN_OFF); 3474 mPowerBcastReceiver.onReceive(mMockContext, intent); 3475 } 3476 3477 /** 3478 * Simulate Location Mode change. Changes the location manager return values and dispatches a 3479 * broadcast. 3480 */ 3481 private void simulateLocationModeChange(boolean isLocationModeEnabled) { 3482 when(mLocationManagerMock.isLocationEnabled()).thenReturn(isLocationModeEnabled); 3483 3484 Intent intent = new Intent(LocationManager.MODE_CHANGED_ACTION); 3485 mLocationModeReceiver.onReceive(mMockContext, intent); 3486 } 3487 3488 /** 3489 * Simulate Wi-Fi state change: broadcast state change and modify the API return value. 3490 */ 3491 private void simulateWifiStateChange(boolean isWifiOn) { 3492 when(mMockWifiManager.getWifiState()).thenReturn( 3493 isWifiOn ? WifiManager.WIFI_STATE_ENABLED : WifiManager.WIFI_STATE_DISABLED); 3494 3495 Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION); 3496 intent.putExtra(WifiManager.EXTRA_WIFI_STATE, 3497 isWifiOn ? WifiManager.WIFI_STATE_ENABLED : WifiManager.WIFI_STATE_DISABLED); 3498 mWifiStateChangedReceiver.onReceive(mMockContext, intent); 3499 } 3500 3501 private static Capabilities getCapabilities() { 3502 Capabilities cap = new Capabilities(); 3503 cap.maxConcurrentAwareClusters = 1; 3504 cap.maxPublishes = 2; 3505 cap.maxSubscribes = 2; 3506 cap.maxServiceNameLen = 255; 3507 cap.maxMatchFilterLen = 255; 3508 cap.maxTotalMatchFilterLen = 255; 3509 cap.maxServiceSpecificInfoLen = 255; 3510 cap.maxExtendedServiceSpecificInfoLen = 255; 3511 cap.maxNdiInterfaces = 1; 3512 cap.maxNdpSessions = 1; 3513 cap.maxAppInfoLen = 255; 3514 cap.maxQueuedTransmitMessages = 6; 3515 return cap; 3516 } 3517 3518 private static class Mutable<E> { 3519 public E value; 3520 3521 Mutable() { 3522 value = null; 3523 } 3524 3525 Mutable(E value) { 3526 this.value = value; 3527 } 3528 } 3529 } 3530 3531