• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
setUp()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
tearDown()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
testSetParameterShellCommandSuccess()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
testSetParameterShellCommandInvalidParameterName()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
testSetParameterShellCommandInvalidValue()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
testRequestMacAddresses()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
testAwareDataPathInterfaceUpDown()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
testDisableUsageDisablesApis()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
testDisableUsageFlow()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
testHalFailureEnableAndConfigure()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
testAwareEventsDelivery()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
testHalNoResponseTimeout()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
testPublishFail()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
testPublishSuccessTerminated()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
testPublishUpdateFail()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
testDisconnectWhilePublishPending()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
testSubscribeFail()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
testSubscribeSuccessTerminated()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
testSubscribeUpdateFail()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
testDisconnectWhileSubscribePending()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
testMatchAndMessages()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
testMultipleMessageSources()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
testMessageWhilePeerChangesIdentity()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
testSendMessageToInvalidPeerId()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
testSendMessageErrorsImmediateQueueTimeout()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
testSendMessageRetransmitSuccess()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
testSendMessageRetransmitFail()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
testSendMessageQueueSequence()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
testSendMessageQueueSequenceImperfect()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
testSendEmptyMessages()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 
SendMessageQueueModelAnswer(int maxQueueDepth, Set<Integer> failQueueCommandImmediately, Set<Integer> failQueueCommandLater, Map<Integer, Integer> numberOfRetries)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 
answer(short transactionId, byte pubSubId, int requestorInstanceId, byte[] dest, byte[] message, int messageId)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          */
process()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          */
queueSize()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
testConfigs()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
testConfigsIdentityCallback()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
testDisconnectWithPendingTransactions()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
testUnknownTransactionType()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
testNoOpTransaction()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
testInvalidCallbackIdParameters()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
testSubscribeOnPublishSessionType()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
testPublishOnSubscribeSessionType()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
testSessionIdIncrement()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
testConfigOnPowerStateChanges()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
testEnableDisableOnDoze()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
testEnableDisableOnLocationModeChanges()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
testEnableDisableOnWifiStateChanges()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      */
validateInternalClientInfoCleanedUp(int clientId)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      */
validateInternalSessionInfoCleanedUp(int clientId, int sessionId)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      */
validateInternalNoSessions(int clientId)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      */
validateCorrectAwareStatusChangeBroadcast(InOrder inOrder, boolean expectedEnabled)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      */
setSettableParam(String name, String value, boolean expectSuccess)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 
dumpDut(String prefix)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 
installMocksInStateManager(WifiAwareStateManager awareStateManager, WifiAwareDataPathStateManager mockDpMgr)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 
getInternalClientState(WifiAwareStateManager dut, int clientId)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 
getInternalSessionState( WifiAwareClientState client, int sessionId)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 
validateInternalSendMessageQueuesCleanedUp(int messageId)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      */
simulatePowerStateChangeDoze(boolean isDozeOn)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      */
simulatePowerStateChangeInteractive(boolean isInteractive)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      */
simulateLocationModeChange(boolean isLocationModeEnabled)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      */
simulateWifiStateChange(boolean isWifiOn)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 
getCapabilities()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 
Mutable()3521         Mutable() {
3522             value = null;
3523         }
3524 
Mutable(E value)3525         Mutable(E value) {
3526             this.value = value;
3527         }
3528     }
3529 }
3530 
3531