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 static com.android.cts.verifier.wifiaware.CallbackUtils.CALLBACK_TIMEOUT_SEC; 20 21 import android.content.Context; 22 import android.net.ConnectivityManager; 23 import android.net.NetworkCapabilities; 24 import android.net.NetworkRequest; 25 import android.net.wifi.aware.PeerHandle; 26 import android.net.wifi.aware.PublishConfig; 27 import android.net.wifi.aware.PublishDiscoverySession; 28 import android.net.wifi.aware.SubscribeConfig; 29 import android.net.wifi.aware.SubscribeDiscoverySession; 30 import android.net.wifi.aware.WifiAwareSession; 31 import android.util.Log; 32 import android.util.Pair; 33 34 import com.android.cts.verifier.R; 35 import com.android.cts.verifier.wifiaware.BaseTestCase; 36 import com.android.cts.verifier.wifiaware.CallbackUtils; 37 38 import java.util.ArrayList; 39 import java.util.Arrays; 40 import java.util.List; 41 42 /** 43 * Test case for data-path, in-band test cases: 44 * open/passphrase * solicited/unsolicited * publish/subscribe. 45 * 46 * Subscribe test sequence: 47 * 1. Attach 48 * wait for results (session) 49 * 2. Subscribe 50 * wait for results (subscribe session) 51 * 3. Wait for discovery 52 * 4. Send message 53 * Wait for success 54 * 5. Wait for rx message 55 * 6. Request network 56 * Wait for network 57 * 7. Destroy session 58 * 59 * Publish test sequence: 60 * 1. Attach 61 * wait for results (session) 62 * 2. Publish 63 * wait for results (publish session) 64 * 3. Wait for rx message 65 * 4. Request network 66 * 5. Send message 67 * Wait for success 68 * 6. Wait for network 69 * 7. Destroy session 70 */ 71 public class DataPathInBandTestCase extends BaseTestCase { 72 private static final String TAG = "DataPathInBandTestCase"; 73 private static final boolean DBG = true; 74 75 private static final String SERVICE_NAME = "CtsVerifierTestService"; 76 private static final byte[] MATCH_FILTER_BYTES = "bytes used for matching".getBytes(); 77 private static final byte[] PUB_SSI = "Extra bytes in the publisher discovery".getBytes(); 78 private static final byte[] SUB_SSI = "Arbitrary bytes for the subscribe discovery".getBytes(); 79 private static final byte[] MSG_SUB_TO_PUB = "Let's talk".getBytes(); 80 private static final byte[] MSG_PUB_TO_SUB = "Ready".getBytes(); 81 private static final String PASSPHRASE = "Some super secret password"; 82 private static final int MESSAGE_ID = 1234; 83 84 private boolean mIsSecurityOpen; 85 private boolean mIsPublish; 86 private boolean mIsUnsolicited; 87 88 private final Object mLock = new Object(); 89 90 private String mFailureReason; 91 private WifiAwareSession mWifiAwareSession; 92 93 public DataPathInBandTestCase(Context context, boolean isSecurityOpen, boolean isPublish, 94 boolean isUnsolicited) { 95 super(context); 96 mIsSecurityOpen = isSecurityOpen; 97 mIsPublish = isPublish; 98 mIsUnsolicited = isUnsolicited; 99 } 100 101 @Override 102 protected boolean executeTest() throws InterruptedException { 103 if (DBG) { 104 Log.d(TAG, 105 "executeTest: mIsSecurityOpen=" + mIsSecurityOpen + ", mIsPublish=" + mIsPublish 106 + ", mIsUnsolicited=" + mIsUnsolicited); 107 } 108 109 // 1. attach 110 CallbackUtils.AttachCb attachCb = new CallbackUtils.AttachCb(); 111 mWifiAwareManager.attach(attachCb, mHandler); 112 Pair<Integer, WifiAwareSession> results = attachCb.waitForAttach(); 113 switch (results.first) { 114 case CallbackUtils.AttachCb.TIMEOUT: 115 setFailureReason(mContext.getString(R.string.aware_status_attach_timeout)); 116 Log.e(TAG, "executeTest: attach TIMEOUT"); 117 return false; 118 case CallbackUtils.AttachCb.ON_ATTACH_FAILED: 119 setFailureReason(mContext.getString(R.string.aware_status_attach_fail)); 120 Log.e(TAG, "executeTest: attach ON_ATTACH_FAILED"); 121 return false; 122 } 123 mWifiAwareSession = results.second; 124 if (mWifiAwareSession == null) { 125 setFailureReason(mContext.getString(R.string.aware_status_attach_fail)); 126 Log.e(TAG, "executeTest: attach callback succeeded but null session returned!?"); 127 return false; 128 } 129 mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_attached)); 130 if (DBG) { 131 Log.d(TAG, "executeTest: attach succeeded"); 132 } 133 134 if (mIsPublish) { 135 return executeTestPublisher(); 136 } else { 137 return executeTestSubscriber(); 138 } 139 } 140 141 private void setFailureReason(String reason) { 142 synchronized (mLock) { 143 mFailureReason = reason; 144 } 145 } 146 147 @Override 148 protected String getFailureReason() { 149 synchronized (mLock) { 150 return mFailureReason; 151 } 152 } 153 154 @Override 155 protected void tearDown() { 156 if (mWifiAwareSession != null) { 157 mWifiAwareSession.close(); 158 mWifiAwareSession = null; 159 } 160 super.tearDown(); 161 } 162 163 private boolean executeTestSubscriber() throws InterruptedException { 164 if (DBG) Log.d(TAG, "executeTestSubscriber"); 165 CallbackUtils.DiscoveryCb discoveryCb = new CallbackUtils.DiscoveryCb(); 166 167 // 2. subscribe 168 List<byte[]> matchFilter = new ArrayList<>(); 169 matchFilter.add(MATCH_FILTER_BYTES); 170 SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().setServiceName( 171 SERVICE_NAME).setServiceSpecificInfo(SUB_SSI).setMatchFilter( 172 matchFilter).setSubscribeType( 173 mIsUnsolicited ? SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE 174 : SubscribeConfig.SUBSCRIBE_TYPE_ACTIVE).setTerminateNotificationEnabled( 175 true).build(); 176 if (DBG) Log.d(TAG, "executeTestSubscriber: subscribeConfig=" + subscribeConfig); 177 mWifiAwareSession.subscribe(subscribeConfig, discoveryCb, mHandler); 178 179 // wait for results - subscribe session 180 CallbackUtils.DiscoveryCb.CallbackData callbackData = discoveryCb.waitForCallbacks( 181 CallbackUtils.DiscoveryCb.ON_SUBSCRIBE_STARTED 182 | CallbackUtils.DiscoveryCb.ON_SESSION_CONFIG_FAILED); 183 switch (callbackData.callback) { 184 case CallbackUtils.DiscoveryCb.TIMEOUT: 185 setFailureReason(mContext.getString(R.string.aware_status_subscribe_timeout)); 186 Log.e(TAG, "executeTestSubscriber: subscribe TIMEOUT"); 187 return false; 188 case CallbackUtils.DiscoveryCb.ON_SESSION_CONFIG_FAILED: 189 setFailureReason(mContext.getString(R.string.aware_status_subscribe_failed)); 190 Log.e(TAG, "executeTestSubscriber: subscribe ON_SESSION_CONFIG_FAILED"); 191 return false; 192 } 193 SubscribeDiscoverySession discoverySession = callbackData.subscribeDiscoverySession; 194 if (discoverySession == null) { 195 setFailureReason(mContext.getString(R.string.aware_status_subscribe_null_session)); 196 Log.e(TAG, "executeTestSubscriber: subscribe succeeded but null session returned"); 197 return false; 198 } 199 mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_subscribe_started)); 200 if (DBG) Log.d(TAG, "executeTestSubscriber: subscribe succeeded"); 201 202 // 3. wait for discovery 203 callbackData = discoveryCb.waitForCallbacks( 204 CallbackUtils.DiscoveryCb.ON_SERVICE_DISCOVERED); 205 switch (callbackData.callback) { 206 case CallbackUtils.DiscoveryCb.TIMEOUT: 207 setFailureReason(mContext.getString(R.string.aware_status_discovery_timeout)); 208 Log.e(TAG, "executeTestSubscriber: waiting for discovery TIMEOUT"); 209 return false; 210 } 211 PeerHandle peerHandle = callbackData.peerHandle; 212 mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_discovery)); 213 if (DBG) Log.d(TAG, "executeTestSubscriber: discovery"); 214 215 // validate discovery parameters match 216 if (!Arrays.equals(PUB_SSI, callbackData.serviceSpecificInfo)) { 217 setFailureReason(mContext.getString(R.string.aware_status_discovery_fail)); 218 Log.e(TAG, "executeTestSubscriber: discovery but SSI mismatch: rx='" + new String( 219 callbackData.serviceSpecificInfo) + "'"); 220 return false; 221 } 222 if (callbackData.matchFilter.size() != 1 || !Arrays.equals(MATCH_FILTER_BYTES, 223 callbackData.matchFilter.get(0))) { 224 setFailureReason(mContext.getString(R.string.aware_status_discovery_fail)); 225 StringBuffer sb = new StringBuffer(); 226 sb.append("size=").append(callbackData.matchFilter.size()); 227 for (byte[] mf: callbackData.matchFilter) { 228 sb.append(", e='").append(new String(mf)).append("'"); 229 } 230 Log.e(TAG, "executeTestSubscriber: discovery but matchFilter mismatch: " 231 + sb.toString()); 232 return false; 233 } 234 if (peerHandle == null) { 235 setFailureReason(mContext.getString(R.string.aware_status_discovery_fail)); 236 Log.e(TAG, "executeTestSubscriber: discovery but null peerHandle"); 237 return false; 238 } 239 240 // 4. send message & wait for send status 241 discoverySession.sendMessage(peerHandle, MESSAGE_ID, MSG_SUB_TO_PUB); 242 callbackData = discoveryCb.waitForCallbacks( 243 CallbackUtils.DiscoveryCb.ON_MESSAGE_SEND_SUCCEEDED 244 | CallbackUtils.DiscoveryCb.ON_MESSAGE_SEND_FAILED); 245 switch (callbackData.callback) { 246 case CallbackUtils.DiscoveryCb.TIMEOUT: 247 setFailureReason(mContext.getString(R.string.aware_status_send_timeout)); 248 Log.e(TAG, "executeTestSubscriber: send message TIMEOUT"); 249 return false; 250 case CallbackUtils.DiscoveryCb.ON_MESSAGE_SEND_FAILED: 251 setFailureReason(mContext.getString(R.string.aware_status_send_failed)); 252 Log.e(TAG, "executeTestSubscriber: send message ON_MESSAGE_SEND_FAILED"); 253 return false; 254 } 255 mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_send_success)); 256 if (DBG) Log.d(TAG, "executeTestSubscriber: send message succeeded"); 257 258 if (callbackData.messageId != MESSAGE_ID) { 259 setFailureReason(mContext.getString(R.string.aware_status_send_fail_parameter)); 260 Log.e(TAG, "executeTestSubscriber: send message message ID mismatch: " 261 + callbackData.messageId); 262 return false; 263 } 264 265 // 5. wait to receive message 266 callbackData = discoveryCb.waitForCallbacks(CallbackUtils.DiscoveryCb.ON_MESSAGE_RECEIVED); 267 switch (callbackData.callback) { 268 case CallbackUtils.DiscoveryCb.TIMEOUT: 269 setFailureReason(mContext.getString(R.string.aware_status_receive_timeout)); 270 Log.e(TAG, "executeTestSubscriber: receive message TIMEOUT"); 271 return false; 272 } 273 mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_received)); 274 if (DBG) Log.d(TAG, "executeTestSubscriber: received message"); 275 276 // validate that received the expected message 277 if (!Arrays.equals(MSG_PUB_TO_SUB, callbackData.serviceSpecificInfo)) { 278 setFailureReason(mContext.getString(R.string.aware_status_receive_failure)); 279 Log.e(TAG, "executeTestSubscriber: receive message message content mismatch: rx='" 280 + new String(callbackData.serviceSpecificInfo) + "'"); 281 return false; 282 } 283 284 // 6. request network 285 ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService( 286 Context.CONNECTIVITY_SERVICE); 287 NetworkRequest nr = new NetworkRequest.Builder().addTransportType( 288 NetworkCapabilities.TRANSPORT_WIFI_AWARE).setNetworkSpecifier( 289 mIsSecurityOpen ? discoverySession.createNetworkSpecifierOpen(peerHandle) 290 : discoverySession.createNetworkSpecifierPassphrase(peerHandle, 291 PASSPHRASE)).build(); 292 CallbackUtils.NetworkCb networkCb = new CallbackUtils.NetworkCb(); 293 cm.requestNetwork(nr, networkCb, CALLBACK_TIMEOUT_SEC * 1000); 294 mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_network_requested)); 295 if (DBG) Log.d(TAG, "executeTestSubscriber: requested network"); 296 boolean networkAvailable = networkCb.waitForNetwork(); 297 cm.unregisterNetworkCallback(networkCb); 298 if (!networkAvailable) { 299 setFailureReason(mContext.getString(R.string.aware_status_network_failed)); 300 Log.e(TAG, "executeTestSubscriber: network request rejected - ON_UNAVAILABLE"); 301 return false; 302 } 303 mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_network_success)); 304 if (DBG) Log.d(TAG, "executeTestSubscriber: network request granted - AVAILABLE"); 305 306 // 7. destroy session 307 discoverySession.close(); 308 309 mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_lifecycle_ok)); 310 return true; 311 } 312 313 private boolean executeTestPublisher() throws InterruptedException { 314 if (DBG) Log.d(TAG, "executeTestPublisher"); 315 CallbackUtils.DiscoveryCb discoveryCb = new CallbackUtils.DiscoveryCb(); 316 317 // 2. publish 318 List<byte[]> matchFilter = new ArrayList<>(); 319 matchFilter.add(MATCH_FILTER_BYTES); 320 PublishConfig publishConfig = new PublishConfig.Builder().setServiceName( 321 SERVICE_NAME).setServiceSpecificInfo(PUB_SSI).setMatchFilter( 322 matchFilter).setPublishType(mIsUnsolicited ? PublishConfig.PUBLISH_TYPE_UNSOLICITED 323 : PublishConfig.PUBLISH_TYPE_SOLICITED).setTerminateNotificationEnabled( 324 true).build(); 325 if (DBG) Log.d(TAG, "executeTestPublisher: publishConfig=" + publishConfig); 326 mWifiAwareSession.publish(publishConfig, discoveryCb, mHandler); 327 328 // wait for results - publish session 329 CallbackUtils.DiscoveryCb.CallbackData callbackData = discoveryCb.waitForCallbacks( 330 CallbackUtils.DiscoveryCb.ON_PUBLISH_STARTED 331 | CallbackUtils.DiscoveryCb.ON_SESSION_CONFIG_FAILED); 332 switch (callbackData.callback) { 333 case CallbackUtils.DiscoveryCb.TIMEOUT: 334 setFailureReason(mContext.getString(R.string.aware_status_publish_timeout)); 335 Log.e(TAG, "executeTestPublisher: publish TIMEOUT"); 336 return false; 337 case CallbackUtils.DiscoveryCb.ON_SESSION_CONFIG_FAILED: 338 setFailureReason(mContext.getString(R.string.aware_status_publish_failed)); 339 Log.e(TAG, "executeTestPublisher: publish ON_SESSION_CONFIG_FAILED"); 340 return false; 341 } 342 PublishDiscoverySession discoverySession = callbackData.publishDiscoverySession; 343 if (discoverySession == null) { 344 setFailureReason(mContext.getString(R.string.aware_status_publish_null_session)); 345 Log.e(TAG, "executeTestPublisher: publish succeeded but null session returned"); 346 return false; 347 } 348 mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_publish_started)); 349 if (DBG) Log.d(TAG, "executeTestPublisher: publish succeeded"); 350 351 // 3. wait to receive message: no timeout since this depends on (human) operator starting 352 // the test on the subscriber device. 353 callbackData = discoveryCb.waitForCallbacksNoTimeout( 354 CallbackUtils.DiscoveryCb.ON_MESSAGE_RECEIVED); 355 PeerHandle peerHandle = callbackData.peerHandle; 356 mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_received)); 357 if (DBG) Log.d(TAG, "executeTestPublisher: received message"); 358 359 // validate that received the expected message 360 if (!Arrays.equals(MSG_SUB_TO_PUB, callbackData.serviceSpecificInfo)) { 361 setFailureReason(mContext.getString(R.string.aware_status_receive_failure)); 362 Log.e(TAG, "executeTestPublisher: receive message message content mismatch: rx='" 363 + new String(callbackData.serviceSpecificInfo) + "'"); 364 return false; 365 } 366 if (peerHandle == null) { 367 setFailureReason(mContext.getString(R.string.aware_status_receive_failure)); 368 Log.e(TAG, "executeTestPublisher: received message but peerHandle is null!?"); 369 return false; 370 } 371 372 // 4. Request network 373 ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService( 374 Context.CONNECTIVITY_SERVICE); 375 NetworkRequest nr = new NetworkRequest.Builder().addTransportType( 376 NetworkCapabilities.TRANSPORT_WIFI_AWARE).setNetworkSpecifier( 377 mIsSecurityOpen ? discoverySession.createNetworkSpecifierOpen(peerHandle) 378 : discoverySession.createNetworkSpecifierPassphrase(peerHandle, 379 PASSPHRASE)).build(); 380 CallbackUtils.NetworkCb networkCb = new CallbackUtils.NetworkCb(); 381 cm.requestNetwork(nr, networkCb, CALLBACK_TIMEOUT_SEC * 1000); 382 mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_network_requested)); 383 if (DBG) Log.d(TAG, "executeTestPublisher: requested network"); 384 385 // 5. send message & wait for send status 386 discoverySession.sendMessage(peerHandle, MESSAGE_ID, MSG_PUB_TO_SUB); 387 callbackData = discoveryCb.waitForCallbacks( 388 CallbackUtils.DiscoveryCb.ON_MESSAGE_SEND_SUCCEEDED 389 | CallbackUtils.DiscoveryCb.ON_MESSAGE_SEND_FAILED); 390 switch (callbackData.callback) { 391 case CallbackUtils.DiscoveryCb.TIMEOUT: 392 setFailureReason(mContext.getString(R.string.aware_status_send_timeout)); 393 Log.e(TAG, "executeTestPublisher: send message TIMEOUT"); 394 return false; 395 case CallbackUtils.DiscoveryCb.ON_MESSAGE_SEND_FAILED: 396 setFailureReason(mContext.getString(R.string.aware_status_send_failed)); 397 Log.e(TAG, "executeTestPublisher: send message ON_MESSAGE_SEND_FAILED"); 398 return false; 399 } 400 mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_send_success)); 401 if (DBG) Log.d(TAG, "executeTestPublisher: send message succeeded"); 402 403 if (callbackData.messageId != MESSAGE_ID) { 404 setFailureReason(mContext.getString(R.string.aware_status_send_fail_parameter)); 405 Log.e(TAG, "executeTestPublisher: send message succeeded but message ID mismatch : " 406 + callbackData.messageId); 407 return false; 408 } 409 410 // 6. wait for network 411 boolean networkAvailable = networkCb.waitForNetwork(); 412 cm.unregisterNetworkCallback(networkCb); 413 if (!networkAvailable) { 414 setFailureReason(mContext.getString(R.string.aware_status_network_failed)); 415 Log.e(TAG, "executeTestPublisher: request network rejected - ON_UNAVAILABLE"); 416 return false; 417 } 418 mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_network_success)); 419 if (DBG) Log.d(TAG, "executeTestPublisher: network request granted - AVAILABLE"); 420 421 // 7. destroy session 422 discoverySession.close(); 423 424 mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_lifecycle_ok)); 425 return true; 426 427 } 428 } 429