Merge "[NAN] Refactor WifiNanManager to create separate sessions per connect."

This commit is contained in:
Etan Cohen
2016-09-21 20:14:13 +00:00
committed by Gerrit Code Review
9 changed files with 326 additions and 311 deletions

View File

@@ -23,7 +23,7 @@ package android.net.wifi.nan;
*/ */
oneway interface IWifiNanDiscoverySessionCallback oneway interface IWifiNanDiscoverySessionCallback
{ {
void onSessionStarted(int sessionId); void onSessionStarted(int discoverySessionId);
void onSessionConfigSuccess(); void onSessionConfigSuccess();
void onSessionConfigFail(int reason); void onSessionConfigFail(int reason);
void onSessionTerminated(int reason); void onSessionTerminated(int reason);

View File

@@ -26,7 +26,7 @@ import android.net.wifi.RttManager;
*/ */
oneway interface IWifiNanEventCallback oneway interface IWifiNanEventCallback
{ {
void onConnectSuccess(); void onConnectSuccess(int clientId);
void onConnectFail(int reason); void onConnectFail(int reason);
void onIdentityChanged(in byte[] mac); void onIdentityChanged(in byte[] mac);

View File

@@ -38,7 +38,7 @@ interface IWifiNanManager
boolean isUsageEnabled(); boolean isUsageEnabled();
// client API // client API
int connect(in IBinder binder, in String callingPackage, in IWifiNanEventCallback callback, void connect(in IBinder binder, in String callingPackage, in IWifiNanEventCallback callback,
in ConfigRequest configRequest); in ConfigRequest configRequest);
void disconnect(int clientId, in IBinder binder); void disconnect(int clientId, in IBinder binder);
@@ -48,10 +48,10 @@ interface IWifiNanManager
in IWifiNanDiscoverySessionCallback callback); in IWifiNanDiscoverySessionCallback callback);
// session API // session API
void updatePublish(int clientId, int sessionId, in PublishConfig publishConfig); void updatePublish(int clientId, int discoverySessionId, in PublishConfig publishConfig);
void updateSubscribe(int clientId, int sessionId, in SubscribeConfig subscribeConfig); void updateSubscribe(int clientId, int discoverySessionId, in SubscribeConfig subscribeConfig);
void sendMessage(int clientId, int sessionId, int peerId, in byte[] message, int messageId, void sendMessage(int clientId, int discoverySessionId, int peerId, in byte[] message, int messageId,
int retryCount); int retryCount);
void terminateSession(int clientId, int sessionId); void terminateSession(int clientId, int discoverySessionId);
int startRanging(int clientId, int sessionId, in RttManager.ParcelableRttParams parms); int startRanging(int clientId, int discoverySessionId, in RttManager.ParcelableRttParams parms);
} }

View File

@@ -50,6 +50,8 @@ public class WifiNanDiscoveryBaseSession {
/** @hide */ /** @hide */
protected WeakReference<WifiNanManager> mMgr; protected WeakReference<WifiNanManager> mMgr;
/** @hide */ /** @hide */
protected final int mClientId;
/** @hide */
protected final int mSessionId; protected final int mSessionId;
/** @hide */ /** @hide */
protected boolean mTerminated = false; protected boolean mTerminated = false;
@@ -67,10 +69,14 @@ public class WifiNanDiscoveryBaseSession {
} }
/** @hide */ /** @hide */
public WifiNanDiscoveryBaseSession(WifiNanManager manager, int sessionId) { public WifiNanDiscoveryBaseSession(WifiNanManager manager, int clientId, int sessionId) {
if (VDBG) Log.v(TAG, "New client created: manager=" + manager + ", sessionId=" + sessionId); if (VDBG) {
Log.v(TAG, "New discovery session created: manager=" + manager + ", clientId="
+ clientId + ", sessionId=" + sessionId);
}
mMgr = new WeakReference<>(manager); mMgr = new WeakReference<>(manager);
mClientId = clientId;
mSessionId = sessionId; mSessionId = sessionId;
mCloseGuard.open("terminate"); mCloseGuard.open("terminate");
@@ -93,7 +99,7 @@ public class WifiNanDiscoveryBaseSession {
Log.w(TAG, "terminate: called post GC on WifiNanManager"); Log.w(TAG, "terminate: called post GC on WifiNanManager");
return; return;
} }
mgr.terminateSession(mSessionId); mgr.terminateSession(mClientId, mSessionId);
mTerminated = true; mTerminated = true;
mMgr.clear(); mMgr.clear();
mCloseGuard.close(); mCloseGuard.close();
@@ -166,7 +172,7 @@ public class WifiNanDiscoveryBaseSession {
return; return;
} }
mgr.sendMessage(mSessionId, peerId, message, messageId, retryCount); mgr.sendMessage(mClientId, mSessionId, peerId, message, messageId, retryCount);
} }
} }
@@ -223,7 +229,7 @@ public class WifiNanDiscoveryBaseSession {
return; return;
} }
mgr.startRanging(mSessionId, params, listener); mgr.startRanging(mClientId, mSessionId, params, listener);
} }
} }
@@ -237,7 +243,7 @@ public class WifiNanDiscoveryBaseSession {
* discovery or communication (in such scenarios the MAC address of the peer is shielded by * discovery or communication (in such scenarios the MAC address of the peer is shielded by
* an opaque peer ID handle). If a NAN connection is needed to a peer discovered using other * an opaque peer ID handle). If a NAN connection is needed to a peer discovered using other
* OOB (out-of-band) mechanism then use the alternative * OOB (out-of-band) mechanism then use the alternative
* {@link WifiNanManager#createNetworkSpecifier(int, byte[], byte[])} method - which uses the * {@link WifiNanSession#createNetworkSpecifier(int, byte[], byte[])} method - which uses the
* peer's MAC address. * peer's MAC address.
* *
* @param role The role of this device: * @param role The role of this device:
@@ -272,7 +278,7 @@ public class WifiNanDiscoveryBaseSession {
return null; return null;
} }
return mgr.createNetworkSpecifier(role, mSessionId, peerId, token); return mgr.createNetworkSpecifier(mClientId, role, mSessionId, peerId, token);
} }
} }
} }

