OSDN Git Service

[NAN] Refactor WifiNanManager to create separate sessions per connect. [DO NOT MERGE]
authorEtan Cohen <etancohen@google.com>
Thu, 15 Sep 2016 19:15:10 +0000 (12:15 -0700)
committerEtan Cohen <etancohen@google.com>
Mon, 19 Sep 2016 17:15:56 +0000 (10:15 -0700)
Separate session enables separate namespace for functions which depend
on a connection to exist.

Bug: 31470256
Test: unit tests, integration (sl4a) tests.
Change-Id: I83d69acf18de6be2b96a34d2a608a6390ecdecbf

wifi/java/android/net/wifi/nan/IWifiNanDiscoverySessionCallback.aidl
wifi/java/android/net/wifi/nan/IWifiNanEventCallback.aidl
wifi/java/android/net/wifi/nan/IWifiNanManager.aidl
wifi/java/android/net/wifi/nan/WifiNanDiscoveryBaseSession.java
wifi/java/android/net/wifi/nan/WifiNanEventCallback.java
wifi/java/android/net/wifi/nan/WifiNanManager.java
wifi/java/android/net/wifi/nan/WifiNanPublishDiscoverySession.java
wifi/java/android/net/wifi/nan/WifiNanSession.java [new file with mode: 0644]
wifi/java/android/net/wifi/nan/WifiNanSubscribeDiscoverySession.java

