• 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;
18 
19 import android.net.ConnectivityManager;
20 import android.net.Network;
21 import android.net.NetworkCapabilities;
22 import android.net.wifi.aware.AttachCallback;
23 import android.net.wifi.aware.DiscoverySessionCallback;
24 import android.net.wifi.aware.IdentityChangedListener;
25 import android.net.wifi.aware.PeerHandle;
26 import android.net.wifi.aware.PublishDiscoverySession;
27 import android.net.wifi.aware.SubscribeDiscoverySession;
28 import android.net.wifi.aware.WifiAwareSession;
29 import android.net.wifi.rtt.RangingResult;
30 import android.net.wifi.rtt.RangingResultCallback;
31 import android.util.Log;
32 import android.util.Pair;
33 
34 import java.util.ArrayDeque;
35 import java.util.List;
36 import java.util.concurrent.CountDownLatch;
37 import java.util.concurrent.TimeUnit;
38 
39 /**
40  * Blocking callbacks for Wi-Fi Aware and Connectivity Manager.
41  */
42 public class CallbackUtils {
43     private static final String TAG = "CallbackUtils";
44 
45     public static final int CALLBACK_TIMEOUT_SEC = 15;
46 
47     /**
48      * Utility AttachCallback - provides mechanism to block execution with the
49      * waitForAttach method.
50      */
51     public static class AttachCb extends AttachCallback {
52         public static final int TIMEOUT = -1;
53         public static final int ON_ATTACHED = 0;
54         public static final int ON_ATTACH_FAILED = 1;
55 
56         private CountDownLatch mBlocker = new CountDownLatch(1);
57         private int mCallback = TIMEOUT;
58         private WifiAwareSession mWifiAwareSession = null;
59 
60         @Override
onAttached(WifiAwareSession session)61         public void onAttached(WifiAwareSession session) {
62             mCallback = ON_ATTACHED;
63             mWifiAwareSession = session;
64             mBlocker.countDown();
65         }
66 
67         @Override
onAttachFailed()68         public void onAttachFailed() {
69             mCallback = ON_ATTACH_FAILED;
70             mBlocker.countDown();
71         }
72 
73         /**
74          * Wait (blocks) for any AttachCallback callback or timeout.
75          *
76          * @return A pair of values: the callback constant (or TIMEOUT) and the WifiAwareSession
77          * created when attach successful - null otherwise (attach failure or timeout).
78          */
waitForAttach()79         public Pair<Integer, WifiAwareSession> waitForAttach() throws InterruptedException {
80             if (mBlocker.await(CALLBACK_TIMEOUT_SEC, TimeUnit.SECONDS)) {
81                 return new Pair<>(mCallback, mWifiAwareSession);
82             }
83 
84             return new Pair<>(TIMEOUT, null);
85         }
86     }
87 
88     /**
89      * Utility IdentityChangedListener - provides mechanism to block execution with the
90      * waitForIdentity method. Single shot listener - only listens for the first triggered
91      * callback.
92      */
93     public static class IdentityListenerSingleShot extends IdentityChangedListener {
94         private CountDownLatch mBlocker = new CountDownLatch(1);
95         private byte[] mMac = null;
96 
97         @Override
onIdentityChanged(byte[] mac)98         public void onIdentityChanged(byte[] mac) {
99             if (mMac != null) {
100                 return;
101             }
102 
103             mMac = mac;
104             mBlocker.countDown();
105         }
106 
107         /**
108          * Wait (blocks) for the onIdentityChanged callback or a timeout.
109          *
110          * @return The MAC address returned by the onIdentityChanged() callback, or null on timeout.
111          */
waitForMac()112         public byte[] waitForMac() throws InterruptedException {
113             if (mBlocker.await(CALLBACK_TIMEOUT_SEC, TimeUnit.SECONDS)) {
114                 return mMac;
115             }
116 
117             return null;
118         }
119     }
120 
121     /**
122      * Utility NetworkCallback - provides mechanism for blocking/serializing access with the
123      * waitForNetwork method.
124      */
125     public static class NetworkCb extends ConnectivityManager.NetworkCallback {
126         private CountDownLatch mBlocker = new CountDownLatch(1);
127         private Network mNetwork = null;
128         private NetworkCapabilities mNetworkCapabilities = null;
129 
130         @Override
onUnavailable()131         public void onUnavailable() {
132             mNetworkCapabilities = null;
133             mBlocker.countDown();
134         }
135 
136         @Override
onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities)137         public void onCapabilitiesChanged(Network network,
138                 NetworkCapabilities networkCapabilities) {
139             mNetwork = network;
140             mNetworkCapabilities = networkCapabilities;
141             mBlocker.countDown();
142         }
143 
144         /**
145          * Wait (blocks) for Capabilities Changed callback - or timesout.
146          *
147          * @return Network + NetworkCapabilities (pair) if occurred, null otherwise.
148          */
waitForNetworkCapabilities()149         public Pair<Network, NetworkCapabilities> waitForNetworkCapabilities()
150                 throws InterruptedException {
151             if (mBlocker.await(CALLBACK_TIMEOUT_SEC, TimeUnit.SECONDS)) {
152                 return Pair.create(mNetwork, mNetworkCapabilities);
153             }
154             return null;
155         }
156     }
157 
158     /**
159      * Utility DiscoverySessionCallback - provides mechanism to block/serialize Aware discovery
160      * operations using the waitForCallbacks() method.
161      */
162     public static class DiscoveryCb extends DiscoverySessionCallback {
163         public static final int TIMEOUT = -1;
164         public static final int ON_PUBLISH_STARTED = 0x1 << 0;
165         public static final int ON_SUBSCRIBE_STARTED = 0x1 << 1;
166         public static final int ON_SESSION_CONFIG_UPDATED = 0x1 << 2;
167         public static final int ON_SESSION_CONFIG_FAILED = 0x1 << 3;
168         public static final int ON_SESSION_TERMINATED = 0x1 << 4;
169         public static final int ON_SERVICE_DISCOVERED = 0x1 << 5;
170         public static final int ON_MESSAGE_SEND_SUCCEEDED = 0x1 << 6;
171         public static final int ON_MESSAGE_SEND_FAILED = 0x1 << 7;
172         public static final int ON_MESSAGE_RECEIVED = 0x1 << 8;
173         public static final int ON_SERVICE_DISCOVERED_WITH_RANGE = 0x1 << 9;
174 
175         /**
176          * Data container for all parameters which can be returned by any DiscoverySessionCallback
177          * callback.
178          */
179         public static class CallbackData {
CallbackData(int callback)180             public CallbackData(int callback) {
181                 this.callback = callback;
182             }
183 
184             public int callback;
185 
186             public PublishDiscoverySession publishDiscoverySession;
187             public SubscribeDiscoverySession subscribeDiscoverySession;
188             public PeerHandle peerHandle;
189             public byte[] serviceSpecificInfo;
190             public List<byte[]> matchFilter;
191             public int messageId;
192             public int distanceMm;
193         }
194 
195         private CountDownLatch mBlocker = null;
196         private int mWaitForCallbackMask = 0;
197 
198         private final Object mLock = new Object();
199         private ArrayDeque<CallbackData> mCallbackQueue = new ArrayDeque<>();
200 
processCallback(CallbackData callbackData)201         private void processCallback(CallbackData callbackData) {
202             synchronized (mLock) {
203                 mCallbackQueue.addLast(callbackData);
204                 if (mBlocker != null && (mWaitForCallbackMask & callbackData.callback)
205                         == callbackData.callback) {
206                     mBlocker.countDown();
207                 }
208             }
209         }
210 
getAndRemoveFirst(int callbackMask)211         private CallbackData getAndRemoveFirst(int callbackMask) {
212             synchronized (mLock) {
213                 for (CallbackData cbd : mCallbackQueue) {
214                     if ((cbd.callback & callbackMask) == cbd.callback) {
215                         mCallbackQueue.remove(cbd);
216                         return cbd;
217                     }
218                 }
219             }
220 
221             return null;
222         }
223 
waitForCallbacks(int callbackMask, boolean timeout)224         private CallbackData waitForCallbacks(int callbackMask, boolean timeout)
225                 throws InterruptedException {
226             synchronized (mLock) {
227                 CallbackData cbd = getAndRemoveFirst(callbackMask);
228                 if (cbd != null) {
229                     return cbd;
230                 }
231 
232                 mWaitForCallbackMask = callbackMask;
233                 mBlocker = new CountDownLatch(1);
234             }
235 
236             boolean finishedNormally = true;
237             if (timeout) {
238                 finishedNormally = mBlocker.await(CALLBACK_TIMEOUT_SEC, TimeUnit.SECONDS);
239             } else {
240                 mBlocker.await();
241             }
242             if (finishedNormally) {
243                 CallbackData cbd = getAndRemoveFirst(callbackMask);
244                 if (cbd != null) {
245                     return cbd;
246                 }
247 
248                 Log.wtf(TAG, "DiscoveryCb.waitForCallback: callbackMask=" + callbackMask
249                         + ": did not time-out but doesn't have any of the requested callbacks in "
250                         + "the stack!?");
251                 // falling-through to TIMEOUT
252             }
253 
254             return new CallbackData(TIMEOUT);
255         }
256 
257         /**
258          * Wait for the specified callbacks - a bitmask of any of the ON_* constants. Returns the
259          * CallbackData structure whose CallbackData.callback specifies the callback which was
260          * triggered. The callback may be TIMEOUT.
261          *
262          * Note: other callbacks happening while while waiting for the specified callback(s) will
263          * be queued.
264          */
waitForCallbacks(int callbackMask)265         public CallbackData waitForCallbacks(int callbackMask) throws InterruptedException {
266             return waitForCallbacks(callbackMask, true);
267         }
268 
269         /**
270          * Wait for the specified callbacks - a bitmask of any of the ON_* constants. Returns the
271          * CallbackData structure whose CallbackData.callback specifies the callback which was
272          * triggered.
273          *
274          * This call will not timeout - it can be interrupted though (which results in a thrown
275          * exception).
276          *
277          * Note: other callbacks happening while while waiting for the specified callback(s) will
278          * be queued.
279          */
waitForCallbacksNoTimeout(int callbackMask)280         public CallbackData waitForCallbacksNoTimeout(int callbackMask)
281                 throws InterruptedException {
282             return waitForCallbacks(callbackMask, false);
283         }
284 
285         @Override
onPublishStarted(PublishDiscoverySession session)286         public void onPublishStarted(PublishDiscoverySession session) {
287             CallbackData callbackData = new CallbackData(ON_PUBLISH_STARTED);
288             callbackData.publishDiscoverySession = session;
289             processCallback(callbackData);
290         }
291 
292         @Override
onSubscribeStarted(SubscribeDiscoverySession session)293         public void onSubscribeStarted(SubscribeDiscoverySession session) {
294             CallbackData callbackData = new CallbackData(ON_SUBSCRIBE_STARTED);
295             callbackData.subscribeDiscoverySession = session;
296             processCallback(callbackData);
297         }
298 
299         @Override
onSessionConfigUpdated()300         public void onSessionConfigUpdated() {
301             CallbackData callbackData = new CallbackData(ON_SESSION_CONFIG_UPDATED);
302             processCallback(callbackData);
303         }
304 
305         @Override
onSessionConfigFailed()306         public void onSessionConfigFailed() {
307             CallbackData callbackData = new CallbackData(ON_SESSION_CONFIG_FAILED);
308             processCallback(callbackData);
309         }
310 
311         @Override
onSessionTerminated()312         public void onSessionTerminated() {
313             CallbackData callbackData = new CallbackData(ON_SESSION_TERMINATED);
314             processCallback(callbackData);
315         }
316 
317         @Override
onServiceDiscovered(PeerHandle peerHandle, byte[] serviceSpecificInfo, List<byte[]> matchFilter)318         public void onServiceDiscovered(PeerHandle peerHandle, byte[] serviceSpecificInfo,
319                 List<byte[]> matchFilter) {
320             CallbackData callbackData = new CallbackData(ON_SERVICE_DISCOVERED);
321             callbackData.peerHandle = peerHandle;
322             callbackData.serviceSpecificInfo = serviceSpecificInfo;
323             callbackData.matchFilter = matchFilter;
324             processCallback(callbackData);
325         }
326 
327         @Override
onServiceDiscoveredWithinRange(PeerHandle peerHandle, byte[] serviceSpecificInfo, List<byte[]> matchFilter, int distanceMm)328         public void onServiceDiscoveredWithinRange(PeerHandle peerHandle,
329                 byte[] serviceSpecificInfo,
330                 List<byte[]> matchFilter, int distanceMm) {
331             CallbackData callbackData = new CallbackData(ON_SERVICE_DISCOVERED_WITH_RANGE);
332             callbackData.peerHandle = peerHandle;
333             callbackData.serviceSpecificInfo = serviceSpecificInfo;
334             callbackData.matchFilter = matchFilter;
335             callbackData.distanceMm = distanceMm;
336             processCallback(callbackData);
337         }
338 
339         @Override
onMessageSendSucceeded(int messageId)340         public void onMessageSendSucceeded(int messageId) {
341             CallbackData callbackData = new CallbackData(ON_MESSAGE_SEND_SUCCEEDED);
342             callbackData.messageId = messageId;
343             processCallback(callbackData);
344         }
345 
346         @Override
onMessageSendFailed(int messageId)347         public void onMessageSendFailed(int messageId) {
348             CallbackData callbackData = new CallbackData(ON_MESSAGE_SEND_FAILED);
349             callbackData.messageId = messageId;
350             processCallback(callbackData);
351         }
352 
353         @Override
onMessageReceived(PeerHandle peerHandle, byte[] message)354         public void onMessageReceived(PeerHandle peerHandle, byte[] message) {
355             CallbackData callbackData = new CallbackData(ON_MESSAGE_RECEIVED);
356             callbackData.peerHandle = peerHandle;
357             callbackData.serviceSpecificInfo = message;
358             processCallback(callbackData);
359         }
360     }
361 
362     /**
363      * Utility RangingResultCallback - provides mechanism for blocking/serializing access with the
364      * waitForRangingResults method.
365      */
366     public static class RangingCb extends RangingResultCallback {
367         public static final int TIMEOUT = -1;
368         public static final int ON_FAILURE = 0;
369         public static final int ON_RESULTS = 1;
370 
371         private CountDownLatch mBlocker = new CountDownLatch(1);
372         private int mStatus = TIMEOUT;
373         private List<RangingResult> mResults = null;
374 
375         /**
376          * Wait (blocks) for Ranging results callbacks - or times-out.
377          *
378          * @return Pair of status & Ranging results if succeeded, null otherwise.
379          */
waitForRangingResults()380         public Pair<Integer, List<RangingResult>> waitForRangingResults()
381                 throws InterruptedException {
382             if (mBlocker.await(CALLBACK_TIMEOUT_SEC, TimeUnit.SECONDS)) {
383                 return new Pair<>(mStatus, mResults);
384             }
385             return new Pair<>(TIMEOUT, null);
386         }
387 
388         @Override
onRangingFailure(int code)389         public void onRangingFailure(int code) {
390             mStatus = ON_FAILURE;
391             mBlocker.countDown();
392         }
393 
394         @Override
onRangingResults(List<RangingResult> results)395         public void onRangingResults(List<RangingResult> results) {
396             mStatus = ON_RESULTS;
397             mResults = results;
398             mBlocker.countDown();
399         }
400     }
401 }
402