• 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 static android.Manifest.permission.ACCESS_FINE_LOCATION;
20 import static android.Manifest.permission.ACCESS_WIFI_STATE;
21 import static android.Manifest.permission.CHANGE_WIFI_STATE;
22 import static android.Manifest.permission.NEARBY_WIFI_DEVICES;
23 
24 import android.annotation.NonNull;
25 import android.annotation.Nullable;
26 import android.annotation.RequiresPermission;
27 import android.annotation.SystemApi;
28 import android.net.NetworkSpecifier;
29 import android.os.Binder;
30 import android.os.Handler;
31 import android.os.Looper;
32 import android.util.CloseGuard;
33 import android.util.Log;
34 
35 import com.android.internal.annotations.VisibleForTesting;
36 
37 import java.lang.ref.Reference;
38 import java.lang.ref.WeakReference;
39 
40 /**
41  * This class represents a Wi-Fi Aware session - an attachment to the Wi-Fi Aware service through
42  * which the app can execute discovery operations.
43  */
44 public class WifiAwareSession implements AutoCloseable {
45     private static final String TAG = "WifiAwareSession";
46     private static final boolean DBG = false;
47     private static final boolean VDBG = false; // STOPSHIP if true
48 
49     private final WeakReference<WifiAwareManager> mMgr;
50     private final Binder mBinder;
51     private final int mClientId;
52 
53     private boolean mTerminated = true;
54     private final CloseGuard mCloseGuard = new CloseGuard();
55 
56     /** @hide */
WifiAwareSession(WifiAwareManager manager, Binder binder, int clientId)57     public WifiAwareSession(WifiAwareManager manager, Binder binder, int clientId) {
58         if (VDBG) Log.v(TAG, "New session created: manager=" + manager + ", clientId=" + clientId);
59 
60         mMgr = new WeakReference<>(manager);
61         mBinder = binder;
62         mClientId = clientId;
63         mTerminated = false;
64 
65         mCloseGuard.open("close");
66     }
67 
68     /**
69      * Destroy the Wi-Fi Aware service session and, if no other applications are attached to Aware,
70      * also disable Aware. This method destroys all outstanding operations - i.e. all publish and
71      * subscribes are terminated, and any outstanding data-links are shut-down. However, it is
72      * good practice to destroy these discovery sessions and connections explicitly before a
73      * session-wide destroy.
74      * <p>
75      * An application may re-attach after a destroy using
76      * {@link WifiAwareManager#attach(AttachCallback, Handler)} .
77      */
78     @Override
close()79     public void close() {
80         WifiAwareManager mgr = mMgr.get();
81         if (mgr == null) {
82             Log.w(TAG, "destroy: called post GC on WifiAwareManager");
83             return;
84         }
85         mgr.disconnect(mClientId, mBinder);
86         mTerminated = true;
87         mMgr.clear();
88         mCloseGuard.close();
89         Reference.reachabilityFence(this);
90     }
91 
92     /** @hide */
93     @Override
finalize()94     protected void finalize() throws Throwable {
95         try {
96             if (mCloseGuard != null) {
97                 mCloseGuard.warnIfOpen();
98             }
99 
100             if (!mTerminated) {
101                 close();
102             }
103         } finally {
104             super.finalize();
105         }
106     }
107 
108     /**
109      * Access the client ID of the Aware session.
110      *
111      * Note: internal visibility for testing.
112      *
113      * @return The internal client ID.
114      *
115      * @hide
116      */
117     @VisibleForTesting
getClientId()118     public int getClientId() {
119         return mClientId;
120     }
121 
122     /**
123      * Issue a request to the Aware service to create a new Aware publish discovery session, using
124      * the specified {@code publishConfig} configuration. The results of the publish operation
125      * are routed to the callbacks of {@link DiscoverySessionCallback}:
126      * <ul>
127      *     <li>
128      *     {@link DiscoverySessionCallback#onPublishStarted(
129      *PublishDiscoverySession)}
130      *     is called when the publish session is created and provides a handle to the session.
131      *     Further operations on the publish session can be executed on that object.
132      *     <li>{@link DiscoverySessionCallback#onSessionConfigFailed()} is called if the
133      *     publish operation failed.
134      * </ul>
135      * <p>
136      * Other results of the publish session operations will also be routed to callbacks
137      * on the {@code callback} object. The resulting publish session can be modified using
138      * {@link PublishDiscoverySession#updatePublish(PublishConfig)}.
139      * <p> The total count of currently available Wi-Fi Aware publish sessions is limited and is
140      * available via the {@link AwareResources#getAvailablePublishSessionsCount()} method.
141      * <p>
142      *      An application must use the {@link DiscoverySession#close()} to
143      *      terminate the publish discovery session once it isn't needed. This will free
144      *      resources as well terminate any on-air transmissions.
145      * <p>
146      * If targeting {@link android.os.Build.VERSION_CODES#TIRAMISU} or later, the application must
147      * have {@link android.Manifest.permission#NEARBY_WIFI_DEVICES} with
148      * android:usesPermissionFlags="neverForLocation". If the application does not declare
149      * android:usesPermissionFlags="neverForLocation", then it must also have
150      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
151      *
152      * If targeting an earlier release than {@link android.os.Build.VERSION_CODES#TIRAMISU}, the
153      * application must have {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
154      *
155      * @param publishConfig The {@link PublishConfig} specifying the
156      *            configuration of the requested publish session.
157      * @param callback A {@link DiscoverySessionCallback} derived object to be used for
158      *                 session event callbacks.
159      * @param handler The Handler on whose thread to execute the callbacks of the {@code
160      * callback} object. If a null is provided then the application's main thread will be used.
161      */
162     @RequiresPermission(allOf = {
163             ACCESS_WIFI_STATE,
164             CHANGE_WIFI_STATE,
165             ACCESS_FINE_LOCATION,
166             NEARBY_WIFI_DEVICES}, conditional = true)
publish(@onNull PublishConfig publishConfig, @NonNull DiscoverySessionCallback callback, @Nullable Handler handler)167     public void publish(@NonNull PublishConfig publishConfig,
168             @NonNull DiscoverySessionCallback callback, @Nullable Handler handler) {
169         WifiAwareManager mgr = mMgr.get();
170         if (mgr == null) {
171             Log.e(TAG, "publish: called post GC on WifiAwareManager");
172             return;
173         }
174         if (mTerminated) {
175             Log.e(TAG, "publish: called after termination");
176             return;
177         }
178         mgr.publish(mClientId, (handler == null) ? Looper.getMainLooper() : handler.getLooper(),
179                 publishConfig, callback);
180     }
181 
182     /**
183      * Issue a request to the Aware service to create a new Aware subscribe discovery session, using
184      * the specified {@code subscribeConfig} configuration. The results of the subscribe
185      * operation are routed to the callbacks of {@link DiscoverySessionCallback}:
186      * <ul>
187      *     <li>
188      *  {@link DiscoverySessionCallback#onSubscribeStarted(
189      *SubscribeDiscoverySession)}
190      *     is called when the subscribe session is created and provides a handle to the session.
191      *     Further operations on the subscribe session can be executed on that object.
192      *     <li>{@link DiscoverySessionCallback#onSessionConfigFailed()} is called if the
193      *     subscribe operation failed.
194      * </ul>
195      * <p>
196      * Other results of the subscribe session operations will also be routed to callbacks
197      * on the {@code callback} object. The resulting subscribe session can be modified using
198      * {@link SubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
199      * <p> The total count of currently available Wi-Fi Aware subscribe sessions is limited and is
200      * available via the {@link AwareResources#getAvailableSubscribeSessionsCount()} method.
201      * <p>
202      *      An application must use the {@link DiscoverySession#close()} to
203      *      terminate the subscribe discovery session once it isn't needed. This will free
204      *      resources as well terminate any on-air transmissions.
205      * <p>
206      * If targeting {@link android.os.Build.VERSION_CODES#TIRAMISU} or later, the application must
207      * have {@link android.Manifest.permission#NEARBY_WIFI_DEVICES} with
208      * android:usesPermissionFlags="neverForLocation". If the application does not declare
209      * android:usesPermissionFlags="neverForLocation", then it must also have
210      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
211      *
212      * If targeting an earlier release than {@link android.os.Build.VERSION_CODES#TIRAMISU}, the
213      * application must have {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
214      *
215      * @param subscribeConfig The {@link SubscribeConfig} specifying the
216      *            configuration of the requested subscribe session.
217      * @param callback A {@link DiscoverySessionCallback} derived object to be used for
218      *                 session event callbacks.
219      * @param handler The Handler on whose thread to execute the callbacks of the {@code
220      * callback} object. If a null is provided then the application's main thread will be used.
221      */
222     @RequiresPermission(allOf = {
223             ACCESS_WIFI_STATE,
224             CHANGE_WIFI_STATE,
225             ACCESS_FINE_LOCATION,
226             NEARBY_WIFI_DEVICES}, conditional = true)
subscribe(@onNull SubscribeConfig subscribeConfig, @NonNull DiscoverySessionCallback callback, @Nullable Handler handler)227     public void subscribe(@NonNull SubscribeConfig subscribeConfig,
228             @NonNull DiscoverySessionCallback callback, @Nullable Handler handler) {
229         WifiAwareManager mgr = mMgr.get();
230         if (mgr == null) {
231             Log.e(TAG, "publish: called post GC on WifiAwareManager");
232             return;
233         }
234         if (mTerminated) {
235             Log.e(TAG, "publish: called after termination");
236             return;
237         }
238         mgr.subscribe(mClientId, (handler == null) ? Looper.getMainLooper() : handler.getLooper(),
239                 subscribeConfig, callback);
240     }
241 
242     /**
243      * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} for
244      * an unencrypted WiFi Aware connection (link) to the specified peer. The
245      * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to
246      * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
247      * <p>
248      *     This API is targeted for applications which can obtain the peer MAC address using OOB
249      *     (out-of-band) discovery. Aware discovery does not provide the MAC address of the peer -
250      *     when using Aware discovery use the alternative network specifier method -
251      *     {@link android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder}.
252      * <p>
253      * To set up an encrypted link use the
254      * {@link #createNetworkSpecifierPassphrase(int, byte[], String)} API.
255      *
256      * @deprecated Please use in-band data-path setup, refer to
257      * {@link WifiAwareNetworkSpecifier.Builder},
258      * {@link #publish(PublishConfig, DiscoverySessionCallback, Handler)} and
259      * {@link #subscribe(SubscribeConfig, DiscoverySessionCallback, Handler)}
260      *
261      * @param role  The role of this device:
262      *              {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_INITIATOR} or
263      *              {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_RESPONDER}
264      * @param peer  The MAC address of the peer's Aware discovery interface. On a RESPONDER this
265      *              value is used to gate the acceptance of a connection request from only that
266      *              peer.
267      *
268      * @return A {@link NetworkSpecifier} to be used to construct
269      * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} to pass to
270      * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,
271      * android.net.ConnectivityManager.NetworkCallback)}
272      * [or other varieties of that API].
273      */
274     @Deprecated
createNetworkSpecifierOpen( @ifiAwareManager.DataPathRole int role, @NonNull byte[] peer)275     public NetworkSpecifier createNetworkSpecifierOpen(
276             @WifiAwareManager.DataPathRole int role, @NonNull byte[] peer) {
277         WifiAwareManager mgr = mMgr.get();
278         if (mgr == null) {
279             Log.e(TAG, "createNetworkSpecifierOpen: called post GC on WifiAwareManager");
280             return null;
281         }
282         if (mTerminated) {
283             Log.e(TAG, "createNetworkSpecifierOpen: called after termination");
284             return null;
285         }
286         return mgr.createNetworkSpecifier(mClientId, role, peer, null, null);
287     }
288 
289     /**
290      * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} for
291      * an encrypted WiFi Aware connection (link) to the specified peer. The
292      * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to
293      * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
294      * <p>
295      *     This API is targeted for applications which can obtain the peer MAC address using OOB
296      *     (out-of-band) discovery. Aware discovery does not provide the MAC address of the peer -
297      *     when using Aware discovery use the alternative network specifier method -
298      *     {@link android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder}.
299      *
300      * @deprecated Please use in-band data-path setup, refer to
301      * {@link WifiAwareNetworkSpecifier.Builder},
302      * {@link #publish(PublishConfig, DiscoverySessionCallback, Handler)} and
303      * {@link #subscribe(SubscribeConfig, DiscoverySessionCallback, Handler)}
304      *
305      * @param role  The role of this device:
306      *              {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_INITIATOR} or
307      *              {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_RESPONDER}
308      * @param peer  The MAC address of the peer's Aware discovery interface. On a RESPONDER this
309      *              value is used to gate the acceptance of a connection request from only that
310      *              peer.
311      * @param passphrase The passphrase to be used to encrypt the link. The PMK is generated from
312      *                   the passphrase. Use {@link #createNetworkSpecifierOpen(int, byte[])} to
313      *                   specify an open (unencrypted) link.
314      *
315      * @return A {@link NetworkSpecifier} to be used to construct
316      * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} to pass to
317      * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,
318      * android.net.ConnectivityManager.NetworkCallback)}
319      * [or other varieties of that API].
320      */
321     @Deprecated
createNetworkSpecifierPassphrase( @ifiAwareManager.DataPathRole int role, @NonNull byte[] peer, @NonNull String passphrase)322     public NetworkSpecifier createNetworkSpecifierPassphrase(
323             @WifiAwareManager.DataPathRole int role, @NonNull byte[] peer,
324             @NonNull String passphrase) {
325         WifiAwareManager mgr = mMgr.get();
326         if (mgr == null) {
327             Log.e(TAG, "createNetworkSpecifierPassphrase: called post GC on WifiAwareManager");
328             return null;
329         }
330         if (mTerminated) {
331             Log.e(TAG, "createNetworkSpecifierPassphrase: called after termination");
332             return null;
333         }
334         if (!WifiAwareUtils.validatePassphrase(passphrase)) {
335             throw new IllegalArgumentException("Passphrase must meet length requirements");
336         }
337 
338         return mgr.createNetworkSpecifier(mClientId, role, peer, null, passphrase);
339     }
340 
341     /**
342      * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} for
343      * an encrypted WiFi Aware connection (link) to the specified peer. The
344      * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to
345      * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
346      * <p>
347      *     This API is targeted for applications which can obtain the peer MAC address using OOB
348      *     (out-of-band) discovery. Aware discovery does not provide the MAC address of the peer -
349      *     when using Aware discovery use the alternative network specifier method -
350      *     {@link android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder}.
351      *
352      * @deprecated Please use in-band data-path setup, refer to
353      * {@link WifiAwareNetworkSpecifier.Builder},
354      * {@link #publish(PublishConfig, DiscoverySessionCallback, Handler)} and
355      * {@link #subscribe(SubscribeConfig, DiscoverySessionCallback, Handler)}
356      *
357      * @param role  The role of this device:
358      *              {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_INITIATOR} or
359      *              {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_RESPONDER}
360      * @param peer  The MAC address of the peer's Aware discovery interface. On a RESPONDER this
361      *              value is used to gate the acceptance of a connection request from only that
362      *              peer.
363      * @param pmk A PMK (pairwise master key, see IEEE 802.11i) specifying the key to use for
364      *            encrypting the data-path. Use the
365      *            {@link #createNetworkSpecifierPassphrase(int, byte[], String)} to specify a
366      *            Passphrase or {@link #createNetworkSpecifierOpen(int, byte[])} to specify an
367      *            open (unencrypted) link.
368      *
369      * @return A {@link NetworkSpecifier} to be used to construct
370      * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} to pass to
371      * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,
372      * android.net.ConnectivityManager.NetworkCallback)}
373      * [or other varieties of that API].
374      *
375      * @hide
376      */
377     @Deprecated
378     @SystemApi
createNetworkSpecifierPmk( @ifiAwareManager.DataPathRole int role, @NonNull byte[] peer, @NonNull byte[] pmk)379     public NetworkSpecifier createNetworkSpecifierPmk(
380             @WifiAwareManager.DataPathRole int role, @NonNull byte[] peer, @NonNull byte[] pmk) {
381         WifiAwareManager mgr = mMgr.get();
382         if (mgr == null) {
383             Log.e(TAG, "createNetworkSpecifierPmk: called post GC on WifiAwareManager");
384             return null;
385         }
386         if (mTerminated) {
387             Log.e(TAG, "createNetworkSpecifierPmk: called after termination");
388             return null;
389         }
390         if (!WifiAwareUtils.validatePmk(pmk)) {
391             throw new IllegalArgumentException("PMK must 32 bytes");
392         }
393         return mgr.createNetworkSpecifier(mClientId, role, peer, pmk, null);
394     }
395 }
396