WifiAwareDataPathStateManagerTest.java revision bd0447ff06c5719494960e2e3ec95b84941baf2a
1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.wifi.aware;
18
19import static android.hardware.wifi.V1_0.NanDataPathChannelCfg.REQUEST_CHANNEL_SETUP;
20
21import static org.hamcrest.core.IsEqual.equalTo;
22import static org.junit.Assert.assertTrue;
23import static org.mockito.ArgumentMatchers.any;
24import static org.mockito.ArgumentMatchers.anyBoolean;
25import static org.mockito.ArgumentMatchers.anyInt;
26import static org.mockito.ArgumentMatchers.anyShort;
27import static org.mockito.ArgumentMatchers.eq;
28import static org.mockito.Mockito.inOrder;
29import static org.mockito.Mockito.mock;
30import static org.mockito.Mockito.verify;
31import static org.mockito.Mockito.verifyNoMoreInteractions;
32import static org.mockito.Mockito.when;
33
34import android.app.test.TestAlarmManager;
35import android.content.Context;
36import android.net.ConnectivityManager;
37import android.net.NetworkCapabilities;
38import android.net.NetworkFactory;
39import android.net.NetworkRequest;
40import android.net.NetworkSpecifier;
41import android.net.wifi.aware.AttachCallback;
42import android.net.wifi.aware.ConfigRequest;
43import android.net.wifi.aware.DiscoverySession;
44import android.net.wifi.aware.DiscoverySessionCallback;
45import android.net.wifi.aware.IWifiAwareDiscoverySessionCallback;
46import android.net.wifi.aware.IWifiAwareEventCallback;
47import android.net.wifi.aware.IWifiAwareManager;
48import android.net.wifi.aware.PeerHandle;
49import android.net.wifi.aware.PublishConfig;
50import android.net.wifi.aware.PublishDiscoverySession;
51import android.net.wifi.aware.SubscribeConfig;
52import android.net.wifi.aware.SubscribeDiscoverySession;
53import android.net.wifi.aware.WifiAwareManager;
54import android.net.wifi.aware.WifiAwareNetworkSpecifier;
55import android.net.wifi.aware.WifiAwareSession;
56import android.os.Handler;
57import android.os.INetworkManagementService;
58import android.os.Message;
59import android.os.Messenger;
60import android.os.test.TestLooper;
61import android.test.suitebuilder.annotation.SmallTest;
62import android.util.Pair;
63
64import com.android.internal.util.AsyncChannel;
65
66import libcore.util.HexEncoding;
67
68import org.junit.Before;
69import org.junit.Rule;
70import org.junit.Test;
71import org.junit.rules.ErrorCollector;
72import org.mockito.ArgumentCaptor;
73import org.mockito.InOrder;
74import org.mockito.Mock;
75import org.mockito.MockitoAnnotations;
76
77import java.lang.reflect.Field;
78import java.util.Arrays;
79
80/**
81 * Unit test harness for WifiAwareDataPathStateManager class.
82 */
83@SmallTest
84public class WifiAwareDataPathStateManagerTest {
85    private static final String sAwareInterfacePrefix = "aware_data";
86
87    private TestLooper mMockLooper;
88    private Handler mMockLooperHandler;
89    private WifiAwareStateManager mDut;
90    @Mock private WifiAwareNativeApi mMockNative;
91    @Mock private Context mMockContext;
92    @Mock private IWifiAwareManager mMockAwareService;
93    @Mock private ConnectivityManager mMockCm;
94    @Mock private INetworkManagementService mMockNwMgt;
95    @Mock private WifiAwareDataPathStateManager.NetworkInterfaceWrapper mMockNetworkInterface;
96    @Mock private IWifiAwareEventCallback mMockCallback;
97    @Mock IWifiAwareDiscoverySessionCallback mMockSessionCallback;
98    TestAlarmManager mAlarmManager;
99
100    @Rule
101    public ErrorCollector collector = new ErrorCollector();
102
103    /**
104     * Initialize mocks.
105     */
106    @Before
107    public void setUp() throws Exception {
108        MockitoAnnotations.initMocks(this);
109
110        mAlarmManager = new TestAlarmManager();
111        when(mMockContext.getSystemService(Context.ALARM_SERVICE))
112                .thenReturn(mAlarmManager.getAlarmManager());
113
114        when(mMockContext.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn(mMockCm);
115
116        mMockLooper = new TestLooper();
117        mMockLooperHandler = new Handler(mMockLooper.getLooper());
118
119        mDut = new WifiAwareStateManager();
120        mDut.setNative(mMockNative);
121        mDut.start(mMockContext, mMockLooper.getLooper());
122        mDut.startLate();
123
124        when(mMockNative.getCapabilities(anyShort())).thenReturn(true);
125        when(mMockNative.enableAndConfigure(anyShort(), any(), anyBoolean(),
126                anyBoolean())).thenReturn(true);
127        when(mMockNative.disable(anyShort())).thenReturn(true);
128        when(mMockNative.publish(anyShort(), anyInt(), any())).thenReturn(true);
129        when(mMockNative.subscribe(anyShort(), anyInt(), any()))
130                .thenReturn(true);
131        when(mMockNative.sendMessage(anyShort(), anyInt(), anyInt(), any(),
132                any(), anyInt())).thenReturn(true);
133        when(mMockNative.stopPublish(anyShort(), anyInt())).thenReturn(true);
134        when(mMockNative.stopSubscribe(anyShort(), anyInt())).thenReturn(true);
135        when(mMockNative.createAwareNetworkInterface(anyShort(), any())).thenReturn(true);
136        when(mMockNative.deleteAwareNetworkInterface(anyShort(), any())).thenReturn(true);
137        when(mMockNative.initiateDataPath(anyShort(), anyInt(), anyInt(), anyInt(),
138                any(), any(), any(), any(),
139                any())).thenReturn(true);
140        when(mMockNative.respondToDataPathRequest(anyShort(), anyBoolean(), anyInt(), any(),
141                any(), any(), any())).thenReturn(true);
142        when(mMockNative.endDataPath(anyShort(), anyInt())).thenReturn(true);
143
144        when(mMockNetworkInterface.configureAgentProperties(any(), any(), anyInt(), any(), any(),
145                any())).thenReturn(true);
146
147        installDataPathStateManagerMocks();
148    }
149
150    /**
151     * Validates that creating and deleting all interfaces works based on capabilities.
152     */
153    @Test
154    public void testCreateDeleteAllInterfaces() throws Exception {
155        final int numNdis = 3;
156        final int failCreateInterfaceIndex = 1;
157
158        Capabilities capabilities = new Capabilities();
159        capabilities.maxNdiInterfaces = numNdis;
160
161        ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class);
162        ArgumentCaptor<String> interfaceName = ArgumentCaptor.forClass(String.class);
163        InOrder inOrder = inOrder(mMockNative);
164
165        // (1) get capabilities
166        mDut.queryCapabilities();
167        mMockLooper.dispatchAll();
168        inOrder.verify(mMockNative).getCapabilities(transactionId.capture());
169        mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), capabilities);
170        mMockLooper.dispatchAll();
171
172        // (2) create all interfaces
173        mDut.createAllDataPathInterfaces();
174        mMockLooper.dispatchAll();
175        for (int i = 0; i < numNdis; ++i) {
176            inOrder.verify(mMockNative).createAwareNetworkInterface(transactionId.capture(),
177                    interfaceName.capture());
178            collector.checkThat("interface created -- " + i, sAwareInterfacePrefix + i,
179                    equalTo(interfaceName.getValue()));
180            mDut.onCreateDataPathInterfaceResponse(transactionId.getValue(), true, 0);
181            mMockLooper.dispatchAll();
182        }
183
184        // (3) delete all interfaces [one unsuccessfully] - note that will not necessarily be
185        // done sequentially
186        boolean[] done = new boolean[numNdis];
187        Arrays.fill(done, false);
188        mDut.deleteAllDataPathInterfaces();
189        mMockLooper.dispatchAll();
190        for (int i = 0; i < numNdis; ++i) {
191            inOrder.verify(mMockNative).deleteAwareNetworkInterface(transactionId.capture(),
192                    interfaceName.capture());
193            int interfaceIndex = Integer.valueOf(
194                    interfaceName.getValue().substring(sAwareInterfacePrefix.length()));
195            done[interfaceIndex] = true;
196            if (interfaceIndex == failCreateInterfaceIndex) {
197                mDut.onDeleteDataPathInterfaceResponse(transactionId.getValue(), false, 0);
198            } else {
199                mDut.onDeleteDataPathInterfaceResponse(transactionId.getValue(), true, 0);
200            }
201            mMockLooper.dispatchAll();
202        }
203        for (int i = 0; i < numNdis; ++i) {
204            collector.checkThat("interface deleted -- " + i, done[i], equalTo(true));
205        }
206
207        // (4) create all interfaces (should get a delete for the one which couldn't delete earlier)
208        mDut.createAllDataPathInterfaces();
209        mMockLooper.dispatchAll();
210        for (int i = 0; i < numNdis; ++i) {
211            if (i == failCreateInterfaceIndex) {
212                inOrder.verify(mMockNative).deleteAwareNetworkInterface(transactionId.capture(),
213                        interfaceName.capture());
214                collector.checkThat("interface delete pre-create -- " + i,
215                        sAwareInterfacePrefix + i, equalTo(interfaceName.getValue()));
216                mDut.onDeleteDataPathInterfaceResponse(transactionId.getValue(), true, 0);
217                mMockLooper.dispatchAll();
218            }
219            inOrder.verify(mMockNative).createAwareNetworkInterface(transactionId.capture(),
220                    interfaceName.capture());
221            collector.checkThat("interface created -- " + i, sAwareInterfacePrefix + i,
222                    equalTo(interfaceName.getValue()));
223            mDut.onCreateDataPathInterfaceResponse(transactionId.getValue(), true, 0);
224            mMockLooper.dispatchAll();
225        }
226
227        verifyNoMoreInteractions(mMockNative);
228    }
229
230    /*
231     * Initiator tests
232     */
233
234    /**
235     * Validate the success flow of the Initiator: using session network specifier with a non-null
236     * token.
237     */
238    @Test
239    public void testDataPathInitiatorMacTokenSuccess() throws Exception {
240        testDataPathInitiatorUtility(false, true, true, true, false);
241    }
242
243    /**
244     * Validate the fail flow of the Initiator: using session network specifier with a 0
245     * peer ID.
246     */
247    @Test(expected = IllegalArgumentException.class)
248    public void testDataPathInitiatorNoMacFail() throws Exception {
249        testDataPathInitiatorUtility(false, false, true, true, false);
250    }
251
252    /**
253     * Validate the success flow of the Initiator: using a direct network specifier with a non-null
254     * peer mac and non-null token.
255     */
256    @Test
257    public void testDataPathInitiatorDirectMacTokenSuccess() throws Exception {
258        testDataPathInitiatorUtility(true, true, true, true, false);
259    }
260
261    /**
262     * Validate the fail flow of the Initiator: using a direct network specifier with a null peer
263     * mac and non-null token.
264     */
265    @Test(expected = IllegalArgumentException.class)
266    public void testDataPathInitiatorDirectNoMacTokenFail() throws Exception {
267        testDataPathInitiatorUtility(true, false, true, true, false);
268    }
269
270    /**
271     * Validate the fail flow of the Initiator: using a direct network specifier with a null peer
272     * mac and null token.
273     */
274    @Test(expected = IllegalArgumentException.class)
275    public void testDataPathInitiatorDirectNoMacNoTokenFail() throws Exception {
276        testDataPathInitiatorUtility(true, false, false, true, false);
277    }
278
279    /**
280     * Validate the fail flow of the Initiator: use a session network specifier with a non-null
281     * token, but don't get a confirmation.
282     */
283    @Test
284    public void testDataPathInitiatorNoConfirmationTimeoutFail() throws Exception {
285        testDataPathInitiatorUtility(false, true, true, false, false);
286    }
287
288    /**
289     * Validate the fail flow of the Initiator: use a session network specifier with a non-null
290     * token, but get an immediate failure
291     */
292    @Test
293    public void testDataPathInitiatorNoConfirmationHalFail() throws Exception {
294        testDataPathInitiatorUtility(false, true, true, true, true);
295    }
296
297    /**
298     * Validate the fail flow of a mis-configured request: Publisher as Initiator
299     */
300    @Test
301    public void testDataPathInitiatorOnPublisherError() throws Exception {
302        testDataPathInitiatorResponderMismatchUtility(true);
303    }
304
305    /*
306     * Responder tests
307     */
308
309    /**
310     * Validate the success flow of the Responder: using session network specifier with a non-null
311     * token.
312     */
313    @Test
314    public void testDataPathResonderMacTokenSuccess() throws Exception {
315        testDataPathResponderUtility(false, true, true, true);
316    }
317
318    /**
319     * Validate the success flow of the Responder: using session network specifier with a null
320     * token.
321     */
322    @Test
323    public void testDataPathResonderMacNoTokenSuccess() throws Exception {
324        testDataPathResponderUtility(false, true, false, true);
325    }
326
327    /**
328     * Validate the success flow of the Responder: using session network specifier with a
329     * token and no peer ID (i.e. 0).
330     */
331    @Test
332    public void testDataPathResonderMacTokenNoPeerIdSuccess() throws Exception {
333        testDataPathResponderUtility(false, false, true, true);
334    }
335
336    /**
337     * Validate the success flow of the Responder: using session network specifier with a null
338     * token and no peer ID (i.e. 0).
339     */
340    @Test
341    public void testDataPathResonderMacTokenNoPeerIdNoTokenSuccess() throws Exception {
342        testDataPathResponderUtility(false, false, false, true);
343    }
344
345    /**
346     * Validate the success flow of the Responder: using a direct network specifier with a non-null
347     * peer mac and non-null token.
348     */
349    @Test
350    public void testDataPathResonderDirectMacTokenSuccess() throws Exception {
351        testDataPathResponderUtility(true, true, true, true);
352    }
353
354    /**
355     * Validate the success flow of the Responder: using a direct network specifier with a non-null
356     * peer mac and null token.
357     */
358    @Test
359    public void testDataPathResonderDirectMacNoTokenSuccess() throws Exception {
360        testDataPathResponderUtility(true, true, false, true);
361    }
362
363    /**
364     * Validate the success flow of the Responder: using a direct network specifier with a null peer
365     * mac and non-null token.
366     */
367    @Test
368    public void testDataPathResonderDirectNoMacTokenSuccess() throws Exception {
369        testDataPathResponderUtility(true, false, true, true);
370    }
371
372    /**
373     * Validate the success flow of the Responder: using a direct network specifier with a null peer
374     * mac and null token.
375     */
376    @Test
377    public void testDataPathResonderDirectNoMacNoTokenSuccess() throws Exception {
378        testDataPathResponderUtility(true, false, false, true);
379    }
380
381    /**
382     * Validate the fail flow of the Responder: use a session network specifier with a non-null
383     * token, but don't get a confirmation.
384     */
385    @Test
386    public void testDataPathResponderNoConfirmationTimeoutFail() throws Exception {
387        testDataPathResponderUtility(false, true, true, false);
388    }
389
390    /**
391     * Validate the fail flow of a mis-configured request: Subscriber as Responder
392     */
393    @Test
394    public void testDataPathResponderOnSubscriberError() throws Exception {
395        testDataPathInitiatorResponderMismatchUtility(false);
396    }
397
398    /*
399     * Utilities
400     */
401
402    private void testDataPathInitiatorResponderMismatchUtility(boolean doPublish) throws Exception {
403        final int clientId = 123;
404        final int pubSubId = 11234;
405        final int ndpId = 2;
406        final byte[] pmk = "some bytes".getBytes();
407        final PeerHandle peerHandle = new PeerHandle(1341234);
408        final byte[] peerDiscoveryMac = HexEncoding.decode("000102030405".toCharArray(), false);
409
410        InOrder inOrder = inOrder(mMockNative, mMockCm, mMockCallback, mMockSessionCallback);
411
412        // (0) initialize
413        Pair<Integer, Messenger> res = initDataPathEndPoint(clientId, pubSubId, peerHandle,
414                peerDiscoveryMac, inOrder, doPublish);
415
416        // (1) request network
417        NetworkRequest nr = getSessionNetworkRequest(clientId, res.first, peerHandle, pmk,
418                doPublish);
419
420        // corrupt the network specifier: reverse the role (so it's mis-matched)
421        WifiAwareNetworkSpecifier ns =
422                (WifiAwareNetworkSpecifier) nr.networkCapabilities.getNetworkSpecifier();
423        ns = new WifiAwareNetworkSpecifier(
424                ns.type,
425                1 - ns.role, // corruption hack
426                ns.clientId,
427                ns.sessionId,
428                ns.peerId,
429                ns.peerMac,
430                ns.pmk,
431                ns.passphrase
432                );
433        nr.networkCapabilities.setNetworkSpecifier(ns);
434
435        Message reqNetworkMsg = Message.obtain();
436        reqNetworkMsg.what = NetworkFactory.CMD_REQUEST_NETWORK;
437        reqNetworkMsg.obj = nr;
438        reqNetworkMsg.arg1 = 0;
439        res.second.send(reqNetworkMsg);
440        mMockLooper.dispatchAll();
441
442        // consequences of failure:
443        //   Responder (publisher): responds with a rejection to any data-path requests
444        //   Initiator (subscribe): doesn't initiate (i.e. no HAL requests)
445        if (doPublish) {
446            // (2) get request & respond
447            mDut.onDataPathRequestNotification(pubSubId, peerDiscoveryMac, ndpId);
448            mMockLooper.dispatchAll();
449            inOrder.verify(mMockNative).respondToDataPathRequest(anyShort(), eq(false),
450                    eq(ndpId), eq(""), eq(null), eq(null), any());
451        }
452
453        verifyNoMoreInteractions(mMockNative, mMockCm);
454    }
455
456    private void testDataPathInitiatorUtility(boolean useDirect, boolean provideMac,
457            boolean providePmk, boolean getConfirmation, boolean immediateHalFailure)
458            throws Exception {
459        final int clientId = 123;
460        final int pubSubId = 11234;
461        final PeerHandle peerHandle = new PeerHandle(1341234);
462        final int ndpId = 2;
463        final byte[] pmk = "some bytes".getBytes();
464        final String peerToken = "let's go!";
465        final byte[] peerDiscoveryMac = HexEncoding.decode("000102030405".toCharArray(), false);
466        final byte[] peerDataPathMac = HexEncoding.decode("0A0B0C0D0E0F".toCharArray(), false);
467
468        ArgumentCaptor<Messenger> messengerCaptor = ArgumentCaptor.forClass(Messenger.class);
469        ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class);
470        InOrder inOrder = inOrder(mMockNative, mMockCm, mMockCallback, mMockSessionCallback);
471
472        if (immediateHalFailure) {
473            when(mMockNative.initiateDataPath(anyShort(), anyInt(), anyInt(), anyInt(), any(),
474                    any(), any(), any(), any())).thenReturn(false);
475
476        }
477
478        // (0) initialize
479        Pair<Integer, Messenger> res = initDataPathEndPoint(clientId, pubSubId, peerHandle,
480                peerDiscoveryMac, inOrder, false);
481
482        // (1) request network
483        NetworkRequest nr;
484        if (useDirect) {
485            nr = getDirectNetworkRequest(clientId,
486                    WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR,
487                    provideMac ? peerDiscoveryMac : null, providePmk ? pmk : null);
488        } else {
489            nr = getSessionNetworkRequest(clientId, res.first, provideMac ? peerHandle : null,
490                    providePmk ? pmk : null, false);
491        }
492
493        Message reqNetworkMsg = Message.obtain();
494        reqNetworkMsg.what = NetworkFactory.CMD_REQUEST_NETWORK;
495        reqNetworkMsg.obj = nr;
496        reqNetworkMsg.arg1 = 0;
497        res.second.send(reqNetworkMsg);
498        mMockLooper.dispatchAll();
499        inOrder.verify(mMockNative).initiateDataPath(transactionId.capture(),
500                eq(useDirect ? 0 : peerHandle.peerId),
501                eq(REQUEST_CHANNEL_SETUP), eq(2437), eq(peerDiscoveryMac),
502                eq(sAwareInterfacePrefix + "0"), eq(pmk), eq(null), any());
503        if (immediateHalFailure) {
504            // short-circuit the rest of this test
505            verifyNoMoreInteractions(mMockNative, mMockCm);
506            return;
507        }
508
509        mDut.onInitiateDataPathResponseSuccess(transactionId.getValue(), ndpId);
510        mMockLooper.dispatchAll();
511
512        // (2) get confirmation OR timeout
513        if (getConfirmation) {
514            mDut.onDataPathConfirmNotification(ndpId, peerDataPathMac, true, 0,
515                    peerToken.getBytes());
516            mMockLooper.dispatchAll();
517            inOrder.verify(mMockCm).registerNetworkAgent(messengerCaptor.capture(), any(), any(),
518                    any(), anyInt(), any());
519        } else {
520            assertTrue(mAlarmManager.dispatch(
521                    WifiAwareStateManager.HAL_DATA_PATH_CONFIRM_TIMEOUT_TAG));
522            mMockLooper.dispatchAll();
523            inOrder.verify(mMockNative).endDataPath(transactionId.capture(), eq(ndpId));
524            mDut.onEndDataPathResponse(transactionId.getValue(), true, 0);
525            mMockLooper.dispatchAll();
526        }
527
528        // (3) end data-path (unless didn't get confirmation)
529        if (getConfirmation) {
530            Message endNetworkReqMsg = Message.obtain();
531            endNetworkReqMsg.what = NetworkFactory.CMD_CANCEL_REQUEST;
532            endNetworkReqMsg.obj = nr;
533            res.second.send(endNetworkReqMsg);
534
535            Message endNetworkUsageMsg = Message.obtain();
536            endNetworkUsageMsg.what = AsyncChannel.CMD_CHANNEL_DISCONNECTED;
537            messengerCaptor.getValue().send(endNetworkUsageMsg);
538
539            mMockLooper.dispatchAll();
540            inOrder.verify(mMockNative).endDataPath(transactionId.capture(), eq(ndpId));
541            mDut.onEndDataPathResponse(transactionId.getValue(), true, 0);
542            mMockLooper.dispatchAll();
543        }
544
545        verifyNoMoreInteractions(mMockNative, mMockCm);
546    }
547
548    private void testDataPathResponderUtility(boolean useDirect, boolean provideMac,
549            boolean providePmk, boolean getConfirmation) throws Exception {
550        final int clientId = 123;
551        final int pubSubId = 11234;
552        final PeerHandle peerHandle = new PeerHandle(1341234);
553        final int ndpId = 2;
554        final byte[] pmk = "some bytes".getBytes();
555        final String peerToken = "let's go!";
556        final byte[] peerDiscoveryMac = HexEncoding.decode("000102030405".toCharArray(), false);
557        final byte[] peerDataPathMac = HexEncoding.decode("0A0B0C0D0E0F".toCharArray(), false);
558
559        ArgumentCaptor<Messenger> messengerCaptor = ArgumentCaptor.forClass(Messenger.class);
560        ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class);
561        InOrder inOrder = inOrder(mMockNative, mMockCm, mMockCallback, mMockSessionCallback);
562
563        // (0) initialize
564        Pair<Integer, Messenger> res = initDataPathEndPoint(clientId, pubSubId, peerHandle,
565                peerDiscoveryMac, inOrder, true);
566
567        // (1) request network
568        NetworkRequest nr;
569        if (useDirect) {
570            nr = getDirectNetworkRequest(clientId,
571                    WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER,
572                    provideMac ? peerDiscoveryMac : null, providePmk ? pmk : null);
573        } else {
574            nr = getSessionNetworkRequest(clientId, res.first, provideMac ? peerHandle : null,
575                    providePmk ? pmk : null, true);
576        }
577
578        Message reqNetworkMsg = Message.obtain();
579        reqNetworkMsg.what = NetworkFactory.CMD_REQUEST_NETWORK;
580        reqNetworkMsg.obj = nr;
581        reqNetworkMsg.arg1 = 0;
582        res.second.send(reqNetworkMsg);
583        mMockLooper.dispatchAll();
584
585        // (2) get request & respond
586        mDut.onDataPathRequestNotification(pubSubId, peerDiscoveryMac, ndpId);
587        mMockLooper.dispatchAll();
588        inOrder.verify(mMockNative).respondToDataPathRequest(transactionId.capture(), eq(true),
589                eq(ndpId), eq(sAwareInterfacePrefix + "0"), eq(providePmk ? pmk : null), eq(null),
590                any());
591        mDut.onRespondToDataPathSetupRequestResponse(transactionId.getValue(), true, 0);
592        mMockLooper.dispatchAll();
593
594        // (3) get confirmation OR timeout
595        if (getConfirmation) {
596            mDut.onDataPathConfirmNotification(ndpId, peerDataPathMac, true, 0,
597                    peerToken.getBytes());
598            mMockLooper.dispatchAll();
599            inOrder.verify(mMockCm).registerNetworkAgent(messengerCaptor.capture(), any(), any(),
600                    any(), anyInt(), any());
601        } else {
602            assertTrue(mAlarmManager.dispatch(
603                    WifiAwareStateManager.HAL_DATA_PATH_CONFIRM_TIMEOUT_TAG));
604            mMockLooper.dispatchAll();
605            inOrder.verify(mMockNative).endDataPath(transactionId.capture(), eq(ndpId));
606            mDut.onEndDataPathResponse(transactionId.getValue(), true, 0);
607            mMockLooper.dispatchAll();
608        }
609
610        // (4) end data-path (unless didn't get confirmation)
611        if (getConfirmation) {
612            Message endNetworkMsg = Message.obtain();
613            endNetworkMsg.what = NetworkFactory.CMD_CANCEL_REQUEST;
614            endNetworkMsg.obj = nr;
615            res.second.send(endNetworkMsg);
616
617            Message endNetworkUsageMsg = Message.obtain();
618            endNetworkUsageMsg.what = AsyncChannel.CMD_CHANNEL_DISCONNECTED;
619            messengerCaptor.getValue().send(endNetworkUsageMsg);
620
621            mMockLooper.dispatchAll();
622            inOrder.verify(mMockNative).endDataPath(transactionId.capture(), eq(ndpId));
623            mDut.onEndDataPathResponse(transactionId.getValue(), true, 0);
624            mMockLooper.dispatchAll();
625        }
626
627        verifyNoMoreInteractions(mMockNative, mMockCm);
628    }
629
630    private void installDataPathStateManagerMocks() throws Exception {
631        Field field = WifiAwareStateManager.class.getDeclaredField("mDataPathMgr");
632        field.setAccessible(true);
633        Object mDataPathMgr = field.get(mDut);
634
635        field = WifiAwareDataPathStateManager.class.getDeclaredField("mNwService");
636        field.setAccessible(true);
637        field.set(mDataPathMgr, mMockNwMgt);
638
639        field = WifiAwareDataPathStateManager.class.getDeclaredField("mNiWrapper");
640        field.setAccessible(true);
641        field.set(mDataPathMgr, mMockNetworkInterface);
642    }
643
644    private NetworkRequest getSessionNetworkRequest(int clientId, int sessionId,
645            PeerHandle peerHandle, byte[] pmk, boolean doPublish)
646            throws Exception {
647        final WifiAwareManager mgr = new WifiAwareManager(mMockContext, mMockAwareService);
648        final ConfigRequest configRequest = new ConfigRequest.Builder().build();
649        final PublishConfig publishConfig = new PublishConfig.Builder().build();
650        final SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build();
651
652        ArgumentCaptor<WifiAwareSession> sessionCaptor = ArgumentCaptor.forClass(
653                WifiAwareSession.class);
654        ArgumentCaptor<IWifiAwareEventCallback> clientProxyCallback = ArgumentCaptor
655                .forClass(IWifiAwareEventCallback.class);
656        ArgumentCaptor<IWifiAwareDiscoverySessionCallback> sessionProxyCallback = ArgumentCaptor
657                .forClass(IWifiAwareDiscoverySessionCallback.class);
658        ArgumentCaptor<DiscoverySession> discoverySession = ArgumentCaptor
659                .forClass(DiscoverySession.class);
660
661        AttachCallback mockCallback = mock(AttachCallback.class);
662        DiscoverySessionCallback mockSessionCallback = mock(
663                DiscoverySessionCallback.class);
664
665        mgr.attach(mMockLooperHandler, configRequest, mockCallback, null);
666        verify(mMockAwareService).connect(any(), any(),
667                clientProxyCallback.capture(), eq(configRequest), eq(false));
668        clientProxyCallback.getValue().onConnectSuccess(clientId);
669        mMockLooper.dispatchAll();
670        verify(mockCallback).onAttached(sessionCaptor.capture());
671        if (doPublish) {
672            sessionCaptor.getValue().publish(publishConfig, mockSessionCallback,
673                    mMockLooperHandler);
674            verify(mMockAwareService).publish(eq(clientId), eq(publishConfig),
675                    sessionProxyCallback.capture());
676        } else {
677            sessionCaptor.getValue().subscribe(subscribeConfig, mockSessionCallback,
678                    mMockLooperHandler);
679            verify(mMockAwareService).subscribe(eq(clientId), eq(subscribeConfig),
680                    sessionProxyCallback.capture());
681        }
682        sessionProxyCallback.getValue().onSessionStarted(sessionId);
683        mMockLooper.dispatchAll();
684        if (doPublish) {
685            verify(mockSessionCallback).onPublishStarted(
686                    (PublishDiscoverySession) discoverySession.capture());
687        } else {
688            verify(mockSessionCallback).onSubscribeStarted(
689                    (SubscribeDiscoverySession) discoverySession.capture());
690        }
691
692        NetworkSpecifier ns;
693        if (pmk == null) {
694            ns = discoverySession.getValue().createNetworkSpecifierOpen(peerHandle);
695        } else {
696            ns = discoverySession.getValue().createNetworkSpecifierPmk(peerHandle, pmk);
697        }
698
699        NetworkCapabilities nc = new NetworkCapabilities();
700        nc.clearAll();
701        nc.addTransportType(NetworkCapabilities.TRANSPORT_WIFI_AWARE);
702        nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN).addCapability(
703                NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
704        nc.setNetworkSpecifier(ns);
705        nc.setLinkUpstreamBandwidthKbps(1);
706        nc.setLinkDownstreamBandwidthKbps(1);
707        nc.setSignalStrength(1);
708
709        return new NetworkRequest(nc, 0, 0, NetworkRequest.Type.NONE);
710    }
711
712    private NetworkRequest getDirectNetworkRequest(int clientId, int role, byte[] peer,
713            byte[] pmk) throws Exception {
714        final ConfigRequest configRequest = new ConfigRequest.Builder().build();
715        final WifiAwareManager mgr = new WifiAwareManager(mMockContext, mMockAwareService);
716
717        ArgumentCaptor<WifiAwareSession> sessionCaptor = ArgumentCaptor.forClass(
718                WifiAwareSession.class);
719        ArgumentCaptor<IWifiAwareEventCallback> clientProxyCallback = ArgumentCaptor
720                .forClass(IWifiAwareEventCallback.class);
721
722        AttachCallback mockCallback = mock(AttachCallback.class);
723
724        mgr.attach(mMockLooperHandler, configRequest, mockCallback, null);
725        verify(mMockAwareService).connect(any(), any(),
726                clientProxyCallback.capture(), eq(configRequest), eq(false));
727        clientProxyCallback.getValue().onConnectSuccess(clientId);
728        mMockLooper.dispatchAll();
729        verify(mockCallback).onAttached(sessionCaptor.capture());
730
731        NetworkSpecifier ns;
732        if (pmk == null) {
733            ns = sessionCaptor.getValue().createNetworkSpecifierOpen(role, peer);
734        } else {
735            ns = sessionCaptor.getValue().createNetworkSpecifierPmk(role, peer, pmk);
736        }
737        NetworkCapabilities nc = new NetworkCapabilities();
738        nc.clearAll();
739        nc.addTransportType(NetworkCapabilities.TRANSPORT_WIFI_AWARE);
740        nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN).addCapability(
741                NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
742        nc.setNetworkSpecifier(ns);
743        nc.setLinkUpstreamBandwidthKbps(1);
744        nc.setLinkDownstreamBandwidthKbps(1);
745        nc.setSignalStrength(1);
746
747        return new NetworkRequest(nc, 0, 0, NetworkRequest.Type.REQUEST);
748    }
749
750    private Pair<Integer, Messenger> initDataPathEndPoint(int clientId, int pubSubId,
751            PeerHandle peerHandle, byte[] peerDiscoveryMac, InOrder inOrder,
752            boolean doPublish)
753            throws Exception {
754        final int uid = 1000;
755        final int pid = 2000;
756        final String callingPackage = "com.android.somePackage";
757        final String someMsg = "some arbitrary message from peer";
758        final ConfigRequest configRequest = new ConfigRequest.Builder().build();
759        final PublishConfig publishConfig = new PublishConfig.Builder().build();
760        final SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build();
761
762        Capabilities capabilities = new Capabilities();
763        capabilities.maxNdiInterfaces = 1;
764
765        ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class);
766        ArgumentCaptor<Integer> sessionId = ArgumentCaptor.forClass(Integer.class);
767        ArgumentCaptor<Messenger> messengerCaptor = ArgumentCaptor.forClass(Messenger.class);
768        ArgumentCaptor<String> strCaptor = ArgumentCaptor.forClass(String.class);
769
770        // (0) start/registrations
771        inOrder.verify(mMockCm).registerNetworkFactory(messengerCaptor.capture(),
772                strCaptor.capture());
773        collector.checkThat("factory name", "WIFI_AWARE_FACTORY", equalTo(strCaptor.getValue()));
774
775        // (1) get capabilities
776        mDut.queryCapabilities();
777        mMockLooper.dispatchAll();
778        inOrder.verify(mMockNative).getCapabilities(transactionId.capture());
779        mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), capabilities);
780        mMockLooper.dispatchAll();
781
782        // (2) enable usage (creates interfaces)
783        mDut.enableUsage();
784        mMockLooper.dispatchAll();
785        inOrder.verify(mMockNative).createAwareNetworkInterface(transactionId.capture(),
786                strCaptor.capture());
787        collector.checkThat("interface created -- 0", sAwareInterfacePrefix + 0,
788                equalTo(strCaptor.getValue()));
789        mDut.onCreateDataPathInterfaceResponse(transactionId.getValue(), true, 0);
790        mMockLooper.dispatchAll();
791
792        // (3) create client & session & rx message
793        mDut.connect(clientId, uid, pid, callingPackage, mMockCallback, configRequest, false);
794        mMockLooper.dispatchAll();
795        inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(),
796                eq(configRequest), eq(false), eq(true));
797        mDut.onConfigSuccessResponse(transactionId.getValue());
798        mMockLooper.dispatchAll();
799        inOrder.verify(mMockCallback).onConnectSuccess(clientId);
800        if (doPublish) {
801            mDut.publish(clientId, publishConfig, mMockSessionCallback);
802        } else {
803            mDut.subscribe(clientId, subscribeConfig, mMockSessionCallback);
804        }
805        mMockLooper.dispatchAll();
806        if (doPublish) {
807            inOrder.verify(mMockNative).publish(transactionId.capture(), eq(0), eq(publishConfig));
808        } else {
809            inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq(0),
810                    eq(subscribeConfig));
811        }
812        mDut.onSessionConfigSuccessResponse(transactionId.getValue(), doPublish, pubSubId);
813        mMockLooper.dispatchAll();
814        inOrder.verify(mMockSessionCallback).onSessionStarted(sessionId.capture());
815        mDut.onMessageReceivedNotification(pubSubId, peerHandle.peerId, peerDiscoveryMac,
816                someMsg.getBytes());
817        mMockLooper.dispatchAll();
818        inOrder.verify(mMockSessionCallback).onMessageReceived(peerHandle.peerId,
819                someMsg.getBytes());
820
821        return new Pair<>(sessionId.getValue(), messengerCaptor.getValue());
822    }
823}
824