index 8c1b892..f2e371d 100644 (file)
@@ -23,7 +23,7 @@ package android.net.wifi.nan;
  */
 oneway interface IWifiNanDiscoverySessionCallback
 {
-    void onSessionStarted(int sessionId);
+    void onSessionStarted(int discoverySessionId);
     void onSessionConfigSuccess();
     void onSessionConfigFail(int reason);
     void onSessionTerminated(int reason);
index a4e590b..9ac7bf2 100644 (file)
@@ -26,7 +26,7 @@ import android.net.wifi.RttManager;
  */
 oneway interface IWifiNanEventCallback
 {
-    void onConnectSuccess();
+    void onConnectSuccess(int clientId);
     void onConnectFail(int reason);
     void onIdentityChanged(in byte[] mac);
 
index 4711bad..4e1f607 100644 (file)
@@ -38,7 +38,7 @@ interface IWifiNanManager
     boolean isUsageEnabled();
 
     // 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);
     void disconnect(int clientId, in IBinder binder);
 
@@ -48,10 +48,10 @@ interface IWifiNanManager
             in IWifiNanDiscoverySessionCallback callback);
 
     // session API
-    void updatePublish(int clientId, int sessionId, in PublishConfig publishConfig);
-    void updateSubscribe(int clientId, int sessionId, in SubscribeConfig subscribeConfig);
-    void sendMessage(int clientId, int sessionId, int peerId, in byte[] message, int messageId,
+    void updatePublish(int clientId, int discoverySessionId, in PublishConfig publishConfig);
+    void updateSubscribe(int clientId, int discoverySessionId, in SubscribeConfig subscribeConfig);
+    void sendMessage(int clientId, int discoverySessionId, int peerId, in byte[] message, int messageId,
         int retryCount);
-    void terminateSession(int clientId, int sessionId);
-    int startRanging(int clientId, int sessionId, in RttManager.ParcelableRttParams parms);
+    void terminateSession(int clientId, int discoverySessionId);
+    int startRanging(int clientId, int discoverySessionId, in RttManager.ParcelableRttParams parms);
 }
index 58971db..c2f3735 100644 (file)
@@ -50,6 +50,8 @@ public class WifiNanDiscoveryBaseSession {
     /** @hide */
     protected WeakReference<WifiNanManager> mMgr;
     /** @hide */
+    protected final int mClientId;
+    /** @hide */
     protected final int mSessionId;
     /** @hide */
     protected boolean mTerminated = false;
@@ -67,10 +69,14 @@ public class WifiNanDiscoveryBaseSession {
     }
 
     /** @hide */
-    public WifiNanDiscoveryBaseSession(WifiNanManager manager, int sessionId) {
-        if (VDBG) Log.v(TAG, "New client created: manager=" + manager + ", sessionId=" + sessionId);
+    public WifiNanDiscoveryBaseSession(WifiNanManager manager, int clientId, int sessionId) {
+        if (VDBG) {
+            Log.v(TAG, "New discovery session created: manager=" + manager + ", clientId="
+                    + clientId + ", sessionId=" + sessionId);
+        }
 
         mMgr = new WeakReference<>(manager);
+        mClientId = clientId;
         mSessionId = sessionId;
 
         mCloseGuard.open("terminate");
@@ -93,7 +99,7 @@ public class WifiNanDiscoveryBaseSession {
             Log.w(TAG, "terminate: called post GC on WifiNanManager");
             return;
         }
-        mgr.terminateSession(mSessionId);
+        mgr.terminateSession(mClientId, mSessionId);
         mTerminated = true;
         mMgr.clear();
         mCloseGuard.close();
@@ -166,7 +172,7 @@ public class WifiNanDiscoveryBaseSession {
                 return;
             }
 
-            mgr.sendMessage(mSessionId, peerId, message, messageId, retryCount);
+            mgr.sendMessage(mClientId, mSessionId, peerId, message, messageId, retryCount);
         }
     }
 
@@ -223,7 +229,7 @@ public class WifiNanDiscoveryBaseSession {
                 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
      * 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
-     * {@link WifiNanManager#createNetworkSpecifier(int, byte[], byte[])} method - which uses the
+     * {@link WifiNanSession#createNetworkSpecifier(int, byte[], byte[])} method - which uses the
      * peer's MAC address.
      *
      * @param role The role of this device:
@@ -272,7 +278,7 @@ public class WifiNanDiscoveryBaseSession {
                 return null;
             }
 
-            return mgr.createNetworkSpecifier(role, mSessionId, peerId, token);
+            return mgr.createNetworkSpecifier(mClientId, role, mSessionId, peerId, token);
         }
     }
 }
index a66afc1..28c5ca2 100644 (file)
@@ -62,8 +62,11 @@ public class WifiNanEventCallback {
      * Called when NAN connect operation
      * {@link WifiNanManager#connect(android.os.Handler, WifiNanEventCallback)}
      * 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 */
     }
 
index cf13fe0..435019d 100644 (file)
@@ -28,7 +28,6 @@ import android.net.wifi.RttManager;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
@@ -38,8 +37,6 @@ import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
 
-import dalvik.system.CloseGuard;
-
 import libcore.util.HexEncoding;
 
 import org.json.JSONException;
@@ -59,15 +56,15 @@ import java.util.Arrays;
  * The class provides access to:
  * <ul>
  * <li>Initialize a NAN cluster (peer-to-peer synchronization). Refer to
- * {@link #connect(Handler, WifiNanEventCallback)}.
- * <li>Create discovery sessions (publish or subscribe sessions).
- * Refer to {@link #publish(PublishConfig, WifiNanDiscoverySessionCallback)} and
- * {@link #subscribe(SubscribeConfig, WifiNanDiscoverySessionCallback)}.
- * <li>Create a NAN network specifier to be used with
+ * {@link #connect(Handler, WifiNanEventCallback)}. <li>Create discovery sessions (publish or
+ * subscribe sessions). Refer to
+ * {@link WifiNanSession#publish(PublishConfig, WifiNanDiscoverySessionCallback)} and
+ * {@link WifiNanSession#subscribe(SubscribeConfig, WifiNanDiscoverySessionCallback)}. <li>Create
+ * a NAN network specifier to be used with
  * {@link ConnectivityManager#requestNetwork(NetworkRequest, ConnectivityManager.NetworkCallback)}
  * to set-up a NAN connection with a peer. Refer to
  * {@link WifiNanDiscoveryBaseSession#createNetworkSpecifier(int, int, byte[])} and
- * {@link #createNetworkSpecifier(int, byte[], byte[])}.
+ * {@link WifiNanSession#createNetworkSpecifier(int, byte[], byte[])}.
  * </ul>
  * <p>
  *     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
  *     returned in callbacks of {@link WifiNanEventCallback}. Proceed with NAN discovery or
  *     connection setup only after receiving confirmation that NAN connection succeeded -
- *     {@link WifiNanEventCallback#onConnectSuccess()}.
- *     When an application is finished using NAN it <b>must</b> use the {@link #disconnect()} API
+ *     {@link WifiNanEventCallback#onConnectSuccess(WifiNanSession)}. When an application is
+ *     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
  *     device will actually disconnect from the NAN cluster once the last application disconnects.
  * <p>
  *     Once a NAN connection is confirmed use the
- *     {@link #publish(PublishConfig, WifiNanDiscoverySessionCallback)} or
- *     {@link #subscribe(SubscribeConfig, WifiNanDiscoverySessionCallback)} to create publish or
- *     subscribe NAN discovery sessions. Events are called on the provided callback object
- *     {@link WifiNanDiscoverySessionCallback}. Specifically, the
+ *     {@link WifiNanSession#publish(PublishConfig, WifiNanDiscoverySessionCallback)} or
+ *     {@link WifiNanSession#subscribe(SubscribeConfig, WifiNanDiscoverySessionCallback)} to
+ *     create publish or subscribe NAN discovery sessions. Events are called on the provided
+ *     callback object {@link WifiNanDiscoverySessionCallback}. Specifically, the
  *     {@link WifiNanDiscoverySessionCallback#onPublishStarted(WifiNanPublishDiscoverySession)}
  *     and
  *     {@link WifiNanDiscoverySessionCallback#onSubscribeStarted(WifiNanSubscribeDiscoverySession)}
@@ -111,7 +108,7 @@ import java.util.Arrays;
  *        <li>{@link NetworkRequest.Builder#addTransportType(int)} of
  *        {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_NAN}.
  *        <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[])}.
  *    </ul>
  *
@@ -122,8 +119,6 @@ public class WifiNanManager {
     private static final boolean DBG = false;
     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
      * is formatted as a JSON string.
@@ -251,7 +246,7 @@ public class WifiNanManager {
      * when requesting a NAN network.
      *
      * @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;
 
@@ -260,26 +255,16 @@ public class WifiNanManager {
      * when requesting a NAN network.
      *
      * @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;
 
     private final Context mContext;
     private final IWifiNanManager mService;
-    private final CloseGuard mCloseGuard = CloseGuard.get();
 
     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")
     private SparseArray<RttManager.RttListener> mRangingListeners = new SparseArray<>();
 
     /** @hide */
@@ -340,8 +325,8 @@ public class WifiNanManager {
      * 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
      * (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
-     * connection.
+     * An application <b>must</b> call {@link WifiNanSession#disconnect()} when done with the
+     * Wi-Fi NAN connection.
      * <p>
      * 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.
@@ -360,10 +345,10 @@ public class WifiNanManager {
      * 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
      * (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
-     * connection. Allows requesting a specific configuration using {@link ConfigRequest}. If not
-     * necessary (default configuration should usually work) use the
-     * {@link #connect(Handler, WifiNanEventCallback)} method instead.
+     * An application <b>must</b> call {@link WifiNanSession#disconnect()} when done with the
+     * Wi-Fi NAN connection. Allows requesting a specific configuration using
+     * {@link ConfigRequest}. If not necessary (default configuration should usually work) use
+     * the {@link #connect(Handler, WifiNanEventCallback)} method instead.
      * <p>
      * 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.
@@ -383,50 +368,23 @@ public class WifiNanManager {
         }
 
         synchronized (mLock) {
-            mLooper = (handler == null) ? Looper.getMainLooper() : handler.getLooper();
+            Looper looper = (handler == null) ? Looper.getMainLooper() : handler.getLooper();
 
             try {
-                mClientId = mService.connect(mBinder, mContext.getOpPackageName(),
-                        new WifiNanEventCallbackProxy(this, mLooper, callback), configRequest);
+                Binder binder = new Binder();
+                mService.connect(binder, mContext.getOpPackageName(),
+                        new WifiNanEventCallbackProxy(this, looper, binder, callback),
+                        configRequest);
             } catch (RemoteException e) {
-                mClientId = INVALID_CLIENT_ID;
-                mLooper = null;
                 e.rethrowAsRuntimeException();
             }
         }
-
-        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() {
+    /** @hide */
+    public void disconnect(int clientId, Binder binder) {
         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 {
             mService.disconnect(clientId, binder);
         } catch (RemoteException e) {
@@ -435,78 +393,26 @@ public class WifiNanManager {
     }
 
     /** @hide */
-    @Override
-    protected void finalize() throws Throwable {
-        try {
-            mCloseGuard.warnIfOpen();
-            disconnect();
-        } finally {
-            super.finalize();
-        }
-    }
+    public void publish(int clientId, Looper looper, PublishConfig publishConfig,
+            WifiNanDiscoverySessionCallback callback) {
+        if (VDBG) Log.v(TAG, "publish(): clientId=" + clientId + ", config=" + publishConfig);
 
-    /**
-     * 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 {
             mService.publish(clientId, publishConfig,
-                    new WifiNanDiscoverySessionCallbackProxy(this, looper, true, callback));
+                    new WifiNanDiscoverySessionCallbackProxy(this, looper, true, callback,
+                            clientId));
         } catch (RemoteException e) {
             e.rethrowAsRuntimeException();
         }
     }
 
     /** @hide */
-    public void updatePublish(int sessionId, PublishConfig publishConfig) {
-        if (VDBG) Log.v(TAG, "updatePublish(): config=" + publishConfig);
-
-        int clientId;
-        synchronized (mLock) {
-            if (mClientId == INVALID_CLIENT_ID) {
-                Log.e(TAG, "updatePublish(): called with invalid client ID - not connected first?");
-                return;
-            }
-
-            clientId = mClientId;
+    public void updatePublish(int clientId, int sessionId, PublishConfig publishConfig) {
+        if (VDBG) {
+            Log.v(TAG, "updatePublish(): clientId=" + clientId + ",sessionId=" + sessionId
+                    + ", config=" + publishConfig);
         }
+
         try {
             mService.updatePublish(clientId, sessionId, publishConfig);
         } catch (RemoteException e) {
@@ -514,73 +420,30 @@ public class WifiNanManager {
         }
     }
 
-    /**
-     * 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) {
+    /** @hide */
+    public void subscribe(int clientId, Looper looper, SubscribeConfig subscribeConfig,
+            WifiNanDiscoverySessionCallback callback) {
         if (VDBG) {
-            Log.v(TAG, "subscribe(): 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;
+            if (VDBG) {
+                Log.v(TAG,
+                        "subscribe(): clientId=" + clientId + ", config=" + subscribeConfig);
             }
-
-            clientId = mClientId;
-            looper = mLooper;
         }
 
         try {
             mService.subscribe(clientId, subscribeConfig,
-                    new WifiNanDiscoverySessionCallbackProxy(this, looper, false, callback));
+                    new WifiNanDiscoverySessionCallbackProxy(this, looper, false, callback,
+                            clientId));
         } catch (RemoteException e) {
             e.rethrowAsRuntimeException();
         }
     }
 
     /** @hide */
-    public void updateSubscribe(int sessionId, SubscribeConfig subscribeConfig) {
+    public void updateSubscribe(int clientId, int sessionId, SubscribeConfig subscribeConfig) {
         if (VDBG) {
-            Log.v(TAG, "subscribe(): 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;
+            Log.v(TAG, "updateSubscribe(): clientId=" + clientId + ",sessionId=" + sessionId
+                    + ", config=" + subscribeConfig);
         }
 
         try {
@@ -591,18 +454,10 @@ public class WifiNanManager {
     }
 
     /** @hide */
-    public void terminateSession(int sessionId) {
-        if (DBG) Log.d(TAG, "Terminate NAN session #" + sessionId);
-
-        int clientId;
-        synchronized (mLock) {
-            if (mClientId == INVALID_CLIENT_ID) {
-                Log.e(TAG,
-                        "terminateSession(): called with invalid client ID - not connected first?");
-                return;
-            }
-
-            clientId = mClientId;
+    public void terminateSession(int clientId, int sessionId) {
+        if (VDBG) {
+            Log.d(TAG,
+                    "terminateSession(): clientId=" + clientId + ", sessionId=" + sessionId);
         }
 
         try {
@@ -613,21 +468,12 @@ public class WifiNanManager {
     }
 
     /** @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) {
         if (VDBG) {
-            Log.v(TAG, "sendMessage(): 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;
+            Log.v(TAG,
+                    "sendMessage(): clientId=" + clientId + ", sessionId=" + sessionId + ", peerId="
+                            + peerId + ", messageId=" + messageId + ", retryCount=" + retryCount);
         }
 
         try {
@@ -638,21 +484,11 @@ public class WifiNanManager {
     }
 
     /** @hide */
-    public void startRanging(int sessionId, RttManager.RttParams[] params,
+    public void startRanging(int clientId, int sessionId, RttManager.RttParams[] params,
                              RttManager.RttListener listener) {
         if (VDBG) {
-            Log.v(TAG, "startRanging: sessionId=" + sessionId + ", " + "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;
+            Log.v(TAG, "startRanging: clientId=" + clientId + ", sessionId=" + sessionId + ", "
+                    + "params=" + Arrays.toString(params) + ", listener=" + listener);
         }
 
         int rangingKey = 0;
@@ -669,7 +505,7 @@ public class WifiNanManager {
     }
 
     /** @hide */
-    public String createNetworkSpecifier(@DataPathRole int role, int sessionId, int peerId,
+    public String createNetworkSpecifier(int clientId, int role, int sessionId, int peerId,
             byte[] token) {
         if (VDBG) {
             Log.v(TAG, "createNetworkSpecifier: role=" + role + ", sessionId=" + sessionId
@@ -705,18 +541,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;
         try {
             json = new JSONObject();
@@ -738,36 +562,8 @@ public class WifiNanManager {
         return json.toString();
     }
 
-    /**
-     * 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, ConnectivityManager.NetworkCallback)}
-     * [or other varieties of that API].
-     */
-    public String createNetworkSpecifier(@DataPathRole int role, @Nullable byte[] peer,
+    /** @hide */
+    public String createNetworkSpecifier(int clientId, @DataPathRole int role, @Nullable byte[] peer,
             @Nullable byte[] token) {
         if (VDBG) {
             Log.v(TAG, "createNetworkSpecifier: role=" + role + ", token=" + token);
@@ -806,18 +602,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;
         try {
             json = new JSONObject();
@@ -848,6 +632,8 @@ public class WifiNanManager {
 
         private final Handler mHandler;
         private final WeakReference<WifiNanManager> mNanManager;
+        private final Binder mBinder;
+        private final Looper mLooper;
 
         RttManager.RttListener getAndRemoveRangingListener(int rangingId) {
             WifiNanManager mgr = mNanManager.get();
@@ -869,9 +655,11 @@ public class WifiNanManager {
          *
          * @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) {
             mNanManager = new WeakReference<>(mgr);
+            mLooper = looper;
+            mBinder = binder;
 
             if (VDBG) Log.v(TAG, "WifiNanEventCallbackProxy ctor: looper=" + looper);
             mHandler = new Handler(looper) {
@@ -889,13 +677,10 @@ public class WifiNanManager {
 
                     switch (msg.what) {
                         case CALLBACK_CONNECT_SUCCESS:
-                            originalCallback.onConnectSuccess();
+                            originalCallback.onConnectSuccess(
+                                    new WifiNanSession(mgr, mBinder, mLooper, msg.arg1));
                             break;
                         case CALLBACK_CONNECT_FAIL:
-                            synchronized (mgr.mLock) {
-                                mgr.mLooper = null;
-                                mgr.mClientId = INVALID_CLIENT_ID;
-                            }
                             mNanManager.clear();
                             originalCallback.onConnectFail(msg.arg1);
                             break;
@@ -939,10 +724,11 @@ public class WifiNanManager {
         }
 
         @Override
-        public void onConnectSuccess() {
+        public void onConnectSuccess(int clientId) {
             if (VDBG) Log.v(TAG, "onConnectSuccess");
 
             Message msg = mHandler.obtainMessage(CALLBACK_CONNECT_SUCCESS);
+            msg.arg1 = clientId;
             mHandler.sendMessage(msg);
         }
 
@@ -1019,15 +805,17 @@ public class WifiNanManager {
         private final WeakReference<WifiNanManager> mNanManager;
         private final boolean mIsPublish;
         private final WifiNanDiscoverySessionCallback mOriginalCallback;
+        private final int mClientId;
 
         private final Handler mHandler;
         private WifiNanDiscoveryBaseSession mSession;
 
         WifiNanDiscoverySessionCallbackProxy(WifiNanManager mgr, Looper looper, boolean isPublish,
-                WifiNanDiscoverySessionCallback originalCallback) {
+                WifiNanDiscoverySessionCallback originalCallback, int clientId) {
             mNanManager = new WeakReference<>(mgr);
             mIsPublish = isPublish;
             mOriginalCallback = originalCallback;
+            mClientId = clientId;
 
             if (VDBG) {
                 Log.v(TAG, "WifiNanDiscoverySessionCallbackProxy ctor: isPublish=" + isPublish);
@@ -1183,12 +971,12 @@ public class WifiNanManager {
 
             if (mIsPublish) {
                 WifiNanPublishDiscoverySession session = new WifiNanPublishDiscoverySession(mgr,
-                        sessionId);
+                        mClientId, sessionId);
                 mSession = session;
                 mOriginalCallback.onPublishStarted(session);
             } else {
                 WifiNanSubscribeDiscoverySession
-                        session = new WifiNanSubscribeDiscoverySession(mgr, sessionId);
+                        session = new WifiNanSubscribeDiscoverySession(mgr, mClientId, sessionId);
                 mSession = session;
                 mOriginalCallback.onSubscribeStarted(session);
             }
index cacbdbf..c1731bb 100644 (file)
@@ -34,8 +34,8 @@ public class WifiNanPublishDiscoverySession extends WifiNanDiscoveryBaseSession
     private static final String TAG = "WifiNanPublishDiscSsn";
 
     /** @hide */
-    public WifiNanPublishDiscoverySession(WifiNanManager manager, int sessionId) {
-        super(manager, sessionId);
+    public WifiNanPublishDiscoverySession(WifiNanManager manager, int clientId, int sessionId) {
+        super(manager, clientId, sessionId);
     }
 
     /**
@@ -64,7 +64,7 @@ public class WifiNanPublishDiscoverySession extends WifiNanDiscoveryBaseSession
                 return;
             }
 
-            mgr.updatePublish(mSessionId, publishConfig);
+            mgr.updatePublish(mClientId, mSessionId, publishConfig);
         }
     }
 }
diff --git a/wifi/java/android/net/wifi/nan/WifiNanSession.java b/wifi/java/android/net/wifi/nan/WifiNanSession.java
new file mode 100644 (file)
index 0000000..f9e6017
--- /dev/null
@@ -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);
+    }
+}
index 58c52d5..b8d77aa 100644 (file)
@@ -36,8 +36,8 @@ public class WifiNanSubscribeDiscoverySession extends WifiNanDiscoveryBaseSessio
     /**
      * {@hide}
      */
-    public WifiNanSubscribeDiscoverySession(WifiNanManager manager, int sessionId) {
-        super(manager, sessionId);
+    public WifiNanSubscribeDiscoverySession(WifiNanManager manager, int clientId, int sessionId) {
+        super(manager, clientId, sessionId);
     }
 
     /**
@@ -67,7 +67,7 @@ public class WifiNanSubscribeDiscoverySession extends WifiNanDiscoveryBaseSessio
                 return;
             }
 
-            mgr.updateSubscribe(mSessionId, subscribeConfig);
+            mgr.updateSubscribe(mClientId, mSessionId, subscribeConfig);
         }
     }
 }