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