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