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