Home | History | Annotate | Download | only in testcase
      1 /*
      2  * Copyright (C) 2017 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 
     17 package com.android.cts.verifier.wifiaware.testcase;
     18 
     19 import android.content.Context;
     20 import android.net.MacAddress;
     21 import android.net.wifi.aware.DiscoverySession;
     22 import android.net.wifi.aware.PeerHandle;
     23 import android.net.wifi.aware.PublishConfig;
     24 import android.net.wifi.aware.SubscribeConfig;
     25 import android.net.wifi.aware.WifiAwareSession;
     26 import android.util.Log;
     27 import android.util.Pair;
     28 
     29 import com.android.cts.verifier.R;
     30 import com.android.cts.verifier.wifiaware.BaseTestCase;
     31 import com.android.cts.verifier.wifiaware.CallbackUtils;
     32 
     33 import java.util.ArrayList;
     34 import java.util.Arrays;
     35 import java.util.List;
     36 
     37 /**
     38  * Base test case providing utilities for Discovery:
     39  *
     40  * Subscribe test sequence:
     41  * 1. Attach
     42  *    wait for results (session)
     43  * 2. Subscribe
     44  *    wait for results (subscribe session)
     45  * 3. Wait for discovery (possibly with ranging)
     46  * 4. Send message
     47  *    Wait for success
     48  *
     49  * Publish test sequence:
     50  * 1. Attach
     51  *    wait for results (session)
     52  * 2. Publish
     53  *    wait for results (publish session)
     54  * 3. Wait for rx message
     55  */
     56 public abstract class DiscoveryBaseTestCase extends BaseTestCase {
     57     private static final String TAG = "DiscoveryBaseTestCase";
     58     private static final boolean DBG = true;
     59 
     60     private static final String SERVICE_NAME = "CtsVerifierTestService";
     61     private static final byte[] MATCH_FILTER_BYTES = "bytes used for matching".getBytes();
     62     private static final byte[] PUB_SSI = "Extra bytes in the publisher discovery".getBytes();
     63     private static final byte[] SUB_SSI = "Arbitrary bytes for the subscribe discovery".getBytes();
     64     private static final byte[] MSG_SUB_TO_PUB = "Let's talk".getBytes();
     65     protected static final int MESSAGE_ID = 1234;
     66     protected static final int LARGE_ENOUGH_DISTANCE = 100000; // 100 meters
     67 
     68     protected boolean mIsUnsolicited;
     69     protected boolean mIsRangingRequired;
     70 
     71     protected final Object mLock = new Object();
     72 
     73     private String mFailureReason;
     74     protected WifiAwareSession mWifiAwareSession;
     75     protected DiscoverySession mWifiAwareDiscoverySession;
     76     protected CallbackUtils.DiscoveryCb mDiscoveryCb;
     77     protected PeerHandle mPeerHandle;
     78     protected MacAddress mMyMacAddress;
     79     protected MacAddress mPeerMacAddress;
     80 
     81     public DiscoveryBaseTestCase(Context context, boolean isUnsolicited,
     82             boolean isRangingRequired) {
     83         super(context);
     84 
     85         mIsUnsolicited = isUnsolicited;
     86         mIsRangingRequired = isRangingRequired;
     87     }
     88 
     89     private boolean executeAttach() throws InterruptedException {
     90         // attach (optionally with an identity listener)
     91         CallbackUtils.AttachCb attachCb = new CallbackUtils.AttachCb();
     92         CallbackUtils.IdentityListenerSingleShot identityL = new CallbackUtils
     93                 .IdentityListenerSingleShot();
     94         if (mIsRangingRequired) {
     95             mWifiAwareManager.attach(attachCb, identityL, mHandler);
     96         } else {
     97             mWifiAwareManager.attach(attachCb, mHandler);
     98         }
     99         Pair<Integer, WifiAwareSession> results = attachCb.waitForAttach();
    100         switch (results.first) {
    101             case CallbackUtils.AttachCb.TIMEOUT:
    102                 setFailureReason(mContext.getString(R.string.aware_status_attach_timeout));
    103                 Log.e(TAG, "executeTest: attach TIMEOUT");
    104                 return false;
    105             case CallbackUtils.AttachCb.ON_ATTACH_FAILED:
    106                 setFailureReason(mContext.getString(R.string.aware_status_attach_fail));
    107                 Log.e(TAG, "executeTest: attach ON_ATTACH_FAILED");
    108                 return false;
    109         }
    110         mWifiAwareSession = results.second;
    111         if (mWifiAwareSession == null) {
    112             setFailureReason(mContext.getString(R.string.aware_status_attach_fail));
    113             Log.e(TAG, "executeTest: attach callback succeeded but null session returned!?");
    114             return false;
    115         }
    116         mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_attached));
    117         if (DBG) {
    118             Log.d(TAG, "executeTest: attach succeeded");
    119         }
    120 
    121         // 1.5 optionally wait for identity (necessary in ranging cases)
    122         if (mIsRangingRequired) {
    123             byte[] mac = identityL.waitForMac();
    124             if (mac == null) {
    125                 setFailureReason(mContext.getString(R.string.aware_status_identity_fail));
    126                 Log.e(TAG, "executeAttach: identity callback not triggered");
    127                 return false;
    128             }
    129             mMyMacAddress = MacAddress.fromBytes(mac);
    130             mListener.onTestMsgReceived(mResources.getString(R.string.aware_status_identity,
    131                     mMyMacAddress));
    132             if (DBG) {
    133                 Log.d(TAG, "executeAttach: identity received: " + mMyMacAddress.toString());
    134             }
    135         }
    136 
    137         return true;
    138     }
    139 
    140     protected boolean executeSubscribe() throws InterruptedException {
    141         // 1. attach
    142         if (!executeAttach()) {
    143             return false;
    144         }
    145 
    146         mDiscoveryCb = new CallbackUtils.DiscoveryCb();
    147 
    148         // 2. subscribe
    149         List<byte[]> matchFilter = new ArrayList<>();
    150         matchFilter.add(MATCH_FILTER_BYTES);
    151         SubscribeConfig.Builder builder = new SubscribeConfig.Builder().setServiceName(
    152                 SERVICE_NAME).setServiceSpecificInfo(SUB_SSI).setMatchFilter(
    153                 matchFilter).setSubscribeType(
    154                 mIsUnsolicited ? SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE
    155                         : SubscribeConfig.SUBSCRIBE_TYPE_ACTIVE).setTerminateNotificationEnabled(
    156                 true);
    157         if (mIsRangingRequired) {
    158             // set up a distance that will always trigger - i.e. that we're already in that range
    159             builder.setMaxDistanceMm(LARGE_ENOUGH_DISTANCE);
    160         }
    161         SubscribeConfig subscribeConfig = builder.build();
    162         if (DBG) Log.d(TAG, "executeTestSubscriber: subscribeConfig=" + subscribeConfig);
    163         mWifiAwareSession.subscribe(subscribeConfig, mDiscoveryCb, mHandler);
    164 
    165         //    wait for results - subscribe session
    166         CallbackUtils.DiscoveryCb.CallbackData callbackData = mDiscoveryCb.waitForCallbacks(
    167                 CallbackUtils.DiscoveryCb.ON_SUBSCRIBE_STARTED
    168                         | CallbackUtils.DiscoveryCb.ON_SESSION_CONFIG_FAILED);
    169         switch (callbackData.callback) {
    170             case CallbackUtils.DiscoveryCb.TIMEOUT:
    171                 setFailureReason(mContext.getString(R.string.aware_status_subscribe_timeout));
    172                 Log.e(TAG, "executeTestSubscriber: subscribe TIMEOUT");
    173                 return false;
    174             case CallbackUtils.DiscoveryCb.ON_SESSION_CONFIG_FAILED:
    175                 setFailureReason(mContext.getString(R.string.aware_status_subscribe_failed));
    176                 Log.e(TAG, "executeTestSubscriber: subscribe ON_SESSION_CONFIG_FAILED");
    177                 return false;
    178         }
    179         mWifiAwareDiscoverySession = callbackData.subscribeDiscoverySession;
    180         if (mWifiAwareDiscoverySession == null) {
    181             setFailureReason(mContext.getString(R.string.aware_status_subscribe_null_session));
    182             Log.e(TAG, "executeTestSubscriber: subscribe succeeded but null session returned");
    183             return false;
    184         }
    185         mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_subscribe_started));
    186         if (DBG) Log.d(TAG, "executeTestSubscriber: subscribe succeeded");
    187 
    188         // 3. wait for discovery
    189         callbackData = mDiscoveryCb.waitForCallbacks(
    190                 mIsRangingRequired ? CallbackUtils.DiscoveryCb.ON_SERVICE_DISCOVERED_WITH_RANGE
    191                         : CallbackUtils.DiscoveryCb.ON_SERVICE_DISCOVERED);
    192         switch (callbackData.callback) {
    193             case CallbackUtils.DiscoveryCb.TIMEOUT:
    194                 setFailureReason(mContext.getString(R.string.aware_status_discovery_timeout));
    195                 Log.e(TAG, "executeTestSubscriber: waiting for discovery TIMEOUT");
    196                 return false;
    197         }
    198         mPeerHandle = callbackData.peerHandle;
    199         if (!mIsRangingRequired) {
    200             mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_discovery));
    201             if (DBG) Log.d(TAG, "executeTestSubscriber: discovery");
    202         } else {
    203             if (DBG) {
    204                 Log.d(TAG, "executeTestSubscriber: discovery with range="
    205                         + callbackData.distanceMm);
    206             }
    207         }
    208 
    209         //    validate discovery parameters match
    210         if (mIsRangingRequired) {
    211             try {
    212                 mPeerMacAddress = MacAddress.fromBytes(callbackData.serviceSpecificInfo);
    213             } catch (IllegalArgumentException e) {
    214                 setFailureReason(mContext.getString(R.string.aware_status_discovery_fail));
    215                 Log.e(TAG, "executeTestSubscriber: invalid MAC received in SSI: rx='" + new String(
    216                         callbackData.serviceSpecificInfo) + "'");
    217                 return false;
    218             }
    219             mListener.onTestMsgReceived(
    220                     mResources.getString(R.string.aware_status_discovery_with_info,
    221                             mPeerMacAddress));
    222         } else {
    223             if (!Arrays.equals(PUB_SSI, callbackData.serviceSpecificInfo)) {
    224                 setFailureReason(mContext.getString(R.string.aware_status_discovery_fail));
    225                 Log.e(TAG, "executeTestSubscriber: discovery but SSI mismatch: rx='" + new String(
    226                         callbackData.serviceSpecificInfo) + "'");
    227                 return false;
    228             }
    229         }
    230         if (callbackData.matchFilter.size() != 1 || !Arrays.equals(MATCH_FILTER_BYTES,
    231                 callbackData.matchFilter.get(0))) {
    232             setFailureReason(mContext.getString(R.string.aware_status_discovery_fail));
    233             StringBuffer sb = new StringBuffer();
    234             sb.append("size=").append(callbackData.matchFilter.size());
    235             for (byte[] mf: callbackData.matchFilter) {
    236                 sb.append(", e='").append(new String(mf)).append("'");
    237             }
    238             Log.e(TAG, "executeTestSubscriber: discovery but matchFilter mismatch: "
    239                     + sb.toString());
    240             return false;
    241         }
    242         if (mPeerHandle == null) {
    243             setFailureReason(mContext.getString(R.string.aware_status_discovery_fail));
    244             Log.e(TAG, "executeTestSubscriber: discovery but null peerHandle");
    245             return false;
    246         }
    247 
    248         // 4. send message & wait for send status
    249         mWifiAwareDiscoverySession.sendMessage(mPeerHandle, MESSAGE_ID,
    250                 mIsRangingRequired ? mMyMacAddress.toByteArray() : MSG_SUB_TO_PUB);
    251         callbackData = mDiscoveryCb.waitForCallbacks(
    252                 CallbackUtils.DiscoveryCb.ON_MESSAGE_SEND_SUCCEEDED
    253                         | CallbackUtils.DiscoveryCb.ON_MESSAGE_SEND_FAILED);
    254         switch (callbackData.callback) {
    255             case CallbackUtils.DiscoveryCb.TIMEOUT:
    256                 setFailureReason(mContext.getString(R.string.aware_status_send_timeout));
    257                 Log.e(TAG, "executeTestSubscriber: send message TIMEOUT");
    258                 return false;
    259             case CallbackUtils.DiscoveryCb.ON_MESSAGE_SEND_FAILED:
    260                 setFailureReason(mContext.getString(R.string.aware_status_send_failed));
    261                 Log.e(TAG, "executeTestSubscriber: send message ON_MESSAGE_SEND_FAILED");
    262                 return false;
    263         }
    264         mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_send_success));
    265         if (DBG) Log.d(TAG, "executeTestSubscriber: send message succeeded");
    266 
    267         if (callbackData.messageId != MESSAGE_ID) {
    268             setFailureReason(mContext.getString(R.string.aware_status_send_fail_parameter));
    269             Log.e(TAG, "executeTestSubscriber: send message message ID mismatch: "
    270                     + callbackData.messageId);
    271             return false;
    272         }
    273 
    274         return true;
    275     }
    276 
    277     protected boolean executePublish() throws InterruptedException {
    278         // 1. attach
    279         if (!executeAttach()) {
    280             return false;
    281         }
    282 
    283         mDiscoveryCb = new CallbackUtils.DiscoveryCb();
    284 
    285         // 2. publish
    286         List<byte[]> matchFilter = new ArrayList<>();
    287         matchFilter.add(MATCH_FILTER_BYTES);
    288         PublishConfig publishConfig = new PublishConfig.Builder().setServiceName(
    289                 SERVICE_NAME).setServiceSpecificInfo(
    290                 mIsRangingRequired ? mMyMacAddress.toByteArray() : PUB_SSI).setMatchFilter(
    291                 matchFilter).setPublishType(mIsUnsolicited ? PublishConfig.PUBLISH_TYPE_UNSOLICITED
    292                 : PublishConfig.PUBLISH_TYPE_SOLICITED).setTerminateNotificationEnabled(
    293                 true).setRangingEnabled(mIsRangingRequired).build();
    294         if (DBG) Log.d(TAG, "executeTestPublisher: publishConfig=" + publishConfig);
    295         mWifiAwareSession.publish(publishConfig, mDiscoveryCb, mHandler);
    296 
    297         //    wait for results - publish session
    298         CallbackUtils.DiscoveryCb.CallbackData callbackData = mDiscoveryCb.waitForCallbacks(
    299                 CallbackUtils.DiscoveryCb.ON_PUBLISH_STARTED
    300                         | CallbackUtils.DiscoveryCb.ON_SESSION_CONFIG_FAILED);
    301         switch (callbackData.callback) {
    302             case CallbackUtils.DiscoveryCb.TIMEOUT:
    303                 setFailureReason(mContext.getString(R.string.aware_status_publish_timeout));
    304                 Log.e(TAG, "executeTestPublisher: publish TIMEOUT");
    305                 return false;
    306             case CallbackUtils.DiscoveryCb.ON_SESSION_CONFIG_FAILED:
    307                 setFailureReason(mContext.getString(R.string.aware_status_publish_failed));
    308                 Log.e(TAG, "executeTestPublisher: publish ON_SESSION_CONFIG_FAILED");
    309                 return false;
    310         }
    311         mWifiAwareDiscoverySession = callbackData.publishDiscoverySession;
    312         if (mWifiAwareDiscoverySession == null) {
    313             setFailureReason(mContext.getString(R.string.aware_status_publish_null_session));
    314             Log.e(TAG, "executeTestPublisher: publish succeeded but null session returned");
    315             return false;
    316         }
    317         mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_publish_started));
    318         if (DBG) Log.d(TAG, "executeTestPublisher: publish succeeded");
    319 
    320         // 3. wait to receive message: no timeout since this depends on (human) operator starting
    321         //    the test on the subscriber device.
    322         callbackData = mDiscoveryCb.waitForCallbacksNoTimeout(
    323                 CallbackUtils.DiscoveryCb.ON_MESSAGE_RECEIVED);
    324         mPeerHandle = callbackData.peerHandle;
    325         mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_received));
    326         if (DBG) Log.d(TAG, "executeTestPublisher: received message");
    327 
    328         //    validate that received the expected message
    329         if (mIsRangingRequired) {
    330             try {
    331                 mPeerMacAddress = MacAddress.fromBytes(callbackData.serviceSpecificInfo);
    332             } catch (IllegalArgumentException e) {
    333                 setFailureReason(mContext.getString(R.string.aware_status_discovery_fail));
    334                 Log.e(TAG, "executeTestSubscriber: invalid MAC received in SSI: rx='" + new String(
    335                         callbackData.serviceSpecificInfo) + "'");
    336                 return false;
    337             }
    338             mListener.onTestMsgReceived(mResources.getString(R.string.aware_status_received_mac,
    339                     mPeerMacAddress));
    340         } else {
    341             if (!Arrays.equals(MSG_SUB_TO_PUB, callbackData.serviceSpecificInfo)) {
    342                 setFailureReason(mContext.getString(R.string.aware_status_receive_failure));
    343                 Log.e(TAG, "executeTestPublisher: receive message message content mismatch: rx='"
    344                         + new String(callbackData.serviceSpecificInfo) + "'");
    345                 return false;
    346             }
    347         }
    348         if (mPeerHandle == null) {
    349             setFailureReason(mContext.getString(R.string.aware_status_receive_failure));
    350             Log.e(TAG, "executeTestPublisher: received message but peerHandle is null!?");
    351             return false;
    352         }
    353 
    354         return true;
    355     }
    356 
    357     protected void setFailureReason(String reason) {
    358         synchronized (mLock) {
    359             mFailureReason = reason;
    360         }
    361     }
    362 
    363     @Override
    364     protected String getFailureReason() {
    365         synchronized (mLock) {
    366             return mFailureReason;
    367         }
    368     }
    369 
    370     @Override
    371     protected void tearDown() {
    372         if (mWifiAwareDiscoverySession != null) {
    373             mWifiAwareDiscoverySession.close();
    374             mWifiAwareDiscoverySession = null;
    375         }
    376         if (mWifiAwareSession != null) {
    377             mWifiAwareSession.close();
    378             mWifiAwareSession = null;
    379         }
    380         super.tearDown();
    381     }
    382 }
    383