From 2a73c7fb2a4aba4dd75341414f1583e5fb1f4613 Mon Sep 17 00:00:00 2001 From: Etan Cohen Date: Mon, 14 Mar 2016 18:06:46 -0700 Subject: [PATCH] [NAN] Refactor session lifecycle to clarify API & eliminate race conditions [DO NOT MERGE] Bug: 27257965 Change-Id: I4d7eaa6fa1f089bed2e9185f59a37f59b530975d --- .../java/android/net/wifi/nan/IWifiNanManager.aidl | 12 +- .../net/wifi/nan/IWifiNanSessionCallback.aidl | 1 + .../android/net/wifi/nan/WifiNanEventCallback.java | 133 +------ wifi/java/android/net/wifi/nan/WifiNanManager.java | 421 +++++++++++++++++---- .../net/wifi/nan/WifiNanPublishSession.java | 18 +- wifi/java/android/net/wifi/nan/WifiNanSession.java | 58 ++- .../net/wifi/nan/WifiNanSessionCallback.java | 208 ++-------- .../net/wifi/nan/WifiNanSubscribeSession.java | 20 +- 8 files changed, 455 insertions(+), 416 deletions(-) diff --git a/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl b/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl index 4b0dce85dff3..5c64480f0adc 100644 --- a/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl +++ b/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl @@ -36,12 +36,14 @@ interface IWifiNanManager void disconnect(int clientId, in IBinder binder); void requestConfig(int clientId, in ConfigRequest configRequest); + void publish(int clientId, in PublishConfig publishConfig, in IWifiNanSessionCallback callback); + void subscribe(int clientId, in SubscribeConfig subscribeConfig, + in IWifiNanSessionCallback callback); + // session API - int createSession(int clientId, in IWifiNanSessionCallback callback); - void publish(int clientId, int sessionId, in PublishConfig publishConfig); - void subscribe(int clientId, int sessionId, in SubscribeConfig subscribeConfig); + 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 messageLength, int messageId); - void stopSession(int clientId, int sessionId); - void destroySession(int clientId, int sessionId); + void terminateSession(int clientId, int sessionId); } diff --git a/wifi/java/android/net/wifi/nan/IWifiNanSessionCallback.aidl b/wifi/java/android/net/wifi/nan/IWifiNanSessionCallback.aidl index 1714ebac1842..cff3c7e59801 100644 --- a/wifi/java/android/net/wifi/nan/IWifiNanSessionCallback.aidl +++ b/wifi/java/android/net/wifi/nan/IWifiNanSessionCallback.aidl @@ -23,6 +23,7 @@ package android.net.wifi.nan; */ oneway interface IWifiNanSessionCallback { + void onSessionStarted(int sessionId); void onSessionConfigFail(int reason); void onSessionTerminated(int reason); diff --git a/wifi/java/android/net/wifi/nan/WifiNanEventCallback.java b/wifi/java/android/net/wifi/nan/WifiNanEventCallback.java index 8b700872c5a6..c243b5b3591e 100644 --- a/wifi/java/android/net/wifi/nan/WifiNanEventCallback.java +++ b/wifi/java/android/net/wifi/nan/WifiNanEventCallback.java @@ -16,11 +16,6 @@ package android.net.wifi.nan; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.util.Log; - /** * Base class for NAN events callbacks. Should be extended by applications * wanting notifications. These are callbacks applying to the NAN connection as @@ -30,65 +25,8 @@ import android.util.Log; * @hide PROPOSED_NAN_API */ public class WifiNanEventCallback { - private static final String TAG = "WifiNanEventCallback"; - private static final boolean DBG = false; - private static final boolean VDBG = false; // STOPSHIP if true - - /** @hide */ - public static final int CALLBACK_CONFIG_COMPLETED = 0; - /** @hide */ - public static final int CALLBACK_CONFIG_FAILED = 1; - /** @hide */ - public static final int CALLBACK_NAN_DOWN = 2; - /** @hide */ - public static final int CALLBACK_IDENTITY_CHANGED = 3; - - private final Handler mHandler; - - /** - * Constructs a {@link WifiNanEventCallback} using the looper of the current - * thread. I.e. all callbacks will be delivered on the current thread. - */ - public WifiNanEventCallback() { - this(Looper.myLooper()); - } - /** - * Constructs a {@link WifiNanEventCallback} using the specified looper. - * I.e. all callbacks will delivered on the thread of the specified looper. - * - * @param looper The looper on which to execute the callbacks. - */ - public WifiNanEventCallback(Looper looper) { - if (VDBG) Log.v(TAG, "ctor: looper=" + looper); - mHandler = new Handler(looper) { - @Override - public void handleMessage(Message msg) { - if (DBG) Log.d(TAG, "What=" + msg.what + ", msg=" + msg); - switch (msg.what) { - case CALLBACK_CONFIG_COMPLETED: - WifiNanEventCallback.this.onConfigCompleted((ConfigRequest) msg.obj); - break; - case CALLBACK_CONFIG_FAILED: - WifiNanEventCallback.this.onConfigFailed((ConfigRequest) msg.obj, msg.arg1); - break; - case CALLBACK_NAN_DOWN: - WifiNanEventCallback.this.onNanDown(msg.arg1); - break; - case CALLBACK_IDENTITY_CHANGED: - WifiNanEventCallback.this.onIdentityChanged(); - break; - } - } - }; - } - - /** - * Called when NAN configuration is completed. Event will only be delivered - * if registered using - * {@link WifiNanEventCallback#CALLBACK_CONFIG_COMPLETED}. A dummy (empty - * implementation printing out a warning). Make sure to override if - * registered. + * Called when NAN configuration is completed. * * @param completedConfig The actual configuration request which was * completed. Note that it may be different from that requested @@ -96,89 +34,36 @@ public class WifiNanEventCallback { * requests from all applications. */ public void onConfigCompleted(ConfigRequest completedConfig) { - Log.w(TAG, "onConfigCompleted: called in stub - override if interested or disable"); + /* empty */ } /** - * Called when NAN configuration failed. Event will only be delivered if - * registered using {@link WifiNanEventCallback#CALLBACK_CONFIG_FAILED}. A - * dummy (empty implementation printing out a warning). Make sure to - * override if registered. + * Called when NAN configuration failed. * * @param reason Failure reason code, see * {@code WifiNanSessionCallback.FAIL_*}. */ - public void onConfigFailed(ConfigRequest failedConfig, int reason) { - Log.w(TAG, "onConfigFailed: called in stub - override if interested or disable"); + public void onConfigFailed(@SuppressWarnings("unused") ConfigRequest failedConfig, int reason) { + /* empty */ } /** - * Called when NAN cluster is down. Event will only be delivered if - * registered using {@link WifiNanEventCallback#CALLBACK_NAN_DOWN}. A dummy - * (empty implementation printing out a warning). Make sure to override if - * registered. + * Called when NAN cluster is down * * @param reason Reason code for event, see * {@code WifiNanSessionCallback.FAIL_*}. */ public void onNanDown(int reason) { - Log.w(TAG, "onNanDown: called in stub - override if interested or disable"); + /* empty */ } /** * Called when NAN identity has changed. This may be due to joining a * cluster, starting a cluster, or discovery interface change. The * implication is that peers you've been communicating with may no longer - * recognize you and you need to re-establish your identity. Event will only - * be delivered if registered using - * {@link WifiNanEventCallback#CALLBACK_IDENTITY_CHANGED}. A dummy (empty - * implementation printing out a warning). Make sure to override if - * registered. + * recognize you and you need to re-establish your identity. */ public void onIdentityChanged() { - if (VDBG) Log.v(TAG, "onIdentityChanged: called in stub - override if interested"); + /* empty */ } - - /** - * {@hide} - */ - public IWifiNanEventCallback callback = new IWifiNanEventCallback.Stub() { - @Override - public void onConfigCompleted(ConfigRequest completedConfig) { - if (VDBG) Log.v(TAG, "onConfigCompleted: configRequest=" + completedConfig); - - Message msg = mHandler.obtainMessage(CALLBACK_CONFIG_COMPLETED); - msg.obj = completedConfig; - mHandler.sendMessage(msg); - } - - @Override - public void onConfigFailed(ConfigRequest failedConfig, int reason) { - if (VDBG) { - Log.v(TAG, "onConfigFailed: failedConfig=" + failedConfig + ", reason=" + reason); - } - - Message msg = mHandler.obtainMessage(CALLBACK_CONFIG_FAILED); - msg.arg1 = reason; - msg.obj = failedConfig; - mHandler.sendMessage(msg); - } - - @Override - public void onNanDown(int reason) { - if (VDBG) Log.v(TAG, "onNanDown: reason=" + reason); - - Message msg = mHandler.obtainMessage(CALLBACK_NAN_DOWN); - msg.arg1 = reason; - mHandler.sendMessage(msg); - } - - @Override - public void onIdentityChanged() { - if (VDBG) Log.v(TAG, "onIdentityChanged"); - - Message msg = mHandler.obtainMessage(CALLBACK_IDENTITY_CHANGED); - mHandler.sendMessage(msg); - } - }; } diff --git a/wifi/java/android/net/wifi/nan/WifiNanManager.java b/wifi/java/android/net/wifi/nan/WifiNanManager.java index c24b1f8beed1..bb19ee7117c1 100644 --- a/wifi/java/android/net/wifi/nan/WifiNanManager.java +++ b/wifi/java/android/net/wifi/nan/WifiNanManager.java @@ -17,7 +17,11 @@ package android.net.wifi.nan; 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; import android.util.Log; @@ -44,6 +48,7 @@ public class WifiNanManager { private IBinder mBinder; private int mClientId = -1; private IWifiNanManager mService; + private Looper mLooper; /** * {@hide} @@ -56,22 +61,29 @@ public class WifiNanManager { * Re-connect to the Wi-Fi NAN service - enabling the application to execute * {@link WifiNanManager} APIs. * + * @param looper The Looper on which to execute all callbacks related to the + * connection - including all sessions opened as part of this + * connection. * @param callback A callback extended from {@link WifiNanEventCallback}. */ - public void connect(WifiNanEventCallback callback) { + public void connect(Looper looper, WifiNanEventCallback callback) { + if (VDBG) Log.v(TAG, "connect()"); + + if (callback == null) { + throw new IllegalArgumentException("Invalid callback - must not be null"); + } + + if (mClientId != -1) { + Log.e(TAG, "connect(): mClientId=" + mClientId + + ": seems to calling connect() without disconnecting() first!"); + throw new IllegalStateException("Calling connect() without disconnecting() first!"); + } + + mLooper = looper; + mBinder = new Binder(); + try { - if (VDBG) Log.v(TAG, "connect()"); - if (callback == null) { - throw new IllegalArgumentException("Invalid callback - must not be null"); - } - if (mClientId != -1) { - Log.w(TAG, "connect(): mClientId=" + mClientId - + ": seems to calling connect() without disconnecting() first!"); - } - if (mBinder == null) { - mBinder = new Binder(); - } - mClientId = mService.connect(mBinder, callback.callback); + mClientId = mService.connect(mBinder, new WifiNanEventCallbackProxy(mLooper, callback)); } catch (RemoteException e) { Log.w(TAG, "connect RemoteException (FYI - ignoring): " + e); } @@ -84,9 +96,18 @@ public class WifiNanManager { * are cancelled. *

