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