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 17package android.net.wifi.aware; 18 19import android.annotation.NonNull; 20import android.annotation.Nullable; 21import android.annotation.SystemApi; 22import android.net.NetworkSpecifier; 23import android.os.Binder; 24import android.os.Handler; 25import android.os.Looper; 26import android.util.Log; 27 28import com.android.internal.annotations.VisibleForTesting; 29 30import dalvik.system.CloseGuard; 31 32import 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 */ 38public 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 = CloseGuard.get(); 49 50 /** @hide */ 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 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 } 84 85 /** @hide */ 86 @Override 87 protected void finalize() throws Throwable { 88 try { 89 if (mCloseGuard != null) { 90 mCloseGuard.warnIfOpen(); 91 } 92 93 if (!mTerminated) { 94 close(); 95 } 96 } finally { 97 super.finalize(); 98 } 99 } 100 101 /** 102 * Access the client ID of the Aware session. 103 * 104 * Note: internal visibility for testing. 105 * 106 * @return The internal client ID. 107 * 108 * @hide 109 */ 110 @VisibleForTesting 111 public int getClientId() { 112 return mClientId; 113 } 114 115 /** 116 * Issue a request to the Aware service to create a new Aware publish discovery session, using 117 * the specified {@code publishConfig} configuration. The results of the publish operation 118 * are routed to the callbacks of {@link DiscoverySessionCallback}: 119 * <ul> 120 * <li> 121 * {@link DiscoverySessionCallback#onPublishStarted( 122 *PublishDiscoverySession)} 123 * is called when the publish session is created and provides a handle to the session. 124 * Further operations on the publish session can be executed on that object. 125 * <li>{@link DiscoverySessionCallback#onSessionConfigFailed()} is called if the 126 * publish operation failed. 127 * </ul> 128 * <p> 129 * Other results of the publish session operations will also be routed to callbacks 130 * on the {@code callback} object. The resulting publish session can be modified using 131 * {@link PublishDiscoverySession#updatePublish(PublishConfig)}. 132 * <p> 133 * An application must use the {@link DiscoverySession#close()} to 134 * terminate the publish discovery session once it isn't needed. This will free 135 * resources as well terminate any on-air transmissions. 136 * <p>The application must have the {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} 137 * permission to start a publish discovery session. 138 * 139 * @param publishConfig The {@link PublishConfig} specifying the 140 * configuration of the requested publish session. 141 * @param callback A {@link DiscoverySessionCallback} derived object to be used for 142 * session event callbacks. 143 * @param handler The Handler on whose thread to execute the callbacks of the {@code 144 * callback} object. If a null is provided then the application's main thread will be used. 145 */ 146 public void publish(@NonNull PublishConfig publishConfig, 147 @NonNull DiscoverySessionCallback callback, @Nullable Handler handler) { 148 WifiAwareManager mgr = mMgr.get(); 149 if (mgr == null) { 150 Log.e(TAG, "publish: called post GC on WifiAwareManager"); 151 return; 152 } 153 if (mTerminated) { 154 Log.e(TAG, "publish: called after termination"); 155 return; 156 } 157 mgr.publish(mClientId, (handler == null) ? Looper.getMainLooper() : handler.getLooper(), 158 publishConfig, callback); 159 } 160 161 /** 162 * Issue a request to the Aware service to create a new Aware subscribe discovery session, using 163 * the specified {@code subscribeConfig} configuration. The results of the subscribe 164 * operation are routed to the callbacks of {@link DiscoverySessionCallback}: 165 * <ul> 166 * <li> 167 * {@link DiscoverySessionCallback#onSubscribeStarted( 168 *SubscribeDiscoverySession)} 169 * is called when the subscribe session is created and provides a handle to the session. 170 * Further operations on the subscribe session can be executed on that object. 171 * <li>{@link DiscoverySessionCallback#onSessionConfigFailed()} is called if the 172 * subscribe operation failed. 173 * </ul> 174 * <p> 175 * Other results of the subscribe session operations will also be routed to callbacks 176 * on the {@code callback} object. The resulting subscribe session can be modified using 177 * {@link SubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}. 178 * <p> 179 * An application must use the {@link DiscoverySession#close()} to 180 * terminate the subscribe discovery session once it isn't needed. This will free 181 * resources as well terminate any on-air transmissions. 182 * <p>The application must have the {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} 183 * permission to start a subscribe discovery session. 184 * 185 * @param subscribeConfig The {@link SubscribeConfig} specifying the 186 * configuration of the requested subscribe session. 187 * @param callback A {@link DiscoverySessionCallback} derived object to be used for 188 * session event callbacks. 189 * @param handler The Handler on whose thread to execute the callbacks of the {@code 190 * callback} object. If a null is provided then the application's main thread will be used. 191 */ 192 public void subscribe(@NonNull SubscribeConfig subscribeConfig, 193 @NonNull DiscoverySessionCallback callback, @Nullable Handler handler) { 194 WifiAwareManager mgr = mMgr.get(); 195 if (mgr == null) { 196 Log.e(TAG, "publish: called post GC on WifiAwareManager"); 197 return; 198 } 199 if (mTerminated) { 200 Log.e(TAG, "publish: called after termination"); 201 return; 202 } 203 mgr.subscribe(mClientId, (handler == null) ? Looper.getMainLooper() : handler.getLooper(), 204 subscribeConfig, callback); 205 } 206 207 /** 208 * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} for 209 * an unencrypted WiFi Aware connection (link) to the specified peer. The 210 * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to 211 * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}. 212 * <p> 213 * This API is targeted for applications which can obtain the peer MAC address using OOB 214 * (out-of-band) discovery. Aware discovery does not provide the MAC address of the peer - 215 * when using Aware discovery use the alternative network specifier method - 216 * {@link DiscoverySession#createNetworkSpecifierOpen(PeerHandle)}. 217 * <p> 218 * To set up an encrypted link use the 219 * {@link #createNetworkSpecifierPassphrase(int, byte[], String)} API. 220 * 221 * @param role The role of this device: 222 * {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_INITIATOR} or 223 * {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_RESPONDER} 224 * @param peer The MAC address of the peer's Aware discovery interface. On a RESPONDER this 225 * value is used to gate the acceptance of a connection request from only that 226 * peer. 227 * 228 * @return A {@link NetworkSpecifier} to be used to construct 229 * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} to pass to 230 * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest, 231 * android.net.ConnectivityManager.NetworkCallback)} 232 * [or other varieties of that API]. 233 */ 234 public NetworkSpecifier createNetworkSpecifierOpen( 235 @WifiAwareManager.DataPathRole int role, @NonNull byte[] peer) { 236 WifiAwareManager mgr = mMgr.get(); 237 if (mgr == null) { 238 Log.e(TAG, "createNetworkSpecifierOpen: called post GC on WifiAwareManager"); 239 return null; 240 } 241 if (mTerminated) { 242 Log.e(TAG, "createNetworkSpecifierOpen: called after termination"); 243 return null; 244 } 245 return mgr.createNetworkSpecifier(mClientId, role, peer, null, null); 246 } 247 248 /** 249 * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} for 250 * an encrypted WiFi Aware connection (link) to the specified peer. The 251 * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to 252 * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}. 253 * <p> 254 * This API is targeted for applications which can obtain the peer MAC address using OOB 255 * (out-of-band) discovery. Aware discovery does not provide the MAC address of the peer - 256 * when using Aware discovery use the alternative network specifier method - 257 * {@link DiscoverySession#createNetworkSpecifierPassphrase(PeerHandle, String)}. 258 * 259 * @param role The role of this device: 260 * {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_INITIATOR} or 261 * {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_RESPONDER} 262 * @param peer The MAC address of the peer's Aware discovery interface. On a RESPONDER this 263 * value is used to gate the acceptance of a connection request from only that 264 * peer. 265 * @param passphrase The passphrase to be used to encrypt the link. The PMK is generated from 266 * the passphrase. Use {@link #createNetworkSpecifierOpen(int, byte[])} to 267 * specify an open (unencrypted) link. 268 * 269 * @return A {@link NetworkSpecifier} to be used to construct 270 * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} to pass to 271 * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest, 272 * android.net.ConnectivityManager.NetworkCallback)} 273 * [or other varieties of that API]. 274 */ 275 public NetworkSpecifier createNetworkSpecifierPassphrase( 276 @WifiAwareManager.DataPathRole int role, @NonNull byte[] peer, 277 @NonNull String passphrase) { 278 WifiAwareManager mgr = mMgr.get(); 279 if (mgr == null) { 280 Log.e(TAG, "createNetworkSpecifierPassphrase: called post GC on WifiAwareManager"); 281 return null; 282 } 283 if (mTerminated) { 284 Log.e(TAG, "createNetworkSpecifierPassphrase: called after termination"); 285 return null; 286 } 287 if (!WifiAwareUtils.validatePassphrase(passphrase)) { 288 throw new IllegalArgumentException("Passphrase must meet length requirements"); 289 } 290 291 return mgr.createNetworkSpecifier(mClientId, role, peer, null, passphrase); 292 } 293 294 /** 295 * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} for 296 * an encrypted 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 DiscoverySession#createNetworkSpecifierPassphrase(PeerHandle, String)}. 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 pmk A PMK (pairwise master key, see IEEE 802.11i) specifying the key to use for 312 * encrypting the data-path. Use the 313 * {@link #createNetworkSpecifierPassphrase(int, byte[], String)} to specify a 314 * Passphrase or {@link #createNetworkSpecifierOpen(int, byte[])} to specify an 315 * open (unencrypted) link. 316 * 317 * @return A {@link NetworkSpecifier} to be used to construct 318 * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} to pass to 319 * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest, 320 * android.net.ConnectivityManager.NetworkCallback)} 321 * [or other varieties of that API]. 322 * 323 * @hide 324 */ 325 @SystemApi 326 public NetworkSpecifier createNetworkSpecifierPmk( 327 @WifiAwareManager.DataPathRole int role, @NonNull byte[] peer, @NonNull byte[] pmk) { 328 WifiAwareManager mgr = mMgr.get(); 329 if (mgr == null) { 330 Log.e(TAG, "createNetworkSpecifierPmk: called post GC on WifiAwareManager"); 331 return null; 332 } 333 if (mTerminated) { 334 Log.e(TAG, "createNetworkSpecifierPmk: called after termination"); 335 return null; 336 } 337 if (!WifiAwareUtils.validatePmk(pmk)) { 338 throw new IllegalArgumentException("PMK must 32 bytes"); 339 } 340 return mgr.createNetworkSpecifier(mClientId, role, peer, pmk, null); 341 } 342} 343