blob: b05478134a17beddb88e50a221eaa26ceb08e72a [file] [log] [blame]
/*
* Copyright (C) 2017 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.cts.verifier.wifiaware.testcase;
import static com.android.cts.verifier.wifiaware.CallbackUtils.CALLBACK_TIMEOUT_SEC;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
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.WifiAwareSession;
import android.util.Log;
import android.util.Pair;
import com.android.cts.verifier.R;
import com.android.cts.verifier.wifiaware.BaseTestCase;
import com.android.cts.verifier.wifiaware.CallbackUtils;
/**
*Test case for data-path, out-of-band (OOB) test cases:
* open/passphrase * responder/initiator.
*
* OOB assumes that there's an alternative channel over which to communicate the discovery MAC
* address of the Aware interface. That channel (e.g. bluetooth or a host test device) is not
* readily available (don't want to have Aware tests dependent on BLE). Instead will fake the OOB
* channel using Aware itself: will do normal discovery during which the devices will exchange their
* MAC addresses, then destroy the discovery sessions and use the MAC addresses to perform OOB data-
* path requests.
*
* Responder test sequence:
* 1. Attach (with identity listener)
* wait for results (session)
* wait for identity
* 2. Publish
* wait for results (publish session)
* 3. Wait for rx message (with MAC)
* 4. Send message with MAC
* wait for success
* 5. Destroy discovery session
* 6. Request network (as Responder)
* wait for network
*
* Initiator test sequence:
* 1. Attach (with identity listener)
* wait for results (session)
* wait for identity
* 2. Subscribe
* wait for results (subscribe session)
* 3. Wait for discovery
* 4. Send message with MAC
* wait for success
* 5. Wait for rx message (with MAC)
* 6. Destroy discovery session
* 7. Sleep for 5 seconds to let Responder time to set up
* 8. Request network (as Initiator)
* wait for network
*/
public class DataPathOutOfBandTestCase extends BaseTestCase {
private static final String TAG = "DataPathOutOfBandTestCase";
private static final boolean DBG = true;
private static final int MAC_BYTES_LEN = 6;
private static final String SERVICE_NAME = "CtsVerifierTestService";
private static final String PASSPHRASE = "Some super secret password";
private static final int MESSAGE_ID = 1234;
private boolean mIsSecurityOpen;
private boolean mIsResponder;
private final Object mLock = new Object();
private String mFailureReason;
private WifiAwareSession mWifiAwareSession;
private byte[] mDiscoveryMac;
public DataPathOutOfBandTestCase(Context context, boolean isSecurityOpen,
boolean isResponder) {
super(context);
mIsSecurityOpen = isSecurityOpen;
mIsResponder = isResponder;
}
@Override
protected boolean executeTest() throws InterruptedException {
if (DBG) {
Log.d(TAG, "executeTest: mIsSecurityOpen=" + mIsSecurityOpen + ", mIsResponder="
+ mIsResponder);
}
// 1. attach (with identity listener)
CallbackUtils.AttachCb attachCb = new CallbackUtils.AttachCb();
CallbackUtils.IdentityListenerSingleShot identityL = new CallbackUtils
.IdentityListenerSingleShot();
mWifiAwareManager.attach(attachCb, identityL, mHandler);
Pair<Integer, WifiAwareSession> results = attachCb.waitForAttach();
switch (results.first) {
case CallbackUtils.AttachCb.TIMEOUT:
setFailureReason(mContext.getString(R.string.aware_status_attach_timeout));
Log.e(TAG, "executeTest: attach TIMEOUT");
return false;
case CallbackUtils.AttachCb.ON_ATTACH_FAILED:
setFailureReason(mContext.getString(R.string.aware_status_attach_fail));
Log.e(TAG, "executeTest: attach ON_ATTACH_FAILED");
return false;
}
mWifiAwareSession = results.second;
if (mWifiAwareSession == null) {
setFailureReason(mContext.getString(R.string.aware_status_attach_fail));
Log.e(TAG, "executeTest: attach callback succeeded but null session returned!?");
return false;
}
mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_attached));
if (DBG) {
Log.d(TAG, "executeTest: attach succeeded");
}
mDiscoveryMac = identityL.waitForMac();
if (mDiscoveryMac == null) {
setFailureReason(mContext.getString(R.string.aware_status_identity_fail));
Log.e(TAG, "executeTest: identity callback not triggered");
return false;
}
mListener.onTestMsgReceived(mResources.getString(R.string.aware_status_identity,
bytesToHex(mDiscoveryMac, ':')));
if (DBG) {
Log.d(TAG, "executeTest: identity received: " + bytesToHex(mDiscoveryMac, ':'));
}
if (mIsResponder) {
return executeTestResponder();
} else {
return executeTestInitiator();
}
}
private void setFailureReason(String reason) {
synchronized (mLock) {
mFailureReason = reason;
}
}
@Override
protected String getFailureReason() {
synchronized (mLock) {
return mFailureReason;
}
}
@Override
protected void tearDown() {
if (mWifiAwareSession != null) {
mWifiAwareSession.close();
mWifiAwareSession = null;
}
super.tearDown();
}
private boolean executeTestResponder() throws InterruptedException {
if (DBG) Log.d(TAG, "executeTestResponder");
CallbackUtils.DiscoveryCb discoveryCb = new CallbackUtils.DiscoveryCb();
// 2. publish
PublishConfig publishConfig = new PublishConfig.Builder().setServiceName(
SERVICE_NAME).build();
if (DBG) Log.d(TAG, "executeTestResponder: publishConfig=" + publishConfig);
mWifiAwareSession.publish(publishConfig, discoveryCb, mHandler);
// wait for results - publish session
CallbackUtils.DiscoveryCb.CallbackData callbackData = discoveryCb.waitForCallbacks(
CallbackUtils.DiscoveryCb.ON_PUBLISH_STARTED
| CallbackUtils.DiscoveryCb.ON_SESSION_CONFIG_FAILED);
switch (callbackData.callback) {
case CallbackUtils.DiscoveryCb.TIMEOUT:
setFailureReason(mContext.getString(R.string.aware_status_publish_timeout));
Log.e(TAG, "executeTestResponder: publish TIMEOUT");
return false;
case CallbackUtils.DiscoveryCb.ON_SESSION_CONFIG_FAILED:
setFailureReason(mContext.getString(R.string.aware_status_publish_failed));
Log.e(TAG, "executeTestResponder: publish ON_SESSION_CONFIG_FAILED");
return false;
}
PublishDiscoverySession discoverySession = callbackData.publishDiscoverySession;
if (discoverySession == null) {
setFailureReason(mContext.getString(R.string.aware_status_publish_null_session));
Log.e(TAG, "executeTestResponder: publish succeeded but null session returned");
return false;
}
mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_publish_started));
if (DBG) Log.d(TAG, "executeTestResponder: publish succeeded");
// 3. Wait for rx message (with MAC)
callbackData = discoveryCb.waitForCallbacks(CallbackUtils.DiscoveryCb.ON_MESSAGE_RECEIVED);
switch (callbackData.callback) {
case CallbackUtils.DiscoveryCb.TIMEOUT:
setFailureReason(mContext.getString(R.string.aware_status_receive_timeout));
Log.e(TAG, "executeTestResponder: receive message TIMEOUT");
return false;
}
if (callbackData.serviceSpecificInfo == null
|| callbackData.serviceSpecificInfo.length != MAC_BYTES_LEN) {
setFailureReason(mContext.getString(R.string.aware_status_receive_failure));
Log.e(TAG, "executeTestResponder: receive message message content mismatch: "
+ bytesToHex(callbackData.serviceSpecificInfo, ':'));
return false;
}
PeerHandle peerHandle = callbackData.peerHandle;
byte[] peerMac = callbackData.serviceSpecificInfo;
mListener.onTestMsgReceived(mResources.getString(R.string.aware_status_received_mac,
bytesToHex(peerMac, ':')));
if (DBG) {
Log.d(TAG, "executeTestResponder: received MAC address: " + bytesToHex(peerMac, ':'));
}
// 4. Send message with MAC and wait for success
discoverySession.sendMessage(peerHandle, MESSAGE_ID, mDiscoveryMac);
callbackData = discoveryCb.waitForCallbacks(
CallbackUtils.DiscoveryCb.ON_MESSAGE_SEND_SUCCEEDED
| CallbackUtils.DiscoveryCb.ON_MESSAGE_SEND_FAILED);
switch (callbackData.callback) {
case CallbackUtils.DiscoveryCb.TIMEOUT:
setFailureReason(mContext.getString(R.string.aware_status_send_timeout));
Log.e(TAG, "executeTestResponder: send message TIMEOUT");
return false;
case CallbackUtils.DiscoveryCb.ON_MESSAGE_SEND_FAILED:
setFailureReason(mContext.getString(R.string.aware_status_send_failed));
Log.e(TAG, "executeTestResponder: send message ON_MESSAGE_SEND_FAILED");
return false;
}
mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_send_success));
if (DBG) Log.d(TAG, "executeTestResponder: send message succeeded");
if (callbackData.messageId != MESSAGE_ID) {
setFailureReason(mContext.getString(R.string.aware_status_send_fail_parameter));
Log.e(TAG, "executeTestResponder: send message message ID mismatch: "
+ callbackData.messageId);
return false;
}
// 5. Destroy discovery session
discoverySession.close();
// 6. Request network (as Responder) and wait for network
ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(
Context.CONNECTIVITY_SERVICE);
NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
NetworkCapabilities.TRANSPORT_WIFI_AWARE).setNetworkSpecifier(
mIsSecurityOpen ? mWifiAwareSession.createNetworkSpecifierOpen(
WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER, peerMac)
: mWifiAwareSession.createNetworkSpecifierPassphrase(
WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER, peerMac,
PASSPHRASE)).build();
CallbackUtils.NetworkCb networkCb = new CallbackUtils.NetworkCb();
cm.requestNetwork(nr, networkCb, CALLBACK_TIMEOUT_SEC * 1000);
mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_network_requested));
if (DBG) Log.d(TAG, "executeTestResponder: requested network");
boolean networkAvailable = networkCb.waitForNetwork();
cm.unregisterNetworkCallback(networkCb);
if (!networkAvailable) {
setFailureReason(mContext.getString(R.string.aware_status_network_failed));
Log.e(TAG, "executeTestResponder: network request rejected - ON_UNAVAILABLE");
return false;
}
mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_network_success));
if (DBG) Log.d(TAG, "executeTestResponder: network request granted - AVAILABLE");
mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_lifecycle_ok));
return true;
}
private boolean executeTestInitiator() throws InterruptedException {
if (DBG) Log.d(TAG, "executeTestInitiator");
CallbackUtils.DiscoveryCb discoveryCb = new CallbackUtils.DiscoveryCb();
// 2. Subscribe
SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().setServiceName(
SERVICE_NAME).build();
if (DBG) Log.d(TAG, "executeTestInitiator: subscribeConfig=" + subscribeConfig);
mWifiAwareSession.subscribe(subscribeConfig, discoveryCb, mHandler);
// wait for results - subscribe session
CallbackUtils.DiscoveryCb.CallbackData callbackData = discoveryCb.waitForCallbacks(
CallbackUtils.DiscoveryCb.ON_SUBSCRIBE_STARTED
| CallbackUtils.DiscoveryCb.ON_SESSION_CONFIG_FAILED);
switch (callbackData.callback) {
case CallbackUtils.DiscoveryCb.TIMEOUT:
setFailureReason(mContext.getString(R.string.aware_status_subscribe_timeout));
Log.e(TAG, "executeTestInitiator: subscribe TIMEOUT");
return false;
case CallbackUtils.DiscoveryCb.ON_SESSION_CONFIG_FAILED:
setFailureReason(mContext.getString(R.string.aware_status_subscribe_failed));
Log.e(TAG, "executeTestInitiator: subscribe ON_SESSION_CONFIG_FAILED");
return false;
}
SubscribeDiscoverySession discoverySession = callbackData.subscribeDiscoverySession;
if (discoverySession == null) {
setFailureReason(mContext.getString(R.string.aware_status_subscribe_null_session));
Log.e(TAG, "executeTestInitiator: subscribe succeeded but null session returned");
return false;
}
mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_subscribe_started));
if (DBG) Log.d(TAG, "executeTestInitiator: subscribe succeeded");
// 3. Wait for discovery
callbackData = discoveryCb.waitForCallbacks(
CallbackUtils.DiscoveryCb.ON_SERVICE_DISCOVERED);
switch (callbackData.callback) {
case CallbackUtils.DiscoveryCb.TIMEOUT:
setFailureReason(mContext.getString(R.string.aware_status_discovery_timeout));
Log.e(TAG, "executeTestInitiator: waiting for discovery TIMEOUT");
return false;
}
PeerHandle peerHandle = callbackData.peerHandle;
mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_discovery));
if (DBG) Log.d(TAG, "executeTestInitiator: discovery");
// 4. Send message with MAC and wait for success
discoverySession.sendMessage(peerHandle, MESSAGE_ID, mDiscoveryMac);
callbackData = discoveryCb.waitForCallbacks(
CallbackUtils.DiscoveryCb.ON_MESSAGE_SEND_SUCCEEDED
| CallbackUtils.DiscoveryCb.ON_MESSAGE_SEND_FAILED);
switch (callbackData.callback) {
case CallbackUtils.DiscoveryCb.TIMEOUT:
setFailureReason(mContext.getString(R.string.aware_status_send_timeout));
Log.e(TAG, "executeTestInitiator: send message TIMEOUT");
return false;
case CallbackUtils.DiscoveryCb.ON_MESSAGE_SEND_FAILED:
setFailureReason(mContext.getString(R.string.aware_status_send_failed));
Log.e(TAG, "executeTestInitiator: send message ON_MESSAGE_SEND_FAILED");
return false;
}
mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_send_success));
if (DBG) Log.d(TAG, "executeTestInitiator: send message succeeded");
if (callbackData.messageId != MESSAGE_ID) {
setFailureReason(mContext.getString(R.string.aware_status_send_fail_parameter));
Log.e(TAG, "executeTestInitiator: send message message ID mismatch: "
+ callbackData.messageId);
return false;
}
// 5. Wait for rx message (with MAC)
callbackData = discoveryCb.waitForCallbacks(CallbackUtils.DiscoveryCb.ON_MESSAGE_RECEIVED);
switch (callbackData.callback) {
case CallbackUtils.DiscoveryCb.TIMEOUT:
setFailureReason(mContext.getString(R.string.aware_status_receive_timeout));
Log.e(TAG, "executeTestInitiator: receive message TIMEOUT");
return false;
}
if (callbackData.serviceSpecificInfo == null
|| callbackData.serviceSpecificInfo.length != MAC_BYTES_LEN) {
setFailureReason(mContext.getString(R.string.aware_status_receive_failure));
Log.e(TAG, "executeTestInitiator: receive message message content mismatch: "
+ bytesToHex(callbackData.serviceSpecificInfo, ':'));
return false;
}
byte[] peerMac = callbackData.serviceSpecificInfo;
mListener.onTestMsgReceived(mResources.getString(R.string.aware_status_received_mac,
bytesToHex(peerMac, ':')));
if (DBG) {
Log.d(TAG, "executeTestInitiator: received MAC address: " + bytesToHex(peerMac, ':'));
}
// 6. Destroy discovery session
discoverySession.close();
// 7. Sleep for 5 seconds to let Responder time to set up
mListener.onTestMsgReceived(
mContext.getString(R.string.aware_status_sleeping_wait_for_responder));
Thread.sleep(5000);
// 8. Request network (as Initiator) and wait for network
ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(
Context.CONNECTIVITY_SERVICE);
NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
NetworkCapabilities.TRANSPORT_WIFI_AWARE).setNetworkSpecifier(
mIsSecurityOpen ? mWifiAwareSession.createNetworkSpecifierOpen(
WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR, peerMac)
: mWifiAwareSession.createNetworkSpecifierPassphrase(
WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR, peerMac,
PASSPHRASE)).build();
CallbackUtils.NetworkCb networkCb = new CallbackUtils.NetworkCb();
cm.requestNetwork(nr, networkCb, CALLBACK_TIMEOUT_SEC * 1000);
mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_network_requested));
if (DBG) Log.d(TAG, "executeTestInitiator: requested network");
boolean networkAvailable = networkCb.waitForNetwork();
cm.unregisterNetworkCallback(networkCb);
if (!networkAvailable) {
setFailureReason(mContext.getString(R.string.aware_status_network_failed));
Log.e(TAG, "executeTestInitiator: network request rejected - ON_UNAVAILABLE");
return false;
}
mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_network_success));
if (DBG) Log.d(TAG, "executeTestInitiator: network request granted - AVAILABLE");
mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_lifecycle_ok));
return true;
}
}