View File

@@ -62,8 +62,11 @@ public class WifiNanEventCallback {
* Called when NAN connect operation * Called when NAN connect operation
* {@link WifiNanManager#connect(android.os.Handler, WifiNanEventCallback)} * {@link WifiNanManager#connect(android.os.Handler, WifiNanEventCallback)}
* is completed and that we can now start discovery sessions or connections. * is completed and that we can now start discovery sessions or connections.
*
* @param session The NAN connection on which we can execute further NAN operations - e.g.
* discovery, connections.
*/ */
public void onConnectSuccess() { public void onConnectSuccess(WifiNanSession session) {
/* empty */ /* empty */
} }

View File

@@ -28,7 +28,6 @@ import android.net.wifi.RttManager;
import android.os.Binder; import android.os.Binder;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.IBinder;
import android.os.Looper; import android.os.Looper;
import android.os.Message; import android.os.Message;
import android.os.RemoteException; import android.os.RemoteException;
@@ -38,8 +37,6 @@ import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy;
import dalvik.system.CloseGuard;
import libcore.util.HexEncoding; import libcore.util.HexEncoding;
import org.json.JSONException; import org.json.JSONException;
@@ -59,15 +56,15 @@ import java.util.Arrays;
* The class provides access to: * The class provides access to:
* <ul> * <ul>
* <li>Initialize a NAN cluster (peer-to-peer synchronization). Refer to * <li>Initialize a NAN cluster (peer-to-peer synchronization). Refer to
* {@link #connect(Handler, WifiNanEventCallback)}. * {@link #connect(Handler, WifiNanEventCallback)}. <li>Create discovery sessions (publish or
* <li>Create discovery sessions (publish or subscribe sessions). * subscribe sessions). Refer to
* Refer to {@link #publish(PublishConfig, WifiNanDiscoverySessionCallback)} and * {@link WifiNanSession#publish(PublishConfig, WifiNanDiscoverySessionCallback)} and
* {@link #subscribe(SubscribeConfig, WifiNanDiscoverySessionCallback)}. * {@link WifiNanSession#subscribe(SubscribeConfig, WifiNanDiscoverySessionCallback)}. <li>Create
* <li>Create a NAN network specifier to be used with * a NAN network specifier to be used with
* {@link ConnectivityManager#requestNetwork(NetworkRequest, ConnectivityManager.NetworkCallback)} * {@link ConnectivityManager#requestNetwork(NetworkRequest, ConnectivityManager.NetworkCallback)}
* to set-up a NAN connection with a peer. Refer to * to set-up a NAN connection with a peer. Refer to
* {@link WifiNanDiscoveryBaseSession#createNetworkSpecifier(int, int, byte[])} and * {@link WifiNanDiscoveryBaseSession#createNetworkSpecifier(int, int, byte[])} and
* {@link #createNetworkSpecifier(int, byte[], byte[])}. * {@link WifiNanSession#createNetworkSpecifier(int, byte[], byte[])}.
* </ul> * </ul>
* <p> * <p>
* NAN may not be usable when Wi-Fi is disabled (and other conditions). To validate that * NAN may not be usable when Wi-Fi is disabled (and other conditions). To validate that
@@ -82,16 +79,16 @@ import java.util.Arrays;
* starts one if none can be found). Information about connection success (or failure) are * starts one if none can be found). Information about connection success (or failure) are
* returned in callbacks of {@link WifiNanEventCallback}. Proceed with NAN discovery or * returned in callbacks of {@link WifiNanEventCallback}. Proceed with NAN discovery or
* connection setup only after receiving confirmation that NAN connection succeeded - * connection setup only after receiving confirmation that NAN connection succeeded -
* {@link WifiNanEventCallback#onConnectSuccess()}. * {@link WifiNanEventCallback#onConnectSuccess(WifiNanSession)}. When an application is
* When an application is finished using NAN it <b>must</b> use the {@link #disconnect()} API * finished using NAN it <b>must</b> use the {@link WifiNanSession#disconnect()} API
* to indicate to the NAN service that the device may disconnect from the NAN cluster. The * to indicate to the NAN service that the device may disconnect from the NAN cluster. The
* device will actually disconnect from the NAN cluster once the last application disconnects. * device will actually disconnect from the NAN cluster once the last application disconnects.
* <p> * <p>
* Once a NAN connection is confirmed use the * Once a NAN connection is confirmed use the
* {@link #publish(PublishConfig, WifiNanDiscoverySessionCallback)} or * {@link WifiNanSession#publish(PublishConfig, WifiNanDiscoverySessionCallback)} or
* {@link #subscribe(SubscribeConfig, WifiNanDiscoverySessionCallback)} to create publish or * {@link WifiNanSession#subscribe(SubscribeConfig, WifiNanDiscoverySessionCallback)} to
* subscribe NAN discovery sessions. Events are called on the provided callback object * create publish or subscribe NAN discovery sessions. Events are called on the provided
* {@link WifiNanDiscoverySessionCallback}. Specifically, the * callback object {@link WifiNanDiscoverySessionCallback}. Specifically, the
* {@link WifiNanDiscoverySessionCallback#onPublishStarted(WifiNanPublishDiscoverySession)} * {@link WifiNanDiscoverySessionCallback#onPublishStarted(WifiNanPublishDiscoverySession)}
* and * and
* {@link WifiNanDiscoverySessionCallback#onSubscribeStarted(WifiNanSubscribeDiscoverySession)} * {@link WifiNanDiscoverySessionCallback#onSubscribeStarted(WifiNanSubscribeDiscoverySession)}
@@ -111,7 +108,7 @@ import java.util.Arrays;
* <li>{@link NetworkRequest.Builder#addTransportType(int)} of * <li>{@link NetworkRequest.Builder#addTransportType(int)} of
* {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_NAN}. * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_NAN}.
* <li>{@link NetworkRequest.Builder#setNetworkSpecifier(String)} using * <li>{@link NetworkRequest.Builder#setNetworkSpecifier(String)} using
* {@link #createNetworkSpecifier(int, byte[], byte[])} or * {@link WifiNanSession#createNetworkSpecifier(int, byte[], byte[])} or
* {@link WifiNanDiscoveryBaseSession#createNetworkSpecifier(int, int, byte[])}. * {@link WifiNanDiscoveryBaseSession#createNetworkSpecifier(int, int, byte[])}.
* </ul> * </ul>
* *
@@ -122,8 +119,6 @@ public class WifiNanManager {
private static final boolean DBG = false; private static final boolean DBG = false;
private static final boolean VDBG = false; // STOPSHIP if true private static final boolean VDBG = false; // STOPSHIP if true
private static final int INVALID_CLIENT_ID = 0;
/** /**
* Keys used to generate a Network Specifier for the NAN network request. The network specifier * Keys used to generate a Network Specifier for the NAN network request. The network specifier
* is formatted as a JSON string. * is formatted as a JSON string.
@@ -251,7 +246,7 @@ public class WifiNanManager {
* when requesting a NAN network. * when requesting a NAN network.
* *
* @see WifiNanDiscoveryBaseSession#createNetworkSpecifier(int, int, byte[]) * @see WifiNanDiscoveryBaseSession#createNetworkSpecifier(int, int, byte[])
* @see #createNetworkSpecifier(int, byte[], byte[]) * @see WifiNanSession#createNetworkSpecifier(int, byte[], byte[])
*/ */
public static final int WIFI_NAN_DATA_PATH_ROLE_INITIATOR = 0; public static final int WIFI_NAN_DATA_PATH_ROLE_INITIATOR = 0;
@@ -260,25 +255,15 @@ public class WifiNanManager {
* when requesting a NAN network. * when requesting a NAN network.
* *
* @see WifiNanDiscoveryBaseSession#createNetworkSpecifier(int, int, byte[]) * @see WifiNanDiscoveryBaseSession#createNetworkSpecifier(int, int, byte[])
* @see #createNetworkSpecifier(int, byte[], byte[]) * @see WifiNanSession#createNetworkSpecifier(int, byte[], byte[])
*/ */
public static final int WIFI_NAN_DATA_PATH_ROLE_RESPONDER = 1; public static final int WIFI_NAN_DATA_PATH_ROLE_RESPONDER = 1;
private final Context mContext; private final Context mContext;
private final IWifiNanManager mService; private final IWifiNanManager mService;
private final CloseGuard mCloseGuard = CloseGuard.get();
private final Object mLock = new Object(); // lock access to the following vars private final Object mLock = new Object(); // lock access to the following vars
@GuardedBy("mLock")
private final IBinder mBinder = new Binder();
@GuardedBy("mLock")
private int mClientId = INVALID_CLIENT_ID;
@GuardedBy("mLock")
private Looper mLooper;
@GuardedBy("mLock") @GuardedBy("mLock")
private SparseArray<RttManager.RttListener> mRangingListeners = new SparseArray<>(); private SparseArray<RttManager.RttListener> mRangingListeners = new SparseArray<>();
@@ -338,8 +323,8 @@ public class WifiNanManager {
* create connection to peers. The device will connect to an existing cluster if it can find * create connection to peers. The device will connect to an existing cluster if it can find
* one or create a new cluster (if it is the first to enable NAN in its vicinity). Results * one or create a new cluster (if it is the first to enable NAN in its vicinity). Results
* (e.g. successful connection to a cluster) are provided to the {@code callback} object. * (e.g. successful connection to a cluster) are provided to the {@code callback} object.
* An application <b>must</b> call {@link #disconnect()} when done with the Wi-Fi NAN * An application <b>must</b> call {@link WifiNanSession#disconnect()} when done with the
* connection. * Wi-Fi NAN connection.
* <p> * <p>
* Note: a NAN cluster is a shared resource - if the device is already connected to a cluster * Note: a NAN cluster is a shared resource - if the device is already connected to a cluster
* than this function will simply indicate success immediately. * than this function will simply indicate success immediately.
@@ -358,10 +343,10 @@ public class WifiNanManager {
* create connection to peers. The device will connect to an existing cluster if it can find * create connection to peers. The device will connect to an existing cluster if it can find
* one or create a new cluster (if it is the first to enable NAN in its vicinity). Results * one or create a new cluster (if it is the first to enable NAN in its vicinity). Results
* (e.g. successful connection to a cluster) are provided to the {@code callback} object. * (e.g. successful connection to a cluster) are provided to the {@code callback} object.
* An application <b>must</b> call {@link #disconnect()} when done with the Wi-Fi NAN * An application <b>must</b> call {@link WifiNanSession#disconnect()} when done with the
* connection. Allows requesting a specific configuration using {@link ConfigRequest}. If not * Wi-Fi NAN connection. Allows requesting a specific configuration using
* necessary (default configuration should usually work) use the * {@link ConfigRequest}. If not necessary (default configuration should usually work) use
* {@link #connect(Handler, WifiNanEventCallback)} method instead. * the {@link #connect(Handler, WifiNanEventCallback)} method instead.
* <p> * <p>
* Note: a NAN cluster is a shared resource - if the device is already connected to a cluster * Note: a NAN cluster is a shared resource - if the device is already connected to a cluster
* than this function will simply indicate success immediately. * than this function will simply indicate success immediately.
@@ -381,50 +366,23 @@ public class WifiNanManager {
} }
synchronized (mLock) { synchronized (mLock) {
mLooper = (handler == null) ? Looper.getMainLooper() : handler.getLooper(); Looper looper = (handler == null) ? Looper.getMainLooper() : handler.getLooper();
try { try {
mClientId = mService.connect(mBinder, mContext.getOpPackageName(), Binder binder = new Binder();
new WifiNanEventCallbackProxy(this, mLooper, callback), configRequest); mService.connect(binder, mContext.getOpPackageName(),
new WifiNanEventCallbackProxy(this, looper, binder, callback),
configRequest);
} catch (RemoteException e) { } catch (RemoteException e) {
mClientId = INVALID_CLIENT_ID;
mLooper = null;
throw e.rethrowFromSystemServer(); throw e.rethrowFromSystemServer();
} }
} }
mCloseGuard.open("disconnect");
} }
/** /** @hide */
* Disconnect from the Wi-Fi NAN service and, if no other applications are connected to NAN, public void disconnect(int clientId, Binder binder) {
* also disconnect from the NAN cluster. 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 terminate these discovery sessions and
* connections explicitly before a disconnect.
* <p>
* An application may re-connect after a disconnect using
* {@link WifiNanManager#connect(Handler, WifiNanEventCallback)} .
*/
public void disconnect() {
if (VDBG) Log.v(TAG, "disconnect()"); if (VDBG) Log.v(TAG, "disconnect()");
IBinder binder;
int clientId;
synchronized (mLock) {
if (mClientId == INVALID_CLIENT_ID) {
Log.w(TAG, "disconnect(): called with invalid client ID - not connected first?");
return;
}
binder = mBinder;
clientId = mClientId;
mLooper = null;
mClientId = INVALID_CLIENT_ID;
}
mCloseGuard.close();
try { try {
mService.disconnect(clientId, binder); mService.disconnect(clientId, binder);
} catch (RemoteException e) { } catch (RemoteException e) {
@@ -433,78 +391,26 @@ public class WifiNanManager {
} }
/** @hide */ /** @hide */
@Override public void publish(int clientId, Looper looper, PublishConfig publishConfig,
protected void finalize() throws Throwable { WifiNanDiscoverySessionCallback callback) {
try { if (VDBG) Log.v(TAG, "publish(): clientId=" + clientId + ", config=" + publishConfig);
mCloseGuard.warnIfOpen();
disconnect();
} finally {
super.finalize();
}
}
/**
* Issue a request to the NAN service to create a new NAN publish discovery session, using
* the specified {@code publishConfig} configuration. The results of the publish operation
* are routed to the callbacks of {@link WifiNanDiscoverySessionCallback}:
* <ul>
* <li>{@link WifiNanDiscoverySessionCallback#onPublishStarted(WifiNanPublishDiscoverySession)}
* 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 WifiNanDiscoverySessionCallback#onSessionConfigFail(int)} 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 WifiNanPublishDiscoverySession#updatePublish(PublishConfig)}.
* <p>
* An application must use the {@link WifiNanDiscoveryBaseSession#terminate()} to
* terminate the publish discovery session once it isn't needed. This will free
* resources as well terminate any on-air transmissions.
*
* @param publishConfig The {@link PublishConfig} specifying the
* configuration of the requested publish session.
* @param callback A {@link WifiNanDiscoverySessionCallback} derived object to be used for
* session event callbacks.
*/
public void publish(@NonNull PublishConfig publishConfig,
@NonNull WifiNanDiscoverySessionCallback callback) {
if (VDBG) Log.v(TAG, "publish(): config=" + publishConfig);
int clientId;
Looper looper;
synchronized (mLock) {
if (mLooper == null || mClientId == INVALID_CLIENT_ID) {
Log.e(TAG, "publish(): called with null looper or invalid client ID - "
+ "not connected first?");
return;
}
clientId = mClientId;
looper = mLooper;
}
try { try {
mService.publish(clientId, publishConfig, mService.publish(clientId, publishConfig,
new WifiNanDiscoverySessionCallbackProxy(this, looper, true, callback)); new WifiNanDiscoverySessionCallbackProxy(this, looper, true, callback,
clientId));
} catch (RemoteException e) { } catch (RemoteException e) {
throw e.rethrowFromSystemServer(); throw e.rethrowFromSystemServer();
} }
} }
/** @hide */ /** @hide */
public void updatePublish(int sessionId, PublishConfig publishConfig) { public void updatePublish(int clientId, int sessionId, PublishConfig publishConfig) {
if (VDBG) Log.v(TAG, "updatePublish(): config=" + publishConfig); if (VDBG) {
Log.v(TAG, "updatePublish(): clientId=" + clientId + ",sessionId=" + sessionId
int clientId; + ", config=" + publishConfig);
synchronized (mLock) {
if (mClientId == INVALID_CLIENT_ID) {
Log.e(TAG, "updatePublish(): called with invalid client ID - not connected first?");
return;
}
clientId = mClientId;
} }
try { try {
mService.updatePublish(clientId, sessionId, publishConfig); mService.updatePublish(clientId, sessionId, publishConfig);
} catch (RemoteException e) { } catch (RemoteException e) {
@@ -512,73 +418,30 @@ public class WifiNanManager {
} }
} }
/** /** @hide */
* Issue a request to the NAN service to create a new NAN subscribe discovery session, using public void subscribe(int clientId, Looper looper, SubscribeConfig subscribeConfig,
* the specified {@code subscribeConfig} configuration. The results of the subscribe WifiNanDiscoverySessionCallback callback) {
* operation are routed to the callbacks of {@link WifiNanDiscoverySessionCallback}:
* <ul>
* <li>{@link WifiNanDiscoverySessionCallback#onSubscribeStarted(WifiNanSubscribeDiscoverySession)}
* 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 WifiNanDiscoverySessionCallback#onSessionConfigFail(int)} 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 WifiNanSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
* <p>
* An application must use the {@link WifiNanDiscoveryBaseSession#terminate()} to
* terminate the subscribe discovery session once it isn't needed. This will free
* resources as well terminate any on-air transmissions.
*
* @param subscribeConfig The {@link SubscribeConfig} specifying the
* configuration of the requested subscribe session.
* @param callback A {@link WifiNanDiscoverySessionCallback} derived object to be used for
* session event callbacks.
*/
public void subscribe(@NonNull SubscribeConfig subscribeConfig,
@NonNull WifiNanDiscoverySessionCallback callback) {
if (VDBG) { if (VDBG) {
Log.v(TAG, "subscribe(): config=" + subscribeConfig); if (VDBG) {
} Log.v(TAG,
"subscribe(): clientId=" + clientId + ", config=" + subscribeConfig);
int clientId;
Looper looper;
synchronized (mLock) {
if (mLooper == null || mClientId == INVALID_CLIENT_ID) {
Log.e(TAG, "subscribe(): called with null looper or invalid client ID - "
+ "not connected first?");
return;
} }
clientId = mClientId;
looper = mLooper;
} }
try { try {
mService.subscribe(clientId, subscribeConfig, mService.subscribe(clientId, subscribeConfig,
new WifiNanDiscoverySessionCallbackProxy(this, looper, false, callback)); new WifiNanDiscoverySessionCallbackProxy(this, looper, false, callback,
clientId));
} catch (RemoteException e) { } catch (RemoteException e) {
throw e.rethrowFromSystemServer(); throw e.rethrowFromSystemServer();
} }
} }
/** @hide */ /** @hide */
public void updateSubscribe(int sessionId, SubscribeConfig subscribeConfig) { public void updateSubscribe(int clientId, int sessionId, SubscribeConfig subscribeConfig) {
if (VDBG) { if (VDBG) {
Log.v(TAG, "subscribe(): config=" + subscribeConfig); Log.v(TAG, "updateSubscribe(): clientId=" + clientId + ",sessionId=" + sessionId
} + ", config=" + subscribeConfig);
int clientId;
synchronized (mLock) {
if (mClientId == INVALID_CLIENT_ID) {
Log.e(TAG,
"updateSubscribe(): called with invalid client ID - not connected first?");
return;
}
clientId = mClientId;
} }
try { try {
@@ -589,18 +452,10 @@ public class WifiNanManager {
} }
/** @hide */ /** @hide */
public void terminateSession(int sessionId) { public void terminateSession(int clientId, int sessionId) {
if (DBG) Log.d(TAG, "Terminate NAN session #" + sessionId); if (VDBG) {
Log.d(TAG,
int clientId; "terminateSession(): clientId=" + clientId + ", sessionId=" + sessionId);
synchronized (mLock) {
if (mClientId == INVALID_CLIENT_ID) {
Log.e(TAG,
"terminateSession(): called with invalid client ID - not connected first?");
return;
}
clientId = mClientId;
} }
try { try {
@@ -611,21 +466,12 @@ public class WifiNanManager {
} }
/** @hide */ /** @hide */
public void sendMessage(int sessionId, int peerId, byte[] message, int messageId, public void sendMessage(int clientId, int sessionId, int peerId, byte[] message, int messageId,
int retryCount) { int retryCount) {
if (VDBG) { if (VDBG) {
Log.v(TAG, "sendMessage(): sessionId=" + sessionId + ", peerId=" + peerId Log.v(TAG,
+ ", messageId=" + messageId + ", retryCount=" + retryCount); "sendMessage(): clientId=" + clientId + ", sessionId=" + sessionId + ", peerId="
} + peerId + ", messageId=" + messageId + ", retryCount=" + retryCount);
int clientId;
synchronized (mLock) {
if (mClientId == INVALID_CLIENT_ID) {
Log.e(TAG, "sendMessage(): called with invalid client ID - not connected first?");
return;
}
clientId = mClientId;
} }
try { try {
@@ -636,21 +482,11 @@ public class WifiNanManager {
} }
/** @hide */ /** @hide */
public void startRanging(int sessionId, RttManager.RttParams[] params, public void startRanging(int clientId, int sessionId, RttManager.RttParams[] params,
RttManager.RttListener listener) { RttManager.RttListener listener) {
if (VDBG) { if (VDBG) {
Log.v(TAG, "startRanging: sessionId=" + sessionId + ", " + "params=" Log.v(TAG, "startRanging: clientId=" + clientId + ", sessionId=" + sessionId + ", "
+ Arrays.toString(params) + ", listener=" + listener); + "params=" + Arrays.toString(params) + ", listener=" + listener);
}
int clientId;
synchronized (mLock) {
if (mClientId == INVALID_CLIENT_ID) {
Log.e(TAG, "startRanging(): called with invalid client ID - not connected first?");
return;
}
clientId = mClientId;
} }
int rangingKey = 0; int rangingKey = 0;
@@ -667,7 +503,7 @@ public class WifiNanManager {
} }
/** @hide */ /** @hide */
public String createNetworkSpecifier(@DataPathRole int role, int sessionId, int peerId, public String createNetworkSpecifier(int clientId, int role, int sessionId, int peerId,
byte[] token) { byte[] token) {
if (VDBG) { if (VDBG) {
Log.v(TAG, "createNetworkSpecifier: role=" + role + ", sessionId=" + sessionId Log.v(TAG, "createNetworkSpecifier: role=" + role + ", sessionId=" + sessionId
@@ -703,18 +539,6 @@ public class WifiNanManager {
} }
} }
int clientId;
synchronized (mLock) {
if (mClientId == INVALID_CLIENT_ID) {
Log.e(TAG,
"createNetworkSpecifier: called with invalid client ID - not connected "
+ "first?");
return null;
}
clientId = mClientId;
}
JSONObject json; JSONObject json;
try { try {
json = new JSONObject(); json = new JSONObject();
@@ -736,36 +560,8 @@ public class WifiNanManager {
return json.toString(); return json.toString();
} }
/** /** @hide */
* Create a {@link NetworkRequest.Builder#setNetworkSpecifier(String)} for a public String createNetworkSpecifier(int clientId, @DataPathRole int role, @Nullable byte[] peer,
* WiFi NAN connection to the specified peer. The
* {@link NetworkRequest.Builder#addTransportType(int)} should be set to
* {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_NAN}.
* <p>
* This API is targeted for applications which can obtain the peer MAC address using OOB
* (out-of-band) discovery. NAN discovery does not provide the MAC address of the peer -
* when using NAN discovery use the alternative network specifier method -
* {@link WifiNanDiscoveryBaseSession#createNetworkSpecifier(int, int, byte[])}.
*
* @param role The role of this device:
* {@link WifiNanManager#WIFI_NAN_DATA_PATH_ROLE_INITIATOR} or
* {@link WifiNanManager#WIFI_NAN_DATA_PATH_ROLE_RESPONDER}
* @param peer The MAC address of the peer's NAN discovery interface. On a RESPONDER this
* value is used to gate the acceptance of a connection request from only that
* peer. A RESPONDER may specified a null - indicating that it will accept
* connection requests from any device.
* @param token An arbitrary token (message) to be used to match connection initiation request
* to a responder setup. A RESPONDER is set up with a {@code token} which must
* be matched by the token provided by the INITIATOR. A null token is permitted
* on the RESPONDER and matches any peer token. An empty ({@code ""}) token is
* not the same as a null token and requires the peer token to be empty as well.
*
* @return A string to be used to construct
* {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to
* {@link android.net.ConnectivityManager#requestNetwork(NetworkRequest, ConnectivityManager.NetworkCallback)}
* [or other varieties of that API].
*/
public String createNetworkSpecifier(@DataPathRole int role, @Nullable byte[] peer,
@Nullable byte[] token) { @Nullable byte[] token) {
if (VDBG) { if (VDBG) {
Log.v(TAG, "createNetworkSpecifier: role=" + role + ", token=" + token); Log.v(TAG, "createNetworkSpecifier: role=" + role + ", token=" + token);
@@ -804,18 +600,6 @@ public class WifiNanManager {
} }
} }
int clientId;
synchronized (mLock) {
if (mClientId == INVALID_CLIENT_ID) {
Log.e(TAG,
"createNetworkSpecifier: called with invalid client ID - not connected "
+ "first?");
return null;
}
clientId = mClientId;
}
JSONObject json; JSONObject json;
try { try {
json = new JSONObject(); json = new JSONObject();
@@ -846,6 +630,8 @@ public class WifiNanManager {
private final Handler mHandler; private final Handler mHandler;
private final WeakReference<WifiNanManager> mNanManager; private final WeakReference<WifiNanManager> mNanManager;
private final Binder mBinder;
private final Looper mLooper;
RttManager.RttListener getAndRemoveRangingListener(int rangingId) { RttManager.RttListener getAndRemoveRangingListener(int rangingId) {
WifiNanManager mgr = mNanManager.get(); WifiNanManager mgr = mNanManager.get();
@@ -867,9 +653,11 @@ public class WifiNanManager {
* *
* @param looper The looper on which to execute the callbacks. * @param looper The looper on which to execute the callbacks.
*/ */
WifiNanEventCallbackProxy(WifiNanManager mgr, Looper looper, WifiNanEventCallbackProxy(WifiNanManager mgr, Looper looper, Binder binder,
final WifiNanEventCallback originalCallback) { final WifiNanEventCallback originalCallback) {
mNanManager = new WeakReference<>(mgr); mNanManager = new WeakReference<>(mgr);
mLooper = looper;
mBinder = binder;
if (VDBG) Log.v(TAG, "WifiNanEventCallbackProxy ctor: looper=" + looper); if (VDBG) Log.v(TAG, "WifiNanEventCallbackProxy ctor: looper=" + looper);
mHandler = new Handler(looper) { mHandler = new Handler(looper) {
@@ -887,13 +675,10 @@ public class WifiNanManager {
switch (msg.what) { switch (msg.what) {
case CALLBACK_CONNECT_SUCCESS: case CALLBACK_CONNECT_SUCCESS:
originalCallback.onConnectSuccess(); originalCallback.onConnectSuccess(
new WifiNanSession(mgr, mBinder, mLooper, msg.arg1));
break; break;
case CALLBACK_CONNECT_FAIL: case CALLBACK_CONNECT_FAIL:
synchronized (mgr.mLock) {
mgr.mLooper = null;
mgr.mClientId = INVALID_CLIENT_ID;
}
mNanManager.clear(); mNanManager.clear();
originalCallback.onConnectFail(msg.arg1); originalCallback.onConnectFail(msg.arg1);
break; break;
@@ -937,10 +722,11 @@ public class WifiNanManager {
} }
@Override @Override
public void onConnectSuccess() { public void onConnectSuccess(int clientId) {
if (VDBG) Log.v(TAG, "onConnectSuccess"); if (VDBG) Log.v(TAG, "onConnectSuccess");
Message msg = mHandler.obtainMessage(CALLBACK_CONNECT_SUCCESS); Message msg = mHandler.obtainMessage(CALLBACK_CONNECT_SUCCESS);
msg.arg1 = clientId;
mHandler.sendMessage(msg); mHandler.sendMessage(msg);
} }
@@ -1017,15 +803,17 @@ public class WifiNanManager {
private final WeakReference<WifiNanManager> mNanManager; private final WeakReference<WifiNanManager> mNanManager;
private final boolean mIsPublish; private final boolean mIsPublish;
private final WifiNanDiscoverySessionCallback mOriginalCallback; private final WifiNanDiscoverySessionCallback mOriginalCallback;
private final int mClientId;
private final Handler mHandler; private final Handler mHandler;
private WifiNanDiscoveryBaseSession mSession; private WifiNanDiscoveryBaseSession mSession;
WifiNanDiscoverySessionCallbackProxy(WifiNanManager mgr, Looper looper, boolean isPublish, WifiNanDiscoverySessionCallbackProxy(WifiNanManager mgr, Looper looper, boolean isPublish,
WifiNanDiscoverySessionCallback originalCallback) { WifiNanDiscoverySessionCallback originalCallback, int clientId) {
mNanManager = new WeakReference<>(mgr); mNanManager = new WeakReference<>(mgr);
mIsPublish = isPublish; mIsPublish = isPublish;
mOriginalCallback = originalCallback; mOriginalCallback = originalCallback;
mClientId = clientId;
if (VDBG) { if (VDBG) {
Log.v(TAG, "WifiNanDiscoverySessionCallbackProxy ctor: isPublish=" + isPublish); Log.v(TAG, "WifiNanDiscoverySessionCallbackProxy ctor: isPublish=" + isPublish);
@@ -1181,12 +969,12 @@ public class WifiNanManager {
if (mIsPublish) { if (mIsPublish) {
WifiNanPublishDiscoverySession session = new WifiNanPublishDiscoverySession(mgr, WifiNanPublishDiscoverySession session = new WifiNanPublishDiscoverySession(mgr,
sessionId); mClientId, sessionId);
mSession = session; mSession = session;
mOriginalCallback.onPublishStarted(session); mOriginalCallback.onPublishStarted(session);
} else { } else {
WifiNanSubscribeDiscoverySession WifiNanSubscribeDiscoverySession
session = new WifiNanSubscribeDiscoverySession(mgr, sessionId); session = new WifiNanSubscribeDiscoverySession(mgr, mClientId, sessionId);
mSession = session; mSession = session;
mOriginalCallback.onSubscribeStarted(session); mOriginalCallback.onSubscribeStarted(session);
} }

View File

@@ -34,8 +34,8 @@ public class WifiNanPublishDiscoverySession extends WifiNanDiscoveryBaseSession
private static final String TAG = "WifiNanPublishDiscSsn"; private static final String TAG = "WifiNanPublishDiscSsn";
/** @hide */ /** @hide */
public WifiNanPublishDiscoverySession(WifiNanManager manager, int sessionId) { public WifiNanPublishDiscoverySession(WifiNanManager manager, int clientId, int sessionId) {
super(manager, sessionId); super(manager, clientId, sessionId);
} }
/** /**
@@ -64,7 +64,7 @@ public class WifiNanPublishDiscoverySession extends WifiNanDiscoveryBaseSession
return; return;
} }
mgr.updatePublish(mSessionId, publishConfig); mgr.updatePublish(mClientId, mSessionId, publishConfig);
} }
} }
} }

View File

@@ -0,0 +1,218 @@
/*
* 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.nan;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.net.NetworkRequest;
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 NAN session - an attachment to the Wi-Fi NAN service through
* which the app can execute discovery operations.
*
* @hide PROPOSED_NAN_API
*/
public class WifiNanSession {
private static final String TAG = "WifiNanSession";
private static final boolean DBG = false;
private static final boolean VDBG = false; // STOPSHIP if true
private final WeakReference<WifiNanManager> mMgr;
private final Binder mBinder;
private final Looper mLooper;
private final int mClientId;
private boolean mTerminated = true;
private final CloseGuard mCloseGuard = CloseGuard.get();
/** @hide */
public WifiNanSession(WifiNanManager manager, Binder binder, Looper looper, int clientId) {
if (VDBG) Log.v(TAG, "New session created: manager=" + manager + ", clientId=" + clientId);
mMgr = new WeakReference<>(manager);
mBinder = binder;
mLooper = looper;
mClientId = clientId;
mTerminated = false;
mCloseGuard.open("disconnect");
}
/**
* Disconnect from the Wi-Fi NAN service and, if no other applications are connected to NAN,
* also disconnect from the NAN cluster. 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 terminate these discovery sessions and
* connections explicitly before a disconnect.
* <p>
* An application may re-connect after a disconnect using
* {@link WifiNanManager#connect(Handler, WifiNanEventCallback)} .
*/
public void disconnect() {
WifiNanManager mgr = mMgr.get();
if (mgr == null) {
Log.w(TAG, "disconnect: called post GC on WifiNanManager");
return;
}
mgr.disconnect(mClientId, mBinder);
mTerminated = true;
mMgr.clear();
mCloseGuard.close();
}
/** @hide */
@Override
protected void finalize() throws Throwable {
try {
if (!mTerminated) {
mCloseGuard.warnIfOpen();
disconnect();
}
} finally {
super.finalize();
}
}
/**
* Issue a request to the NAN service to create a new NAN publish discovery session, using
* the specified {@code publishConfig} configuration. The results of the publish operation
* are routed to the callbacks of {@link WifiNanDiscoverySessionCallback}:
* <ul>
* <li>{@link WifiNanDiscoverySessionCallback#onPublishStarted(WifiNanPublishDiscoverySession)}
* 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 WifiNanDiscoverySessionCallback#onSessionConfigFail(int)} 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 WifiNanPublishDiscoverySession#updatePublish(PublishConfig)}.
* <p>
* An application must use the {@link WifiNanDiscoveryBaseSession#terminate()} to
* terminate the publish discovery session once it isn't needed. This will free
* resources as well terminate any on-air transmissions.
*
* @param publishConfig The {@link PublishConfig} specifying the
* configuration of the requested publish session.
* @param callback A {@link WifiNanDiscoverySessionCallback} derived object to be used for
* session event callbacks.
*/
public void publish(@NonNull PublishConfig publishConfig,
@NonNull WifiNanDiscoverySessionCallback callback) {
WifiNanManager mgr = mMgr.get();
if (mgr == null) {
Log.e(TAG, "publish: called post GC on WifiNanManager");
return;
}
if (mTerminated) {
Log.e(TAG, "publish: called after termination");
return;
}
mgr.publish(mClientId, mLooper, publishConfig, callback);
}
/**
* Issue a request to the NAN service to create a new NAN subscribe discovery session, using
* the specified {@code subscribeConfig} configuration. The results of the subscribe
* operation are routed to the callbacks of {@link WifiNanDiscoverySessionCallback}:
* <ul>
* <li>{@link WifiNanDiscoverySessionCallback#onSubscribeStarted(WifiNanSubscribeDiscoverySession)}
* 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 WifiNanDiscoverySessionCallback#onSessionConfigFail(int)} 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 WifiNanSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
* <p>
* An application must use the {@link WifiNanDiscoveryBaseSession#terminate()} to
* terminate the subscribe discovery session once it isn't needed. This will free
* resources as well terminate any on-air transmissions.
*
* @param subscribeConfig The {@link SubscribeConfig} specifying the
* configuration of the requested subscribe session.
* @param callback A {@link WifiNanDiscoverySessionCallback} derived object to be used for
* session event callbacks.
*/
public void subscribe(@NonNull SubscribeConfig subscribeConfig,
@NonNull WifiNanDiscoverySessionCallback callback) {
WifiNanManager mgr = mMgr.get();
if (mgr == null) {
Log.e(TAG, "publish: called post GC on WifiNanManager");
return;
}
if (mTerminated) {
Log.e(TAG, "publish: called after termination");
return;
}
mgr.subscribe(mClientId, mLooper, subscribeConfig, callback);
}
/**
* Create a {@link NetworkRequest.Builder#setNetworkSpecifier(String)} for a
* WiFi NAN connection to the specified peer. The
* {@link NetworkRequest.Builder#addTransportType(int)} should be set to
* {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_NAN}.
* <p>
* This API is targeted for applications which can obtain the peer MAC address using OOB
* (out-of-band) discovery. NAN discovery does not provide the MAC address of the peer -
* when using NAN discovery use the alternative network specifier method -
* {@link WifiNanDiscoveryBaseSession#createNetworkSpecifier(int, int, byte[])}.
*
* @param role The role of this device:
* {@link WifiNanManager#WIFI_NAN_DATA_PATH_ROLE_INITIATOR} or
* {@link WifiNanManager#WIFI_NAN_DATA_PATH_ROLE_RESPONDER}
* @param peer The MAC address of the peer's NAN discovery interface. On a RESPONDER this
* value is used to gate the acceptance of a connection request from only that
* peer. A RESPONDER may specified a null - indicating that it will accept
* connection requests from any device.
* @param token An arbitrary token (message) to be used to match connection initiation request
* to a responder setup. A RESPONDER is set up with a {@code token} which must
* be matched by the token provided by the INITIATOR. A null token is permitted
* on the RESPONDER and matches any peer token. An empty ({@code ""}) token is
* not the same as a null token and requires the peer token to be empty as well.
*
* @return A string to be used to construct
* {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to
* {@link android.net.ConnectivityManager#requestNetwork(NetworkRequest, android.net.ConnectivityManager.NetworkCallback)}
* [or other varieties of that API].
*/
public String createNetworkSpecifier(@WifiNanManager.DataPathRole int role, @Nullable byte[] peer,
@Nullable byte[] token) {
WifiNanManager mgr = mMgr.get();
if (mgr == null) {
Log.e(TAG, "createNetworkSpecifier: called post GC on WifiNanManager");
return "";
}
if (mTerminated) {
Log.e(TAG, "createNetworkSpecifier: called after termination");
return "";
}
return mgr.createNetworkSpecifier(mClientId, role, peer, token);
}
}

View File

@@ -36,8 +36,8 @@ public class WifiNanSubscribeDiscoverySession extends WifiNanDiscoveryBaseSessio
/** /**
* {@hide} * {@hide}
*/ */
public WifiNanSubscribeDiscoverySession(WifiNanManager manager, int sessionId) { public WifiNanSubscribeDiscoverySession(WifiNanManager manager, int clientId, int sessionId) {
super(manager, sessionId); super(manager, clientId, sessionId);
} }
/** /**
@@ -67,7 +67,7 @@ public class WifiNanSubscribeDiscoverySession extends WifiNanDiscoveryBaseSessio
return; return;
} }
mgr.updateSubscribe(mSessionId, subscribeConfig); mgr.updateSubscribe(mClientId, mSessionId, subscribeConfig);
} }
} }
} }