From 52b3a24a029e3c5d9436a09b4175f6c49e02d92e Mon Sep 17 00:00:00 2001 From: Etan Cohen Date: Fri, 18 Mar 2016 08:43:38 -0700 Subject: [PATCH] [NAN] Re-factor connect/config flow Simplify flow: configure and connect in a single call. Prevent info leak: no longer provide configuration back to caller. Update error status codes Bug: 27617910 Bug: 27553226 Bug: 27579450 Bug: 27674927 Change-Id: Id7aba816a074dbbe0cb188cfe498c97dccbdcb27 --- .../android/net/wifi/nan/ConfigRequest.java | 68 ++- .../net/wifi/nan/IWifiNanEventCallback.aidl | 4 +- .../android/net/wifi/nan/IWifiNanManager.aidl | 4 +- .../net/wifi/nan/IWifiNanSessionCallback.aidl | 1 + .../android/net/wifi/nan/PublishConfig.java | 49 +- .../android/net/wifi/nan/SubscribeConfig.java | 68 ++- .../net/wifi/nan/WifiNanEventCallback.java | 63 ++- .../android/net/wifi/nan/WifiNanManager.java | 433 +++++++++++------- .../net/wifi/nan/WifiNanPublishSession.java | 19 +- .../android/net/wifi/nan/WifiNanSession.java | 62 ++- .../net/wifi/nan/WifiNanSessionCallback.java | 97 ++-- .../net/wifi/nan/WifiNanSubscribeSession.java | 19 +- 12 files changed, 624 insertions(+), 263 deletions(-) diff --git a/wifi/java/android/net/wifi/nan/ConfigRequest.java b/wifi/java/android/net/wifi/nan/ConfigRequest.java index de6b8a9c505a1..759098e9b0c2e 100644 --- a/wifi/java/android/net/wifi/nan/ConfigRequest.java +++ b/wifi/java/android/net/wifi/nan/ConfigRequest.java @@ -22,9 +22,10 @@ import android.os.Parcelable; /** * Defines a request object to configure a Wi-Fi NAN network. Built using * {@link ConfigRequest.Builder}. Configuration is requested using - * {@link WifiNanManager#requestConfig(ConfigRequest)}. Note that the actual - * achieved configuration may be different from the requested configuration - - * since multiple applications may request different configurations. + * {@link WifiNanManager#connect(android.os.Looper, WifiNanEventCallback, ConfigRequest)} + * . Note that the actual achieved configuration may be different from the + * requested configuration - since multiple applications may request different + * configurations. * * @hide PROPOSED_NAN_API */ @@ -146,6 +147,30 @@ public class ConfigRequest implements Parcelable { && mEnableIdentityChangeCallback == lhs.mEnableIdentityChangeCallback; } + /** + * Checks for equality of two configuration - but only considering their + * on-the-air NAN configuration impact. + * + * @param o Object to compare to. + * @return true if configuration objects have the same on-the-air + * configuration, false otherwise. + * @hide + */ + public boolean equalsOnTheAir(Object o) { + if (this == o) { + return true; + } + + if (!(o instanceof ConfigRequest)) { + return false; + } + + ConfigRequest lhs = (ConfigRequest) o; + + return mSupport5gBand == lhs.mSupport5gBand && mMasterPreference == lhs.mMasterPreference + && mClusterLow == lhs.mClusterLow && mClusterHigh == lhs.mClusterHigh; + } + @Override public int hashCode() { int result = 17; @@ -159,6 +184,39 @@ public class ConfigRequest implements Parcelable { return result; } + /** + * Validates that the contents of the ConfigRequest are valid. Otherwise + * throws an IllegalArgumentException. + * + * @hide + */ + public void validate() throws IllegalArgumentException { + if (mMasterPreference < 0) { + throw new IllegalArgumentException( + "Master Preference specification must be non-negative"); + } + if (mMasterPreference == 1 || mMasterPreference == 255 || mMasterPreference > 255) { + throw new IllegalArgumentException("Master Preference specification must not " + + "exceed 255 or use 1 or 255 (reserved values)"); + } + if (mClusterLow < CLUSTER_ID_MIN) { + throw new IllegalArgumentException("Cluster specification must be non-negative"); + } + if (mClusterLow > CLUSTER_ID_MAX) { + throw new IllegalArgumentException("Cluster specification must not exceed 0xFFFF"); + } + if (mClusterHigh < CLUSTER_ID_MIN) { + throw new IllegalArgumentException("Cluster specification must be non-negative"); + } + if (mClusterHigh > CLUSTER_ID_MAX) { + throw new IllegalArgumentException("Cluster specification must not exceed 0xFFFF"); + } + if (mClusterLow > mClusterHigh) { + throw new IllegalArgumentException( + "Invalid argument combination - must have Cluster Low <= Cluster High"); + } + } + /** * Builder used to build {@link ConfigRequest} objects. */ @@ -175,6 +233,7 @@ public class ConfigRequest implements Parcelable { * @param support5gBand Support for 5G band is required. * @return The builder to facilitate chaining * {@code builder.setXXX(..).setXXX(..)}. + * @hide PROPOSED_NAN_SYSTEM_API */ public Builder setSupport5gBand(boolean support5gBand) { mSupport5gBand = support5gBand; @@ -188,6 +247,7 @@ public class ConfigRequest implements Parcelable { * @param masterPreference The requested master preference * @return The builder to facilitate chaining * {@code builder.setXXX(..).setXXX(..)}. + * @hide PROPOSED_NAN_SYSTEM_API */ public Builder setMasterPreference(int masterPreference) { if (masterPreference < 0) { @@ -214,6 +274,7 @@ public class ConfigRequest implements Parcelable { * @param clusterLow The lower range of the generated cluster ID. * @return The builder to facilitate chaining * {@code builder.setClusterLow(..).setClusterHigh(..)}. + * @hide PROPOSED_NAN_SYSTEM_API */ public Builder setClusterLow(int clusterLow) { if (clusterLow < CLUSTER_ID_MIN) { @@ -238,6 +299,7 @@ public class ConfigRequest implements Parcelable { * @param clusterHigh The upper range of the generated cluster ID. * @return The builder to facilitate chaining * {@code builder.setClusterLow(..).setClusterHigh(..)}. + * @hide PROPOSED_NAN_SYSTEM_API */ public Builder setClusterHigh(int clusterHigh) { if (clusterHigh < CLUSTER_ID_MIN) { diff --git a/wifi/java/android/net/wifi/nan/IWifiNanEventCallback.aidl b/wifi/java/android/net/wifi/nan/IWifiNanEventCallback.aidl index c4ba928bf5493..1e7f26b446fc7 100644 --- a/wifi/java/android/net/wifi/nan/IWifiNanEventCallback.aidl +++ b/wifi/java/android/net/wifi/nan/IWifiNanEventCallback.aidl @@ -25,8 +25,8 @@ import android.net.wifi.nan.ConfigRequest; */ oneway interface IWifiNanEventCallback { - void onConfigCompleted(in ConfigRequest completedConfig); - void onConfigFailed(in ConfigRequest failedConfig, int reason); + void onConnectSuccess(); + void onConnectFail(int reason); void onNanDown(int reason); void onIdentityChanged(); } diff --git a/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl b/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl index 5c64480f0adcf..29f14da083fd9 100644 --- a/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl +++ b/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl @@ -32,9 +32,9 @@ import android.net.wifi.nan.SubscribeConfig; interface IWifiNanManager { // client API - int connect(in IBinder binder, in IWifiNanEventCallback callback); + int connect(in IBinder binder, in IWifiNanEventCallback callback, + in ConfigRequest configRequest); 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, diff --git a/wifi/java/android/net/wifi/nan/IWifiNanSessionCallback.aidl b/wifi/java/android/net/wifi/nan/IWifiNanSessionCallback.aidl index cff3c7e59801f..7162be72a3c5b 100644 --- a/wifi/java/android/net/wifi/nan/IWifiNanSessionCallback.aidl +++ b/wifi/java/android/net/wifi/nan/IWifiNanSessionCallback.aidl @@ -24,6 +24,7 @@ package android.net.wifi.nan; oneway interface IWifiNanSessionCallback { void onSessionStarted(int sessionId); + void onSessionConfigSuccess(); void onSessionConfigFail(int reason); void onSessionTerminated(int reason); diff --git a/wifi/java/android/net/wifi/nan/PublishConfig.java b/wifi/java/android/net/wifi/nan/PublishConfig.java index 01a9ae12a148a..19cd4cf6e8864 100644 --- a/wifi/java/android/net/wifi/nan/PublishConfig.java +++ b/wifi/java/android/net/wifi/nan/PublishConfig.java @@ -24,8 +24,8 @@ import java.util.Arrays; /** * Defines the configuration of a NAN publish session. Built using * {@link PublishConfig.Builder}. Publish is done using - * {@link WifiNanManager#publish(PublishConfig, WifiNanSessionCallback, int)} or - * {@link WifiNanPublishSession#publish(PublishConfig)}. + * {@link WifiNanManager#publish(PublishConfig, WifiNanSessionCallback)} or + * {@link WifiNanPublishSession#updatePublish(PublishConfig)}. * * @hide PROPOSED_NAN_API */ @@ -264,6 +264,45 @@ public class PublishConfig implements Parcelable { return result; } + /** + * Validates that the contents of the PublishConfig are valid. Otherwise + * throws an IllegalArgumentException. + * + * @hide + */ + public void validate() throws IllegalArgumentException { + if (mServiceSpecificInfoLength != 0 && (mServiceSpecificInfo == null + || mServiceSpecificInfo.length < mServiceSpecificInfoLength)) { + throw new IllegalArgumentException("Non-matching combination of " + + "serviceSpecificInfo and serviceSpecificInfoLength"); + } + if (mTxFilterLength != 0 && (mTxFilter == null || mTxFilter.length < mTxFilterLength)) { + throw new IllegalArgumentException( + "Non-matching combination of txFilter and txFilterLength"); + } + if (mRxFilterLength != 0 && (mRxFilter == null || mRxFilter.length < mRxFilterLength)) { + throw new IllegalArgumentException( + "Non-matching combination of rxFilter and rxFilterLength"); + } + if (mPublishType < PUBLISH_TYPE_UNSOLICITED || mPublishType > PUBLISH_TYPE_SOLICITED) { + throw new IllegalArgumentException("Invalid publishType - " + mPublishType); + } + if (mPublishCount < 0) { + throw new IllegalArgumentException("Invalid publishCount - must be non-negative"); + } + if (mTtlSec < 0) { + throw new IllegalArgumentException("Invalid ttlSec - must be non-negative"); + } + if (mPublishType == PublishConfig.PUBLISH_TYPE_UNSOLICITED && mRxFilterLength != 0) { + throw new IllegalArgumentException("Invalid publish config: UNSOLICITED " + + "publishes (active) can't have an Rx filter"); + } + if (mPublishType == PublishConfig.PUBLISH_TYPE_SOLICITED && mTxFilterLength != 0) { + throw new IllegalArgumentException("Invalid publish config: SOLICITED " + + "publishes (passive) can't have a Tx filter"); + } + } + /** * Builder used to build {@link PublishConfig} objects. */ @@ -417,7 +456,7 @@ public class PublishConfig implements Parcelable { * Sets the number of times a solicited ( * {@link PublishConfig.Builder#setPublishType(int)}) publish session * will transmit a packet. When the count is reached an event will be - * generated for {@link WifiNanSessionCallback#onPublishTerminated(int)} + * generated for {@link WifiNanSessionCallback#onSessionTerminated(int)} * with reason={@link WifiNanSessionCallback#TERMINATE_REASON_DONE}. * * @param publishCount Number of publish packets to transmit. @@ -437,7 +476,7 @@ public class PublishConfig implements Parcelable { * {@link PublishConfig.Builder#setPublishCount(int)}) publish session * will be alive - i.e. transmitting a packet. When the TTL is reached * an event will be generated for - * {@link WifiNanSessionCallback#onPublishTerminated(int)} with reason= + * {@link WifiNanSessionCallback#onSessionTerminated(int)} with reason= * {@link WifiNanSessionCallback#TERMINATE_REASON_DONE}. * * @param ttlSec Lifetime of a publish session in seconds. @@ -454,7 +493,7 @@ public class PublishConfig implements Parcelable { /** * Configure whether a publish terminate notification - * {@link WifiNanSessionCallback#onPublishTerminated(int)} is reported + * {@link WifiNanSessionCallback#onSessionTerminated(int)} is reported * back to the callback. * * @param enable If true the terminate callback will be called when the diff --git a/wifi/java/android/net/wifi/nan/SubscribeConfig.java b/wifi/java/android/net/wifi/nan/SubscribeConfig.java index fcf509d931970..50cbc4853bfce 100644 --- a/wifi/java/android/net/wifi/nan/SubscribeConfig.java +++ b/wifi/java/android/net/wifi/nan/SubscribeConfig.java @@ -25,7 +25,7 @@ import java.util.Arrays; * Defines the configuration of a NAN subscribe session. Built using * {@link SubscribeConfig.Builder}. Subscribe is done using * {@link WifiNanManager#subscribe(SubscribeConfig, WifiNanSessionCallback)} or - * {@link WifiNanSubscribeSession#subscribe(SubscribeConfig)}. + * {@link WifiNanSubscribeSession#updateSubscribe(SubscribeConfig)}. * * @hide PROPOSED_NAN_API */ @@ -286,6 +286,49 @@ public class SubscribeConfig implements Parcelable { return result; } + /** + * Validates that the contents of the SubscribeConfig are valid. Otherwise + * throws an IllegalArgumentException. + * + * @hide + */ + public void validate() throws IllegalArgumentException { + if (mServiceSpecificInfoLength != 0 && (mServiceSpecificInfo == null + || mServiceSpecificInfo.length < mServiceSpecificInfoLength)) { + throw new IllegalArgumentException("Non-matching combination of " + + "serviceSpecificInfo and serviceSpecificInfoLength"); + } + if (mTxFilterLength != 0 && (mTxFilter == null || mTxFilter.length < mTxFilterLength)) { + throw new IllegalArgumentException( + "Non-matching combination of txFilter and txFilterLength"); + } + if (mRxFilterLength != 0 && (mRxFilter == null || mRxFilter.length < mRxFilterLength)) { + throw new IllegalArgumentException( + "Non-matching combination of rxFilter and rxFilterLength"); + } + if (mSubscribeType < SUBSCRIBE_TYPE_PASSIVE || mSubscribeType > SUBSCRIBE_TYPE_ACTIVE) { + throw new IllegalArgumentException("Invalid subscribeType - " + mSubscribeType); + } + if (mSubscribeCount < 0) { + throw new IllegalArgumentException("Invalid subscribeCount - must be non-negative"); + } + if (mTtlSec < 0) { + throw new IllegalArgumentException("Invalid ttlSec - must be non-negative"); + } + if (mMatchStyle != MATCH_STYLE_FIRST_ONLY && mMatchStyle != MATCH_STYLE_ALL) { + throw new IllegalArgumentException( + "Invalid matchType - must be MATCH_FIRST_ONLY or MATCH_ALL"); + } + if (mSubscribeType == SubscribeConfig.SUBSCRIBE_TYPE_ACTIVE && mRxFilterLength != 0) { + throw new IllegalArgumentException( + "Invalid subscribe config: ACTIVE subscribes can't have an Rx filter"); + } + if (mSubscribeType == SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE && mTxFilterLength != 0) { + throw new IllegalArgumentException( + "Invalid subscribe config: PASSIVE subscribes can't have a Tx filter"); + } + } + /** * Builder used to build {@link SubscribeConfig} objects. */ @@ -332,6 +375,11 @@ public class SubscribeConfig implements Parcelable { */ public Builder setServiceSpecificInfo(byte[] serviceSpecificInfo, int serviceSpecificInfoLength) { + if (serviceSpecificInfoLength != 0 && (serviceSpecificInfo == null + || serviceSpecificInfo.length < serviceSpecificInfoLength)) { + throw new IllegalArgumentException("Non-matching combination of " + + "serviceSpecificInfo and serviceSpecificInfoLength"); + } mServiceSpecificInfoLength = serviceSpecificInfoLength; mServiceSpecificInfo = serviceSpecificInfo; return this; @@ -374,6 +422,10 @@ public class SubscribeConfig implements Parcelable { * {@code builder.setXXX(..).setXXX(..)}. */ public Builder setTxFilter(byte[] txFilter, int txFilterLength) { + if (txFilterLength != 0 && (txFilter == null || txFilter.length < txFilterLength)) { + throw new IllegalArgumentException( + "Non-matching combination of txFilter and txFilterLength"); + } mTxFilter = txFilter; mTxFilterLength = txFilterLength; return this; @@ -397,6 +449,10 @@ public class SubscribeConfig implements Parcelable { * {@code builder.setXXX(..).setXXX(..)}. */ public Builder setRxFilter(byte[] rxFilter, int rxFilterLength) { + if (rxFilterLength != 0 && (rxFilter == null || rxFilter.length < rxFilterLength)) { + throw new IllegalArgumentException( + "Non-matching combination of rxFilter and rxFilterLength"); + } mRxFilter = rxFilter; mRxFilterLength = rxFilterLength; return this; @@ -427,8 +483,8 @@ public class SubscribeConfig implements Parcelable { * {@link SubscribeConfig.Builder#setSubscribeType(int)}) subscribe * session will transmit a packet. When the count is reached an event * will be generated for - * {@link WifiNanSessionCallback#onSubscribeTerminated(int)} with - * reason= {@link WifiNanSessionCallback#TERMINATE_REASON_DONE}. + * {@link WifiNanSessionCallback#onSessionTerminated(int)} with reason= + * {@link WifiNanSessionCallback#TERMINATE_REASON_DONE}. * * @param subscribeCount Number of subscribe packets to transmit. * @return The builder to facilitate chaining @@ -447,8 +503,8 @@ public class SubscribeConfig implements Parcelable { * {@link SubscribeConfig.Builder#setSubscribeType(int)}) subscribe * session will be alive - i.e. transmitting a packet. When the TTL is * reached an event will be generated for - * {@link WifiNanSessionCallback#onSubscribeTerminated(int)} with - * reason= {@link WifiNanSessionCallback#TERMINATE_REASON_DONE}. + * {@link WifiNanSessionCallback#onSessionTerminated(int)} with reason= + * {@link WifiNanSessionCallback#TERMINATE_REASON_DONE}. * * @param ttlSec Lifetime of a subscribe session in seconds. * @return The builder to facilitate chaining @@ -486,7 +542,7 @@ public class SubscribeConfig implements Parcelable { /** * Configure whether a subscribe terminate notification - * {@link WifiNanSessionCallback#onSubscribeTerminated(int)} is reported + * {@link WifiNanSessionCallback#onSessionTerminated(int)} is reported * back to the callback. * * @param enable If true the terminate callback will be called when the diff --git a/wifi/java/android/net/wifi/nan/WifiNanEventCallback.java b/wifi/java/android/net/wifi/nan/WifiNanEventCallback.java index c243b5b3591ee..41290114ffa8c 100644 --- a/wifi/java/android/net/wifi/nan/WifiNanEventCallback.java +++ b/wifi/java/android/net/wifi/nan/WifiNanEventCallback.java @@ -16,6 +16,11 @@ package android.net.wifi.nan; +import android.annotation.IntDef; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * Base class for NAN events callbacks. Should be extended by applications * wanting notifications. These are callbacks applying to the NAN connection as @@ -25,25 +30,59 @@ package android.net.wifi.nan; * @hide PROPOSED_NAN_API */ public class WifiNanEventCallback { + @IntDef({ + REASON_INVALID_ARGS, REASON_ALREADY_CONNECTED_INCOMPAT_CONFIG, REASON_REQUESTED, + REASON_OTHER }) + @Retention(RetentionPolicy.SOURCE) + public @interface EventReasonCodes { + } + /** - * Called when NAN configuration is completed. - * - * @param completedConfig The actual configuration request which was - * completed. Note that it may be different from that requested - * by the application. The service combines configuration - * requests from all applications. + * Failure reason flag for {@link WifiNanEventCallback} callbacks. Indicates + * invalid argument in the requested operation. */ - public void onConfigCompleted(ConfigRequest completedConfig) { + public static final int REASON_INVALID_ARGS = 1000; + + /** + * Failure reason flag for {@link WifiNanEventCallback} callbacks. Indicates + * that a {@link ConfigRequest} passed in + * {@link WifiNanManager#connect(android.os.Looper, WifiNanEventCallback, ConfigRequest)} + * couldn't be applied since other connections already exist with an + * incompatible configurations. + */ + public static final int REASON_ALREADY_CONNECTED_INCOMPAT_CONFIG = 1001; + + /** + * Reason flag for {@link WifiNanEventCallback#onNanDown(int)} callback. + * Indicates NAN is shut-down per user request. + */ + public static final int REASON_REQUESTED = 1002; + + /** + * Failure reason flag for {@link WifiNanEventCallback} callbacks. Indicates + * an unspecified error occurred during the operation. + */ + public static final int REASON_OTHER = 1003; + + /** + * Called when NAN connect operation + * {@link WifiNanManager#connect(android.os.Looper, WifiNanEventCallback)} + * is completed. Doesn't necessarily mean that have joined or started a NAN + * cluster. An indication is provided by {@link #onIdentityChanged()}. + */ + public void onConnectSuccess() { /* empty */ } /** - * Called when NAN configuration failed. + * Called when NAN connect operation + * {@code WifiNanManager#connect(android.os.Looper, WifiNanEventCallback)} + * failed. * * @param reason Failure reason code, see - * {@code WifiNanSessionCallback.FAIL_*}. + * {@code WifiNanEventCallback.REASON_*}. */ - public void onConfigFailed(@SuppressWarnings("unused") ConfigRequest failedConfig, int reason) { + public void onConnectFail(@EventReasonCodes int reason) { /* empty */ } @@ -51,9 +90,9 @@ public class WifiNanEventCallback { * Called when NAN cluster is down * * @param reason Reason code for event, see - * {@code WifiNanSessionCallback.FAIL_*}. + * {@code WifiNanEventCallback.REASON_*}. */ - public void onNanDown(int reason) { + public void onNanDown(@EventReasonCodes int reason) { /* empty */ } diff --git a/wifi/java/android/net/wifi/nan/WifiNanManager.java b/wifi/java/android/net/wifi/nan/WifiNanManager.java index bb19ee7117c1e..1c333f3bb8cf1 100644 --- a/wifi/java/android/net/wifi/nan/WifiNanManager.java +++ b/wifi/java/android/net/wifi/nan/WifiNanManager.java @@ -25,6 +25,10 @@ import android.os.Message; import android.os.RemoteException; import android.util.Log; +import com.android.internal.annotations.GuardedBy; + +import java.lang.ref.WeakReference; + /** * This class provides the primary API for managing Wi-Fi NAN operation: * including discovery and data-links. Get an instance of this class by calling @@ -45,9 +49,31 @@ public class WifiNanManager { private static final boolean DBG = false; private static final boolean VDBG = false; // STOPSHIP if true + private final IWifiNanManager mService; + + /* + * State transitions: + * UNCONNECTED -- (connect()) --> CONNECTING -- (onConnectSuccess()) --> CONNECTED + * UNCONNECTED -- (connect()) --> CONNECTING -- (onConnectFail()) --> UNCONNECTED + * CONNECTED||CONNECTING -- (disconnect()) --> UNCONNECTED + * CONNECTED||CONNECTING -- onNanDown() --> UNCONNECTED + */ + private static final int STATE_UNCONNECTED = 0; + private static final int STATE_CONNECTING = 1; + private static final int STATE_CONNECTED = 2; + + private Object mLock = new Object(); // lock access to the following vars + + @GuardedBy("mLock") + private int mState = STATE_UNCONNECTED; + + @GuardedBy("mLock") private IBinder mBinder; - private int mClientId = -1; - private IWifiNanManager mService; + + @GuardedBy("mLock") + private int mClientId; + + @GuardedBy("mLock") private Looper mLooper; /** @@ -58,7 +84,7 @@ public class WifiNanManager { } /** - * Re-connect to the Wi-Fi NAN service - enabling the application to execute + * 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 @@ -67,25 +93,45 @@ public class WifiNanManager { * @param callback A callback extended from {@link WifiNanEventCallback}. */ public void connect(Looper looper, WifiNanEventCallback callback) { - if (VDBG) Log.v(TAG, "connect()"); + connect(looper, callback, null); + } - if (callback == null) { - throw new IllegalArgumentException("Invalid callback - must not be null"); + /** + * Connect to the Wi-Fi NAN service - enabling the application to execute + * {@link WifiNanManager} APIs. Allows requesting a specific configuration + * using {@link ConfigRequest} structure. Limited to privileged access. + * + * @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}. + * @param configRequest The requested NAN configuration. + */ + public void connect(Looper looper, WifiNanEventCallback callback, ConfigRequest configRequest) { + if (VDBG) { + Log.v(TAG, "connect(): looper=" + looper + ", callback=" + callback + ", configRequest=" + + configRequest); } - if (mClientId != -1) { - Log.e(TAG, "connect(): mClientId=" + mClientId - + ": seems to calling connect() without disconnecting() first!"); - throw new IllegalStateException("Calling connect() without disconnecting() first!"); - } + synchronized (mLock) { + if (mState != STATE_UNCONNECTED) { + Log.e(TAG, "connect(): Calling connect() when state != UNCONNECTED!"); + return; + } - mLooper = looper; - mBinder = new Binder(); + mLooper = looper; + mBinder = new Binder(); + mState = STATE_CONNECTING; - try { - mClientId = mService.connect(mBinder, new WifiNanEventCallbackProxy(mLooper, callback)); - } catch (RemoteException e) { - Log.w(TAG, "connect RemoteException (FYI - ignoring): " + e); + try { + mClientId = mService.connect(mBinder, + new WifiNanEventCallbackProxy(this, looper, callback), configRequest); + } catch (RemoteException e) { + mLooper = null; + mBinder = null; + mState = STATE_UNCONNECTED; + e.rethrowAsRuntimeException(); + } } } @@ -99,61 +145,39 @@ public class WifiNanManager { * {@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); + if (VDBG) Log.v(TAG, "disconnect()"); + + IBinder binder; + int clientId; + synchronized (mLock) { + if (mState == STATE_UNCONNECTED) { + Log.e(TAG, "disconnect(): called while UNCONNECTED - ignored"); + return; + } + + binder = mBinder; + clientId = mClientId; + + mState = STATE_UNCONNECTED; mBinder = null; - mClientId = -1; + mLooper = null; + mClientId = 0; + } + + try { + mService.disconnect(clientId, binder); } catch (RemoteException e) { - Log.w(TAG, "disconnect RemoteException (FYI - ignoring): " + e); + e.rethrowAsRuntimeException(); } } @Override protected void finalize() throws Throwable { - if (mBinder != null) { - if (DBG) Log.d(TAG, "finalize: disconnect() not called - executing now"); + if (mState != STATE_UNCONNECTED) { 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 - * single cluster. Thus the service may merge configuration requests from - * multiple applications and configure NAN differently from individual - * requests. - *

- * The {@link WifiNanEventCallback#onConfigCompleted(ConfigRequest)} will be - * called when configuration is completed (if a callback is registered for - * this specific event). - * - * @param configRequest The requested NAN configuration. - */ - 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) { - Log.w(TAG, "requestConfig RemoteException (FYI - ignoring): " + e); - } - } - /** * Request a NAN publish session. The actual publish session is provided by * the @@ -170,30 +194,22 @@ public class WifiNanManager { public void publish(PublishConfig publishConfig, WifiNanSessionCallback callback) { if (VDBG) Log.v(TAG, "publish(): config=" + publishConfig); - if (publishConfig.mPublishType == PublishConfig.PUBLISH_TYPE_UNSOLICITED - && publishConfig.mRxFilterLength != 0) { - throw new IllegalArgumentException("Invalid publish config: UNSOLICITED " - + "publishes (active) can't have an Rx filter"); - } - if (publishConfig.mPublishType == PublishConfig.PUBLISH_TYPE_SOLICITED - && publishConfig.mTxFilterLength != 0) { - throw new IllegalArgumentException("Invalid publish config: SOLICITED " - + "publishes (passive) can't have a Tx filter"); - } - if (callback == null) { - throw new IllegalArgumentException("Invalid callback - must not be null"); - } + int clientId; + Looper looper; + synchronized (mLock) { + if (mState != STATE_CONNECTED) { + Log.e(TAG, "publish(): called when not CONNECTED!"); + return; + } - if (mClientId == -1) { - Log.e(TAG, "publish(): called without an initial connect()!"); - throw new IllegalStateException("Calling publish() without a connect() first!"); + clientId = mClientId; + looper = mLooper; } - try { - mService.publish(mClientId, publishConfig, - new WifiNanSessionCallbackProxy(mLooper, true, callback)); + mService.publish(clientId, publishConfig, + new WifiNanSessionCallbackProxy(this, looper, true, callback)); } catch (RemoteException e) { - Log.w(TAG, "publish RemoteException: " + e); + e.rethrowAsRuntimeException(); } } @@ -203,21 +219,19 @@ public class WifiNanManager { 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) { - throw new IllegalArgumentException("Invalid publish config: UNSOLICITED " - + "publishes (active) can't have an Rx filter"); - } - if (publishConfig.mPublishType == PublishConfig.PUBLISH_TYPE_SOLICITED - && publishConfig.mTxFilterLength != 0) { - throw new IllegalArgumentException("Invalid publish config: SOLICITED " - + "publishes (passive) can't have a Tx filter"); - } + int clientId; + synchronized (mLock) { + if (mState != STATE_CONNECTED) { + Log.e(TAG, "updatePublish(): called when not CONNECTED)!"); + return; + } + clientId = mClientId; + } try { - mService.updatePublish(mClientId, sessionId, publishConfig); + mService.updatePublish(clientId, sessionId, publishConfig); } catch (RemoteException e) { - Log.w(TAG, "updatePublish RemoteException: " + e); + e.rethrowAsRuntimeException(); } } @@ -239,27 +253,23 @@ public class WifiNanManager { Log.v(TAG, "subscribe(): config=" + subscribeConfig); } - if (subscribeConfig.mSubscribeType == SubscribeConfig.SUBSCRIBE_TYPE_ACTIVE - && subscribeConfig.mRxFilterLength != 0) { - throw new IllegalArgumentException( - "Invalid subscribe config: ACTIVE subscribes can't have an Rx filter"); - } - if (subscribeConfig.mSubscribeType == SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE - && subscribeConfig.mTxFilterLength != 0) { - throw new IllegalArgumentException( - "Invalid subscribe config: PASSIVE subscribes can't have a Tx filter"); - } + int clientId; + Looper looper; + synchronized (mLock) { + if (mState != STATE_CONNECTED) { + Log.e(TAG, "subscribe(): called when not CONNECTED!"); + return; + } - if (mClientId == -1) { - Log.e(TAG, "subscribe(): called without an initial connect()!"); - throw new IllegalStateException("Calling subscribe() without a connect() first!"); + clientId = mClientId; + looper = mLooper; } try { - mService.subscribe(mClientId, subscribeConfig, - new WifiNanSessionCallbackProxy(mLooper, false, callback)); + mService.subscribe(clientId, subscribeConfig, + new WifiNanSessionCallbackProxy(this, looper, false, callback)); } catch (RemoteException e) { - Log.w(TAG, "subscribe RemoteException: " + e); + e.rethrowAsRuntimeException(); } } @@ -271,21 +281,20 @@ public class WifiNanManager { Log.v(TAG, "subscribe(): config=" + subscribeConfig); } - if (subscribeConfig.mSubscribeType == SubscribeConfig.SUBSCRIBE_TYPE_ACTIVE - && subscribeConfig.mRxFilterLength != 0) { - throw new IllegalArgumentException( - "Invalid subscribe config: ACTIVE subscribes can't have an Rx filter"); - } - if (subscribeConfig.mSubscribeType == SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE - && subscribeConfig.mTxFilterLength != 0) { - throw new IllegalArgumentException( - "Invalid subscribe config: PASSIVE subscribes can't have a Tx filter"); + int clientId; + synchronized (mLock) { + if (mState != STATE_CONNECTED) { + Log.e(TAG, "updateSubscribe(): called when not CONNECTED!"); + return; + } + + clientId = mClientId; } try { - mService.updateSubscribe(mClientId, sessionId, subscribeConfig); + mService.updateSubscribe(clientId, sessionId, subscribeConfig); } catch (RemoteException e) { - Log.w(TAG, "updateSubscribe RemoteException: " + e); + e.rethrowAsRuntimeException(); } } @@ -295,10 +304,20 @@ public class WifiNanManager { public void terminateSession(int sessionId) { if (DBG) Log.d(TAG, "Terminate NAN session #" + sessionId); + int clientId; + synchronized (mLock) { + if (mState != STATE_CONNECTED) { + Log.e(TAG, "terminateSession(): called when not CONNECTED!"); + return; + } + + clientId = mClientId; + } + try { - mService.terminateSession(mClientId, sessionId); + mService.terminateSession(clientId, sessionId); } catch (RemoteException e) { - Log.w(TAG, "terminateSession RemoteException (FYI - ignoring): " + e); + e.rethrowAsRuntimeException(); } } @@ -307,24 +326,34 @@ public class WifiNanManager { */ public void sendMessage(int sessionId, int peerId, byte[] message, int messageLength, int messageId) { - try { - if (VDBG) { - Log.v(TAG, "sendMessage(): sessionId=" + sessionId + ", peerId=" + peerId - + ", messageLength=" + messageLength + ", messageId=" + messageId); + if (VDBG) { + Log.v(TAG, "sendMessage(): sessionId=" + sessionId + ", peerId=" + peerId + + ", messageLength=" + messageLength + ", messageId=" + messageId); + } + + int clientId; + synchronized (mLock) { + if (mState != STATE_CONNECTED) { + Log.e(TAG, "sendMessage(): called when not CONNECTED!"); + return; } - mService.sendMessage(mClientId, sessionId, peerId, message, messageLength, messageId); + + clientId = mClientId; + } + + try { + mService.sendMessage(clientId, sessionId, peerId, message, messageLength, messageId); } catch (RemoteException e) { - Log.w(TAG, "subscribe RemoteException (FYI - ignoring): " + e); + e.rethrowAsRuntimeException(); } } 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_CONNECT_SUCCESS = 0; + private static final int CALLBACK_CONNECT_FAIL = 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; /** @@ -333,26 +362,64 @@ public class WifiNanManager { * * @param looper The looper on which to execute the callbacks. */ - WifiNanEventCallbackProxy(Looper looper, WifiNanEventCallback originalCallback) { - mOriginalCallback = originalCallback; + WifiNanEventCallbackProxy(WifiNanManager mgr, Looper looper, + final WifiNanEventCallback originalCallback) { + final WeakReference nanManager = new WeakReference(mgr); 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); + if (DBG) { + Log.d(TAG, "WifiNanEventCallbackProxy: What=" + msg.what + ", msg=" + msg); + } + + WifiNanManager mgr = nanManager.get(); + if (mgr == null) { + Log.w(TAG, "WifiNanEventCallbackProxy: handleMessage post GC"); + return; + } + switch (msg.what) { - case CALLBACK_CONFIG_COMPLETED: - mOriginalCallback.onConfigCompleted((ConfigRequest) msg.obj); + case CALLBACK_CONNECT_SUCCESS: + synchronized (mgr.mLock) { + if (mgr.mState != STATE_CONNECTING) { + Log.w(TAG, "onConnectSuccess indication received but not in " + + "CONNECTING state. Ignoring."); + return; + } + mgr.mState = STATE_CONNECTED; + } + originalCallback.onConnectSuccess(); break; - case CALLBACK_CONFIG_FAILED: - mOriginalCallback.onConfigFailed((ConfigRequest) msg.obj, msg.arg1); + case CALLBACK_CONNECT_FAIL: + synchronized (mgr.mLock) { + if (mgr.mState != STATE_CONNECTING) { + Log.w(TAG, "onConnectFail indication received but not in " + + "CONNECTING state. Ignoring."); + return; + } + + mgr.mState = STATE_UNCONNECTED; + mgr.mBinder = null; + mgr.mLooper = null; + mgr.mClientId = 0; + } + nanManager.clear(); + originalCallback.onConnectFail(msg.arg1); break; case CALLBACK_NAN_DOWN: - mOriginalCallback.onNanDown(msg.arg1); + synchronized (mgr.mLock) { + mgr.mState = STATE_UNCONNECTED; + mgr.mBinder = null; + mgr.mLooper = null; + mgr.mClientId = 0; + } + nanManager.clear(); + originalCallback.onNanDown(msg.arg1); break; case CALLBACK_IDENTITY_CHANGED: - mOriginalCallback.onIdentityChanged(); + originalCallback.onIdentityChanged(); break; } } @@ -360,24 +427,19 @@ public class WifiNanManager { } @Override - public void onConfigCompleted(ConfigRequest completedConfig) { - if (VDBG) Log.v(TAG, "onConfigCompleted: configRequest=" + completedConfig); + public void onConnectSuccess() { + if (VDBG) Log.v(TAG, "onConnectSuccess"); - Message msg = mHandler.obtainMessage(CALLBACK_CONFIG_COMPLETED); - msg.obj = completedConfig; + Message msg = mHandler.obtainMessage(CALLBACK_CONNECT_SUCCESS); mHandler.sendMessage(msg); } @Override - public void onConfigFailed(ConfigRequest failedConfig, int reason) { - if (VDBG) { - Log.v(TAG, - "onConfigFailed: failedConfig=" + failedConfig + ", reason=" + reason); - } + public void onConnectFail(int reason) { + if (VDBG) Log.v(TAG, "onConfigFailed: reason=" + reason); - Message msg = mHandler.obtainMessage(CALLBACK_CONFIG_FAILED); + Message msg = mHandler.obtainMessage(CALLBACK_CONNECT_FAIL); msg.arg1 = reason; - msg.obj = failedConfig; mHandler.sendMessage(msg); } @@ -399,27 +461,30 @@ public class WifiNanManager { } } - private class WifiNanSessionCallbackProxy extends IWifiNanSessionCallback.Stub { + private static 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 int CALLBACK_SESSION_CONFIG_SUCCESS = 1; + private static final int CALLBACK_SESSION_CONFIG_FAIL = 2; + private static final int CALLBACK_SESSION_TERMINATED = 3; + private static final int CALLBACK_MATCH = 4; + private static final int CALLBACK_MESSAGE_SEND_SUCCESS = 5; + private static final int CALLBACK_MESSAGE_SEND_FAIL = 6; + private static final int CALLBACK_MESSAGE_RECEIVED = 7; 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 WeakReference mNanManager; private final boolean mIsPublish; private final WifiNanSessionCallback mOriginalCallback; private final Handler mHandler; private WifiNanSession mSession; - WifiNanSessionCallbackProxy(Looper looper, boolean isPublish, + WifiNanSessionCallbackProxy(WifiNanManager mgr, Looper looper, boolean isPublish, WifiNanSessionCallback originalCallback) { + mNanManager = new WeakReference<>(mgr); mIsPublish = isPublish; mOriginalCallback = originalCallback; @@ -429,12 +494,28 @@ public class WifiNanManager { @Override public void handleMessage(Message msg) { if (DBG) Log.d(TAG, "What=" + msg.what + ", msg=" + msg); + + if (mNanManager.get() == null) { + Log.w(TAG, "WifiNanSessionCallbackProxy: handleMessage post GC"); + return; + } + switch (msg.what) { case CALLBACK_SESSION_STARTED: onProxySessionStarted(msg.arg1); break; + case CALLBACK_SESSION_CONFIG_SUCCESS: + mOriginalCallback.onSessionConfigSuccess(); + break; case CALLBACK_SESSION_CONFIG_FAIL: - onProxySessionConfigFail(msg.arg1); + mOriginalCallback.onSessionConfigFail(msg.arg1); + if (mSession == null) { + /* + * creation failed (as opposed to update + * failing) + */ + mNanManager.clear(); + } break; case CALLBACK_SESSION_TERMINATED: onProxySessionTerminated(msg.arg1); @@ -472,6 +553,14 @@ public class WifiNanManager { mHandler.sendMessage(msg); } + @Override + public void onSessionConfigSuccess() { + if (VDBG) Log.v(TAG, "onSessionConfigSuccess"); + + Message msg = mHandler.obtainMessage(CALLBACK_SESSION_CONFIG_SUCCESS); + mHandler.sendMessage(msg); + } + @Override public void onSessionConfigFail(int reason) { if (VDBG) Log.v(TAG, "onSessionConfigFail: reason=" + reason); @@ -554,32 +643,34 @@ public class WifiNanManager { throw new IllegalStateException( "onSessionStarted: sessionId=" + sessionId + ": session already created!?"); } + + WifiNanManager mgr = mNanManager.get(); + if (mgr == null) { + Log.w(TAG, "onProxySessionStarted: mgr GC'd"); + return; + } + if (mIsPublish) { - WifiNanPublishSession session = new WifiNanPublishSession(WifiNanManager.this, - sessionId, mOriginalCallback); + WifiNanPublishSession session = new WifiNanPublishSession(mgr, sessionId); mSession = session; mOriginalCallback.onPublishStarted(session); } else { - WifiNanSubscribeSession session = new WifiNanSubscribeSession(WifiNanManager.this, - sessionId, mOriginalCallback); + WifiNanSubscribeSession session = new WifiNanSubscribeSession(mgr, sessionId); 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(); + mSession.setTerminated(); + mSession = null; } else { Log.w(TAG, "Proxy: onSessionTerminated called but mSession is null!?"); } + mNanManager.clear(); + mOriginalCallback.onSessionTerminated(reason); } } } diff --git a/wifi/java/android/net/wifi/nan/WifiNanPublishSession.java b/wifi/java/android/net/wifi/nan/WifiNanPublishSession.java index 3b1c0942dea59..27e4a54640bf2 100644 --- a/wifi/java/android/net/wifi/nan/WifiNanPublishSession.java +++ b/wifi/java/android/net/wifi/nan/WifiNanPublishSession.java @@ -16,6 +16,8 @@ package android.net.wifi.nan; +import android.util.Log; + /** * A representation of a NAN publish session. Created when * {@link WifiNanManager#publish(PublishConfig, WifiNanSessionCallback)} is @@ -25,12 +27,13 @@ package android.net.wifi.nan; * @hide PROPOSED_NAN_API */ public class WifiNanPublishSession extends WifiNanSession { + private static final String TAG = "WifiNanPublishSession"; + /** * {@hide} */ - public WifiNanPublishSession(WifiNanManager manager, int sessionId, - WifiNanSessionCallback callback) { - super(manager, sessionId, callback); + public WifiNanPublishSession(WifiNanManager manager, int sessionId) { + super(manager, sessionId); } /** @@ -43,10 +46,16 @@ public class WifiNanPublishSession extends WifiNanSession { */ public void updatePublish(PublishConfig publishConfig) { if (mTerminated) { - mCallback.onSessionConfigFail(WifiNanSessionCallback.FAIL_REASON_SESSION_TERMINATED); + Log.w(TAG, "updatePublish: called on terminated session"); return; } else { - mManager.updatePublish(mSessionId, publishConfig); + WifiNanManager mgr = mMgr.get(); + if (mgr == null) { + Log.w(TAG, "updatePublish: called post GC on WifiNanManager"); + return; + } + + mgr.updatePublish(mSessionId, publishConfig); } } } diff --git a/wifi/java/android/net/wifi/nan/WifiNanSession.java b/wifi/java/android/net/wifi/nan/WifiNanSession.java index 50df0aa6f17c4..890f757d6391e 100644 --- a/wifi/java/android/net/wifi/nan/WifiNanSession.java +++ b/wifi/java/android/net/wifi/nan/WifiNanSession.java @@ -18,6 +18,8 @@ package android.net.wifi.nan; import android.util.Log; +import java.lang.ref.WeakReference; + /** * A representation of a single publish or subscribe NAN session. This object * will not be created directly - only its child classes are available: @@ -30,22 +32,29 @@ public class WifiNanSession { private static final boolean DBG = false; private static final boolean VDBG = false; // STOPSHIP if true - protected WifiNanManager mManager; - protected final int mSessionId; - protected final WifiNanSessionCallback mCallback; + /** + * @hide + */ + protected WeakReference mMgr; + /** + * @hide + */ + protected final int mSessionId; + + /** + * @hide + */ protected boolean mTerminated = false; /** * {@hide} */ - public WifiNanSession(WifiNanManager manager, int sessionId, - WifiNanSessionCallback callback) { + public WifiNanSession(WifiNanManager manager, int sessionId) { if (VDBG) Log.v(TAG, "New client created: manager=" + manager + ", sessionId=" + sessionId); - mManager = manager; + mMgr = new WeakReference<>(manager); mSessionId = sessionId; - mCallback = callback; } /** @@ -55,9 +64,29 @@ public class WifiNanSession { * additional operations are termination. */ public void terminate() { - mManager.terminateSession(mSessionId); + WifiNanManager mgr = mMgr.get(); + if (mgr == null) { + Log.w(TAG, "terminate: called post GC on WifiNanManager"); + return; + } + mgr.terminateSession(mSessionId); mTerminated = true; - mManager = null; + mMgr.clear(); + } + + /** + * Sets the status of the session to terminated - i.e. an indication that + * already terminated rather than executing a termination. + * + * @hide + */ + public void setTerminated() { + if (mTerminated) { + Log.w(TAG, "terminate: already terminated."); + return; + } + mTerminated = true; + mMgr.clear(); } @Override @@ -66,8 +95,8 @@ public class WifiNanSession { Log.w(TAG, "WifiNanSession mSessionId=" + mSessionId + " was not explicitly terminated. The session may use resources until " + "terminated so step should be done explicitly"); + terminate(); } - terminate(); } /** @@ -89,11 +118,16 @@ public class WifiNanSession { */ public void sendMessage(int peerId, byte[] message, int messageLength, int messageId) { if (mTerminated) { - mCallback.onMessageSendFail(messageId, - WifiNanSessionCallback.FAIL_REASON_SESSION_TERMINATED); + Log.w(TAG, "sendMessage: called on terminated session"); return; - } + } else { + WifiNanManager mgr = mMgr.get(); + if (mgr == null) { + Log.w(TAG, "sendMessage: called post GC on WifiNanManager"); + return; + } - mManager.sendMessage(mSessionId, peerId, message, messageLength, messageId); + mgr.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 543836e1bc1b4..baa22cc26fb9d 100644 --- a/wifi/java/android/net/wifi/nan/WifiNanSessionCallback.java +++ b/wifi/java/android/net/wifi/nan/WifiNanSessionCallback.java @@ -16,57 +16,70 @@ package android.net.wifi.nan; +import android.annotation.IntDef; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * Base class for NAN session events callbacks. Should be extended by * applications wanting notifications. The callbacks are registered when a * publish or subscribe session is created using * {@link WifiNanManager#publish(PublishConfig, WifiNanSessionCallback)} or * {@link WifiNanManager#subscribe(SubscribeConfig, WifiNanSessionCallback)} . - * These are callbacks applying to a specific NAN session. Events corresponding - * to the NAN link are delivered using {@link WifiNanEventCallback}. + * These are callbacks applying to a specific NAN session. *

* A single callback is registered at session creation - it cannot be replaced. * * @hide PROPOSED_NAN_API */ public class WifiNanSessionCallback { - /** - * Failure reason flag for {@link WifiNanEventCallback} and - * {@link WifiNanSessionCallback} callbacks. Indicates no resources to - * execute the requested operation. - */ - public static final int FAIL_REASON_NO_RESOURCES = 0; + @IntDef({ + REASON_NO_RESOURCES, REASON_INVALID_ARGS, REASON_NO_MATCH_SESSION, + REASON_TX_FAIL, REASON_OTHER }) + @Retention(RetentionPolicy.SOURCE) + public @interface SessionReasonCodes { + } - /** - * Failure reason flag for {@link WifiNanEventCallback} and - * {@link WifiNanSessionCallback} callbacks. Indicates invalid argument in - * the requested operation. - */ - public static final int FAIL_REASON_INVALID_ARGS = 1; - - /** - * Failure reason flag for {@link WifiNanEventCallback} and - * {@link WifiNanSessionCallback} callbacks. Indicates a message is - * transmitted without a match (i.e. a discovery) occurring first. - */ - public static final int FAIL_REASON_NO_MATCH_SESSION = 2; + @IntDef({ + TERMINATE_REASON_DONE, TERMINATE_REASON_FAIL }) + @Retention(RetentionPolicy.SOURCE) + public @interface SessionTerminateCodes { + } /** * 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. + * Indicates no resources to execute the requested operation. */ - public static final int FAIL_REASON_SESSION_TERMINATED = 3; + public static final int REASON_NO_RESOURCES = 0; /** - * Failure reason flag for {@link WifiNanEventCallback} and - * {@link WifiNanSessionCallback} callbacks. Indicates an unspecified error - * occurred during the operation. + * Failure reason flag for {@link WifiNanSessionCallback} callbacks. + * Indicates invalid argument in the requested operation. */ - public static final int FAIL_REASON_OTHER = 4; + public static final int REASON_INVALID_ARGS = 1; + + /** + * Failure reason flag for {@link WifiNanSessionCallback} callbacks. + * Indicates a message is transmitted without a match (i.e. a discovery) + * occurring first. + */ + public static final int REASON_NO_MATCH_SESSION = 2; + + /** + * Failure reason flag for + * {@link WifiNanSessionCallback#onMessageSendFail(int, int)} callback. + * Indicates transmission failure: this may be due to local transmission + * failure or to no ACK received - i.e. remote device didn't receive the + * sent message. + */ + public static final int REASON_TX_FAIL = 3; + + /** + * Failure reason flag for {@link WifiNanSessionCallback} callbacks. + * Indicates an unspecified error occurred during the operation. + */ + public static final int REASON_OTHER = 4; /** * Failure reason flag for @@ -75,7 +88,7 @@ public class WifiNanSessionCallback { * requested operations (per {@link PublishConfig} or * {@link SubscribeConfig}) have been executed. */ - public static final int TERMINATE_REASON_DONE = 0; + public static final int TERMINATE_REASON_DONE = 100; /** * Failure reason flag for @@ -83,7 +96,7 @@ public class WifiNanSessionCallback { * Indicates that publish or subscribe session is terminated due to a * failure. */ - public static final int TERMINATE_REASON_FAIL = 1; + public static final int TERMINATE_REASON_FAIL = 101; /** * Called when a publish operation is started successfully. @@ -105,15 +118,22 @@ public class WifiNanSessionCallback { /* empty */ } + /** + * Called when a session update configuration (publish or subscribe update) + * succeeds. + */ + public void onSessionConfigSuccess() { + /* empty */ + } /** * Called when a session configuration (publish or subscribe setup or * update) fails. * * @param reason The failure reason using - * {@code WifiNanSessionCallback.FAIL_*} codes. + * {@code WifiNanSessionCallback.REASON_*} codes. */ - public void onSessionConfigFail(int reason) { + public void onSessionConfigFail(@SessionReasonCodes int reason) { /* empty */ } @@ -123,7 +143,7 @@ public class WifiNanSessionCallback { * @param reason The termination reason using * {@code WifiNanSessionCallback.TERMINATE_*} codes. */ - public void onSessionTerminated(int reason) { + public void onSessionTerminated(@SessionTerminateCodes int reason) { /* empty */ } @@ -171,9 +191,10 @@ public class WifiNanSessionCallback { * - never both * * @param reason The failure reason using - * {@code WifiNanSessionCallback.FAIL_*} codes. + * {@code WifiNanSessionCallback.REASON_*} codes. */ - public void onMessageSendFail(@SuppressWarnings("unused") int messageId, int reason) { + public void onMessageSendFail(@SuppressWarnings("unused") int messageId, + @SessionReasonCodes int reason) { /* empty */ } diff --git a/wifi/java/android/net/wifi/nan/WifiNanSubscribeSession.java b/wifi/java/android/net/wifi/nan/WifiNanSubscribeSession.java index 8151fd6b48e91..0b2d231485b3c 100644 --- a/wifi/java/android/net/wifi/nan/WifiNanSubscribeSession.java +++ b/wifi/java/android/net/wifi/nan/WifiNanSubscribeSession.java @@ -16,6 +16,8 @@ package android.net.wifi.nan; +import android.util.Log; + /** * A representation of a NAN subscribe session. Created when * {@link WifiNanManager#subscribe(SubscribeConfig, WifiNanSessionCallback)} is @@ -25,12 +27,13 @@ package android.net.wifi.nan; * @hide PROPOSED_NAN_API */ public class WifiNanSubscribeSession extends WifiNanSession { + private static final String TAG = "WifiNanSubscribeSession"; + /** * {@hide} */ - public WifiNanSubscribeSession(WifiNanManager manager, int sessionId, - WifiNanSessionCallback callback) { - super(manager, sessionId, callback); + public WifiNanSubscribeSession(WifiNanManager manager, int sessionId) { + super(manager, sessionId); } /** @@ -43,10 +46,16 @@ public class WifiNanSubscribeSession extends WifiNanSession { */ public void updateSubscribe(SubscribeConfig subscribeConfig) { if (mTerminated) { - mCallback.onSessionConfigFail(WifiNanSessionCallback.FAIL_REASON_SESSION_TERMINATED); + Log.w(TAG, "updateSubscribe: called on terminated session"); return; } else { - mManager.updateSubscribe(mSessionId, subscribeConfig); + WifiNanManager mgr = mMgr.get(); + if (mgr == null) { + Log.w(TAG, "updateSubscribe: called post GC on WifiNanManager"); + return; + } + + mgr.updateSubscribe(mSessionId, subscribeConfig); } } }