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