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