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