blob: 508ee2fb23efe35a6fa3d43016090b21a8d79920 [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.wifi.aware;
import static android.hardware.wifi.V1_0.NanDataPathChannelCfg.CHANNEL_NOT_REQUESTED;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyShort;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import android.Manifest;
import android.app.test.TestAlarmManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.wifi.V1_0.NanStatusType;
import android.location.LocationManager;
import android.net.ConnectivityManager;
import android.net.NetworkCapabilities;
import android.net.NetworkFactory;
import android.net.NetworkRequest;
import android.net.NetworkSpecifier;
import android.net.wifi.WifiManager;
import android.net.wifi.aware.AttachCallback;
import android.net.wifi.aware.ConfigRequest;
import android.net.wifi.aware.DiscoverySession;
import android.net.wifi.aware.DiscoverySessionCallback;
import android.net.wifi.aware.IWifiAwareDiscoverySessionCallback;
import android.net.wifi.aware.IWifiAwareEventCallback;
import android.net.wifi.aware.IWifiAwareManager;
import android.net.wifi.aware.PeerHandle;
import android.net.wifi.aware.PublishConfig;
import android.net.wifi.aware.PublishDiscoverySession;
import android.net.wifi.aware.SubscribeConfig;
import android.net.wifi.aware.SubscribeDiscoverySession;
import android.net.wifi.aware.WifiAwareManager;
import android.net.wifi.aware.WifiAwareNetworkSpecifier;
import android.net.wifi.aware.WifiAwareSession;
import android.os.Build;
import android.os.Handler;
import android.os.INetworkManagementService;
import android.os.IPowerManager;
import android.os.Message;
import android.os.Messenger;
import android.os.PowerManager;
import android.os.Process;
import android.os.test.TestLooper;
import android.support.test.filters.SmallTest;
import com.android.internal.util.AsyncChannel;
import com.android.server.wifi.util.WifiPermissionsUtil;
import com.android.server.wifi.util.WifiPermissionsWrapper;
import libcore.util.HexEncoding;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ErrorCollector;
import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
/**
* Unit test harness for WifiAwareDataPathStateManager class.
*/
@SmallTest
public class WifiAwareDataPathStateManagerTest {
private static final String sAwareInterfacePrefix = "aware_data";
private TestLooper mMockLooper;
private Handler mMockLooperHandler;
private WifiAwareStateManager mDut;
@Mock private WifiAwareNativeManager mMockNativeManager;
@Spy private TestUtils.MonitoredWifiAwareNativeApi mMockNative =
new TestUtils.MonitoredWifiAwareNativeApi();
@Mock private Context mMockContext;
@Mock private ConnectivityManager mMockCm;
@Mock private INetworkManagementService mMockNwMgt;
@Mock private WifiAwareDataPathStateManager.NetworkInterfaceWrapper mMockNetworkInterface;
@Mock private IWifiAwareEventCallback mMockCallback;
@Mock IWifiAwareDiscoverySessionCallback mMockSessionCallback;
@Mock private WifiAwareMetrics mAwareMetricsMock;
@Mock private WifiPermissionsUtil mWifiPermissionsUtil;
@Mock private WifiPermissionsWrapper mPermissionsWrapperMock;
@Mock private LocationManager mLocationManagerMock;
@Mock private WifiManager mMockWifiManager;
TestAlarmManager mAlarmManager;
private PowerManager mMockPowerManager;
@Rule
public ErrorCollector collector = new ErrorCollector();
/**
* Initialize mocks.
*/
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mAlarmManager = new TestAlarmManager();
when(mMockContext.getSystemService(Context.ALARM_SERVICE))
.thenReturn(mAlarmManager.getAlarmManager());
when(mMockContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager);
when(mMockWifiManager.getWifiState()).thenReturn(WifiManager.WIFI_STATE_ENABLED);
mMockLooper = new TestLooper();
mMockLooperHandler = new Handler(mMockLooper.getLooper());
IPowerManager powerManagerService = mock(IPowerManager.class);
mMockPowerManager = new PowerManager(mMockContext, powerManagerService,
new Handler(mMockLooper.getLooper()));
when(mMockContext.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn(mMockCm);
when(mMockContext.getSystemServiceName(PowerManager.class)).thenReturn(
Context.POWER_SERVICE);
when(mMockContext.getSystemService(PowerManager.class)).thenReturn(mMockPowerManager);
when(mMockContext.getSystemService(Context.LOCATION_SERVICE)).thenReturn(
mLocationManagerMock);
when(mLocationManagerMock.isLocationEnabled()).thenReturn(true);
// by default pretend to be an old API: i.e. allow Responders configured as *ANY*. This
// allows older (more extrensive) tests to run.
when(mWifiPermissionsUtil.isLegacyVersion(anyString(), anyInt())).thenReturn(true);
mDut = new WifiAwareStateManager();
mDut.setNative(mMockNativeManager, mMockNative);
mDut.start(mMockContext, mMockLooper.getLooper(), mAwareMetricsMock,
mWifiPermissionsUtil, mPermissionsWrapperMock);
mDut.startLate();
mMockLooper.dispatchAll();
when(mMockNetworkInterface.configureAgentProperties(any(), any(), anyInt(), any(), any(),
any())).thenReturn(true);
when(mMockPowerManager.isDeviceIdleMode()).thenReturn(false);
when(mMockPowerManager.isInteractive()).thenReturn(true);
when(mPermissionsWrapperMock.getUidPermission(eq(Manifest.permission.CONNECTIVITY_INTERNAL),
anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED);
mDut.mDataPathMgr.mNwService = mMockNwMgt;
mDut.mDataPathMgr.mNiWrapper = mMockNetworkInterface;
}
/**
* Post-test validation.
*/
@After
public void tearDown() throws Exception {
mMockNative.validateUniqueTransactionIds();
}
/**
* Validates that creating and deleting all interfaces works based on capabilities.
*/
@Test
public void testCreateDeleteAllInterfaces() throws Exception {
final int numNdis = 3;
final int failCreateInterfaceIndex = 1;
Capabilities capabilities = new Capabilities();
capabilities.maxNdiInterfaces = numNdis;
ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class);
ArgumentCaptor<String> interfaceName = ArgumentCaptor.forClass(String.class);
InOrder inOrder = inOrder(mMockNative);
// (1) get capabilities
mDut.queryCapabilities();
mMockLooper.dispatchAll();
inOrder.verify(mMockNative).getCapabilities(transactionId.capture());
mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), capabilities);
mMockLooper.dispatchAll();
// (2) create all interfaces
mDut.createAllDataPathInterfaces();
mMockLooper.dispatchAll();
for (int i = 0; i < numNdis; ++i) {
inOrder.verify(mMockNative).createAwareNetworkInterface(transactionId.capture(),
interfaceName.capture());
collector.checkThat("interface created -- " + i, sAwareInterfacePrefix + i,
equalTo(interfaceName.getValue()));
mDut.onCreateDataPathInterfaceResponse(transactionId.getValue(), true, 0);
mMockLooper.dispatchAll();
}
// (3) delete all interfaces [one unsuccessfully] - note that will not necessarily be
// done sequentially
boolean[] done = new boolean[numNdis];
Arrays.fill(done, false);
mDut.deleteAllDataPathInterfaces();
mMockLooper.dispatchAll();
for (int i = 0; i < numNdis; ++i) {
inOrder.verify(mMockNative).deleteAwareNetworkInterface(transactionId.capture(),
interfaceName.capture());
int interfaceIndex = Integer.valueOf(
interfaceName.getValue().substring(sAwareInterfacePrefix.length()));
done[interfaceIndex] = true;
if (interfaceIndex == failCreateInterfaceIndex) {
mDut.onDeleteDataPathInterfaceResponse(transactionId.getValue(), false, 0);
} else {
mDut.onDeleteDataPathInterfaceResponse(transactionId.getValue(), true, 0);
}
mMockLooper.dispatchAll();
}
for (int i = 0; i < numNdis; ++i) {
collector.checkThat("interface deleted -- " + i, done[i], equalTo(true));
}
// (4) create all interfaces (should get a delete for the one which couldn't delete earlier)
mDut.createAllDataPathInterfaces();
mMockLooper.dispatchAll();
for (int i = 0; i < numNdis; ++i) {
if (i == failCreateInterfaceIndex) {
inOrder.verify(mMockNative).deleteAwareNetworkInterface(transactionId.capture(),
interfaceName.capture());
collector.checkThat("interface delete pre-create -- " + i,
sAwareInterfacePrefix + i, equalTo(interfaceName.getValue()));
mDut.onDeleteDataPathInterfaceResponse(transactionId.getValue(), true, 0);
mMockLooper.dispatchAll();
}
inOrder.verify(mMockNative).createAwareNetworkInterface(transactionId.capture(),
interfaceName.capture());
collector.checkThat("interface created -- " + i, sAwareInterfacePrefix + i,
equalTo(interfaceName.getValue()));
mDut.onCreateDataPathInterfaceResponse(transactionId.getValue(), true, 0);
mMockLooper.dispatchAll();
}
verifyNoMoreInteractions(mMockNative, mMockNwMgt);
}
/**
* Validate that trying to specify a PMK without permission results in failure.
*/
@Test
public void testDataPathPmkWithoutPermission() throws Exception {
final int clientId = 123;
final byte pubSubId = 55;
final byte[] pmk = "01234567890123456789012345678901".getBytes();
final int requestorId = 1341234;
final byte[] peerDiscoveryMac = HexEncoding.decode("000102030405".toCharArray(), false);
InOrder inOrder = inOrder(mMockNative, mMockCm, mMockCallback, mMockSessionCallback);
InOrder inOrderM = inOrder(mAwareMetricsMock);
when(mPermissionsWrapperMock.getUidPermission(eq(Manifest.permission.CONNECTIVITY_INTERNAL),
anyInt())).thenReturn(PackageManager.PERMISSION_DENIED);
// (0) initialize
DataPathEndPointInfo res = initDataPathEndPoint(true, clientId, pubSubId, requestorId,
peerDiscoveryMac, inOrder, inOrderM, false);
// (1) request network
NetworkRequest nr = getSessionNetworkRequest(clientId, res.mSessionId, res.mPeerHandle, pmk,
null, false, 0);
Message reqNetworkMsg = Message.obtain();
reqNetworkMsg.what = NetworkFactory.CMD_REQUEST_NETWORK;
reqNetworkMsg.obj = nr;
reqNetworkMsg.arg1 = 0;
res.mMessenger.send(reqNetworkMsg);
mMockLooper.dispatchAll();
// failure: no interactions with connectivity manager or native manager
verifyNoMoreInteractions(mMockNative, mMockCm, mAwareMetricsMock, mMockNwMgt);
}
/**
* Validate that if the data-interfaces are deleted while a data-path is being created, the
* process will terminate.
*/
@Test
public void testDestroyNdiDuringNdpSetupResponder() throws Exception {
final int clientId = 123;
final byte pubSubId = 55;
final int requestorId = 1341234;
final byte[] peerDiscoveryMac = HexEncoding.decode("000102030405".toCharArray(), false);
final int ndpId = 3;
InOrder inOrder = inOrder(mMockNative, mMockCm, mMockCallback, mMockSessionCallback);
InOrder inOrderM = inOrder(mAwareMetricsMock);
ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class);
// (0) initialize
DataPathEndPointInfo res = initDataPathEndPoint(true, clientId, pubSubId, requestorId,
peerDiscoveryMac, inOrder, inOrderM, true);
// (1) request network
NetworkRequest nr = getSessionNetworkRequest(clientId, res.mSessionId, res.mPeerHandle,
null, null, true, 0);
Message reqNetworkMsg = Message.obtain();
reqNetworkMsg.what = NetworkFactory.CMD_REQUEST_NETWORK;
reqNetworkMsg.obj = nr;
reqNetworkMsg.arg1 = 0;
res.mMessenger.send(reqNetworkMsg);
mMockLooper.dispatchAll();
// (2) delete interface(s)
mDut.deleteAllDataPathInterfaces();
mMockLooper.dispatchAll();
inOrder.verify(mMockNative).deleteAwareNetworkInterface(transactionId.capture(),
anyString());
mDut.onDeleteDataPathInterfaceResponse(transactionId.getValue(), true, 0);
mMockLooper.dispatchAll();
// (3) have responder receive request
mDut.onDataPathRequestNotification(pubSubId, peerDiscoveryMac, ndpId);
mMockLooper.dispatchAll();
// (4) verify that responder aborts (i.e. refuses request)
inOrder.verify(mMockNative).respondToDataPathRequest(transactionId.capture(), eq(false),
eq(ndpId), eq(""), eq(null), eq(null), eq(false), any());
mDut.onRespondToDataPathSetupRequestResponse(transactionId.getValue(), true, 0);
mMockLooper.dispatchAll();
// failure if there's further activity
verifyNoMoreInteractions(mMockNative, mMockCm, mAwareMetricsMock, mMockNwMgt);
}
/**
* Validate multiple NDPs created on a single NDI. Most importantly that the interface is
* set up on first NDP and torn down on last NDP - and not when one or the other is created or
* deleted.
*
* Procedure:
* - create NDP 1, 2, and 3 (interface up only on first)
* - delete NDP 2, 1, and 3 (interface down only on last)
*/
@Test
public void testMultipleNdpsOnSingleNdi() throws Exception {
final int clientId = 123;
final byte pubSubId = 58;
final int requestorId = 1341234;
final int ndpId = 2;
final int[] startOrder = {0, 1, 2};
final int[] endOrder = {1, 0, 2};
int networkRequestId = 0;
ArgumentCaptor<Messenger> messengerCaptor = ArgumentCaptor.forClass(Messenger.class);
ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class);
InOrder inOrder = inOrder(mMockNative, mMockCm, mMockCallback, mMockSessionCallback,
mMockNwMgt);
InOrder inOrderM = inOrder(mAwareMetricsMock);
NetworkRequest[] nrs = new NetworkRequest[3];
DataPathEndPointInfo[] ress = new DataPathEndPointInfo[3];
Messenger[] agentMessengers = new Messenger[3];
Messenger messenger = null;
boolean first = true;
for (int i : startOrder) {
networkRequestId += 1;
byte[] peerDiscoveryMac = HexEncoding.decode("000102030405".toCharArray(), false);
byte[] peerDataPathMac = HexEncoding.decode("0A0B0C0D0E0F".toCharArray(), false);
peerDiscoveryMac[5] = (byte) (peerDiscoveryMac[5] + i);
peerDataPathMac[5] = (byte) (peerDataPathMac[5] + i);
// (0) initialize
ress[i] = initDataPathEndPoint(first, clientId, (byte) (pubSubId + i),
requestorId + i, peerDiscoveryMac, inOrder, inOrderM, false);
if (first) {
messenger = ress[i].mMessenger;
}
// (1) request network
nrs[i] = getSessionNetworkRequest(clientId, ress[i].mSessionId, ress[i].mPeerHandle,
null, null, false, networkRequestId);
Message reqNetworkMsg = Message.obtain();
reqNetworkMsg.what = NetworkFactory.CMD_REQUEST_NETWORK;
reqNetworkMsg.obj = nrs[i];
reqNetworkMsg.arg1 = 0;
messenger.send(reqNetworkMsg);
mMockLooper.dispatchAll();
inOrder.verify(mMockNative).initiateDataPath(transactionId.capture(),
eq(requestorId + i),
eq(CHANNEL_NOT_REQUESTED), anyInt(), eq(peerDiscoveryMac),
eq(sAwareInterfacePrefix + "0"), eq(null),
eq(null), eq(false), any());
mDut.onInitiateDataPathResponseSuccess(transactionId.getValue(), ndpId + i);
mMockLooper.dispatchAll();
// (2) get confirmation
mDut.onDataPathConfirmNotification(ndpId + i, peerDataPathMac, true, 0, null, null);
mMockLooper.dispatchAll();
if (first) {
inOrder.verify(mMockNwMgt).setInterfaceUp(anyString());
inOrder.verify(mMockNwMgt).enableIpv6(anyString());
first = false;
}
inOrder.verify(mMockCm).registerNetworkAgent(messengerCaptor.capture(), any(), any(),
any(), anyInt(), any(), anyInt());
agentMessengers[i] = messengerCaptor.getValue();
inOrderM.verify(mAwareMetricsMock).recordNdpStatus(eq(NanStatusType.SUCCESS),
eq(false), anyLong());
inOrderM.verify(mAwareMetricsMock).recordNdpCreation(anyInt(), any());
}
// (3) end data-path (unless didn't get confirmation)
int index = 0;
for (int i: endOrder) {
Message endNetworkReqMsg = Message.obtain();
endNetworkReqMsg.what = NetworkFactory.CMD_CANCEL_REQUEST;
endNetworkReqMsg.obj = nrs[i];
messenger.send(endNetworkReqMsg);
Message endNetworkUsageMsg = Message.obtain();
endNetworkUsageMsg.what = AsyncChannel.CMD_CHANNEL_DISCONNECTED;
agentMessengers[i].send(endNetworkUsageMsg);
mMockLooper.dispatchAll();
inOrder.verify(mMockNative).endDataPath(transactionId.capture(), eq(ndpId + i));
mDut.onEndDataPathResponse(transactionId.getValue(), true, 0);
mDut.onDataPathEndNotification(ndpId + i);
mMockLooper.dispatchAll();
if (index++ == endOrder.length - 1) {
inOrder.verify(mMockNwMgt).setInterfaceDown(anyString());
}
inOrderM.verify(mAwareMetricsMock).recordNdpSessionDuration(anyLong());
}
verifyNoMoreInteractions(mMockNative, mMockCm, mAwareMetricsMock, mMockNwMgt);
}
/**
* Validate that multiple NDP requests which resolve to the same canonical request are treated
* as one.
*/
@Test
public void testMultipleIdenticalRequests() throws Exception {
final int numRequestsPre = 6;
final int numRequestsPost = 5;
final int clientId = 123;
final int ndpId = 5;
final byte[] peerDiscoveryMac = HexEncoding.decode("000102030405".toCharArray(), false);
final byte[] peerDataPathMac = HexEncoding.decode("0A0B0C0D0E0F".toCharArray(), false);
NetworkRequest[] nrs = new NetworkRequest[numRequestsPre + numRequestsPost + 1];
ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class);
ArgumentCaptor<Messenger> agentMessengerCaptor = ArgumentCaptor.forClass(Messenger.class);
InOrder inOrder = inOrder(mMockNative, mMockCm, mMockCallback, mMockSessionCallback,
mMockNwMgt);
InOrder inOrderM = inOrder(mAwareMetricsMock);
// (1) initialize all clients
Messenger messenger = initOobDataPathEndPoint(true, 2, clientId, inOrder, inOrderM);
for (int i = 1; i < numRequestsPre + numRequestsPost; ++i) {
initOobDataPathEndPoint(false, 1, clientId + i, inOrder, inOrderM);
}
DataPathEndPointInfo ddepi = initDataPathEndPoint(false,
clientId + numRequestsPre + numRequestsPost, (byte) 10, 11, peerDiscoveryMac,
inOrder, inOrderM, false);
// (2) make initial network requests (all identical under the hood)
for (int i = 0; i < numRequestsPre; ++i) {
nrs[i] = getDirectNetworkRequest(clientId + i,
WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR, peerDiscoveryMac, null,
null, i);
Message reqNetworkMsg = Message.obtain();
reqNetworkMsg.what = NetworkFactory.CMD_REQUEST_NETWORK;
reqNetworkMsg.obj = nrs[i];
reqNetworkMsg.arg1 = 0;
messenger.send(reqNetworkMsg);
}
mMockLooper.dispatchAll();
// (3) verify the start NDP HAL request
inOrder.verify(mMockNative).initiateDataPath(transactionId.capture(), eq(0),
eq(CHANNEL_NOT_REQUESTED), anyInt(), eq(peerDiscoveryMac),
eq(sAwareInterfacePrefix + "0"), eq(null), eq(null), eq(true), any());
// (4) unregister request #0 (the primary)
Message endNetworkReqMsg = Message.obtain();
endNetworkReqMsg.what = NetworkFactory.CMD_CANCEL_REQUEST;
endNetworkReqMsg.obj = nrs[0];
messenger.send(endNetworkReqMsg);
mMockLooper.dispatchAll();
// (5) respond to the registration request
mDut.onInitiateDataPathResponseSuccess(transactionId.getValue(), ndpId);
mMockLooper.dispatchAll();
// (6) unregister request #1
endNetworkReqMsg = Message.obtain();
endNetworkReqMsg.what = NetworkFactory.CMD_CANCEL_REQUEST;
endNetworkReqMsg.obj = nrs[1];
messenger.send(endNetworkReqMsg);
mMockLooper.dispatchAll();
// (7) confirm the NDP creation
mDut.onDataPathConfirmNotification(ndpId, peerDataPathMac, true, 0, null, null);
mMockLooper.dispatchAll();
inOrder.verify(mMockNwMgt).setInterfaceUp(anyString());
inOrder.verify(mMockNwMgt).enableIpv6(anyString());
inOrder.verify(mMockCm).registerNetworkAgent(agentMessengerCaptor.capture(), any(), any(),
any(), anyInt(), any(), anyInt());
inOrderM.verify(mAwareMetricsMock).recordNdpStatus(eq(NanStatusType.SUCCESS),
eq(true), anyLong());
inOrderM.verify(mAwareMetricsMock).recordNdpCreation(anyInt(), any());
// (8) execute 'post' requests
for (int i = numRequestsPre; i < numRequestsPre + numRequestsPost; ++i) {
nrs[i] = getDirectNetworkRequest(clientId + i,
WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR, peerDiscoveryMac, null,
null, i);
Message reqNetworkMsg = Message.obtain();
reqNetworkMsg.what = NetworkFactory.CMD_REQUEST_NETWORK;
reqNetworkMsg.obj = nrs[i];
reqNetworkMsg.arg1 = 0;
messenger.send(reqNetworkMsg);
}
nrs[numRequestsPre + numRequestsPost] = getSessionNetworkRequest(
clientId + numRequestsPre + numRequestsPost, ddepi.mSessionId, ddepi.mPeerHandle,
null, null, false, 11);
Message reqNetworkMsg = Message.obtain();
reqNetworkMsg.what = NetworkFactory.CMD_REQUEST_NETWORK;
reqNetworkMsg.obj = nrs[numRequestsPre + numRequestsPost];
reqNetworkMsg.arg1 = 0;
messenger.send(reqNetworkMsg);
mMockLooper.dispatchAll();
// (9) unregister all requests
for (int i = 2; i < numRequestsPre + numRequestsPost + 1; ++i) {
endNetworkReqMsg = Message.obtain();
endNetworkReqMsg.what = NetworkFactory.CMD_CANCEL_REQUEST;
endNetworkReqMsg.obj = nrs[i];
messenger.send(endNetworkReqMsg);
mMockLooper.dispatchAll();
}
Message endNetworkUsageMsg = Message.obtain();
endNetworkUsageMsg.what = AsyncChannel.CMD_CHANNEL_DISCONNECTED;
agentMessengerCaptor.getValue().send(endNetworkUsageMsg);
mMockLooper.dispatchAll();
// (10) verify that NDP torn down
inOrder.verify(mMockNative).endDataPath(transactionId.capture(), eq(ndpId));
mDut.onEndDataPathResponse(transactionId.getValue(), true, 0);
mDut.onDataPathEndNotification(ndpId);
mMockLooper.dispatchAll();
inOrder.verify(mMockNwMgt).setInterfaceDown(anyString());
inOrderM.verify(mAwareMetricsMock).recordNdpSessionDuration(anyLong());
verifyNoMoreInteractions(mMockNative, mMockCm, mMockCallback, mMockSessionCallback,
mAwareMetricsMock, mMockNwMgt);
}
/**
* Validate that multiple NDP requests to the same peer target different NDIs.
*/
@Test
public void testMultipleNdi() throws Exception {
final int numNdis = 5;
final int clientId = 123;
final int ndpId = 5;
final byte[] peerDiscoveryMac = HexEncoding.decode("000102030405".toCharArray(), false);
final byte[] peerDataPathMac = HexEncoding.decode("0A0B0C0D0E0F".toCharArray(), false);
ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class);
ArgumentCaptor<String> ifNameCaptor = ArgumentCaptor.forClass(String.class);
InOrder inOrder = inOrder(mMockNative, mMockCm, mMockCallback, mMockSessionCallback,
mMockNwMgt);
InOrder inOrderM = inOrder(mAwareMetricsMock);
// (1) initialize all clients
Messenger messenger = initOobDataPathEndPoint(true, numNdis, clientId, inOrder, inOrderM);
for (int i = 1; i < numNdis + 3; ++i) {
initOobDataPathEndPoint(false, numNdis, clientId + i, inOrder, inOrderM);
}
// (2) make N network requests: each unique
Set<String> interfaces = new HashSet<>();
for (int i = 0; i < numNdis + 1; ++i) {
byte[] pmk = new byte[32];
pmk[0] = (byte) i;
NetworkRequest nr = getDirectNetworkRequest(clientId + i,
WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR, peerDiscoveryMac, pmk,
null, i);
Message reqNetworkMsg = Message.obtain();
reqNetworkMsg.what = NetworkFactory.CMD_REQUEST_NETWORK;
reqNetworkMsg.obj = nr;
reqNetworkMsg.arg1 = 0;
messenger.send(reqNetworkMsg);
mMockLooper.dispatchAll();
if (i < numNdis) {
inOrder.verify(mMockNative).initiateDataPath(transactionId.capture(), eq(0),
eq(CHANNEL_NOT_REQUESTED), anyInt(), eq(peerDiscoveryMac),
ifNameCaptor.capture(), eq(pmk), eq(null), eq(true), any());
interfaces.add(ifNameCaptor.getValue());
mDut.onInitiateDataPathResponseSuccess(transactionId.getValue(), ndpId + i);
mDut.onDataPathConfirmNotification(ndpId + i, peerDataPathMac, true, 0, null, null);
mMockLooper.dispatchAll();
inOrder.verify(mMockNwMgt).setInterfaceUp(anyString());
inOrder.verify(mMockNwMgt).enableIpv6(anyString());
inOrder.verify(mMockCm).registerNetworkAgent(any(), any(), any(), any(), anyInt(),
any(), anyInt());
inOrderM.verify(mAwareMetricsMock).recordNdpStatus(eq(NanStatusType.SUCCESS),
eq(true), anyLong());
inOrderM.verify(mAwareMetricsMock).recordNdpCreation(anyInt(), any());
}
}
// verify that each interface name is unique
assertEquals("Number of unique interface names", numNdis, interfaces.size());
verifyNoMoreInteractions(mMockNative, mMockCm, mMockCallback, mMockSessionCallback,
mAwareMetricsMock, mMockNwMgt);
}
/*
* Initiator tests
*/
/**
* Validate the success flow of the Initiator: using session network specifier with a non-null
* PMK.
*/
@Test
public void testDataPathInitiatorMacPmkSuccess() throws Exception {
testDataPathInitiatorUtility(false, true, true, false, true, false);
}
/**
* Validate the success flow of the Initiator: using a direct network specifier with a non-null
* peer mac and non-null PMK.
*/
@Test
public void testDataPathInitiatorDirectMacPmkSuccess() throws Exception {
testDataPathInitiatorUtility(true, true, true, false, true, false);
}
/**
* Validate the fail flow of the Initiator: use a session network specifier with a non-null
* PMK, but don't get a confirmation.
*/
@Test
public void testDataPathInitiatorNoConfirmationTimeoutFail() throws Exception {
testDataPathInitiatorUtility(false, true, true, false, false, false);
}
/**
* Validate the fail flow of the Initiator: use a session network specifier with a non-null
* Passphrase, but get an immediate failure
*/
@Test
public void testDataPathInitiatorNoConfirmationHalFail() throws Exception {
testDataPathInitiatorUtility(false, true, false, true, true, true);
}
/**
* Validate the fail flow of a mis-configured request: Publisher as Initiator
*/
@Test
public void testDataPathInitiatorOnPublisherError() throws Exception {
testDataPathInitiatorResponderMismatchUtility(true);
}
/**
* Validate the fail flow of an Initiator (subscriber) with its UID unset
*/
@Test
public void testDataPathInitiatorUidUnsetError() throws Exception {
testDataPathInitiatorResponderInvalidUidUtility(false, false);
}
/**
* Validate the fail flow of an Initiator (subscriber) with its UID set as a malicious
* attacker (i.e. mismatched to its requested client's UID).
*/
@Test
public void testDataPathInitiatorUidSetIncorrectlyError() throws Exception {
testDataPathInitiatorResponderInvalidUidUtility(false, true);
}
/*
* Responder tests
*/
/**
* Validate the success flow of the Responder: using session network specifier with a
* PMK.
*/
@Test
public void testDataPathResonderMacPmkSuccess() throws Exception {
testDataPathResponderUtility(false, true, true, false, true);
}
/**
* Validate the success flow of the Responder: using session network specifier with a
* Passphrase.
*/
@Test
public void testDataPathResonderMacPassphraseSuccess() throws Exception {
testDataPathResponderUtility(false, true, false, false, true);
}
/**
* Validate the success flow of the Responder: using session network specifier with a
* Passphrase and no peer ID (i.e. 0).
*/
@Test
public void testDataPathResonderMacPassphraseNoPeerIdSuccess() throws Exception {
testDataPathResponderUtility(false, false, false, true, true);
}
/**
* Validate the success flow of the Responder: using session network specifier with a null
* PMK/Passphrase and no peer ID (i.e. 0).
*/
@Test
public void testDataPathResonderMacOpenNoPeerIdNoPmkPassphraseSuccess() throws Exception {
testDataPathResponderUtility(false, false, false, false, true);
}
/**
* Validate the failure flow of the Responder: using session network specifier with a
* Passphrase and no peer ID (i.e. 0) on a NON-LEGACY device.
*/
@Test
public void testDataPathResonderMacPassphraseNoPeerIdSuccessNonLegacy() throws Exception {
when(mWifiPermissionsUtil.isLegacyVersion(anyString(), anyInt())).thenReturn(false);
testDataPathResponderUtility(false, false, false, true, true);
}
/**
* Validate the failure flow of the Responder: using session network specifier with a null
* PMK/Passphrase and no peer ID (i.e. 0) on a NON-LEGACY device.
*/
@Test
public void testDataPathResonderMacOpenNoPeerIdNoPmkPassphraseSuccessNonLegacy()
throws Exception {
when(mWifiPermissionsUtil.isLegacyVersion(anyString(), anyInt())).thenReturn(false);
testDataPathResponderUtility(false, false, false, false, true);
}
/**
* Validate the success flow of the Responder: using a direct network specifier with a non-null
* peer mac and non-null PMK.
*/
@Test
public void testDataPathResonderDirectMacPmkSuccess() throws Exception {
testDataPathResponderUtility(true, true, true, false, true);
}
/**
* Validate the success flow of the Responder: using a direct network specifier with a non-null
* peer mac and null PMK/Passphrase.
*/
@Test
public void testDataPathResonderDirectMacNoPmkPassphraseSuccess() throws Exception {
testDataPathResponderUtility(true, true, false, false, true);
}
/**
* Validate the success flow of the Responder: using a direct network specifier with a null peer
* mac and non-null Passphrase.
*/
@Test
public void testDataPathResonderDirectNoMacPassphraseSuccess() throws Exception {
testDataPathResponderUtility(true, false, false, true, true);
}
/**
* Validate the success flow of the Responder: using a direct network specifier with a null peer
* mac and null Pmk/Passphrase.
*/
@Test
public void testDataPathResonderDirectNoMacNoPmkPassphraseSuccess() throws Exception {
testDataPathResponderUtility(true, false, false, false, true);
}
/**
* Validate the failure flow of the Responder: using a direct network specifier with a null peer
* mac and non-null Passphrase on a NON-LEGACY device.
*/
@Test
public void testDataPathResonderDirectNoMacPassphraseSuccessNonLegacy() throws Exception {
when(mWifiPermissionsUtil.isLegacyVersion(anyString(), anyInt())).thenReturn(false);
testDataPathResponderUtility(true, false, false, true, true);
}
/**
* Validate the failure flow of the Responder: using a direct network specifier with a null peer
* mac and null Pmk/Passphrase on a NON-LEGACY device.
*/
@Test
public void testDataPathResonderDirectNoMacNoPmkPassphraseSuccessNonLegacy() throws Exception {
when(mWifiPermissionsUtil.isLegacyVersion(anyString(), anyInt())).thenReturn(false);
testDataPathResponderUtility(true, false, false, false, true);
}
/**
* Validate the fail flow of the Responder: use a session network specifier with a non-null
* PMK, but don't get a confirmation.
*/
@Test
public void testDataPathResponderNoConfirmationTimeoutFail() throws Exception {
testDataPathResponderUtility(false, true, true, false, false);
}
/**
* Validate the fail flow of a mis-configured request: Subscriber as Responder
*/
@Test
public void testDataPathResponderOnSubscriberError() throws Exception {
testDataPathInitiatorResponderMismatchUtility(false);
}
/**
* Validate the fail flow of an Initiator (subscriber) with its UID unset
*/
@Test
public void testDataPathResponderUidUnsetError() throws Exception {
testDataPathInitiatorResponderInvalidUidUtility(true, false);
}
/**
* Validate the fail flow of an Initiator (subscriber) with its UID set as a malicious
* attacker (i.e. mismatched to its requested client's UID).
*/
@Test
public void testDataPathResponderUidSetIncorrectlyError() throws Exception {
testDataPathInitiatorResponderInvalidUidUtility(true, true);
}
/*
* Utilities
*/
private void testDataPathInitiatorResponderMismatchUtility(boolean doPublish) throws Exception {
final int clientId = 123;
final byte pubSubId = 55;
final int ndpId = 2;
final byte[] pmk = "01234567890123456789012345678901".getBytes();
final int requestorId = 1341234;
final byte[] peerDiscoveryMac = HexEncoding.decode("000102030405".toCharArray(), false);
InOrder inOrder = inOrder(mMockNative, mMockCm, mMockCallback, mMockSessionCallback);
InOrder inOrderM = inOrder(mAwareMetricsMock);
// (0) initialize
DataPathEndPointInfo res = initDataPathEndPoint(true, clientId, pubSubId, requestorId,
peerDiscoveryMac, inOrder, inOrderM, doPublish);
// (1) request network
NetworkRequest nr = getSessionNetworkRequest(clientId, res.mSessionId, res.mPeerHandle, pmk,
null, doPublish, 0);
// corrupt the network specifier: reverse the role (so it's mis-matched)
WifiAwareNetworkSpecifier ns =
(WifiAwareNetworkSpecifier) nr.networkCapabilities.getNetworkSpecifier();
ns = new WifiAwareNetworkSpecifier(
ns.type,
1 - ns.role, // corruption hack
ns.clientId,
ns.sessionId,
ns.peerId,
ns.peerMac,
ns.pmk,
ns.passphrase,
ns.requestorUid);
nr.networkCapabilities.setNetworkSpecifier(ns);
Message reqNetworkMsg = Message.obtain();
reqNetworkMsg.what = NetworkFactory.CMD_REQUEST_NETWORK;
reqNetworkMsg.obj = nr;
reqNetworkMsg.arg1 = 0;
res.mMessenger.send(reqNetworkMsg);
mMockLooper.dispatchAll();
// consequences of failure:
// Responder (publisher): responds with a rejection to any data-path requests
// Initiator (subscribe): doesn't initiate (i.e. no HAL requests)
if (doPublish) {
// (2) get request & respond
mDut.onDataPathRequestNotification(pubSubId, peerDiscoveryMac, ndpId);
mMockLooper.dispatchAll();
inOrder.verify(mMockNative).respondToDataPathRequest(anyShort(), eq(false),
eq(ndpId), eq(""), eq(null), eq(null), anyBoolean(), any());
}
verifyNoMoreInteractions(mMockNative, mMockCm, mAwareMetricsMock, mMockNwMgt);
}
private void testDataPathInitiatorResponderInvalidUidUtility(boolean doPublish,
boolean isUidSet) throws Exception {
final int clientId = 123;
final byte pubSubId = 56;
final int ndpId = 2;
final byte[] pmk = "01234567890123456789012345678901".getBytes();
final int requestorId = 1341234;
final byte[] peerDiscoveryMac = HexEncoding.decode("000102030405".toCharArray(), false);
InOrder inOrder = inOrder(mMockNative, mMockCm, mMockCallback, mMockSessionCallback);
InOrder inOrderM = inOrder(mAwareMetricsMock);
// (0) initialize
DataPathEndPointInfo res = initDataPathEndPoint(true, clientId, pubSubId, requestorId,
peerDiscoveryMac, inOrder, inOrderM, doPublish);
// (1) create network request
NetworkRequest nr = getSessionNetworkRequest(clientId, res.mSessionId, res.mPeerHandle, pmk,
null, doPublish, 0);
// (2) corrupt request's UID
WifiAwareNetworkSpecifier ns =
(WifiAwareNetworkSpecifier) nr.networkCapabilities.getNetworkSpecifier();
ns = new WifiAwareNetworkSpecifier(
ns.type,
ns.role,
ns.clientId,
ns.sessionId,
ns.peerId,
ns.peerMac,
ns.pmk,
ns.passphrase,
ns.requestorUid + 1); // corruption hack
nr.networkCapabilities.setNetworkSpecifier(ns);
// (3) request network
Message reqNetworkMsg = Message.obtain();
reqNetworkMsg.what = NetworkFactory.CMD_REQUEST_NETWORK;
reqNetworkMsg.obj = nr;
reqNetworkMsg.arg1 = 0;
res.mMessenger.send(reqNetworkMsg);
mMockLooper.dispatchAll();
// consequences of failure:
// Responder (publisher): responds with a rejection to any data-path requests
// Initiator (subscribe): doesn't initiate (i.e. no HAL requests)
if (doPublish) {
// (2) get request & respond
mDut.onDataPathRequestNotification(pubSubId, peerDiscoveryMac, ndpId);
mMockLooper.dispatchAll();
inOrder.verify(mMockNative).respondToDataPathRequest(anyShort(), eq(false),
eq(ndpId), eq(""), eq(null), eq(null), anyBoolean(), any());
}
verifyNoMoreInteractions(mMockNative, mMockCm, mAwareMetricsMock, mMockNwMgt);
}
private void testDataPathInitiatorUtility(boolean useDirect, boolean provideMac,
boolean providePmk, boolean providePassphrase, boolean getConfirmation,
boolean immediateHalFailure) throws Exception {
final int clientId = 123;
final byte pubSubId = 58;
final int requestorId = 1341234;
final int ndpId = 2;
final byte[] pmk = "01234567890123456789012345678901".getBytes();
final String passphrase = "some passphrase";
final String peerToken = "let's go!";
final byte[] peerDiscoveryMac = HexEncoding.decode("000102030405".toCharArray(), false);
final byte[] peerDataPathMac = HexEncoding.decode("0A0B0C0D0E0F".toCharArray(), false);
ArgumentCaptor<Messenger> messengerCaptor = ArgumentCaptor.forClass(Messenger.class);
ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class);
InOrder inOrder = inOrder(mMockNative, mMockCm, mMockCallback, mMockSessionCallback,
mMockNwMgt);
InOrder inOrderM = inOrder(mAwareMetricsMock);
if (!providePmk) {
when(mPermissionsWrapperMock.getUidPermission(
eq(Manifest.permission.CONNECTIVITY_INTERNAL), anyInt())).thenReturn(
PackageManager.PERMISSION_DENIED);
}
if (immediateHalFailure) {
when(mMockNative.initiateDataPath(anyShort(), anyInt(), anyInt(), anyInt(), any(),
any(), any(), any(), anyBoolean(), any())).thenReturn(false);
}
// (0) initialize
DataPathEndPointInfo res = initDataPathEndPoint(true, clientId, pubSubId, requestorId,
peerDiscoveryMac, inOrder, inOrderM, false);
// (1) request network
NetworkRequest nr;
if (useDirect) {
nr = getDirectNetworkRequest(clientId,
WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR,
provideMac ? peerDiscoveryMac : null, providePmk ? pmk : null,
providePassphrase ? passphrase : null, 0);
} else {
nr = getSessionNetworkRequest(clientId, res.mSessionId,
provideMac ? res.mPeerHandle : null, providePmk ? pmk : null,
providePassphrase ? passphrase : null, false, 0);
}
Message reqNetworkMsg = Message.obtain();
reqNetworkMsg.what = NetworkFactory.CMD_REQUEST_NETWORK;
reqNetworkMsg.obj = nr;
reqNetworkMsg.arg1 = 0;
res.mMessenger.send(reqNetworkMsg);
mMockLooper.dispatchAll();
inOrder.verify(mMockNative).initiateDataPath(transactionId.capture(),
eq(useDirect ? 0 : requestorId),
eq(CHANNEL_NOT_REQUESTED), anyInt(), eq(peerDiscoveryMac),
eq(sAwareInterfacePrefix + "0"), eq(providePmk ? pmk : null),
eq(providePassphrase ? passphrase : null), eq(useDirect), any());
if (immediateHalFailure) {
// short-circuit the rest of this test
inOrderM.verify(mAwareMetricsMock).recordNdpStatus(eq(NanStatusType.INTERNAL_FAILURE),
eq(useDirect), anyLong());
verifyNoMoreInteractions(mMockNative, mMockCm, mAwareMetricsMock);
return;
}
mDut.onInitiateDataPathResponseSuccess(transactionId.getValue(), ndpId);
mMockLooper.dispatchAll();
// (2) get confirmation OR timeout
if (getConfirmation) {
mDut.onDataPathConfirmNotification(ndpId, peerDataPathMac, true, 0,
peerToken.getBytes(), null);
mMockLooper.dispatchAll();
inOrder.verify(mMockNwMgt).setInterfaceUp(anyString());
inOrder.verify(mMockNwMgt).enableIpv6(anyString());
inOrder.verify(mMockCm).registerNetworkAgent(messengerCaptor.capture(), any(), any(),
any(), anyInt(), any(), anyInt());
inOrderM.verify(mAwareMetricsMock).recordNdpStatus(eq(NanStatusType.SUCCESS),
eq(useDirect), anyLong());
inOrderM.verify(mAwareMetricsMock).recordNdpCreation(anyInt(), any());
} else {
assertTrue(mAlarmManager.dispatch(
WifiAwareStateManager.HAL_DATA_PATH_CONFIRM_TIMEOUT_TAG));
mMockLooper.dispatchAll();
inOrder.verify(mMockNative).endDataPath(transactionId.capture(), eq(ndpId));
mDut.onEndDataPathResponse(transactionId.getValue(), true, 0);
mMockLooper.dispatchAll();
inOrderM.verify(mAwareMetricsMock).recordNdpStatus(eq(NanStatusType.INTERNAL_FAILURE),
eq(useDirect), anyLong());
}
// (3) end data-path (unless didn't get confirmation)
if (getConfirmation) {
Message endNetworkReqMsg = Message.obtain();
endNetworkReqMsg.what = NetworkFactory.CMD_CANCEL_REQUEST;
endNetworkReqMsg.obj = nr;
res.mMessenger.send(endNetworkReqMsg);
Message endNetworkUsageMsg = Message.obtain();
endNetworkUsageMsg.what = AsyncChannel.CMD_CHANNEL_DISCONNECTED;
messengerCaptor.getValue().send(endNetworkUsageMsg);
mDut.onEndDataPathResponse(transactionId.getValue(), true, 0);
mDut.onDataPathEndNotification(ndpId);
mMockLooper.dispatchAll();
inOrder.verify(mMockNwMgt).setInterfaceDown(anyString());
inOrder.verify(mMockNative).endDataPath(transactionId.capture(), eq(ndpId));
inOrderM.verify(mAwareMetricsMock).recordNdpSessionDuration(anyLong());
}
verifyNoMoreInteractions(mMockNative, mMockCm, mAwareMetricsMock, mMockNwMgt);
}
private void testDataPathResponderUtility(boolean useDirect, boolean provideMac,
boolean providePmk, boolean providePassphrase, boolean getConfirmation)
throws Exception {
final int clientId = 123;
final byte pubSubId = 60;
final int requestorId = 1341234;
final int ndpId = 2;
final byte[] pmk = "01234567890123456789012345678901".getBytes();
final String passphrase = "some passphrase";
final String peerToken = "let's go!";
final byte[] peerDiscoveryMac = HexEncoding.decode("000102030405".toCharArray(), false);
final byte[] peerDataPathMac = HexEncoding.decode("0A0B0C0D0E0F".toCharArray(), false);
ArgumentCaptor<Messenger> messengerCaptor = ArgumentCaptor.forClass(Messenger.class);
ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class);
InOrder inOrder = inOrder(mMockNative, mMockCm, mMockCallback, mMockSessionCallback,
mMockNwMgt);
InOrder inOrderM = inOrder(mAwareMetricsMock);
boolean isLegacy = mWifiPermissionsUtil.isLegacyVersion("anything", Build.VERSION_CODES.P);
if (providePmk) {
when(mPermissionsWrapperMock.getUidPermission(
eq(Manifest.permission.CONNECTIVITY_INTERNAL), anyInt())).thenReturn(
PackageManager.PERMISSION_GRANTED);
}
// (0) initialize
DataPathEndPointInfo res = initDataPathEndPoint(true, clientId, pubSubId, requestorId,
peerDiscoveryMac, inOrder, inOrderM, true);
// (1) request network
NetworkRequest nr;
if (useDirect) {
nr = getDirectNetworkRequest(clientId,
WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER,
provideMac ? peerDiscoveryMac : null, providePmk ? pmk : null,
providePassphrase ? passphrase : null, 0);
} else {
nr = getSessionNetworkRequest(clientId, res.mSessionId,
provideMac ? res.mPeerHandle : null, providePmk ? pmk : null,
providePassphrase ? passphrase : null, true, 0);
}
Message reqNetworkMsg = Message.obtain();
reqNetworkMsg.what = NetworkFactory.CMD_REQUEST_NETWORK;
reqNetworkMsg.obj = nr;
reqNetworkMsg.arg1 = 0;
res.mMessenger.send(reqNetworkMsg);
mMockLooper.dispatchAll();
// (2) get request & respond (if legacy)
mDut.onDataPathRequestNotification(pubSubId, peerDiscoveryMac, ndpId);
mMockLooper.dispatchAll();
if (isLegacy) {
inOrder.verify(mMockNative).respondToDataPathRequest(transactionId.capture(), eq(true),
eq(ndpId), eq(sAwareInterfacePrefix + "0"), eq(providePmk ? pmk : null),
eq(providePassphrase ? passphrase : null), eq(useDirect), any());
mDut.onRespondToDataPathSetupRequestResponse(transactionId.getValue(), true, 0);
mMockLooper.dispatchAll();
// (3) get confirmation OR timeout
if (getConfirmation) {
mDut.onDataPathConfirmNotification(ndpId, peerDataPathMac, true, 0,
peerToken.getBytes(), null);
mMockLooper.dispatchAll();
inOrder.verify(mMockNwMgt).setInterfaceUp(anyString());
inOrder.verify(mMockNwMgt).enableIpv6(anyString());
inOrder.verify(mMockCm).registerNetworkAgent(messengerCaptor.capture(), any(),
any(), any(), anyInt(), any(), anyInt());
inOrderM.verify(mAwareMetricsMock).recordNdpStatus(eq(NanStatusType.SUCCESS),
eq(useDirect), anyLong());
inOrderM.verify(mAwareMetricsMock).recordNdpCreation(anyInt(), any());
} else {
assertTrue(mAlarmManager.dispatch(
WifiAwareStateManager.HAL_DATA_PATH_CONFIRM_TIMEOUT_TAG));
mMockLooper.dispatchAll();
inOrder.verify(mMockNative).endDataPath(transactionId.capture(), eq(ndpId));
mDut.onEndDataPathResponse(transactionId.getValue(), true, 0);
mMockLooper.dispatchAll();
inOrderM.verify(mAwareMetricsMock).recordNdpStatus(
eq(NanStatusType.INTERNAL_FAILURE), eq(useDirect), anyLong());
}
// (4) end data-path (unless didn't get confirmation)
if (getConfirmation) {
Message endNetworkMsg = Message.obtain();
endNetworkMsg.what = NetworkFactory.CMD_CANCEL_REQUEST;
endNetworkMsg.obj = nr;
res.mMessenger.send(endNetworkMsg);
Message endNetworkUsageMsg = Message.obtain();
endNetworkUsageMsg.what = AsyncChannel.CMD_CHANNEL_DISCONNECTED;
messengerCaptor.getValue().send(endNetworkUsageMsg);
mDut.onEndDataPathResponse(transactionId.getValue(), true, 0);
mDut.onDataPathEndNotification(ndpId);
mMockLooper.dispatchAll();
inOrder.verify(mMockNwMgt).setInterfaceDown(anyString());
inOrder.verify(mMockNative).endDataPath(transactionId.capture(), eq(ndpId));
inOrderM.verify(mAwareMetricsMock).recordNdpSessionDuration(anyLong());
}
} else {
inOrder.verify(mMockNative).respondToDataPathRequest(transactionId.capture(), eq(false),
eq(ndpId), eq(""), eq(null), eq(null), eq(false), any());
mDut.onRespondToDataPathSetupRequestResponse(transactionId.getValue(), true, 0);
mMockLooper.dispatchAll();
}
verifyNoMoreInteractions(mMockNative, mMockCm, mAwareMetricsMock, mMockNwMgt);
}
private NetworkRequest getSessionNetworkRequest(int clientId, int sessionId,
PeerHandle peerHandle, byte[] pmk, String passphrase, boolean doPublish, int requestId)
throws Exception {
final IWifiAwareManager mockAwareService = mock(IWifiAwareManager.class);
final WifiAwareManager mgr = new WifiAwareManager(mMockContext, mockAwareService);
final ConfigRequest configRequest = new ConfigRequest.Builder().build();
final PublishConfig publishConfig = new PublishConfig.Builder().build();
final SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build();
ArgumentCaptor<WifiAwareSession> sessionCaptor = ArgumentCaptor.forClass(
WifiAwareSession.class);
ArgumentCaptor<IWifiAwareEventCallback> clientProxyCallback = ArgumentCaptor
.forClass(IWifiAwareEventCallback.class);
ArgumentCaptor<IWifiAwareDiscoverySessionCallback> sessionProxyCallback = ArgumentCaptor
.forClass(IWifiAwareDiscoverySessionCallback.class);
ArgumentCaptor<DiscoverySession> discoverySession = ArgumentCaptor
.forClass(DiscoverySession.class);
AttachCallback mockCallback = mock(AttachCallback.class);
DiscoverySessionCallback mockSessionCallback = mock(
DiscoverySessionCallback.class);
InOrder inOrderS = inOrder(mockAwareService, mockCallback, mockSessionCallback);
mgr.attach(mMockLooperHandler, configRequest, mockCallback, null);
inOrderS.verify(mockAwareService).connect(any(), any(),
clientProxyCallback.capture(), eq(configRequest), eq(false));
IWifiAwareEventCallback iwaec = clientProxyCallback.getValue();
iwaec.onConnectSuccess(clientId);
mMockLooper.dispatchAll();
inOrderS.verify(mockCallback).onAttached(sessionCaptor.capture());
if (doPublish) {
sessionCaptor.getValue().publish(publishConfig, mockSessionCallback,
mMockLooperHandler);
inOrderS.verify(mockAwareService).publish(any(), eq(clientId), eq(publishConfig),
sessionProxyCallback.capture());
} else {
sessionCaptor.getValue().subscribe(subscribeConfig, mockSessionCallback,
mMockLooperHandler);
inOrderS.verify(mockAwareService).subscribe(any(), eq(clientId), eq(subscribeConfig),
sessionProxyCallback.capture());
}
sessionProxyCallback.getValue().onSessionStarted(sessionId);
mMockLooper.dispatchAll();
if (doPublish) {
inOrderS.verify(mockSessionCallback).onPublishStarted(
(PublishDiscoverySession) discoverySession.capture());
} else {
inOrderS.verify(mockSessionCallback).onSubscribeStarted(
(SubscribeDiscoverySession) discoverySession.capture());
}
NetworkSpecifier ns;
if (pmk == null && passphrase == null) {
ns = createNetworkSpecifier(clientId,
doPublish ? WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER
: WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR, sessionId,
peerHandle, null, null);
} else if (passphrase == null) {
ns = createNetworkSpecifier(clientId,
doPublish ? WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER
: WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR, sessionId,
peerHandle, pmk, null);
} else {
ns = createNetworkSpecifier(clientId,
doPublish ? WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER
: WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR, sessionId,
peerHandle, null, passphrase);
}
NetworkCapabilities nc = new NetworkCapabilities();
nc.clearAll();
nc.addTransportType(NetworkCapabilities.TRANSPORT_WIFI_AWARE);
nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN).addCapability(
NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
nc.setNetworkSpecifier(ns);
nc.setLinkUpstreamBandwidthKbps(1);
nc.setLinkDownstreamBandwidthKbps(1);
nc.setSignalStrength(1);
return new NetworkRequest(nc, 0, requestId, NetworkRequest.Type.NONE);
}
private NetworkRequest getDirectNetworkRequest(int clientId, int role, byte[] peer,
byte[] pmk, String passphrase, int requestId) throws Exception {
final IWifiAwareManager mockAwareService = mock(IWifiAwareManager.class);
final ConfigRequest configRequest = new ConfigRequest.Builder().build();
final WifiAwareManager mgr = new WifiAwareManager(mMockContext, mockAwareService);
ArgumentCaptor<WifiAwareSession> sessionCaptor = ArgumentCaptor.forClass(
WifiAwareSession.class);
ArgumentCaptor<IWifiAwareEventCallback> clientProxyCallback = ArgumentCaptor
.forClass(IWifiAwareEventCallback.class);
AttachCallback mockCallback = mock(AttachCallback.class);
mgr.attach(mMockLooperHandler, configRequest, mockCallback, null);
verify(mockAwareService).connect(any(), any(),
clientProxyCallback.capture(), eq(configRequest), eq(false));
clientProxyCallback.getValue().onConnectSuccess(clientId);
mMockLooper.dispatchAll();
verify(mockCallback).onAttached(sessionCaptor.capture());
NetworkSpecifier ns;
if (pmk == null && passphrase == null) {
ns = createNetworkSpecifier(clientId, role, peer, null, null);
} else if (passphrase == null) {
ns = createNetworkSpecifier(clientId, role, peer, pmk, null);
} else {
ns = createNetworkSpecifier(clientId, role, peer, null, passphrase);
}
NetworkCapabilities nc = new NetworkCapabilities();
nc.clearAll();
nc.addTransportType(NetworkCapabilities.TRANSPORT_WIFI_AWARE);
nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)
.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED);
nc.setNetworkSpecifier(ns);
nc.setLinkUpstreamBandwidthKbps(1);
nc.setLinkDownstreamBandwidthKbps(1);
nc.setSignalStrength(1);
return new NetworkRequest(nc, 0, requestId, NetworkRequest.Type.REQUEST);
}
private DataPathEndPointInfo initDataPathEndPoint(boolean isFirstIteration, int clientId,
byte pubSubId, int requestorId, byte[] peerDiscoveryMac, InOrder inOrder,
InOrder inOrderM, boolean doPublish)
throws Exception {
final String someMsg = "some arbitrary message from peer";
final PublishConfig publishConfig = new PublishConfig.Builder().build();
final SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build();
ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class);
ArgumentCaptor<Integer> sessionId = ArgumentCaptor.forClass(Integer.class);
ArgumentCaptor<Integer> peerIdCaptor = ArgumentCaptor.forClass(Integer.class);
Messenger messenger = initOobDataPathEndPoint(isFirstIteration, 1, clientId, inOrder,
inOrderM);
if (doPublish) {
mDut.publish(clientId, publishConfig, mMockSessionCallback);
} else {
mDut.subscribe(clientId, subscribeConfig, mMockSessionCallback);
}
mMockLooper.dispatchAll();
if (doPublish) {
inOrder.verify(mMockNative).publish(transactionId.capture(), eq((byte) 0),
eq(publishConfig));
} else {
inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq((byte) 0),
eq(subscribeConfig));
}
mDut.onSessionConfigSuccessResponse(transactionId.getValue(), doPublish, pubSubId);
mMockLooper.dispatchAll();
inOrder.verify(mMockSessionCallback).onSessionStarted(sessionId.capture());
inOrderM.verify(mAwareMetricsMock).recordDiscoverySession(eq(Process.myUid()), any());
inOrderM.verify(mAwareMetricsMock).recordDiscoveryStatus(Process.myUid(),
NanStatusType.SUCCESS, doPublish);
mDut.onMessageReceivedNotification(pubSubId, requestorId, peerDiscoveryMac,
someMsg.getBytes());
mMockLooper.dispatchAll();
inOrder.verify(mMockSessionCallback).onMessageReceived(peerIdCaptor.capture(),
eq(someMsg.getBytes()));
return new DataPathEndPointInfo(sessionId.getValue(), peerIdCaptor.getValue(),
isFirstIteration ? messenger : null);
}
private Messenger initOobDataPathEndPoint(boolean startUpSequence, int maxNdiInterfaces,
int clientId, InOrder inOrder, InOrder inOrderM) throws Exception {
final int pid = 2000;
final String callingPackage = "com.android.somePackage";
final ConfigRequest configRequest = new ConfigRequest.Builder().build();
ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class);
ArgumentCaptor<Messenger> messengerCaptor = ArgumentCaptor.forClass(Messenger.class);
ArgumentCaptor<String> strCaptor = ArgumentCaptor.forClass(String.class);
Capabilities capabilities = new Capabilities();
capabilities.maxNdiInterfaces = maxNdiInterfaces;
if (startUpSequence) {
// (0) start/registrations
inOrder.verify(mMockCm).registerNetworkFactory(messengerCaptor.capture(),
strCaptor.capture());
collector.checkThat("factory name", "WIFI_AWARE_FACTORY",
equalTo(strCaptor.getValue()));
// (1) get capabilities
mDut.queryCapabilities();
mMockLooper.dispatchAll();
inOrder.verify(mMockNative).getCapabilities(transactionId.capture());
mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), capabilities);
mMockLooper.dispatchAll();
// (2) enable usage
mDut.enableUsage();
mMockLooper.dispatchAll();
inOrderM.verify(mAwareMetricsMock).recordEnableUsage();
}
// (3) create client
mDut.connect(clientId, Process.myUid(), pid, callingPackage, mMockCallback,
configRequest,
false);
mMockLooper.dispatchAll();
if (startUpSequence) {
inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(),
eq(configRequest), eq(false), eq(true), eq(true), eq(false));
mDut.onConfigSuccessResponse(transactionId.getValue());
mMockLooper.dispatchAll();
}
inOrder.verify(mMockCallback).onConnectSuccess(clientId);
inOrderM.verify(mAwareMetricsMock).recordAttachSession(eq(Process.myUid()), eq(false),
any());
if (startUpSequence) {
for (int i = 0; i < maxNdiInterfaces; ++i) {
inOrder.verify(mMockNative).createAwareNetworkInterface(transactionId.capture(),
strCaptor.capture());
collector.checkThat("interface created -- " + i, sAwareInterfacePrefix + i,
equalTo(strCaptor.getValue()));
mDut.onCreateDataPathInterfaceResponse(transactionId.getValue(), true, 0);
mMockLooper.dispatchAll();
}
return messengerCaptor.getValue();
}
return null;
}
/**
* Copy of DiscoverySession.createNetworkSpecifier - but without any checks! Allows creating
* network requests which may not be valid (e.g. for the API level).
*/
public NetworkSpecifier createNetworkSpecifier(int clientId, int role, int sessionId,
PeerHandle peerHandle, byte[] pmk, String passphrase) {
return new WifiAwareNetworkSpecifier(
(peerHandle == null) ? WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_IB_ANY_PEER
: WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_IB,
role,
clientId,
sessionId,
peerHandle != null ? peerHandle.peerId : 0, // 0 is an invalid peer ID
null, // peerMac (not used in this method)
pmk,
passphrase,
Process.myUid());
}
/**
* Copy of WifiAwareSession.createNetworkSpecifier - but without any checks! Allows creating
* network requests which may not be valid (e.g. for the API level).
*/
private NetworkSpecifier createNetworkSpecifier(int clientId, int role, byte[] peer, byte[] pmk,
String passphrase) {
return new WifiAwareNetworkSpecifier(
(peer == null) ? WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_OOB_ANY_PEER
: WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_OOB,
role,
clientId,
0, // 0 is an invalid session ID
0, // 0 is an invalid peer ID
peer,
pmk,
passphrase,
Process.myUid());
}
private static class DataPathEndPointInfo {
int mSessionId;
PeerHandle mPeerHandle;
Messenger mMessenger;
DataPathEndPointInfo(int sessionId, int peerId, Messenger messenger) {
mSessionId = sessionId;
mPeerHandle = new PeerHandle(peerId);
mMessenger = messenger;
}
}
}