• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.Network;
24 import android.net.NetworkCapabilities;
25 import android.net.NetworkRequest;
26 import android.net.wifi.aware.DiscoverySession;
27 import android.net.wifi.aware.PeerHandle;
28 import android.net.wifi.aware.PublishConfig;
29 import android.net.wifi.aware.PublishDiscoverySession;
30 import android.net.wifi.aware.SubscribeConfig;
31 import android.net.wifi.aware.SubscribeDiscoverySession;
32 import android.net.wifi.aware.WifiAwareManager;
33 import android.net.wifi.aware.WifiAwareSession;
34 import android.util.Log;
35 import android.util.Pair;
36 
37 import com.android.cts.verifier.R;
38 import com.android.cts.verifier.wifiaware.BaseTestCase;
39 import com.android.cts.verifier.wifiaware.CallbackUtils;
40 
41 /**
42  *Test case for data-path, out-of-band (OOB) test cases:
43  * open/passphrase * responder/initiator.
44  *
45  * OOB assumes that there's an alternative channel over which to communicate the discovery MAC
46  * address of the Aware interface. That channel (e.g. bluetooth or a host test device) is not
47  * readily available (don't want to have Aware tests dependent on BLE). Instead will fake the OOB
48  * channel using Aware itself: will do normal discovery during which the devices will exchange their
49  * MAC addresses, then destroy the discovery sessions and use the MAC addresses to perform OOB data-
50  * path requests.
51  *
52  * Responder test sequence:
53  * 1. Attach (with identity listener)
54  *    wait for results (session)
55  *    wait for identity
56  * 2. Publish
57  *    wait for results (publish session)
58  * 3. Wait for rx message (with MAC)
59  * 4. Send message with MAC
60  *    wait for success
61  * 5. Destroy discovery session
62  * 6. Request network (as Responder)
63  *    wait for network
64  *
65  * Initiator test sequence:
66  * 1. Attach (with identity listener)
67  *    wait for results (session)
68  *    wait for identity
69  * 2. Subscribe
70  *    wait for results (subscribe session)
71  * 3. Wait for discovery
72  * 4. Send message with MAC
73  *    wait for success
74  * 5. Wait for rx message (with MAC)
75  * 6. Destroy discovery session
76  * 7. Sleep for 5 seconds to let Responder time to set up
77  * 8. Request network (as Initiator)
78  *    wait for network
79  */
80 public class DataPathOutOfBandTestCase extends BaseTestCase {
81     private static final String TAG = "DataPathOutOfBandTestCase";
82     private static final boolean DBG = true;
83 
84     private static final int MAC_BYTES_LEN = 6;
85 
86     private static final String SERVICE_NAME = "CtsVerifierTestService";
87     private static final String PASSPHRASE = "Some super secret password";
88     private static final int MESSAGE_ID = 1234;
89 
90     private boolean mIsSecurityOpen;
91     private boolean mIsResponder;
92 
93     private final Object mLock = new Object();
94 
95     private String mFailureReason;
96     private WifiAwareSession mWifiAwareSession;
97     private DiscoverySession mWifiAwareDiscoverySession;
98     private byte[] mDiscoveryMac;
99 
100     private static int sSDKLevel = android.os.Build.VERSION.SDK_INT;
101 
DataPathOutOfBandTestCase(Context context, boolean isSecurityOpen, boolean isResponder)102     public DataPathOutOfBandTestCase(Context context, boolean isSecurityOpen,
103             boolean isResponder) {
104         super(context);
105         mIsSecurityOpen = isSecurityOpen;
106         mIsResponder = isResponder;
107     }
108 
109     @Override
executeTest()110     protected boolean executeTest() throws InterruptedException {
111         if (DBG) {
112             Log.d(TAG, "executeTest: mIsSecurityOpen=" + mIsSecurityOpen + ", mIsResponder="
113                     + mIsResponder);
114         }
115 
116         // 1. attach (with identity listener)
117         CallbackUtils.AttachCb attachCb = new CallbackUtils.AttachCb();
118         CallbackUtils.IdentityListenerSingleShot identityL = new CallbackUtils
119                 .IdentityListenerSingleShot();
120         mWifiAwareManager.attach(attachCb, identityL, mHandler);
121         Pair<Integer, WifiAwareSession> results = attachCb.waitForAttach();
122         switch (results.first) {
123             case CallbackUtils.AttachCb.TIMEOUT:
124                 setFailureReason(mContext.getString(R.string.aware_status_attach_timeout));
125                 Log.e(TAG, "executeTest: attach TIMEOUT");
126                 return false;
127             case CallbackUtils.AttachCb.ON_ATTACH_FAILED:
128                 setFailureReason(mContext.getString(R.string.aware_status_attach_fail));
129                 Log.e(TAG, "executeTest: attach ON_ATTACH_FAILED");
130                 return false;
131         }
132         mWifiAwareSession = results.second;
133         if (mWifiAwareSession == null) {
134             setFailureReason(mContext.getString(R.string.aware_status_attach_fail));
135             Log.e(TAG, "executeTest: attach callback succeeded but null session returned!?");
136             return false;
137         }
138         mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_attached));
139         if (DBG) {
140             Log.d(TAG, "executeTest: attach succeeded");
141         }
142         mDiscoveryMac = identityL.waitForMac();
143         if (mDiscoveryMac == null) {
144             setFailureReason(mContext.getString(R.string.aware_status_identity_fail));
145             Log.e(TAG, "executeTest: identity callback not triggered");
146             return false;
147         }
148         mListener.onTestMsgReceived(mResources.getString(R.string.aware_status_identity,
149                 bytesToHex(mDiscoveryMac, ':')));
150         if (DBG) {
151             Log.d(TAG, "executeTest: identity received: " + bytesToHex(mDiscoveryMac, ':'));
152         }
153 
154         if (mIsResponder) {
155             return executeTestResponder();
156         } else {
157             return executeTestInitiator();
158         }
159     }
160 
setFailureReason(String reason)161     private void setFailureReason(String reason) {
162         synchronized (mLock) {
163             mFailureReason = reason;
164         }
165     }
166 
167     @Override
getFailureReason()168     protected String getFailureReason() {
169         synchronized (mLock) {
170             return mFailureReason;
171         }
172     }
173 
174     @Override
tearDown()175     protected void tearDown() {
176         if (mWifiAwareDiscoverySession != null) {
177             mWifiAwareDiscoverySession.close();
178             mWifiAwareDiscoverySession = null;
179         }
180         if (mWifiAwareSession != null) {
181             mWifiAwareSession.close();
182             mWifiAwareSession = null;
183         }
184         super.tearDown();
185     }
186 
executeTestResponder()187     private boolean executeTestResponder() throws InterruptedException {
188         if (DBG) Log.d(TAG, "executeTestResponder");
189         CallbackUtils.DiscoveryCb discoveryCb = new CallbackUtils.DiscoveryCb();
190 
191         // 2. publish
192         PublishConfig publishConfig = new PublishConfig.Builder().setServiceName(
193                 SERVICE_NAME).build();
194         if (DBG) Log.d(TAG, "executeTestResponder: publishConfig=" + publishConfig);
195         mWifiAwareSession.publish(publishConfig, discoveryCb, mHandler);
196 
197         //    wait for results - publish session
198         CallbackUtils.DiscoveryCb.CallbackData callbackData = discoveryCb.waitForCallbacks(
199                 CallbackUtils.DiscoveryCb.ON_PUBLISH_STARTED
200                         | CallbackUtils.DiscoveryCb.ON_SESSION_CONFIG_FAILED);
201         switch (callbackData.callback) {
202             case CallbackUtils.DiscoveryCb.TIMEOUT:
203                 setFailureReason(mContext.getString(R.string.aware_status_publish_timeout));
204                 Log.e(TAG, "executeTestResponder: publish TIMEOUT");
205                 return false;
206             case CallbackUtils.DiscoveryCb.ON_SESSION_CONFIG_FAILED:
207                 setFailureReason(mContext.getString(R.string.aware_status_publish_failed));
208                 Log.e(TAG, "executeTestResponder: publish ON_SESSION_CONFIG_FAILED");
209                 return false;
210         }
211         PublishDiscoverySession discoverySession = callbackData.publishDiscoverySession;
212         mWifiAwareDiscoverySession = discoverySession;
213         if (discoverySession == null) {
214             setFailureReason(mContext.getString(R.string.aware_status_publish_null_session));
215             Log.e(TAG, "executeTestResponder: publish succeeded but null session returned");
216             return false;
217         }
218         mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_publish_started));
219         if (DBG) Log.d(TAG, "executeTestResponder: publish succeeded");
220 
221         // 3. Wait for rx message (with MAC)
222         callbackData = discoveryCb.waitForCallbacks(CallbackUtils.DiscoveryCb.ON_MESSAGE_RECEIVED);
223         switch (callbackData.callback) {
224             case CallbackUtils.DiscoveryCb.TIMEOUT:
225                 setFailureReason(mContext.getString(R.string.aware_status_receive_timeout));
226                 Log.e(TAG, "executeTestResponder: receive message TIMEOUT");
227                 return false;
228         }
229 
230         if (callbackData.serviceSpecificInfo == null
231                 || callbackData.serviceSpecificInfo.length != MAC_BYTES_LEN) {
232             setFailureReason(mContext.getString(R.string.aware_status_receive_failure));
233             Log.e(TAG, "executeTestResponder: receive message message content mismatch: "
234                     + bytesToHex(callbackData.serviceSpecificInfo, ':'));
235             return false;
236         }
237 
238         PeerHandle peerHandle = callbackData.peerHandle;
239         byte[] peerMac = callbackData.serviceSpecificInfo;
240 
241         mListener.onTestMsgReceived(mResources.getString(R.string.aware_status_received_mac,
242                 bytesToHex(peerMac, ':')));
243         if (DBG) {
244             Log.d(TAG, "executeTestResponder: received MAC address: " + bytesToHex(peerMac, ':'));
245         }
246 
247         // 4. Send message with MAC and wait for success
248         discoverySession.sendMessage(peerHandle, MESSAGE_ID, mDiscoveryMac);
249         callbackData = discoveryCb.waitForCallbacks(
250                 CallbackUtils.DiscoveryCb.ON_MESSAGE_SEND_SUCCEEDED
251                         | CallbackUtils.DiscoveryCb.ON_MESSAGE_SEND_FAILED);
252         switch (callbackData.callback) {
253             case CallbackUtils.DiscoveryCb.TIMEOUT:
254                 setFailureReason(mContext.getString(R.string.aware_status_send_timeout));
255                 Log.e(TAG, "executeTestResponder: send message TIMEOUT");
256                 return false;
257             case CallbackUtils.DiscoveryCb.ON_MESSAGE_SEND_FAILED:
258                 setFailureReason(mContext.getString(R.string.aware_status_send_failed));
259                 Log.e(TAG, "executeTestResponder: send message ON_MESSAGE_SEND_FAILED");
260                 return false;
261         }
262         mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_send_success));
263         if (DBG) Log.d(TAG, "executeTestResponder: send message succeeded");
264 
265         if (callbackData.messageId != MESSAGE_ID) {
266             setFailureReason(mContext.getString(R.string.aware_status_send_fail_parameter));
267             Log.e(TAG, "executeTestResponder: send message message ID mismatch: "
268                     + callbackData.messageId);
269             return false;
270         }
271 
272         // 5. Destroy discovery session
273         discoverySession.close();
274         mWifiAwareDiscoverySession = null;
275 
276         // 6. Request network (as Responder) and wait for network
277         ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(
278                 Context.CONNECTIVITY_SERVICE);
279         NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
280                 NetworkCapabilities.TRANSPORT_WIFI_AWARE).setNetworkSpecifier(
281                 mIsSecurityOpen ? mWifiAwareSession.createNetworkSpecifierOpen(
282                         WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER, peerMac)
283                         : mWifiAwareSession.createNetworkSpecifierPassphrase(
284                                 WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER, peerMac,
285                                 PASSPHRASE)).build();
286         CallbackUtils.NetworkCb networkCb = new CallbackUtils.NetworkCb();
287         cm.requestNetwork(nr, networkCb, CALLBACK_TIMEOUT_SEC * 1000);
288         mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_network_requested));
289         if (DBG) Log.d(TAG, "executeTestResponder: requested network");
290         Pair<Network, NetworkCapabilities> info = networkCb.waitForNetworkCapabilities();
291         cm.unregisterNetworkCallback(networkCb);
292         if (info == null) {
293             setFailureReason(mContext.getString(R.string.aware_status_network_failed));
294             Log.e(TAG, "executeTestResponder: network request rejected - ON_UNAVAILABLE");
295             return false;
296         }
297         if (sSDKLevel <= android.os.Build.VERSION_CODES.P){
298             if (info.second.getNetworkSpecifier() != null) {
299                 setFailureReason(mContext.getString(R.string.aware_status_network_failed_leak));
300                 Log.e(TAG, "executeTestSubscriber: network request accepted - but leaks NS!");
301                 return false;
302             }
303         }
304         mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_network_success));
305         if (DBG) Log.d(TAG, "executeTestResponder: network request granted - AVAILABLE");
306 
307         mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_lifecycle_ok));
308         return true;
309     }
310 
executeTestInitiator()311     private boolean executeTestInitiator() throws InterruptedException {
312         if (DBG) Log.d(TAG, "executeTestInitiator");
313         CallbackUtils.DiscoveryCb discoveryCb = new CallbackUtils.DiscoveryCb();
314 
315         // 2. Subscribe
316         SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().setServiceName(
317                 SERVICE_NAME).build();
318         if (DBG) Log.d(TAG, "executeTestInitiator: subscribeConfig=" + subscribeConfig);
319         mWifiAwareSession.subscribe(subscribeConfig, discoveryCb, mHandler);
320 
321         //    wait for results - subscribe session
322         CallbackUtils.DiscoveryCb.CallbackData callbackData = discoveryCb.waitForCallbacks(
323                 CallbackUtils.DiscoveryCb.ON_SUBSCRIBE_STARTED
324                         | CallbackUtils.DiscoveryCb.ON_SESSION_CONFIG_FAILED);
325         switch (callbackData.callback) {
326             case CallbackUtils.DiscoveryCb.TIMEOUT:
327                 setFailureReason(mContext.getString(R.string.aware_status_subscribe_timeout));
328                 Log.e(TAG, "executeTestInitiator: subscribe TIMEOUT");
329                 return false;
330             case CallbackUtils.DiscoveryCb.ON_SESSION_CONFIG_FAILED:
331                 setFailureReason(mContext.getString(R.string.aware_status_subscribe_failed));
332                 Log.e(TAG, "executeTestInitiator: subscribe ON_SESSION_CONFIG_FAILED");
333                 return false;
334         }
335         SubscribeDiscoverySession discoverySession = callbackData.subscribeDiscoverySession;
336         mWifiAwareDiscoverySession = discoverySession;
337         if (discoverySession == null) {
338             setFailureReason(mContext.getString(R.string.aware_status_subscribe_null_session));
339             Log.e(TAG, "executeTestInitiator: subscribe succeeded but null session returned");
340             return false;
341         }
342         mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_subscribe_started));
343         if (DBG) Log.d(TAG, "executeTestInitiator: subscribe succeeded");
344 
345         // 3. Wait for discovery
346         callbackData = discoveryCb.waitForCallbacks(
347                 CallbackUtils.DiscoveryCb.ON_SERVICE_DISCOVERED);
348         switch (callbackData.callback) {
349             case CallbackUtils.DiscoveryCb.TIMEOUT:
350                 setFailureReason(mContext.getString(R.string.aware_status_discovery_timeout));
351                 Log.e(TAG, "executeTestInitiator: waiting for discovery TIMEOUT");
352                 return false;
353         }
354         PeerHandle peerHandle = callbackData.peerHandle;
355         mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_discovery));
356         if (DBG) Log.d(TAG, "executeTestInitiator: discovery");
357 
358         // 4. Send message with MAC and wait for success
359         discoverySession.sendMessage(peerHandle, MESSAGE_ID, mDiscoveryMac);
360         callbackData = discoveryCb.waitForCallbacks(
361                 CallbackUtils.DiscoveryCb.ON_MESSAGE_SEND_SUCCEEDED
362                         | CallbackUtils.DiscoveryCb.ON_MESSAGE_SEND_FAILED);
363         switch (callbackData.callback) {
364             case CallbackUtils.DiscoveryCb.TIMEOUT:
365                 setFailureReason(mContext.getString(R.string.aware_status_send_timeout));
366                 Log.e(TAG, "executeTestInitiator: send message TIMEOUT");
367                 return false;
368             case CallbackUtils.DiscoveryCb.ON_MESSAGE_SEND_FAILED:
369                 setFailureReason(mContext.getString(R.string.aware_status_send_failed));
370                 Log.e(TAG, "executeTestInitiator: send message ON_MESSAGE_SEND_FAILED");
371                 return false;
372         }
373         mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_send_success));
374         if (DBG) Log.d(TAG, "executeTestInitiator: send message succeeded");
375 
376         if (callbackData.messageId != MESSAGE_ID) {
377             setFailureReason(mContext.getString(R.string.aware_status_send_fail_parameter));
378             Log.e(TAG, "executeTestInitiator: send message message ID mismatch: "
379                     + callbackData.messageId);
380             return false;
381         }
382 
383         // 5. Wait for rx message (with MAC)
384         callbackData = discoveryCb.waitForCallbacks(CallbackUtils.DiscoveryCb.ON_MESSAGE_RECEIVED);
385         switch (callbackData.callback) {
386             case CallbackUtils.DiscoveryCb.TIMEOUT:
387                 setFailureReason(mContext.getString(R.string.aware_status_receive_timeout));
388                 Log.e(TAG, "executeTestInitiator: receive message TIMEOUT");
389                 return false;
390         }
391 
392         if (callbackData.serviceSpecificInfo == null
393                 || callbackData.serviceSpecificInfo.length != MAC_BYTES_LEN) {
394             setFailureReason(mContext.getString(R.string.aware_status_receive_failure));
395             Log.e(TAG, "executeTestInitiator: receive message message content mismatch: "
396                     + bytesToHex(callbackData.serviceSpecificInfo, ':'));
397             return false;
398         }
399 
400         byte[] peerMac = callbackData.serviceSpecificInfo;
401 
402         mListener.onTestMsgReceived(mResources.getString(R.string.aware_status_received_mac,
403                 bytesToHex(peerMac, ':')));
404         if (DBG) {
405             Log.d(TAG, "executeTestInitiator: received MAC address: " + bytesToHex(peerMac, ':'));
406         }
407 
408         // 6. Destroy discovery session
409         discoverySession.close();
410         mWifiAwareDiscoverySession = null;
411 
412         // 7. Sleep for 5 seconds to let Responder time to set up
413         mListener.onTestMsgReceived(
414                 mContext.getString(R.string.aware_status_sleeping_wait_for_responder));
415         Thread.sleep(5000);
416 
417         // 8. Request network (as Initiator) and wait for network
418         ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(
419                 Context.CONNECTIVITY_SERVICE);
420         NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
421                 NetworkCapabilities.TRANSPORT_WIFI_AWARE).setNetworkSpecifier(
422                 mIsSecurityOpen ? mWifiAwareSession.createNetworkSpecifierOpen(
423                         WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR, peerMac)
424                         : mWifiAwareSession.createNetworkSpecifierPassphrase(
425                                 WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR, peerMac,
426                                 PASSPHRASE)).build();
427         CallbackUtils.NetworkCb networkCb = new CallbackUtils.NetworkCb();
428         cm.requestNetwork(nr, networkCb, CALLBACK_TIMEOUT_SEC * 1000);
429         mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_network_requested));
430         if (DBG) Log.d(TAG, "executeTestInitiator: requested network");
431         Pair<Network, NetworkCapabilities> info = networkCb.waitForNetworkCapabilities();
432         cm.unregisterNetworkCallback(networkCb);
433         if (info == null) {
434             setFailureReason(mContext.getString(R.string.aware_status_network_failed));
435             Log.e(TAG, "executeTestInitiator: network request rejected - ON_UNAVAILABLE");
436             return false;
437         }
438         if (sSDKLevel <= android.os.Build.VERSION_CODES.P){
439             if(info.second.getNetworkSpecifier() != null) {
440                 setFailureReason(mContext.getString(R.string.aware_status_network_failed_leak));
441                 Log.e(TAG, "executeTestSubscriber: network request accepted - but leaks NS!");
442                 return false;
443             }
444         }
445         mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_network_success));
446         if (DBG) Log.d(TAG, "executeTestInitiator: network request granted - AVAILABLE");
447 
448         mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_lifecycle_ok));
449         return true;
450     }
451 }
452