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