• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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 android.net.wifi.aware;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.SystemApi;
22 import android.net.NetworkSpecifier;
23 import android.util.CloseGuard;
24 import android.util.Log;
25 
26 import com.android.internal.annotations.VisibleForTesting;
27 
28 import java.lang.ref.Reference;
29 import java.lang.ref.WeakReference;
30 
31 /**
32  * A class representing a single publish or subscribe Aware session. This object
33  * will not be created directly - only its child classes are available:
34  * {@link PublishDiscoverySession} and {@link SubscribeDiscoverySession}. This
35  * class provides functionality common to both publish and subscribe discovery sessions:
36  * <ul>
37  *      <li>Sending messages: {@link #sendMessage(PeerHandle, int, byte[])} method.
38  *      <li>Creating a network-specifier when requesting a Aware connection using
39  *      {@link WifiAwareNetworkSpecifier.Builder}.
40  * </ul>
41  * <p>
42  * The {@link #close()} method must be called to destroy discovery sessions once they are
43  * no longer needed.
44  */
45 public class DiscoverySession implements AutoCloseable {
46     private static final String TAG = "DiscoverySession";
47     private static final boolean DBG = false;
48     private static final boolean VDBG = false; // STOPSHIP if true
49 
50     private static final int MAX_SEND_RETRY_COUNT = 5;
51 
52     /** @hide */
53     protected WeakReference<WifiAwareManager> mMgr;
54     /** @hide */
55     protected final int mClientId;
56     /** @hide */
57     protected final int mSessionId;
58     /** @hide */
59     protected boolean mTerminated = false;
60 
61     private final CloseGuard mCloseGuard = new CloseGuard();
62 
63     /**
64      * Return the maximum permitted retry count when sending messages using
65      * {@link #sendMessage(PeerHandle, int, byte[], int)}.
66      *
67      * @return Maximum retry count when sending messages.
68      *
69      * @hide
70      */
getMaxSendRetryCount()71     public static int getMaxSendRetryCount() {
72         return MAX_SEND_RETRY_COUNT;
73     }
74 
75     /** @hide */
DiscoverySession(WifiAwareManager manager, int clientId, int sessionId)76     public DiscoverySession(WifiAwareManager manager, int clientId, int sessionId) {
77         if (VDBG) {
78             Log.v(TAG, "New discovery session created: manager=" + manager + ", clientId="
79                     + clientId + ", sessionId=" + sessionId);
80         }
81 
82         mMgr = new WeakReference<>(manager);
83         mClientId = clientId;
84         mSessionId = sessionId;
85 
86         mCloseGuard.open("close");
87     }
88 
89     /**
90      * Destroy the publish or subscribe session - free any resources, and stop
91      * transmitting packets on-air (for an active session) or listening for
92      * matches (for a passive session). The session may not be used for any
93      * additional operations after its destruction.
94      * <p>
95      *     This operation must be done on a session which is no longer needed. Otherwise system
96      *     resources will continue to be utilized until the application exits. The only
97      *     exception is a session for which we received a termination callback,
98      *     {@link DiscoverySessionCallback#onSessionTerminated()}.
99      */
100     @Override
close()101     public void close() {
102         WifiAwareManager mgr = mMgr.get();
103         if (mgr == null) {
104             Log.w(TAG, "destroy: called post GC on WifiAwareManager");
105             return;
106         }
107         mgr.terminateSession(mClientId, mSessionId);
108         mTerminated = true;
109         mMgr.clear();
110         mCloseGuard.close();
111         Reference.reachabilityFence(this);
112     }
113 
114     /**
115      * Sets the status of the session to terminated - i.e. an indication that
116      * already terminated rather than executing a termination.
117      *
118      * @hide
119      */
setTerminated()120     public void setTerminated() {
121         if (mTerminated) {
122             Log.w(TAG, "terminate: already terminated.");
123             return;
124         }
125 
126         mTerminated = true;
127         mMgr.clear();
128         mCloseGuard.close();
129     }
130 
131     /** @hide */
132     @Override
finalize()133     protected void finalize() throws Throwable {
134         try {
135             if (mCloseGuard != null) {
136                 mCloseGuard.warnIfOpen();
137             }
138 
139             if (!mTerminated) {
140                 close();
141             }
142         } finally {
143             super.finalize();
144         }
145     }
146 
147     /**
148      * Access the client ID of the Aware session.
149      *
150      * Note: internal visibility for testing.
151      *
152      * @return The internal client ID.
153      *
154      * @hide
155      */
156     @VisibleForTesting
getClientId()157     public int getClientId() {
158         return mClientId;
159     }
160 
161     /**
162      * Access the discovery session ID of the Aware session.
163      *
164      * Note: internal visibility for testing.
165      *
166      * @return The internal discovery session ID.
167      *
168      * @hide
169      */
170     @VisibleForTesting
getSessionId()171     public int getSessionId() {
172         return mSessionId;
173     }
174 
175     /**
176      * Sends a message to the specified destination. Aware messages are transmitted in the context
177      * of a discovery session - executed subsequent to a publish/subscribe
178      * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle,
179      * byte[], java.util.List)} event.
180      * <p>
181      *     Aware messages are not guaranteed delivery. Callbacks on
182      *     {@link DiscoverySessionCallback} indicate message was transmitted successfully,
183      *     {@link DiscoverySessionCallback#onMessageSendSucceeded(int)}, or transmission
184      *     failed (possibly after several retries) -
185      *     {@link DiscoverySessionCallback#onMessageSendFailed(int)}.
186      * <p>
187      *     The peer will get a callback indicating a message was received using
188      *     {@link DiscoverySessionCallback#onMessageReceived(PeerHandle,
189      *     byte[])}.
190      *
191      * @param peerHandle The peer's handle for the message. Must be a result of an
192      * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle,
193      * byte[], java.util.List)} or
194      * {@link DiscoverySessionCallback#onMessageReceived(PeerHandle,
195      * byte[])} events.
196      * @param messageId An arbitrary integer used by the caller to identify the message. The same
197      *            integer ID will be returned in the callbacks indicating message send success or
198      *            failure. The {@code messageId} is not used internally by the Aware service - it
199      *                  can be arbitrary and non-unique.
200      * @param message The message to be transmitted.
201      * @param retryCount An integer specifying how many additional service-level (as opposed to PHY
202      *            or MAC level) retries should be attempted if there is no ACK from the receiver
203      *            (note: no retransmissions are attempted in other failure cases). A value of 0
204      *            indicates no retries. Max permitted value is {@link #getMaxSendRetryCount()}.
205      *
206      * @hide
207      */
sendMessage(@onNull PeerHandle peerHandle, int messageId, @Nullable byte[] message, int retryCount)208     public void sendMessage(@NonNull PeerHandle peerHandle, int messageId,
209             @Nullable byte[] message, int retryCount) {
210         if (mTerminated) {
211             Log.w(TAG, "sendMessage: called on terminated session");
212             return;
213         }
214 
215         WifiAwareManager mgr = mMgr.get();
216         if (mgr == null) {
217             Log.w(TAG, "sendMessage: called post GC on WifiAwareManager");
218             return;
219         }
220 
221         mgr.sendMessage(mClientId, mSessionId, peerHandle, message, messageId, retryCount);
222     }
223 
224     /**
225      * Sends a message to the specified destination. Aware messages are transmitted in the context
226      * of a discovery session - executed subsequent to a publish/subscribe
227      * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle,
228      * byte[], java.util.List)} event.
229      * <p>
230      *     Aware messages are not guaranteed delivery. Callbacks on
231      *     {@link DiscoverySessionCallback} indicate message was transmitted successfully,
232      *     {@link DiscoverySessionCallback#onMessageSendSucceeded(int)}, or transmission
233      *     failed (possibly after several retries) -
234      *     {@link DiscoverySessionCallback#onMessageSendFailed(int)}.
235      * <p>
236      * The peer will get a callback indicating a message was received using
237      * {@link DiscoverySessionCallback#onMessageReceived(PeerHandle,
238      * byte[])}.
239      *
240      * @param peerHandle The peer's handle for the message. Must be a result of an
241      * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle,
242      * byte[], java.util.List)} or
243      * {@link DiscoverySessionCallback#onMessageReceived(PeerHandle,
244      * byte[])} events.
245      * @param messageId An arbitrary integer used by the caller to identify the message. The same
246      *            integer ID will be returned in the callbacks indicating message send success or
247      *            failure. The {@code messageId} is not used internally by the Aware service - it
248      *                  can be arbitrary and non-unique.
249      * @param message The message to be transmitted.
250      */
sendMessage(@onNull PeerHandle peerHandle, int messageId, @Nullable byte[] message)251     public void sendMessage(@NonNull PeerHandle peerHandle, int messageId,
252             @Nullable byte[] message) {
253         sendMessage(peerHandle, messageId, message, 0);
254     }
255 
256     /**
257      * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} for
258      * an unencrypted WiFi Aware connection (link) to the specified peer. The
259      * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to
260      * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
261      * <p>
262      * This method should be used when setting up a connection with a peer discovered through Aware
263      * discovery or communication (in such scenarios the MAC address of the peer is shielded by
264      * an opaque peer ID handle). If an Aware connection is needed to a peer discovered using other
265      * OOB (out-of-band) mechanism then use the alternative
266      * {@link WifiAwareSession#createNetworkSpecifierOpen(int, byte[])} method - which uses the
267      * peer's MAC address.
268      * <p>
269      * Note: per the Wi-Fi Aware specification the roles are fixed - a Subscriber is an INITIATOR
270      * and a Publisher is a RESPONDER.
271      * <p>
272      * To set up an encrypted link use the
273      * {@link #createNetworkSpecifierPassphrase(PeerHandle, String)} API.
274      * @deprecated Use the replacement {@link WifiAwareNetworkSpecifier.Builder}.
275      *
276      * @param peerHandle The peer's handle obtained through
277      * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle, byte[], java.util.List)}
278      *                   or
279      *                   {@link DiscoverySessionCallback#onMessageReceived(PeerHandle, byte[])}.
280      *                   On a RESPONDER this value is used to gate the acceptance of a connection
281      *                   request from only that peer.
282      *
283      * @return A {@link NetworkSpecifier} to be used to construct
284      * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} to pass to
285      * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,
286      * android.net.ConnectivityManager.NetworkCallback)}
287      * [or other varieties of that API].
288      */
289     @Deprecated
createNetworkSpecifierOpen(@onNull PeerHandle peerHandle)290     public NetworkSpecifier createNetworkSpecifierOpen(@NonNull PeerHandle peerHandle) {
291         if (mTerminated) {
292             Log.w(TAG, "createNetworkSpecifierOpen: called on terminated session");
293             return null;
294         }
295 
296         WifiAwareManager mgr = mMgr.get();
297         if (mgr == null) {
298             Log.w(TAG, "createNetworkSpecifierOpen: called post GC on WifiAwareManager");
299             return null;
300         }
301 
302         int role = this instanceof SubscribeDiscoverySession
303                 ? WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
304                 : WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER;
305 
306         return mgr.createNetworkSpecifier(mClientId, role, mSessionId, peerHandle, null, null);
307     }
308 
309     /**
310      * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} for
311      * an encrypted WiFi Aware connection (link) to the specified peer. The
312      * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to
313      * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
314      * <p>
315      * This method should be used when setting up a connection with a peer discovered through Aware
316      * discovery or communication (in such scenarios the MAC address of the peer is shielded by
317      * an opaque peer ID handle). If an Aware connection is needed to a peer discovered using other
318      * OOB (out-of-band) mechanism then use the alternative
319      * {@link WifiAwareSession#createNetworkSpecifierPassphrase(int, byte[], String)} method -
320      * which uses the peer's MAC address.
321      * <p>
322      * Note: per the Wi-Fi Aware specification the roles are fixed - a Subscriber is an INITIATOR
323      * and a Publisher is a RESPONDER.
324      * @deprecated Use the replacement {@link WifiAwareNetworkSpecifier.Builder}.
325      *
326      * @param peerHandle The peer's handle obtained through
327      * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle,
328      * byte[], java.util.List)} or
329      * {@link DiscoverySessionCallback#onMessageReceived(PeerHandle,
330      * byte[])}. On a RESPONDER this value is used to gate the acceptance of a connection request
331      *                   from only that peer.
332      * @param passphrase The passphrase to be used to encrypt the link. The PMK is generated from
333      *                   the passphrase. Use the
334      *                   {@link #createNetworkSpecifierOpen(PeerHandle)} API to
335      *                   specify an open (unencrypted) link.
336      *
337      * @return A {@link NetworkSpecifier} to be used to construct
338      * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} to pass to
339      * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,
340      * android.net.ConnectivityManager.NetworkCallback)}
341      * [or other varieties of that API].
342      */
343     @Deprecated
createNetworkSpecifierPassphrase( @onNull PeerHandle peerHandle, @NonNull String passphrase)344     public NetworkSpecifier createNetworkSpecifierPassphrase(
345             @NonNull PeerHandle peerHandle, @NonNull String passphrase) {
346         if (!WifiAwareUtils.validatePassphrase(passphrase)) {
347             throw new IllegalArgumentException("Passphrase must meet length requirements");
348         }
349 
350         if (mTerminated) {
351             Log.w(TAG, "createNetworkSpecifierPassphrase: called on terminated session");
352             return null;
353         }
354 
355         WifiAwareManager mgr = mMgr.get();
356         if (mgr == null) {
357             Log.w(TAG, "createNetworkSpecifierPassphrase: called post GC on WifiAwareManager");
358             return null;
359         }
360 
361         int role = this instanceof SubscribeDiscoverySession
362                 ? WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
363                 : WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER;
364 
365         return mgr.createNetworkSpecifier(mClientId, role, mSessionId, peerHandle, null,
366                 passphrase);
367     }
368 
369     /**
370      * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} for
371      * an encrypted WiFi Aware connection (link) to the specified peer. The
372      * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to
373      * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
374      * <p>
375      * This method should be used when setting up a connection with a peer discovered through Aware
376      * discovery or communication (in such scenarios the MAC address of the peer is shielded by
377      * an opaque peer ID handle). If an Aware connection is needed to a peer discovered using other
378      * OOB (out-of-band) mechanism then use the alternative
379      * {@link WifiAwareSession#createNetworkSpecifierPmk(int, byte[], byte[])} method - which uses
380      * the peer's MAC address.
381      * <p>
382      * Note: per the Wi-Fi Aware specification the roles are fixed - a Subscriber is an INITIATOR
383      * and a Publisher is a RESPONDER.
384      * @deprecated Use the replacement {@link WifiAwareNetworkSpecifier.Builder}.
385      *
386      * @param peerHandle The peer's handle obtained through
387      * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle,
388      * byte[], java.util.List)} or
389      * {@link DiscoverySessionCallback#onMessageReceived(PeerHandle,
390      * byte[])}. On a RESPONDER this value is used to gate the acceptance of a connection request
391      *                   from only that peer.
392      * @param pmk A PMK (pairwise master key, see IEEE 802.11i) specifying the key to use for
393      *            encrypting the data-path. Use the
394      *            {@link #createNetworkSpecifierPassphrase(PeerHandle, String)} to specify a
395      *            Passphrase or {@link #createNetworkSpecifierOpen(PeerHandle)} to specify an
396      *            open (unencrypted) link.
397      *
398      * @return A {@link NetworkSpecifier} to be used to construct
399      * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} to pass to
400      * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,
401      * android.net.ConnectivityManager.NetworkCallback)}
402      * [or other varieties of that API].
403      *
404      * @hide
405      */
406     @Deprecated
407     @SystemApi
createNetworkSpecifierPmk(@onNull PeerHandle peerHandle, @NonNull byte[] pmk)408     public NetworkSpecifier createNetworkSpecifierPmk(@NonNull PeerHandle peerHandle,
409             @NonNull byte[] pmk) {
410         if (!WifiAwareUtils.validatePmk(pmk)) {
411             throw new IllegalArgumentException("PMK must 32 bytes");
412         }
413 
414         if (mTerminated) {
415             Log.w(TAG, "createNetworkSpecifierPmk: called on terminated session");
416             return null;
417         }
418 
419         WifiAwareManager mgr = mMgr.get();
420         if (mgr == null) {
421             Log.w(TAG, "createNetworkSpecifierPmk: called post GC on WifiAwareManager");
422             return null;
423         }
424 
425         int role = this instanceof SubscribeDiscoverySession
426                 ? WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
427                 : WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER;
428 
429         return mgr.createNetworkSpecifier(mClientId, role, mSessionId, peerHandle, pmk, null);
430     }
431 }
432