* An application may then re-connect using - * {@link WifiNanManager#connect(WifiNanEventCallback, int)} . + * {@link WifiNanManager#connect(Looper, WifiNanEventCallback)} . */ public void disconnect() { + if (mClientId == -1) { + /* + * Warning only since could be called multiple times as cleaning-up + * (and no damage done). + */ + Log.w(TAG, "disconnect(): called without calling connect() first - or called " + + "multiple times."); + return; + } try { if (VDBG) Log.v(TAG, "disconnect()"); mService.disconnect(mClientId, mBinder); @@ -97,6 +118,14 @@ public class WifiNanManager { } } + @Override + protected void finalize() throws Throwable { + if (mBinder != null) { + if (DBG) Log.d(TAG, "finalize: disconnect() not called - executing now"); + disconnect(); + } + } + /** * Requests a NAN configuration, specified by {@link ConfigRequest}. Note * that NAN is a shared resource and the device can only be a member of a @@ -112,6 +141,12 @@ public class WifiNanManager { */ public void requestConfig(ConfigRequest configRequest) { if (VDBG) Log.v(TAG, "requestConfig(): configRequest=" + configRequest); + + if (mClientId == -1) { + Log.e(TAG, "requestConfig(): called without an initial connect()!"); + throw new IllegalStateException("Calling requestConfig() without a connect() first!"); + } + try { mService.requestConfig(mClientId, configRequest); } catch (RemoteException e) { @@ -120,19 +155,19 @@ public class WifiNanManager { } /** - * Request a NAN publish session. The results of the publish session - * operation will result in callbacks to the indicated callback: - * {@link WifiNanSessionCallback NanSessionCallback.on*}. + * Request a NAN publish session. The actual publish session is provided by + * the + * {@link WifiNanSessionCallback#onPublishStarted(WifiNanPublishSession)} + * callback. Other results of the publish session operation will result in + * callbacks to the indicated callback: {@link WifiNanSessionCallback + * NanSessionCallback.on*}. * * @param publishConfig The {@link PublishConfig} specifying the * configuration of the publish session. * @param callback The {@link WifiNanSessionCallback} derived objects to be * used for the event callbacks specified by {@code events}. - * @return The {@link WifiNanPublishSession} which can be used to further - * control the publish session. */ - public WifiNanPublishSession publish(PublishConfig publishConfig, - WifiNanSessionCallback callback) { + public void publish(PublishConfig publishConfig, WifiNanSessionCallback callback) { if (VDBG) Log.v(TAG, "publish(): config=" + publishConfig); if (publishConfig.mPublishType == PublishConfig.PUBLISH_TYPE_UNSOLICITED @@ -149,25 +184,24 @@ public class WifiNanManager { throw new IllegalArgumentException("Invalid callback - must not be null"); } - int sessionId; + if (mClientId == -1) { + Log.e(TAG, "publish(): called without an initial connect()!"); + throw new IllegalStateException("Calling publish() without a connect() first!"); + } try { - sessionId = mService.createSession(mClientId, callback.callback); - if (DBG) Log.d(TAG, "publish: session created - sessionId=" + sessionId); - mService.publish(mClientId, sessionId, publishConfig); + mService.publish(mClientId, publishConfig, + new WifiNanSessionCallbackProxy(mLooper, true, callback)); } catch (RemoteException e) { - Log.w(TAG, "createSession/publish RemoteException: " + e); - return null; + Log.w(TAG, "publish RemoteException: " + e); } - - return new WifiNanPublishSession(this, sessionId); } /** * {@hide} */ - public void publish(int sessionId, PublishConfig publishConfig) { - if (VDBG) Log.v(TAG, "publish(): config=" + publishConfig); + public void updatePublish(int sessionId, PublishConfig publishConfig) { + if (VDBG) Log.v(TAG, "updatePublish(): config=" + publishConfig); if (publishConfig.mPublishType == PublishConfig.PUBLISH_TYPE_UNSOLICITED && publishConfig.mRxFilterLength != 0) { @@ -181,26 +215,26 @@ public class WifiNanManager { } try { - mService.publish(mClientId, sessionId, publishConfig); + mService.updatePublish(mClientId, sessionId, publishConfig); } catch (RemoteException e) { - Log.w(TAG, "publish RemoteException: " + e); + Log.w(TAG, "updatePublish RemoteException: " + e); } } /** - * Request a NAN subscribe session. The results of the subscribe session - * operation will result in callbacks to the indicated callback: - * {@link WifiNanSessionCallback WifiNanSessionCallback.on*}. + * Request a NAN subscribe session. The actual subscribe session is provided + * by the + * {@link WifiNanSessionCallback#onSubscribeStarted(WifiNanSubscribeSession)} + * callback. Other results of the subscribe session operation will result in + * callbacks to the indicated callback: {@link WifiNanSessionCallback + * NanSessionCallback.on*} * * @param subscribeConfig The {@link SubscribeConfig} specifying the * configuration of the subscribe session. * @param callback The {@link WifiNanSessionCallback} derived objects to be * used for the event callbacks specified by {@code events}. - * @return The {@link WifiNanSubscribeSession} which can be used to further - * control the subscribe session. */ - public WifiNanSubscribeSession subscribe(SubscribeConfig subscribeConfig, - WifiNanSessionCallback callback) { + public void subscribe(SubscribeConfig subscribeConfig, WifiNanSessionCallback callback) { if (VDBG) { Log.v(TAG, "subscribe(): config=" + subscribeConfig); } @@ -216,24 +250,23 @@ public class WifiNanManager { "Invalid subscribe config: PASSIVE subscribes can't have a Tx filter"); } - int sessionId; + if (mClientId == -1) { + Log.e(TAG, "subscribe(): called without an initial connect()!"); + throw new IllegalStateException("Calling subscribe() without a connect() first!"); + } try { - sessionId = mService.createSession(mClientId, callback.callback); - if (DBG) Log.d(TAG, "subscribe: session created - sessionId=" + sessionId); - mService.subscribe(mClientId, sessionId, subscribeConfig); + mService.subscribe(mClientId, subscribeConfig, + new WifiNanSessionCallbackProxy(mLooper, false, callback)); } catch (RemoteException e) { - Log.w(TAG, "createSession/subscribe RemoteException: " + e); - return null; + Log.w(TAG, "subscribe RemoteException: " + e); } - - return new WifiNanSubscribeSession(this, sessionId); } /** * {@hide} */ - public void subscribe(int sessionId, SubscribeConfig subscribeConfig) { + public void updateSubscribe(int sessionId, SubscribeConfig subscribeConfig) { if (VDBG) { Log.v(TAG, "subscribe(): config=" + subscribeConfig); } @@ -250,35 +283,22 @@ public class WifiNanManager { } try { - mService.subscribe(mClientId, sessionId, subscribeConfig); + mService.updateSubscribe(mClientId, sessionId, subscribeConfig); } catch (RemoteException e) { - Log.w(TAG, "subscribe RemoteException: " + e); + Log.w(TAG, "updateSubscribe RemoteException: " + e); } } /** * {@hide} */ - public void stopSession(int sessionId) { - if (DBG) Log.d(TAG, "Stop NAN session #" + sessionId); + public void terminateSession(int sessionId) { + if (DBG) Log.d(TAG, "Terminate NAN session #" + sessionId); try { - mService.stopSession(mClientId, sessionId); + mService.terminateSession(mClientId, sessionId); } catch (RemoteException e) { - Log.w(TAG, "stopSession RemoteException (FYI - ignoring): " + e); - } - } - - /** - * {@hide} - */ - public void destroySession(int sessionId) { - if (DBG) Log.d(TAG, "Destroy NAN session #" + sessionId); - - try { - mService.destroySession(mClientId, sessionId); - } catch (RemoteException e) { - Log.w(TAG, "destroySession RemoteException (FYI - ignoring): " + e); + Log.w(TAG, "terminateSession RemoteException (FYI - ignoring): " + e); } } @@ -297,4 +317,269 @@ public class WifiNanManager { Log.w(TAG, "subscribe RemoteException (FYI - ignoring): " + e); } } + + private static class WifiNanEventCallbackProxy extends IWifiNanEventCallback.Stub { + private static final int CALLBACK_CONFIG_COMPLETED = 0; + private static final int CALLBACK_CONFIG_FAILED = 1; + private static final int CALLBACK_NAN_DOWN = 2; + private static final int CALLBACK_IDENTITY_CHANGED = 3; + + private final WifiNanEventCallback mOriginalCallback; + private final Handler mHandler; + + /** + * Constructs a {@link WifiNanEventCallback} using the specified looper. + * I.e. all callbacks will delivered on the thread of the specified looper. + * + * @param looper The looper on which to execute the callbacks. + */ + WifiNanEventCallbackProxy(Looper looper, WifiNanEventCallback originalCallback) { + mOriginalCallback = originalCallback; + + if (VDBG) Log.v(TAG, "WifiNanEventCallbackProxy ctor: looper=" + looper); + mHandler = new Handler(looper) { + @Override + public void handleMessage(Message msg) { + if (DBG) Log.d(TAG, "What=" + msg.what + ", msg=" + msg); + switch (msg.what) { + case CALLBACK_CONFIG_COMPLETED: + mOriginalCallback.onConfigCompleted((ConfigRequest) msg.obj); + break; + case CALLBACK_CONFIG_FAILED: + mOriginalCallback.onConfigFailed((ConfigRequest) msg.obj, msg.arg1); + break; + case CALLBACK_NAN_DOWN: + mOriginalCallback.onNanDown(msg.arg1); + break; + case CALLBACK_IDENTITY_CHANGED: + mOriginalCallback.onIdentityChanged(); + break; + } + } + }; + } + + @Override + public void onConfigCompleted(ConfigRequest completedConfig) { + if (VDBG) Log.v(TAG, "onConfigCompleted: configRequest=" + completedConfig); + + Message msg = mHandler.obtainMessage(CALLBACK_CONFIG_COMPLETED); + msg.obj = completedConfig; + mHandler.sendMessage(msg); + } + + @Override + public void onConfigFailed(ConfigRequest failedConfig, int reason) { + if (VDBG) { + Log.v(TAG, + "onConfigFailed: failedConfig=" + failedConfig + ", reason=" + reason); + } + + Message msg = mHandler.obtainMessage(CALLBACK_CONFIG_FAILED); + msg.arg1 = reason; + msg.obj = failedConfig; + mHandler.sendMessage(msg); + } + + @Override + public void onNanDown(int reason) { + if (VDBG) Log.v(TAG, "onNanDown: reason=" + reason); + + Message msg = mHandler.obtainMessage(CALLBACK_NAN_DOWN); + msg.arg1 = reason; + mHandler.sendMessage(msg); + } + + @Override + public void onIdentityChanged() { + if (VDBG) Log.v(TAG, "onIdentityChanged"); + + Message msg = mHandler.obtainMessage(CALLBACK_IDENTITY_CHANGED); + mHandler.sendMessage(msg); + } + } + + private class WifiNanSessionCallbackProxy extends IWifiNanSessionCallback.Stub { + private static final int CALLBACK_SESSION_STARTED = 0; + private static final int CALLBACK_SESSION_CONFIG_FAIL = 1; + private static final int CALLBACK_SESSION_TERMINATED = 2; + private static final int CALLBACK_MATCH = 3; + private static final int CALLBACK_MESSAGE_SEND_SUCCESS = 4; + private static final int CALLBACK_MESSAGE_SEND_FAIL = 5; + private static final int CALLBACK_MESSAGE_RECEIVED = 6; + + private static final String MESSAGE_BUNDLE_KEY_PEER_ID = "peer_id"; + private static final String MESSAGE_BUNDLE_KEY_MESSAGE = "message"; + private static final String MESSAGE_BUNDLE_KEY_MESSAGE2 = "message2"; + + private final boolean mIsPublish; + private final WifiNanSessionCallback mOriginalCallback; + + private final Handler mHandler; + private WifiNanSession mSession; + + WifiNanSessionCallbackProxy(Looper looper, boolean isPublish, + WifiNanSessionCallback originalCallback) { + mIsPublish = isPublish; + mOriginalCallback = originalCallback; + + if (VDBG) Log.v(TAG, "WifiNanSessionCallbackProxy ctor: isPublish=" + isPublish); + + mHandler = new Handler(looper) { + @Override + public void handleMessage(Message msg) { + if (DBG) Log.d(TAG, "What=" + msg.what + ", msg=" + msg); + switch (msg.what) { + case CALLBACK_SESSION_STARTED: + onProxySessionStarted(msg.arg1); + break; + case CALLBACK_SESSION_CONFIG_FAIL: + onProxySessionConfigFail(msg.arg1); + break; + case CALLBACK_SESSION_TERMINATED: + onProxySessionTerminated(msg.arg1); + break; + case CALLBACK_MATCH: + mOriginalCallback.onMatch( + msg.getData().getInt(MESSAGE_BUNDLE_KEY_PEER_ID), + msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE), + msg.arg1, + msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE2), + msg.arg2); + break; + case CALLBACK_MESSAGE_SEND_SUCCESS: + mOriginalCallback.onMessageSendSuccess(msg.arg1); + break; + case CALLBACK_MESSAGE_SEND_FAIL: + mOriginalCallback.onMessageSendFail(msg.arg1, msg.arg2); + break; + case CALLBACK_MESSAGE_RECEIVED: + mOriginalCallback.onMessageReceived(msg.arg2, + msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE), + msg.arg1); + break; + } + } + }; + } + + @Override + public void onSessionStarted(int sessionId) { + if (VDBG) Log.v(TAG, "onSessionStarted: sessionId=" + sessionId); + + Message msg = mHandler.obtainMessage(CALLBACK_SESSION_STARTED); + msg.arg1 = sessionId; + mHandler.sendMessage(msg); + } + + @Override + public void onSessionConfigFail(int reason) { + if (VDBG) Log.v(TAG, "onSessionConfigFail: reason=" + reason); + + Message msg = mHandler.obtainMessage(CALLBACK_SESSION_CONFIG_FAIL); + msg.arg1 = reason; + mHandler.sendMessage(msg); + } + + @Override + public void onSessionTerminated(int reason) { + if (VDBG) Log.v(TAG, "onSessionTerminated: reason=" + reason); + + Message msg = mHandler.obtainMessage(CALLBACK_SESSION_TERMINATED); + msg.arg1 = reason; + mHandler.sendMessage(msg); + } + + @Override + public void onMatch(int peerId, byte[] serviceSpecificInfo, + int serviceSpecificInfoLength, byte[] matchFilter, int matchFilterLength) { + if (VDBG) Log.v(TAG, "onMatch: peerId=" + peerId); + + Bundle data = new Bundle(); + data.putInt(MESSAGE_BUNDLE_KEY_PEER_ID, peerId); + data.putByteArray(MESSAGE_BUNDLE_KEY_MESSAGE, serviceSpecificInfo); + data.putByteArray(MESSAGE_BUNDLE_KEY_MESSAGE2, matchFilter); + + Message msg = mHandler.obtainMessage(CALLBACK_MATCH); + msg.arg1 = serviceSpecificInfoLength; + msg.arg2 = matchFilterLength; + msg.setData(data); + mHandler.sendMessage(msg); + } + + @Override + public void onMessageSendSuccess(int messageId) { + if (VDBG) Log.v(TAG, "onMessageSendSuccess"); + + Message msg = mHandler.obtainMessage(CALLBACK_MESSAGE_SEND_SUCCESS); + msg.arg1 = messageId; + mHandler.sendMessage(msg); + } + + @Override + public void onMessageSendFail(int messageId, int reason) { + if (VDBG) Log.v(TAG, "onMessageSendFail: reason=" + reason); + + Message msg = mHandler.obtainMessage(CALLBACK_MESSAGE_SEND_FAIL); + msg.arg1 = messageId; + msg.arg2 = reason; + mHandler.sendMessage(msg); + } + + @Override + public void onMessageReceived(int peerId, byte[] message, int messageLength) { + if (VDBG) { + Log.v(TAG, "onMessageReceived: peerId='" + peerId + "', messageLength=" + + messageLength); + } + + Bundle data = new Bundle(); + data.putByteArray(MESSAGE_BUNDLE_KEY_MESSAGE, message); + + Message msg = mHandler.obtainMessage(CALLBACK_MESSAGE_RECEIVED); + msg.arg1 = messageLength; + msg.arg2 = peerId; + msg.setData(data); + mHandler.sendMessage(msg); + } + + /* + * Proxied methods + */ + public void onProxySessionStarted(int sessionId) { + if (VDBG) Log.v(TAG, "Proxy: onSessionStarted: sessionId=" + sessionId); + if (mSession != null) { + Log.e(TAG, + "onSessionStarted: sessionId=" + sessionId + ": session already created!?"); + throw new IllegalStateException( + "onSessionStarted: sessionId=" + sessionId + ": session already created!?"); + } + if (mIsPublish) { + WifiNanPublishSession session = new WifiNanPublishSession(WifiNanManager.this, + sessionId, mOriginalCallback); + mSession = session; + mOriginalCallback.onPublishStarted(session); + } else { + WifiNanSubscribeSession session = new WifiNanSubscribeSession(WifiNanManager.this, + sessionId, mOriginalCallback); + mSession = session; + mOriginalCallback.onSubscribeStarted(session); + } + } + + public void onProxySessionConfigFail(int reason) { + if (VDBG) Log.v(TAG, "Proxy: onSessionConfigFail: reason=" + reason); + mOriginalCallback.onSessionConfigFail(reason); + } + + public void onProxySessionTerminated(int reason) { + if (VDBG) Log.v(TAG, "Proxy: onSessionTerminated: reason=" + reason); + mOriginalCallback.onSessionTerminated(reason); + if (mSession != null) { + mSession.terminate(); + } else { + Log.w(TAG, "Proxy: onSessionTerminated called but mSession is null!?"); + } + } + } } diff --git a/wifi/java/android/net/wifi/nan/WifiNanPublishSession.java b/wifi/java/android/net/wifi/nan/WifiNanPublishSession.java index af1cf7d900a3..3b1c0942dea5 100644 --- a/wifi/java/android/net/wifi/nan/WifiNanPublishSession.java +++ b/wifi/java/android/net/wifi/nan/WifiNanPublishSession.java @@ -18,7 +18,7 @@ package android.net.wifi.nan; /** * A representation of a NAN publish session. Created when - * {@link WifiNanManager#publish(PublishConfig, WifiNanSessionCallback, int)} is + * {@link WifiNanManager#publish(PublishConfig, WifiNanSessionCallback)} is * executed. The object can be used to stop and re-start (re-configure) the * publish session. * @@ -28,19 +28,25 @@ public class WifiNanPublishSession extends WifiNanSession { /** * {@hide} */ - public WifiNanPublishSession(WifiNanManager manager, int sessionId) { - super(manager, sessionId); + public WifiNanPublishSession(WifiNanManager manager, int sessionId, + WifiNanSessionCallback callback) { + super(manager, sessionId, callback); } /** - * Restart/re-configure the publish session. Note that the + * Re-configure the publish session. Note that the * {@link WifiNanSessionCallback} is not replaced - the same listener used * at creation is still used. * * @param publishConfig The configuration ({@link PublishConfig}) of the * publish session. */ - public void publish(PublishConfig publishConfig) { - mManager.publish(mSessionId, publishConfig); + public void updatePublish(PublishConfig publishConfig) { + if (mTerminated) { + mCallback.onSessionConfigFail(WifiNanSessionCallback.FAIL_REASON_SESSION_TERMINATED); + return; + } else { + mManager.updatePublish(mSessionId, publishConfig); + } } } diff --git a/wifi/java/android/net/wifi/nan/WifiNanSession.java b/wifi/java/android/net/wifi/nan/WifiNanSession.java index a903583617bf..50df0aa6f17c 100644 --- a/wifi/java/android/net/wifi/nan/WifiNanSession.java +++ b/wifi/java/android/net/wifi/nan/WifiNanSession.java @@ -30,64 +30,44 @@ public class WifiNanSession { private static final boolean DBG = false; private static final boolean VDBG = false; // STOPSHIP if true - /** - * {@hide} - */ protected WifiNanManager mManager; + protected final int mSessionId; + protected final WifiNanSessionCallback mCallback; - /** - * {@hide} - */ - protected int mSessionId; - - /** - * {@hide} - */ - private boolean mDestroyed; + protected boolean mTerminated = false; /** * {@hide} */ - public WifiNanSession(WifiNanManager manager, int sessionId) { + public WifiNanSession(WifiNanManager manager, int sessionId, + WifiNanSessionCallback callback) { if (VDBG) Log.v(TAG, "New client created: manager=" + manager + ", sessionId=" + sessionId); mManager = manager; mSessionId = sessionId; - mDestroyed = false; + mCallback = callback; } /** * Terminate the current publish or subscribe session - i.e. stop * transmitting packet on-air (for an active session) or listening for - * matches (for a passive session). Note that the session may still receive - * incoming messages and may be re-configured/re-started at a later time. + * matches (for a passive session). The session may not be used for any + * additional operations are termination. */ - public void stop() { - mManager.stopSession(mSessionId); + public void terminate() { + mManager.terminateSession(mSessionId); + mTerminated = true; + mManager = null; } - /** - * Destroy the current publish or subscribe session. Performs a - * {@link WifiNanSession#stop()} function but in addition destroys the session - - * it will not be able to receive any messages or to be restarted at a later - * time. - */ - public void destroy() { - mManager.destroySession(mSessionId); - mDestroyed = true; - } - - /** - * {@hide} - */ @Override protected void finalize() throws Throwable { - if (!mDestroyed) { + if (!mTerminated) { Log.w(TAG, "WifiNanSession mSessionId=" + mSessionId - + " was not explicitly destroyed. The session may use resources until " - + "destroyed so step should be done explicitly"); + + " was not explicitly terminated. The session may use resources until " + + "terminated so step should be done explicitly"); } - destroy(); + terminate(); } /** @@ -108,6 +88,12 @@ public class WifiNanSession { * indicated message send success or failure. */ public void sendMessage(int peerId, byte[] message, int messageLength, int messageId) { + if (mTerminated) { + mCallback.onMessageSendFail(messageId, + WifiNanSessionCallback.FAIL_REASON_SESSION_TERMINATED); + return; + } + mManager.sendMessage(mSessionId, peerId, message, messageLength, messageId); } } diff --git a/wifi/java/android/net/wifi/nan/WifiNanSessionCallback.java b/wifi/java/android/net/wifi/nan/WifiNanSessionCallback.java index 974eab8647b9..543836e1bc1b 100644 --- a/wifi/java/android/net/wifi/nan/WifiNanSessionCallback.java +++ b/wifi/java/android/net/wifi/nan/WifiNanSessionCallback.java @@ -16,12 +16,6 @@ package android.net.wifi.nan; -import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.util.Log; - /** * Base class for NAN session events callbacks. Should be extended by * applications wanting notifications. The callbacks are registered when a @@ -36,23 +30,6 @@ import android.util.Log; * @hide PROPOSED_NAN_API */ public class WifiNanSessionCallback { - private static final String TAG = "WifiNanSessionCallback"; - private static final boolean DBG = false; - private static final boolean VDBG = false; // STOPSHIP if true - - /** @hide */ - public static final int CALLBACK_SESSION_CONFIG_FAIL = 0; - /** @hide */ - public static final int CALLBACK_SESSION_TERMINATED = 1; - /** @hide */ - public static final int CALLBACK_MATCH = 2; - /** @hide */ - public static final int CALLBACK_MESSAGE_SEND_SUCCESS = 3; - /** @hide */ - public static final int CALLBACK_MESSAGE_SEND_FAIL = 4; - /** @hide */ - public static final int CALLBACK_MESSAGE_RECEIVED = 5; - /** * Failure reason flag for {@link WifiNanEventCallback} and * {@link WifiNanSessionCallback} callbacks. Indicates no resources to @@ -75,11 +52,21 @@ public class WifiNanSessionCallback { public static final int FAIL_REASON_NO_MATCH_SESSION = 2; /** + * Failure reason flag for {@link WifiNanSessionCallback} callbacks. + * Indicates that a command has been issued to a session which is + * terminated. Session termination may have been caused explicitly by the + * user using the {@code WifiNanSession#terminate()} or implicitly as a + * result of the original session reaching its lifetime or being terminated + * due to an error. + */ + public static final int FAIL_REASON_SESSION_TERMINATED = 3; + + /** * Failure reason flag for {@link WifiNanEventCallback} and * {@link WifiNanSessionCallback} callbacks. Indicates an unspecified error * occurred during the operation. */ - public static final int FAIL_REASON_OTHER = 3; + public static final int FAIL_REASON_OTHER = 4; /** * Failure reason flag for @@ -98,90 +85,51 @@ public class WifiNanSessionCallback { */ public static final int TERMINATE_REASON_FAIL = 1; - private static final String MESSAGE_BUNDLE_KEY_PEER_ID = "peer_id"; - private static final String MESSAGE_BUNDLE_KEY_MESSAGE = "message"; - private static final String MESSAGE_BUNDLE_KEY_MESSAGE2 = "message2"; - - private final Handler mHandler; - /** - * Constructs a {@link WifiNanSessionCallback} using the looper of the - * current thread. I.e. all callbacks will be delivered on the current - * thread. + * Called when a publish operation is started successfully. + * + * @param session The {@link WifiNanPublishSession} used to control the + * discovery session. */ - public WifiNanSessionCallback() { - this(Looper.myLooper()); + public void onPublishStarted(WifiNanPublishSession session) { + /* empty */ } /** - * Constructs a {@link WifiNanSessionCallback} using the specified looper. - * I.e. all callbacks will delivered on the thread of the specified looper. + * Called when a subscribe operation is started successfully. * - * @param looper The looper on which to execute the callbacks. + * @param session The {@link WifiNanSubscribeSession} used to control the + * discovery session. */ - public WifiNanSessionCallback(Looper looper) { - if (VDBG) Log.v(TAG, "ctor: looper=" + looper); - mHandler = new Handler(looper) { - @Override - public void handleMessage(Message msg) { - if (DBG) Log.d(TAG, "What=" + msg.what + ", msg=" + msg); - switch (msg.what) { - case CALLBACK_SESSION_CONFIG_FAIL: - WifiNanSessionCallback.this.onSessionConfigFail(msg.arg1); - break; - case CALLBACK_SESSION_TERMINATED: - WifiNanSessionCallback.this.onSessionTerminated(msg.arg1); - break; - case CALLBACK_MATCH: - WifiNanSessionCallback.this.onMatch( - msg.getData().getInt(MESSAGE_BUNDLE_KEY_PEER_ID), - msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE), msg.arg1, - msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE2), msg.arg2); - break; - case CALLBACK_MESSAGE_SEND_SUCCESS: - WifiNanSessionCallback.this.onMessageSendSuccess(msg.arg1); - break; - case CALLBACK_MESSAGE_SEND_FAIL: - WifiNanSessionCallback.this.onMessageSendFail(msg.arg1, msg.arg2); - break; - case CALLBACK_MESSAGE_RECEIVED: - WifiNanSessionCallback.this.onMessageReceived(msg.arg2, - msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE), msg.arg1); - break; - } - } - }; + public void onSubscribeStarted(WifiNanSubscribeSession session) { + /* empty */ } + /** - * Called when a session configuration (publish or subscribe setup) fails. - * It is dummy method (empty implementation printing out a log message). - * Override to implement your custom response. + * Called when a session configuration (publish or subscribe setup or + * update) fails. * * @param reason The failure reason using * {@code WifiNanSessionCallback.FAIL_*} codes. */ public void onSessionConfigFail(int reason) { - if (VDBG) Log.v(TAG, "onSessionConfigFail: called in stub - override if interested"); + /* empty */ } /** - * Called when a session (publish or subscribe) terminates. A dummy (empty - * implementation printing out a warning). Make sure to override if - * registered. + * Called when a session (publish or subscribe) terminates. * * @param reason The termination reason using * {@code WifiNanSessionCallback.TERMINATE_*} codes. */ public void onSessionTerminated(int reason) { - Log.w(TAG, "onSessionTerminated: called in stub - override if interested or disable"); + /* empty */ } /** * Called when a discovery (publish or subscribe) operation results in a - * match - i.e. when a peer is discovered. It is dummy method (empty - * implementation printing out a log message). Override to implement your - * custom response. + * match - i.e. when a peer is discovered. * * @param peerId The ID of the peer matching our discovery operation. * @param serviceSpecificInfo The service specific information (arbitrary @@ -195,21 +143,20 @@ public class WifiNanSessionCallback { */ public void onMatch(int peerId, byte[] serviceSpecificInfo, int serviceSpecificInfoLength, byte[] matchFilter, int matchFilterLength) { - if (VDBG) Log.v(TAG, "onMatch: called in stub - override if interested"); + /* empty */ } /** * Called when a message is transmitted successfully - i.e. when we know * that it was received successfully (corresponding to an ACK being - * received). It is dummy method (empty implementation printing out a log - * message). Override to implement your custom response. + * received). *

* Note that either this callback or * {@link WifiNanSessionCallback#onMessageSendFail(int, int)} will be * received - never both. */ - public void onMessageSendSuccess(int messageId) { - if (VDBG) Log.v(TAG, "onMessageSendSuccess: called in stub - override if interested"); + public void onMessageSendSuccess(@SuppressWarnings("unused") int messageId) { + /* empty */ } /** @@ -217,8 +164,7 @@ public class WifiNanSessionCallback { * The hardware will usually attempt to re-transmit several times - this * event is received after all retries are exhausted. There is a possibility * that message was received by the destination successfully but the ACK was - * lost. It is dummy method (empty implementation printing out a log - * message). Override to implement your custom response. + * lost *

* Note that either this callback or * {@link WifiNanSessionCallback#onMessageSendSuccess(int)} will be received @@ -227,14 +173,12 @@ public class WifiNanSessionCallback { * @param reason The failure reason using * {@code WifiNanSessionCallback.FAIL_*} codes. */ - public void onMessageSendFail(int messageId, int reason) { - if (VDBG) Log.v(TAG, "onMessageSendFail: called in stub - override if interested"); + public void onMessageSendFail(@SuppressWarnings("unused") int messageId, int reason) { + /* empty */ } /** - * Called when a message is received from a discovery session peer. It is - * dummy method (empty implementation printing out a log message). Override - * to implement your custom response. + * Called when a message is received from a discovery session peer. * * @param peerId The ID of the peer sending the message. * @param message A byte array containing the message. @@ -242,82 +186,6 @@ public class WifiNanSessionCallback { * message bytes. */ public void onMessageReceived(int peerId, byte[] message, int messageLength) { - if (VDBG) Log.v(TAG, "onMessageReceived: called in stub - override if interested"); + /* empty */ } - - /** - * {@hide} - */ - public IWifiNanSessionCallback callback = new IWifiNanSessionCallback.Stub() { - @Override - public void onSessionConfigFail(int reason) { - if (VDBG) Log.v(TAG, "onSessionConfigFail: reason=" + reason); - - Message msg = mHandler.obtainMessage(CALLBACK_SESSION_CONFIG_FAIL); - msg.arg1 = reason; - mHandler.sendMessage(msg); - } - - @Override - public void onSessionTerminated(int reason) { - if (VDBG) Log.v(TAG, "onSessionTerminated: reason=" + reason); - - Message msg = mHandler.obtainMessage(CALLBACK_SESSION_TERMINATED); - msg.arg1 = reason; - mHandler.sendMessage(msg); - } - - @Override - public void onMatch(int peerId, byte[] serviceSpecificInfo, - int serviceSpecificInfoLength, byte[] matchFilter, int matchFilterLength) { - if (VDBG) Log.v(TAG, "onMatch: peerId=" + peerId); - - Bundle data = new Bundle(); - data.putInt(MESSAGE_BUNDLE_KEY_PEER_ID, peerId); - data.putByteArray(MESSAGE_BUNDLE_KEY_MESSAGE, serviceSpecificInfo); - data.putByteArray(MESSAGE_BUNDLE_KEY_MESSAGE2, matchFilter); - - Message msg = mHandler.obtainMessage(CALLBACK_MATCH); - msg.arg1 = serviceSpecificInfoLength; - msg.arg2 = matchFilterLength; - msg.setData(data); - mHandler.sendMessage(msg); - } - - @Override - public void onMessageSendSuccess(int messageId) { - if (VDBG) Log.v(TAG, "onMessageSendSuccess"); - - Message msg = mHandler.obtainMessage(CALLBACK_MESSAGE_SEND_SUCCESS); - msg.arg1 = messageId; - mHandler.sendMessage(msg); - } - - @Override - public void onMessageSendFail(int messageId, int reason) { - if (VDBG) Log.v(TAG, "onMessageSendFail: reason=" + reason); - - Message msg = mHandler.obtainMessage(CALLBACK_MESSAGE_SEND_FAIL); - msg.arg1 = messageId; - msg.arg2 = reason; - mHandler.sendMessage(msg); - } - - @Override - public void onMessageReceived(int peerId, byte[] message, int messageLength) { - if (VDBG) { - Log.v(TAG, "onMessageReceived: peerId='" + peerId + "', messageLength=" - + messageLength); - } - - Bundle data = new Bundle(); - data.putByteArray(MESSAGE_BUNDLE_KEY_MESSAGE, message); - - Message msg = mHandler.obtainMessage(CALLBACK_MESSAGE_RECEIVED); - msg.arg1 = messageLength; - msg.arg2 = peerId; - msg.setData(data); - mHandler.sendMessage(msg); - } - }; } diff --git a/wifi/java/android/net/wifi/nan/WifiNanSubscribeSession.java b/wifi/java/android/net/wifi/nan/WifiNanSubscribeSession.java index aa128a47ce3b..8151fd6b48e9 100644 --- a/wifi/java/android/net/wifi/nan/WifiNanSubscribeSession.java +++ b/wifi/java/android/net/wifi/nan/WifiNanSubscribeSession.java @@ -18,8 +18,8 @@ package android.net.wifi.nan; /** * A representation of a NAN subscribe session. Created when - * {@link WifiNanManager#subscribe(SubscribeConfig, WifiNanSessionCallback, int)} - * is executed. The object can be used to stop and re-start (re-configure) the + * {@link WifiNanManager#subscribe(SubscribeConfig, WifiNanSessionCallback)} is + * executed. The object can be used to stop and re-start (re-configure) the * subscribe session. * * @hide PROPOSED_NAN_API @@ -28,19 +28,25 @@ public class WifiNanSubscribeSession extends WifiNanSession { /** * {@hide} */ - public WifiNanSubscribeSession(WifiNanManager manager, int sessionId) { - super(manager, sessionId); + public WifiNanSubscribeSession(WifiNanManager manager, int sessionId, + WifiNanSessionCallback callback) { + super(manager, sessionId, callback); } /** - * Restart/re-configure the subscribe session. Note that the + * Re-configure the subscribe session. Note that the * {@link WifiNanSessionCallback} is not replaced - the same listener used * at creation is still used. * * @param subscribeConfig The configuration ({@link SubscribeConfig}) of the * subscribe session. */ - public void subscribe(SubscribeConfig subscribeConfig) { - mManager.subscribe(mSessionId, subscribeConfig); + public void updateSubscribe(SubscribeConfig subscribeConfig) { + if (mTerminated) { + mCallback.onSessionConfigFail(WifiNanSessionCallback.FAIL_REASON_SESSION_TERMINATED); + return; + } else { + mManager.updateSubscribe(mSessionId, subscribeConfig); + } } } -- 2.11.0