Convert Wi-Fi Aware connectivity requests to use a custom
network specifier (as opposed to a string). Aside from
simplifying code, allows for more control of information
printed out, and of additional information to be packaged
and used in network decisions (uid - TBD).
(cherry-pick of commit a5028455a4)
Bug: 36275276
Bug: 36053921
Test: unit tests and integration (sl4a) tests passing.
Merged-In: I776fb348b15ec4830f890a8ac5c41f24594e12a7
Change-Id: I776fb348b15ec4830f890a8ac5c41f24594e12a7
325 lines
15 KiB
Java
325 lines
15 KiB
Java
/*
|
|
* 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 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.
|
|
*/
|
|
public class WifiAwareSession {
|
|
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 */
|
|
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("destroy");
|
|
}
|
|
|
|
/**
|
|
* 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)} .
|
|
*/
|
|
public void destroy() {
|
|
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 */
|
|
@Override
|
|
protected void finalize() throws Throwable {
|
|
try {
|
|
if (!mTerminated) {
|
|
mCloseGuard.warnIfOpen();
|
|
destroy();
|
|
}
|
|
} finally {
|
|
super.finalize();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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#destroy()} 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 {@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#destroy()} 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 {@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. A RESPONDER may specify a {@code null} - indicating that it will accept
|
|
* connection requests from any device.
|
|
*
|
|
* @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, @Nullable 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 {@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. A RESPONDER may specify a {@code null} - indicating that it will accept
|
|
* connection requests from any device.
|
|
* @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, @Nullable 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 (passphrase == null || passphrase.length() == 0) {
|
|
throw new IllegalArgumentException("Passphrase must not be null or empty");
|
|
}
|
|
return mgr.createNetworkSpecifier(mClientId, role, peer, null, passphrase);
|
|
}
|
|
|
|
/**
|
|
* 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. A RESPONDER may specify a null - indicating that it will accept
|
|
* connection requests from any device.
|
|
* @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, @Nullable 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 (pmk == null || pmk.length == 0) {
|
|
throw new IllegalArgumentException("PMK must not be null or empty");
|
|
}
|
|
return mgr.createNetworkSpecifier(mClientId, role, peer, pmk, null);
|
|
}
|
|
}
|