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