From 447b03233443dcae816bf3dfaaee5ec0fb77a2f4 Mon Sep 17 00:00:00 2001 From: Etan Cohen Date: Mon, 9 May 2016 15:30:06 -0700 Subject: [PATCH] [NAN] Add support for NAN RTT. Provide API for NAN RTT through WifiNanManager. While NAN RTT could be executed directly through RttManager the peer information is hidden by WifiNanManager (no MAC address is exposed). Using WifiNanManager keeps the information hidden. Bug: 26564277 Change-Id: I8deeb3f9e360dc05f2ea175d115f287590d50322 (cherry picked from commit fb8021c8371357dbb2b73135c89de57ef27e0131) --- wifi/java/android/net/wifi/RttManager.aidl | 5 +- wifi/java/android/net/wifi/RttManager.java | 74 +++++++++- .../net/wifi/nan/IWifiNanEventCallback.aidl | 5 + .../android/net/wifi/nan/IWifiNanManager.aidl | 2 + .../android/net/wifi/nan/WifiNanManager.java | 134 +++++++++++++++++- .../android/net/wifi/nan/WifiNanSession.java | 29 ++++ 6 files changed, 243 insertions(+), 6 deletions(-) diff --git a/wifi/java/android/net/wifi/RttManager.aidl b/wifi/java/android/net/wifi/RttManager.aidl index 5c6d44710ea5c..9479cf0b936e9 100644 --- a/wifi/java/android/net/wifi/RttManager.aidl +++ b/wifi/java/android/net/wifi/RttManager.aidl @@ -15,4 +15,7 @@ */ package android.net.wifi; -parcelable RttManager.RttCapabilities; \ No newline at end of file + +parcelable RttManager.RttCapabilities; +parcelable RttManager.ParcelableRttResults; +parcelable RttManager.ParcelableRttParams; diff --git a/wifi/java/android/net/wifi/RttManager.java b/wifi/java/android/net/wifi/RttManager.java index 590ff1b1bfaa4..c6f1f6819669c 100644 --- a/wifi/java/android/net/wifi/RttManager.java +++ b/wifi/java/android/net/wifi/RttManager.java @@ -472,6 +472,34 @@ public class RttManager { preamble = PREAMBLE_HT; bandwidth = RTT_BW_20_SUPPORT; } + + /** + * {@hide} + */ + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("deviceType=" + deviceType); + sb.append(", requestType=" + requestType); + sb.append(", secure=" + secure); + sb.append(", bssid=" + bssid); + sb.append(", frequency=" + frequency); + sb.append(", channelWidth=" + channelWidth); + sb.append(", centerFreq0=" + centerFreq0); + sb.append(", centerFreq1=" + centerFreq1); + sb.append(", num_samples=" + num_samples); + sb.append(", num_retries=" + num_retries); + sb.append(", numberBurst=" + numberBurst); + sb.append(", interval=" + interval); + sb.append(", numSamplesPerBurst=" + numSamplesPerBurst); + sb.append(", numRetriesPerMeasurementFrame=" + numRetriesPerMeasurementFrame); + sb.append(", numRetriesPerFTMR=" + numRetriesPerFTMR); + sb.append(", LCIRequest=" + LCIRequest); + sb.append(", LCRRequest=" + LCRRequest); + sb.append(", burstTimeout=" + burstTimeout); + sb.append(", preamble=" + preamble); + sb.append(", bandwidth=" + bandwidth); + return sb.toString(); + } } /** pseudo-private class used to parcel arguments */ @@ -727,6 +755,51 @@ public class RttManager { mResults = results; } + /** + * {@hide} + */ + public String toString() { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < mResults.length; ++i) { + sb.append("[" + i + "]: "); + sb.append("bssid=" + mResults[i].bssid); + sb.append(", burstNumber=" + mResults[i].burstNumber); + sb.append(", measurementFrameNumber=" + mResults[i].measurementFrameNumber); + sb.append(", successMeasurementFrameNumber=" + + mResults[i].successMeasurementFrameNumber); + sb.append(", frameNumberPerBurstPeer=" + mResults[i].frameNumberPerBurstPeer); + sb.append(", status=" + mResults[i].status); + sb.append(", requestType=" + mResults[i].requestType); + sb.append(", measurementType=" + mResults[i].measurementType); + sb.append(", retryAfterDuration=" + mResults[i].retryAfterDuration); + sb.append(", ts=" + mResults[i].ts); + sb.append(", rssi=" + mResults[i].rssi); + sb.append(", rssi_spread=" + mResults[i].rssi_spread); + sb.append(", rssiSpread=" + mResults[i].rssiSpread); + sb.append(", tx_rate=" + mResults[i].tx_rate); + sb.append(", txRate=" + mResults[i].txRate); + sb.append(", rxRate=" + mResults[i].rxRate); + sb.append(", rtt_ns=" + mResults[i].rtt_ns); + sb.append(", rtt=" + mResults[i].rtt); + sb.append(", rtt_sd_ns=" + mResults[i].rtt_sd_ns); + sb.append(", rttStandardDeviation=" + mResults[i].rttStandardDeviation); + sb.append(", rtt_spread_ns=" + mResults[i].rtt_spread_ns); + sb.append(", rttSpread=" + mResults[i].rttSpread); + sb.append(", distance_cm=" + mResults[i].distance_cm); + sb.append(", distance=" + mResults[i].distance); + sb.append(", distance_sd_cm=" + mResults[i].distance_sd_cm); + sb.append(", distanceStandardDeviation=" + mResults[i].distanceStandardDeviation); + sb.append(", distance_spread_cm=" + mResults[i].distance_spread_cm); + sb.append(", distanceSpread=" + mResults[i].distanceSpread); + sb.append(", burstDuration=" + mResults[i].burstDuration); + sb.append(", negotiatedBurstNum=" + mResults[i].negotiatedBurstNum); + sb.append(", LCI=" + mResults[i].LCI); + sb.append(", LCR=" + mResults[i].LCR); + sb.append(", secure=" + mResults[i].secure); + } + return sb.toString(); + } + /** Implement the Parcelable interface {@hide} */ @Override public int describeContents() { @@ -1295,4 +1368,3 @@ public class RttManager { } } - diff --git a/wifi/java/android/net/wifi/nan/IWifiNanEventCallback.aidl b/wifi/java/android/net/wifi/nan/IWifiNanEventCallback.aidl index 556877a9e3a7d..b95140e88ae79 100644 --- a/wifi/java/android/net/wifi/nan/IWifiNanEventCallback.aidl +++ b/wifi/java/android/net/wifi/nan/IWifiNanEventCallback.aidl @@ -17,6 +17,7 @@ package android.net.wifi.nan; import android.net.wifi.nan.ConfigRequest; +import android.net.wifi.RttManager; /** * Callback interface that WifiNanManager implements @@ -28,4 +29,8 @@ oneway interface IWifiNanEventCallback void onConnectSuccess(); void onConnectFail(int reason); void onIdentityChanged(); + + void onRangingSuccess(int rangingId, in RttManager.ParcelableRttResults results); + void onRangingFailure(int rangingId, int reason, in String description); + void onRangingAborted(int rangingId); } diff --git a/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl b/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl index ea7906c4982e1..aaf43e53914d2 100644 --- a/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl +++ b/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl @@ -23,6 +23,7 @@ import android.net.wifi.nan.IWifiNanEventCallback; import android.net.wifi.nan.IWifiNanSessionCallback; import android.net.wifi.nan.PublishConfig; import android.net.wifi.nan.SubscribeConfig; +import android.net.wifi.RttManager; /** * Interface that WifiNanService implements @@ -51,4 +52,5 @@ interface IWifiNanManager void sendMessage(int clientId, int sessionId, int peerId, in byte[] message, int messageLength, int messageId); void terminateSession(int clientId, int sessionId); + int startRanging(int clientId, int sessionId, in RttManager.ParcelableRttParams parms); } diff --git a/wifi/java/android/net/wifi/nan/WifiNanManager.java b/wifi/java/android/net/wifi/nan/WifiNanManager.java index b7eb5a6ecb39b..0505291acb2c6 100644 --- a/wifi/java/android/net/wifi/nan/WifiNanManager.java +++ b/wifi/java/android/net/wifi/nan/WifiNanManager.java @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; +import android.net.wifi.RttManager; import android.os.Binder; import android.os.Bundle; import android.os.Handler; @@ -28,10 +29,12 @@ import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.util.Log; +import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import java.lang.ref.WeakReference; +import java.util.Arrays; /** * This class provides the primary API for managing Wi-Fi NAN operation: @@ -91,7 +94,7 @@ public class WifiNanManager { private final IWifiNanManager mService; - private Object mLock = new Object(); // lock access to the following vars + private final Object mLock = new Object(); // lock access to the following vars @GuardedBy("mLock") private final IBinder mBinder = new Binder(); @@ -102,6 +105,9 @@ public class WifiNanManager { @GuardedBy("mLock") private Looper mLooper; + @GuardedBy("mLock") + private SparseArray mRangingListeners = new SparseArray<>(); + /** * {@hide} */ @@ -237,6 +243,7 @@ public class WifiNanManager { @Override protected void finalize() throws Throwable { disconnect(); + super.finalize(); } /** @@ -415,12 +422,63 @@ public class WifiNanManager { } } + /** + * {@hide} + */ + public void startRanging(int sessionId, RttManager.RttParams[] params, + RttManager.RttListener listener) { + if (VDBG) { + Log.v(TAG, "startRanging: sessionId=" + sessionId + ", " + "params=" + + Arrays.toString(params) + ", listener=" + listener); + } + + int clientId; + synchronized (mLock) { + if (mClientId == INVALID_CLIENT_ID) { + Log.e(TAG, "startRanging(): called with invalid client ID - not connected first?"); + return; + } + + clientId = mClientId; + } + + int rangingKey = 0; + try { + rangingKey = mService.startRanging(clientId, sessionId, + new RttManager.ParcelableRttParams(params)); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + + synchronized (mLock) { + mRangingListeners.put(rangingKey, listener); + } + } + private static class WifiNanEventCallbackProxy extends IWifiNanEventCallback.Stub { private static final int CALLBACK_CONNECT_SUCCESS = 0; private static final int CALLBACK_CONNECT_FAIL = 1; private static final int CALLBACK_IDENTITY_CHANGED = 2; + private static final int CALLBACK_RANGING_SUCCESS = 3; + private static final int CALLBACK_RANGING_FAILURE = 4; + private static final int CALLBACK_RANGING_ABORTED = 5; private final Handler mHandler; + private final WeakReference mNanManager; + + RttManager.RttListener getAndRemoveRangingListener(int rangingId) { + WifiNanManager mgr = mNanManager.get(); + if (mgr == null) { + Log.w(TAG, "getAndRemoveRangingListener: called post GC"); + return null; + } + + synchronized (mgr.mLock) { + RttManager.RttListener listener = mgr.mRangingListeners.get(rangingId); + mgr.mRangingListeners.delete(rangingId); + return listener; + } + } /** * Constructs a {@link WifiNanEventCallback} using the specified looper. @@ -430,7 +488,7 @@ public class WifiNanManager { */ WifiNanEventCallbackProxy(WifiNanManager mgr, Looper looper, final WifiNanEventCallback originalCallback) { - final WeakReference nanManager = new WeakReference(mgr); + mNanManager = new WeakReference<>(mgr); if (VDBG) Log.v(TAG, "WifiNanEventCallbackProxy ctor: looper=" + looper); mHandler = new Handler(looper) { @@ -440,7 +498,7 @@ public class WifiNanManager { Log.d(TAG, "WifiNanEventCallbackProxy: What=" + msg.what + ", msg=" + msg); } - WifiNanManager mgr = nanManager.get(); + WifiNanManager mgr = mNanManager.get(); if (mgr == null) { Log.w(TAG, "WifiNanEventCallbackProxy: handleMessage post GC"); return; @@ -455,12 +513,43 @@ public class WifiNanManager { mgr.mLooper = null; mgr.mClientId = INVALID_CLIENT_ID; } - nanManager.clear(); + mNanManager.clear(); originalCallback.onConnectFail(msg.arg1); break; case CALLBACK_IDENTITY_CHANGED: originalCallback.onIdentityChanged(); break; + case CALLBACK_RANGING_SUCCESS: { + RttManager.RttListener listener = getAndRemoveRangingListener(msg.arg1); + if (listener == null) { + Log.e(TAG, "CALLBACK_RANGING_SUCCESS rangingId=" + msg.arg1 + + ": no listener registered (anymore)"); + } else { + listener.onSuccess( + ((RttManager.ParcelableRttResults) msg.obj).mResults); + } + break; + } + case CALLBACK_RANGING_FAILURE: { + RttManager.RttListener listener = getAndRemoveRangingListener(msg.arg1); + if (listener == null) { + Log.e(TAG, "CALLBACK_RANGING_SUCCESS rangingId=" + msg.arg1 + + ": no listener registered (anymore)"); + } else { + listener.onFailure(msg.arg2, (String) msg.obj); + } + break; + } + case CALLBACK_RANGING_ABORTED: { + RttManager.RttListener listener = getAndRemoveRangingListener(msg.arg1); + if (listener == null) { + Log.e(TAG, "CALLBACK_RANGING_SUCCESS rangingId=" + msg.arg1 + + ": no listener registered (anymore)"); + } else { + listener.onAborted(); + } + break; + } } } }; @@ -490,6 +579,43 @@ public class WifiNanManager { Message msg = mHandler.obtainMessage(CALLBACK_IDENTITY_CHANGED); mHandler.sendMessage(msg); } + + @Override + public void onRangingSuccess(int rangingId, RttManager.ParcelableRttResults results) { + if (VDBG) { + Log.v(TAG, "onRangingSuccess: rangingId=" + rangingId + ", results=" + results); + } + + Message msg = mHandler.obtainMessage(CALLBACK_RANGING_SUCCESS); + msg.arg1 = rangingId; + msg.obj = results; + mHandler.sendMessage(msg); + } + + @Override + public void onRangingFailure(int rangingId, int reason, String description) { + if (VDBG) { + Log.v(TAG, "onRangingSuccess: rangingId=" + rangingId + ", reason=" + reason + + ", description=" + description); + } + + Message msg = mHandler.obtainMessage(CALLBACK_RANGING_FAILURE); + msg.arg1 = rangingId; + msg.arg2 = reason; + msg.obj = description; + mHandler.sendMessage(msg); + + } + + @Override + public void onRangingAborted(int rangingId) { + if (VDBG) Log.v(TAG, "onRangingAborted: rangingId=" + rangingId); + + Message msg = mHandler.obtainMessage(CALLBACK_RANGING_ABORTED); + msg.arg1 = rangingId; + mHandler.sendMessage(msg); + + } } private static class WifiNanSessionCallbackProxy extends IWifiNanSessionCallback.Stub { diff --git a/wifi/java/android/net/wifi/nan/WifiNanSession.java b/wifi/java/android/net/wifi/nan/WifiNanSession.java index 890f757d6391e..32872ba8dc6a8 100644 --- a/wifi/java/android/net/wifi/nan/WifiNanSession.java +++ b/wifi/java/android/net/wifi/nan/WifiNanSession.java @@ -16,6 +16,7 @@ package android.net.wifi.nan; +import android.net.wifi.RttManager; import android.util.Log; import java.lang.ref.WeakReference; @@ -97,6 +98,7 @@ public class WifiNanSession { + "terminated so step should be done explicitly"); terminate(); } + super.finalize(); } /** @@ -130,4 +132,31 @@ public class WifiNanSession { mgr.sendMessage(mSessionId, peerId, message, messageLength, messageId); } } + + /** + * Start a ranging operation with the specified peers. The peer IDs are obtained from an + * {@link WifiNanSessionCallback#onMatch(int, byte[], int, byte[], int)} or + * {@link WifiNanSessionCallback#onMessageReceived(int, byte[], int)} operation - i.e. can only + * range devices which are part of an ongoing discovery session. + * + * @param params RTT parameters - each corresponding to a specific peer ID (the array sizes + * must be identical). The + * {@link android.net.wifi.RttManager.RttParams#bssid} member must be set to + * a peer ID - not to a MAC address. + * @param listener The listener to receive the results of the ranging session. + */ + public void startRanging(RttManager.RttParams[] params, RttManager.RttListener listener) { + if (mTerminated) { + Log.w(TAG, "startRanging: called on terminated session"); + return; + } else { + WifiNanManager mgr = mMgr.get(); + if (mgr == null) { + Log.w(TAG, "startRanging: called post GC on WifiNanManager"); + return; + } + + mgr.startRanging(mSessionId, params, listener); + } + } }