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.wifi.rtt.RangingRequest;
     21 import android.net.wifi.rtt.RangingResult;
     22 import android.net.wifi.rtt.WifiRttManager;
     23 import android.util.Log;
     24 import android.util.Pair;
     25 
     26 import com.android.cts.verifier.R;
     27 import com.android.cts.verifier.wifiaware.CallbackUtils;
     28 
     29 import java.util.Arrays;
     30 import java.util.List;
     31 
     32 /**
     33  * Test case for Discovery + Ranging:
     34  *
     35  * Subscribe test sequence:
     36  * 1. Attach
     37  *    wait for results (session)
     38  * 2. Subscribe
     39  *    wait for results (subscribe session)
     40  * 3. Wait for discovery with ranging
     41  * 4. Send message
     42  *    Wait for success
     43  * 5. Wait for message ("done with RTT")
     44  * 6. Directed Range to Peer with PeerHandle
     45  * 7. Directed Range to Peer with MAC address
     46  * 8. Send message ("done with RTT")
     47  *    Wait for success
     48  * LAST. Destroy session
     49  *
     50  * Publish test sequence:
     51  * 1. Attach
     52  *    wait for results (session)
     53  * 2. Publish
     54  *    wait for results (publish session)
     55  * 3. Wait for rx message
     56  * 4. Directed Range to Peer with PeerHandler
     57  * 5. Directed Range to Peer with MAC address
     58  * 6. Send message ("done with RTT")
     59  *    Wait for success
     60  * 7. Wait for Message ("done with RTT")
     61  * LAST. Destroy session
     62  *
     63  * Validate that measured range is "reasonable" (i.e. 0 <= X <= SPECIFIED_LARGE_RANGE).
     64  *
     65  * Note that the process tries to prevent RTT concurrency, each peer will execute RTT in
     66  * sequence.
     67  */
     68 public class DiscoveryWithRangingTestCase extends DiscoveryBaseTestCase {
     69     private static final String TAG = "DiscWithRangingTestCase";
     70     private static final boolean DBG = true;
     71 
     72     private static final int NUM_RTT_ITERATIONS = 10;
     73     private static final int MAX_RTT_RANGING_SUCCESS = 5; // high: but open environment
     74     private static final int MIN_RSSI = -100;
     75 
     76     private static final byte[] MSG_RTT = "Done with RTT".getBytes();
     77 
     78     private WifiRttManager mWifiRttManager;
     79     private boolean mIsPublish;
     80 
     81     public DiscoveryWithRangingTestCase(Context context, boolean isPublish) {
     82         super(context, true, true);
     83 
     84         mWifiRttManager = (WifiRttManager) mContext.getSystemService(
     85                 Context.WIFI_RTT_RANGING_SERVICE);
     86         mIsPublish = isPublish;
     87     }
     88 
     89     @Override
     90     protected boolean executeTest() throws InterruptedException {
     91         boolean status = executeTestLocal();
     92 
     93         // LAST. destroy session
     94         if (mWifiAwareDiscoverySession != null) {
     95             mWifiAwareDiscoverySession.close();
     96             mWifiAwareDiscoverySession = null;
     97         }
     98 
     99         return status;
    100     }
    101 
    102     /**
    103      * Actual test execution (another level of abstraction to guarantee clean-up code gets
    104      * executed by parent method).
    105      */
    106     private boolean executeTestLocal() throws InterruptedException {
    107         if (DBG) Log.d(TAG, "executeTest: mIsPublish=" + mIsPublish);
    108 
    109         if (mIsPublish) {
    110             if (!executePublish()) {
    111                 return false;
    112             }
    113         } else {
    114             if (!executeSubscribe()) {
    115                 return false;
    116             }
    117         }
    118 
    119         if (!mIsPublish) {
    120             mListener.onTestMsgReceived(
    121                     mContext.getString(R.string.aware_status_waiting_for_peer_rtt));
    122 
    123             // pausing to let Publisher perform its RTT operations (however long)
    124             CallbackUtils.DiscoveryCb.CallbackData callbackData =
    125                     mDiscoveryCb.waitForCallbacksNoTimeout(
    126                             CallbackUtils.DiscoveryCb.ON_MESSAGE_RECEIVED);
    127             if (!Arrays.equals(MSG_RTT, callbackData.serviceSpecificInfo)) {
    128                 setFailureReason(mContext.getString(R.string.aware_status_receive_failure));
    129                 Log.e(TAG, "executeTest: receive RTT message content mismatch: rx=" + (
    130                     (callbackData.serviceSpecificInfo == null) ? "<null>"
    131                         : ("'" + new String(callbackData.serviceSpecificInfo) + "'")));
    132                 return false;
    133             }
    134 
    135             mListener.onTestMsgReceived(
    136                     mContext.getString(R.string.aware_status_received_peer_rtt_done));
    137 
    138             // wait a few seconds to allow the previous RTT session to teardown, semi-arbitrary
    139             Thread.sleep(5000);
    140 
    141             if (DBG) Log.d(TAG, "executeTest: subscriber received message - can proceed with RTT");
    142         }
    143 
    144         mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_starting_rtt));
    145 
    146         // Directed range to peer with PeerHandler
    147         int numFailuresToPeerHandle = 0;
    148         RangingRequest rangeToPeerHandle = new RangingRequest.Builder().addWifiAwarePeer(
    149                 mPeerHandle).build();
    150         for (int i = 0; i < NUM_RTT_ITERATIONS; ++i) {
    151             if (!executeRanging(rangeToPeerHandle)) {
    152                 numFailuresToPeerHandle++;
    153             }
    154         }
    155         Log.d(TAG, "executeTest: Direct RTT to PeerHandle " + numFailuresToPeerHandle + " of "
    156                 + NUM_RTT_ITERATIONS + " FAIL");
    157         if (numFailuresToPeerHandle > MAX_RTT_RANGING_SUCCESS) {
    158             mListener.onTestMsgReceived(
    159                     mContext.getString(R.string.aware_status_ranging_peer_failure,
    160                             numFailuresToPeerHandle, NUM_RTT_ITERATIONS));
    161         } else {
    162             mListener.onTestMsgReceived(
    163                     mContext.getString(R.string.aware_status_ranging_peer_success,
    164                             NUM_RTT_ITERATIONS - numFailuresToPeerHandle, NUM_RTT_ITERATIONS));
    165         }
    166 
    167         // Directed range to peer with MAC address
    168         int numFailuresToPeerMac = 0;
    169         RangingRequest rangeToMAC = new RangingRequest.Builder().addWifiAwarePeer(
    170                 mPeerMacAddress).build();
    171         for (int i = 0; i < NUM_RTT_ITERATIONS; ++i) {
    172             if (!executeRanging(rangeToMAC)) {
    173                 numFailuresToPeerMac++;
    174             }
    175         }
    176         Log.e(TAG, "executeTest: Direct RTT to MAC " + numFailuresToPeerMac + " of "
    177                 + NUM_RTT_ITERATIONS + " FAIL");
    178         if (numFailuresToPeerMac > MAX_RTT_RANGING_SUCCESS) {
    179             mListener.onTestMsgReceived(
    180                     mContext.getString(R.string.aware_status_ranging_mac_failure,
    181                             numFailuresToPeerMac, NUM_RTT_ITERATIONS));
    182         } else {
    183             mListener.onTestMsgReceived(
    184                     mContext.getString(R.string.aware_status_ranging_mac_success,
    185                             NUM_RTT_ITERATIONS - numFailuresToPeerMac, NUM_RTT_ITERATIONS));
    186         }
    187 
    188         // let peer know we're done with our RTT
    189         mWifiAwareDiscoverySession.sendMessage(mPeerHandle, MESSAGE_ID + 2, MSG_RTT);
    190         CallbackUtils.DiscoveryCb.CallbackData callbackData = mDiscoveryCb.waitForCallbacks(
    191                 CallbackUtils.DiscoveryCb.ON_MESSAGE_SEND_SUCCEEDED
    192                         | CallbackUtils.DiscoveryCb.ON_MESSAGE_SEND_FAILED);
    193         switch (callbackData.callback) {
    194             case CallbackUtils.DiscoveryCb.TIMEOUT:
    195                 setFailureReason(mContext.getString(R.string.aware_status_send_timeout));
    196                 Log.e(TAG, "executeTest: send message TIMEOUT");
    197                 return false;
    198             case CallbackUtils.DiscoveryCb.ON_MESSAGE_SEND_FAILED:
    199                 setFailureReason(mContext.getString(R.string.aware_status_send_failed));
    200                 Log.e(TAG, "executeTest: send message ON_MESSAGE_SEND_FAILED");
    201                 return false;
    202         }
    203         if (DBG) {
    204             Log.d(TAG, "executeTest: sent message to peer - I'm done with RTT");
    205         }
    206 
    207         if (mIsPublish) {
    208             mListener.onTestMsgReceived(
    209                     mContext.getString(R.string.aware_status_waiting_for_peer_rtt));
    210 
    211             // then pausing to let Subscriber finish it's RTT (can't terminate our Aware session
    212             // while we want Aware operations to proceed!).
    213             callbackData = mDiscoveryCb.waitForCallbacksNoTimeout(
    214                     CallbackUtils.DiscoveryCb.ON_MESSAGE_RECEIVED);
    215             if (!Arrays.equals(MSG_RTT, callbackData.serviceSpecificInfo)) {
    216                 setFailureReason(mContext.getString(R.string.aware_status_receive_failure));
    217                 Log.e(TAG, "executeTest: receive RTT message content mismatch: rx=" + (
    218                     (callbackData.serviceSpecificInfo == null) ? "<null>"
    219                         : ("'" + new String(callbackData.serviceSpecificInfo) + "'")));
    220                 return false;
    221             }
    222             mListener.onTestMsgReceived(
    223                     mContext.getString(R.string.aware_status_received_peer_rtt_done));
    224             if (DBG) Log.d(TAG, "executeTest: publisher received message - can proceed (finish)");
    225         }
    226 
    227         if (numFailuresToPeerHandle > MAX_RTT_RANGING_SUCCESS
    228                 || numFailuresToPeerMac > MAX_RTT_RANGING_SUCCESS) {
    229             setFailureReason(mContext.getString(R.string.aware_status_lifecycle_failed,
    230                     numFailuresToPeerHandle, NUM_RTT_ITERATIONS));
    231             return false;
    232         }
    233 
    234         mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_lifecycle_ok));
    235         return true;
    236     }
    237 
    238     private boolean executeRanging(RangingRequest request) throws InterruptedException {
    239         CallbackUtils.RangingCb rangingCb = new CallbackUtils.RangingCb();
    240         mWifiRttManager.startRanging(request, command -> mHandler.post(command), rangingCb);
    241         Pair<Integer, List<RangingResult>> results = rangingCb.waitForRangingResults();
    242         switch (results.first) {
    243             case CallbackUtils.RangingCb.TIMEOUT:
    244                 Log.e(TAG, "executeRanging: ranging to peer TIMEOUT");
    245                 return false;
    246             case CallbackUtils.RangingCb.ON_FAILURE:
    247                 Log.e(TAG, "executeRanging: ranging peer ON_FAILURE");
    248                 return false;
    249         }
    250         if (results.second == null || results.second.size() != 1) {
    251             Log.e(TAG, "executeRanging: ranging peer invalid results - null, empty, or wrong length");
    252             return false;
    253         }
    254         RangingResult result = results.second.get(0);
    255         if (result.getStatus() != RangingResult.STATUS_SUCCESS) {
    256             Log.e(TAG, "executeRanging: ranging peer failed - individual result failure code = "
    257                     + result.getStatus());
    258             return false;
    259         }
    260         int distanceMm = result.getDistanceMm();
    261         int rssi = result.getRssi();
    262 
    263         if (distanceMm > LARGE_ENOUGH_DISTANCE || rssi < MIN_RSSI) {
    264             Log.e(TAG, "executeRanging: ranging peer failed - invalid results: result=" + result);
    265             return false;
    266         }
    267 
    268         Log.d(TAG, "executeRanging: result=" + result);
    269         return true;
    270     }
    271 }
    272