/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net.wifi.aware;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.net.NetworkSpecifier;
import android.os.Binder;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import dalvik.system.CloseGuard;
import java.lang.ref.WeakReference;
This class represents a Wi-Fi Aware session - an attachment to the Wi-Fi Aware service through
which the app can execute discovery operations.
/**
* This class represents a Wi-Fi Aware session - an attachment to the Wi-Fi Aware service through
* which the app can execute discovery operations.
*/
public class WifiAwareSession implements AutoCloseable {
private static final String TAG = "WifiAwareSession";
private static final boolean DBG = false;
private static final boolean VDBG = false; // STOPSHIP if true
private final WeakReference<WifiAwareManager> mMgr;
private final Binder mBinder;
private final int mClientId;
private boolean mTerminated = true;
private final CloseGuard mCloseGuard = CloseGuard.get();
@hide
/** @hide */
public WifiAwareSession(WifiAwareManager manager, Binder binder, int clientId) {
if (VDBG) Log.v(TAG, "New session created: manager=" + manager + ", clientId=" + clientId);
mMgr = new WeakReference<>(manager);
mBinder = binder;
mClientId = clientId;
mTerminated = false;
mCloseGuard.open("close");
}
Destroy the Wi-Fi Aware service session and, if no other applications are attached to Aware,
also disable Aware. This method destroys all outstanding operations - i.e. all publish and
subscribes are terminated, and any outstanding data-links are shut-down. However, it is
good practice to destroy these discovery sessions and connections explicitly before a
session-wide destroy.
An application may re-attach after a destroy using WifiAwareManager.attach(AttachCallback, Handler)
.
/**
* Destroy the Wi-Fi Aware service session and, if no other applications are attached to Aware,
* also disable Aware. This method destroys all outstanding operations - i.e. all publish and
* subscribes are terminated, and any outstanding data-links are shut-down. However, it is
* good practice to destroy these discovery sessions and connections explicitly before a
* session-wide destroy.
* <p>
* An application may re-attach after a destroy using
* {@link WifiAwareManager#attach(AttachCallback, Handler)} .
*/
@Override
public void close() {
WifiAwareManager mgr = mMgr.get();
if (mgr == null) {
Log.w(TAG, "destroy: called post GC on WifiAwareManager");
return;
}
mgr.disconnect(mClientId, mBinder);
mTerminated = true;
mMgr.clear();
mCloseGuard.close();
}
@hide
/** @hide */
@Override
protected void finalize() throws Throwable {
try {
if (mCloseGuard != null) {
mCloseGuard.warnIfOpen();
}
if (!mTerminated) {
close();
}
} finally {
super.finalize();
}
}
Access the client ID of the Aware session.
Note: internal visibility for testing.
Returns: The internal client ID. @hide
/**
* Access the client ID of the Aware session.
*
* Note: internal visibility for testing.
*
* @return The internal client ID.
*
* @hide
*/
@VisibleForTesting
public int getClientId() {
return mClientId;
}
Issue a request to the Aware service to create a new Aware publish discovery session, using the specified publishConfig
configuration. The results of the publish operation are routed to the callbacks of DiscoverySessionCallback
:
-
DiscoverySessionCallback.onPublishStarted(PublishDiscoverySession)
is called when the publish session is created and provides a handle to the session. Further operations on the publish session can be executed on that object. DiscoverySessionCallback.onSessionConfigFailed()
is called if the publish operation failed.
Other results of the publish session operations will also be routed to callbacks on the callback
object. The resulting publish session can be modified using PublishDiscoverySession.updatePublish(PublishConfig)
.
An application must use the DiscoverySession.close()
to terminate the publish discovery session once it isn't needed. This will free resources as well terminate any on-air transmissions.
The application must have the ACCESS_COARSE_LOCATION.ACCESS_COARSE_LOCATION
permission to start a publish discovery session.
Params: - publishConfig – The
PublishConfig
specifying the configuration of the requested publish session. - callback – A
DiscoverySessionCallback
derived object to be used for session event callbacks. - handler – The Handler on whose thread to execute the callbacks of the
callback
object. If a null is provided then the application's main thread will be used.
/**
* Issue a request to the Aware service to create a new Aware publish discovery session, using
* the specified {@code publishConfig} configuration. The results of the publish operation
* are routed to the callbacks of {@link DiscoverySessionCallback}:
* <ul>
* <li>
* {@link DiscoverySessionCallback#onPublishStarted(
*PublishDiscoverySession)}
* is called when the publish session is created and provides a handle to the session.
* Further operations on the publish session can be executed on that object.
* <li>{@link DiscoverySessionCallback#onSessionConfigFailed()} is called if the
* publish operation failed.
* </ul>
* <p>
* Other results of the publish session operations will also be routed to callbacks
* on the {@code callback} object. The resulting publish session can be modified using
* {@link PublishDiscoverySession#updatePublish(PublishConfig)}.
* <p>
* An application must use the {@link DiscoverySession#close()} to
* terminate the publish discovery session once it isn't needed. This will free
* resources as well terminate any on-air transmissions.
* <p>The application must have the {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}
* permission to start a publish discovery session.
*
* @param publishConfig The {@link PublishConfig} specifying the
* configuration of the requested publish session.
* @param callback A {@link DiscoverySessionCallback} derived object to be used for
* session event callbacks.
* @param handler The Handler on whose thread to execute the callbacks of the {@code
* callback} object. If a null is provided then the application's main thread will be used.
*/
public void publish(@NonNull PublishConfig publishConfig,
@NonNull DiscoverySessionCallback callback, @Nullable Handler handler) {
WifiAwareManager mgr = mMgr.get();
if (mgr == null) {
Log.e(TAG, "publish: called post GC on WifiAwareManager");
return;
}
if (mTerminated) {
Log.e(TAG, "publish: called after termination");
return;
}
mgr.publish(mClientId, (handler == null) ? Looper.getMainLooper() : handler.getLooper(),
publishConfig, callback);
}
Issue a request to the Aware service to create a new Aware subscribe discovery session, using the specified subscribeConfig
configuration. The results of the subscribe operation are routed to the callbacks of DiscoverySessionCallback
:
-
DiscoverySessionCallback.onSubscribeStarted(SubscribeDiscoverySession)
is called when the subscribe session is created and provides a handle to the session. Further operations on the subscribe session can be executed on that object. DiscoverySessionCallback.onSessionConfigFailed()
is called if the subscribe operation failed.
Other results of the subscribe session operations will also be routed to callbacks on the callback
object. The resulting subscribe session can be modified using SubscribeDiscoverySession.updateSubscribe(SubscribeConfig)
.
An application must use the DiscoverySession.close()
to terminate the subscribe discovery session once it isn't needed. This will free resources as well terminate any on-air transmissions.
The application must have the ACCESS_COARSE_LOCATION.ACCESS_COARSE_LOCATION
permission to start a subscribe discovery session.
Params: - subscribeConfig – The
SubscribeConfig
specifying the configuration of the requested subscribe session. - callback – A
DiscoverySessionCallback
derived object to be used for session event callbacks. - handler – The Handler on whose thread to execute the callbacks of the
callback
object. If a null is provided then the application's main thread will be used.
/**
* Issue a request to the Aware service to create a new Aware subscribe discovery session, using
* the specified {@code subscribeConfig} configuration. The results of the subscribe
* operation are routed to the callbacks of {@link DiscoverySessionCallback}:
* <ul>
* <li>
* {@link DiscoverySessionCallback#onSubscribeStarted(
*SubscribeDiscoverySession)}
* is called when the subscribe session is created and provides a handle to the session.
* Further operations on the subscribe session can be executed on that object.
* <li>{@link DiscoverySessionCallback#onSessionConfigFailed()} is called if the
* subscribe operation failed.
* </ul>
* <p>
* Other results of the subscribe session operations will also be routed to callbacks
* on the {@code callback} object. The resulting subscribe session can be modified using
* {@link SubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
* <p>
* An application must use the {@link DiscoverySession#close()} to
* terminate the subscribe discovery session once it isn't needed. This will free
* resources as well terminate any on-air transmissions.
* <p>The application must have the {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}
* permission to start a subscribe discovery session.
*
* @param subscribeConfig The {@link SubscribeConfig} specifying the
* configuration of the requested subscribe session.
* @param callback A {@link DiscoverySessionCallback} derived object to be used for
* session event callbacks.
* @param handler The Handler on whose thread to execute the callbacks of the {@code
* callback} object. If a null is provided then the application's main thread will be used.
*/
public void subscribe(@NonNull SubscribeConfig subscribeConfig,
@NonNull DiscoverySessionCallback callback, @Nullable Handler handler) {
WifiAwareManager mgr = mMgr.get();
if (mgr == null) {
Log.e(TAG, "publish: called post GC on WifiAwareManager");
return;
}
if (mTerminated) {
Log.e(TAG, "publish: called after termination");
return;
}
mgr.subscribe(mClientId, (handler == null) ? Looper.getMainLooper() : handler.getLooper(),
subscribeConfig, callback);
}
Create a Builder.setNetworkSpecifier(NetworkSpecifier)
for an unencrypted WiFi Aware connection (link) to the specified peer. The Builder.addTransportType(int)
should be set to NetworkCapabilities.TRANSPORT_WIFI_AWARE
. This API is targeted for applications which can obtain the peer MAC address using OOB (out-of-band) discovery. Aware discovery does not provide the MAC address of the peer - when using Aware discovery use the alternative network specifier method - DiscoverySession.createNetworkSpecifierOpen(PeerHandle)
.
To set up an encrypted link use the createNetworkSpecifierPassphrase(int, byte[], String)
API.
Params: - role – The role of this device:
WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
or WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER
- peer – The MAC address of the peer's Aware discovery interface. On a RESPONDER this
value is used to gate the acceptance of a connection request from only that
peer.
Returns: A NetworkSpecifier
to be used to construct Builder.setNetworkSpecifier(NetworkSpecifier)
to pass to ConnectivityManager.requestNetwork(NetworkRequest, NetworkCallback)
[or other varieties of that API].
/**
* Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} for
* an unencrypted WiFi Aware connection (link) to the specified peer. The
* {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to
* {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
* <p>
* This API is targeted for applications which can obtain the peer MAC address using OOB
* (out-of-band) discovery. Aware discovery does not provide the MAC address of the peer -
* when using Aware discovery use the alternative network specifier method -
* {@link DiscoverySession#createNetworkSpecifierOpen(PeerHandle)}.
* <p>
* To set up an encrypted link use the
* {@link #createNetworkSpecifierPassphrase(int, byte[], String)} API.
*
* @param role The role of this device:
* {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_INITIATOR} or
* {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_RESPONDER}
* @param peer The MAC address of the peer's Aware discovery interface. On a RESPONDER this
* value is used to gate the acceptance of a connection request from only that
* peer.
*
* @return A {@link NetworkSpecifier} to be used to construct
* {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} to pass to
* {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,
* android.net.ConnectivityManager.NetworkCallback)}
* [or other varieties of that API].
*/
public NetworkSpecifier createNetworkSpecifierOpen(
@WifiAwareManager.DataPathRole int role, @NonNull byte[] peer) {
WifiAwareManager mgr = mMgr.get();
if (mgr == null) {
Log.e(TAG, "createNetworkSpecifierOpen: called post GC on WifiAwareManager");
return null;
}
if (mTerminated) {
Log.e(TAG, "createNetworkSpecifierOpen: called after termination");
return null;
}
return mgr.createNetworkSpecifier(mClientId, role, peer, null, null);
}
Create a Builder.setNetworkSpecifier(NetworkSpecifier)
for an encrypted WiFi Aware connection (link) to the specified peer. The Builder.addTransportType(int)
should be set to NetworkCapabilities.TRANSPORT_WIFI_AWARE
. This API is targeted for applications which can obtain the peer MAC address using OOB (out-of-band) discovery. Aware discovery does not provide the MAC address of the peer - when using Aware discovery use the alternative network specifier method - DiscoverySession.createNetworkSpecifierPassphrase(PeerHandle, String)
.
Params: - role – The role of this device:
WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
or WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER
- peer – The MAC address of the peer's Aware discovery interface. On a RESPONDER this
value is used to gate the acceptance of a connection request from only that
peer.
- passphrase – The passphrase to be used to encrypt the link. The PMK is generated from the passphrase. Use
createNetworkSpecifierOpen(int, byte[])
to specify an open (unencrypted) link.
Returns: A NetworkSpecifier
to be used to construct Builder.setNetworkSpecifier(NetworkSpecifier)
to pass to ConnectivityManager.requestNetwork(NetworkRequest, NetworkCallback)
[or other varieties of that API].
/**
* Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} for
* an encrypted WiFi Aware connection (link) to the specified peer. The
* {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to
* {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
* <p>
* This API is targeted for applications which can obtain the peer MAC address using OOB
* (out-of-band) discovery. Aware discovery does not provide the MAC address of the peer -
* when using Aware discovery use the alternative network specifier method -
* {@link DiscoverySession#createNetworkSpecifierPassphrase(PeerHandle, String)}.
*
* @param role The role of this device:
* {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_INITIATOR} or
* {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_RESPONDER}
* @param peer The MAC address of the peer's Aware discovery interface. On a RESPONDER this
* value is used to gate the acceptance of a connection request from only that
* peer.
* @param passphrase The passphrase to be used to encrypt the link. The PMK is generated from
* the passphrase. Use {@link #createNetworkSpecifierOpen(int, byte[])} to
* specify an open (unencrypted) link.
*
* @return A {@link NetworkSpecifier} to be used to construct
* {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} to pass to
* {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,
* android.net.ConnectivityManager.NetworkCallback)}
* [or other varieties of that API].
*/
public NetworkSpecifier createNetworkSpecifierPassphrase(
@WifiAwareManager.DataPathRole int role, @NonNull byte[] peer,
@NonNull String passphrase) {
WifiAwareManager mgr = mMgr.get();
if (mgr == null) {
Log.e(TAG, "createNetworkSpecifierPassphrase: called post GC on WifiAwareManager");
return null;
}
if (mTerminated) {
Log.e(TAG, "createNetworkSpecifierPassphrase: called after termination");
return null;
}
if (!WifiAwareUtils.validatePassphrase(passphrase)) {
throw new IllegalArgumentException("Passphrase must meet length requirements");
}
return mgr.createNetworkSpecifier(mClientId, role, peer, null, passphrase);
}
Create a Builder.setNetworkSpecifier(NetworkSpecifier)
for an encrypted WiFi Aware connection (link) to the specified peer. The Builder.addTransportType(int)
should be set to NetworkCapabilities.TRANSPORT_WIFI_AWARE
. This API is targeted for applications which can obtain the peer MAC address using OOB (out-of-band) discovery. Aware discovery does not provide the MAC address of the peer - when using Aware discovery use the alternative network specifier method - DiscoverySession.createNetworkSpecifierPassphrase(PeerHandle, String)
.
Params: - role – The role of this device:
WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
or WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER
- peer – The MAC address of the peer's Aware discovery interface. On a RESPONDER this
value is used to gate the acceptance of a connection request from only that
peer.
- pmk – A PMK (pairwise master key, see IEEE 802.11i) specifying the key to use for encrypting the data-path. Use the
createNetworkSpecifierPassphrase(int, byte[], String)
to specify a Passphrase or createNetworkSpecifierOpen(int, byte[])
to specify an open (unencrypted) link.
Returns: A NetworkSpecifier
to be used to construct Builder.setNetworkSpecifier(NetworkSpecifier)
to pass to ConnectivityManager.requestNetwork(NetworkRequest, NetworkCallback)
[or other varieties of that API]. @hide
/**
* Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} for
* an encrypted WiFi Aware connection (link) to the specified peer. The
* {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to
* {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
* <p>
* This API is targeted for applications which can obtain the peer MAC address using OOB
* (out-of-band) discovery. Aware discovery does not provide the MAC address of the peer -
* when using Aware discovery use the alternative network specifier method -
* {@link DiscoverySession#createNetworkSpecifierPassphrase(PeerHandle, String)}.
*
* @param role The role of this device:
* {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_INITIATOR} or
* {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_RESPONDER}
* @param peer The MAC address of the peer's Aware discovery interface. On a RESPONDER this
* value is used to gate the acceptance of a connection request from only that
* peer.
* @param pmk A PMK (pairwise master key, see IEEE 802.11i) specifying the key to use for
* encrypting the data-path. Use the
* {@link #createNetworkSpecifierPassphrase(int, byte[], String)} to specify a
* Passphrase or {@link #createNetworkSpecifierOpen(int, byte[])} to specify an
* open (unencrypted) link.
*
* @return A {@link NetworkSpecifier} to be used to construct
* {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} to pass to
* {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,
* android.net.ConnectivityManager.NetworkCallback)}
* [or other varieties of that API].
*
* @hide
*/
@SystemApi
public NetworkSpecifier createNetworkSpecifierPmk(
@WifiAwareManager.DataPathRole int role, @NonNull byte[] peer, @NonNull byte[] pmk) {
WifiAwareManager mgr = mMgr.get();
if (mgr == null) {
Log.e(TAG, "createNetworkSpecifierPmk: called post GC on WifiAwareManager");
return null;
}
if (mTerminated) {
Log.e(TAG, "createNetworkSpecifierPmk: called after termination");
return null;
}
if (!WifiAwareUtils.validatePmk(pmk)) {
throw new IllegalArgumentException("PMK must 32 bytes");
}
return mgr.createNetworkSpecifier(mClientId, role, peer, pmk, null);
}
}