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