diff options
author | Etan Cohen <etancohen@google.com> | 2018-08-22 08:51:37 -0700 |
---|---|---|
committer | Etan Cohen <etancohen@google.com> | 2018-10-05 07:41:14 -0700 |
commit | d71b53361125ea4f7340426c5e6c90bb10561dab (patch) | |
tree | 6b998d4f6de108f586884facf3f81b54e307bf7d | |
parent | 6d4cc3ccb1d19e3ee28ae31280ab0bc0bb068afd (diff) |
[RTT] Handle HAL concurrencly limitations on RTT availability
The chip may not support RTT in all modes. The change handles this
correctly: whenever the HAL cannot support RTT (e.g. for multi-mode
chips + switching to AP mode only) the framework will be notified
and can dispatch RTT availability notification to app (both when
becoming non-available and then when becoming available again).
This notification on exact status also fixes the following:
- Initialization is precise: i.e. won't try to execute RTT commands
on an as yet uninitialized chip
- Can revert an early "hack" which re-tried creating a new RTT
controller if the previous one simply stopped working
Bug: 79565105
Bug: 111218083
Test: unit tests (new ones)
Test: ACTS RangeApSupporting11McTest:test_rtt_in_and_after_softap_mode
Change-Id: Ib9ef75bb679cdb0f49384260112c06684f52c693
7 files changed, 511 insertions, 866 deletions
diff --git a/service/java/com/android/server/wifi/HalDeviceManager.java b/service/java/com/android/server/wifi/HalDeviceManager.java index 3c61217d7..2acdc03e4 100644 --- a/service/java/com/android/server/wifi/HalDeviceManager.java +++ b/service/java/com/android/server/wifi/HalDeviceManager.java @@ -384,6 +384,49 @@ public class HalDeviceManager { } /** + * Register a callback object for RTT life-cycle events. The callback object registration + * indicates that an RTT controller should be created whenever possible. The callback object + * will be called with a new RTT controller whenever it is created (or at registration time + * if an RTT controller already exists). The callback object will also be triggered whenever + * an existing RTT controller is destroyed (the previous copies must be discarded by the + * recipient). + * + * @param callback InterfaceRttControllerLifecycleCallback object. + * @param handler Handler on which to dispatch callback + */ + public void registerRttControllerLifecycleCallback( + @NonNull InterfaceRttControllerLifecycleCallback callback, @NonNull Handler handler) { + if (VDBG) { + Log.d(TAG, "registerRttControllerLifecycleCallback: callback=" + callback + ", handler=" + + handler); + } + + if (callback == null || handler == null) { + Log.wtf(TAG, "registerRttControllerLifecycleCallback with nulls!? callback=" + callback + + ", handler=" + handler); + return; + } + + synchronized (mLock) { + InterfaceRttControllerLifecycleCallbackProxy proxy = + new InterfaceRttControllerLifecycleCallbackProxy(callback, handler); + if (!mRttControllerLifecycleCallbacks.add(proxy)) { + Log.d(TAG, + "registerRttControllerLifecycleCallback: registering an existing callback=" + + callback); + return; + } + + if (mIWifiRttController == null) { + mIWifiRttController = createRttControllerIfPossible(); + } + if (mIWifiRttController != null) { + proxy.onNewRttController(mIWifiRttController); + } + } + } + + /** * Return the name of the input interface or null on error. */ public static String getName(IWifiIface iface) { @@ -437,49 +480,31 @@ public class HalDeviceManager { } /** - * Creates a IWifiRttController. A direct match to the IWifiChip.createRttController() method. + * Called on RTT controller lifecycle events. RTT controller is a singleton which will be + * created when possible (after first lifecycle registration) and destroyed if necessary. * - * Returns the created IWifiRttController or a null on error. + * Determination of availability is determined by the HAL. Creation attempts (if requested + * by registration of interface) will be done on any mode changes. */ - public IWifiRttController createRttController() { - if (VDBG) Log.d(TAG, "createRttController"); - synchronized (mLock) { - if (mWifi == null) { - Log.e(TAG, "createRttController: null IWifi"); - return null; - } - - WifiChipInfo[] chipInfos = getAllChipInfo(); - if (chipInfos == null) { - Log.e(TAG, "createRttController: no chip info found"); - stopWifi(); // major error: shutting down - return null; - } - - for (WifiChipInfo chipInfo : chipInfos) { - Mutable<IWifiRttController> rttResp = new Mutable<>(); - try { - chipInfo.chip.createRttController(null, - (WifiStatus status, IWifiRttController rtt) -> { - if (status.code == WifiStatusCode.SUCCESS) { - rttResp.value = rtt; - } else { - Log.e(TAG, - "IWifiChip.createRttController failed: " + statusString( - status)); - } - }); - } catch (RemoteException e) { - Log.e(TAG, "IWifiChip.createRttController exception: " + e); - } - if (rttResp.value != null) { - return rttResp.value; - } - } + public interface InterfaceRttControllerLifecycleCallback { + /** + * Called when an RTT controller was created (or for newly registered listeners - if it + * was already available). The controller provided by this callback may be destroyed by + * the HAL at which point the {@link #onRttControllerDestroyed()} will be called. + * + * Note: this callback can be triggered to replace an existing controller (instead of + * calling the Destroyed callback in between). + * + * @param controller The RTT controller object. + */ + void onNewRttController(@NonNull IWifiRttController controller); - Log.e(TAG, "createRttController: not available from any of the chips"); - return null; - } + /** + * Called when the previously provided RTT controller is destroyed. Clients must discard + * their copy. A new copy may be provided later by + * {@link #onNewRttController(IWifiRttController)}. + */ + void onRttControllerDestroyed(); } // internal state @@ -496,8 +521,11 @@ public class HalDeviceManager { private IServiceManager mServiceManager; private IWifi mWifi; + private IWifiRttController mIWifiRttController; private final WifiEventCallback mWifiEventCallback = new WifiEventCallback(); private final Set<ManagerStatusListenerProxy> mManagerStatusListeners = new HashSet<>(); + private final Set<InterfaceRttControllerLifecycleCallbackProxy> + mRttControllerLifecycleCallbacks = new HashSet<>(); private final SparseArray<Map<InterfaceAvailableForRequestListenerProxy, Boolean>> mInterfaceAvailableForRequestListeners = new SparseArray<>(); private final SparseArray<IWifiChipEventCallback.Stub> mDebugCallbacks = new SparseArray<>(); @@ -594,6 +622,10 @@ public class HalDeviceManager { mInterfaceAvailableForRequestListeners.get(IfaceType.AP).clear(); mInterfaceAvailableForRequestListeners.get(IfaceType.P2P).clear(); mInterfaceAvailableForRequestListeners.get(IfaceType.NAN).clear(); + + mIWifiRttController = null; + dispatchRttControllerLifecycleOnDestroyed(); + mRttControllerLifecycleCallbacks.clear(); } private final HwRemoteBinder.DeathRecipient mServiceManagerDeathRecipient = @@ -1787,6 +1819,7 @@ public class HalDeviceManager { WifiStatus status = ifaceCreationData.chipInfo.chip.configureChip( ifaceCreationData.chipModeId); + updateRttControllerOnModeChange(); if (status.code != WifiStatusCode.SUCCESS) { Log.e(TAG, "executeChipReconfiguration: configureChip error: " + statusString(status)); @@ -2077,6 +2110,135 @@ public class HalDeviceManager { } } + private class InterfaceRttControllerLifecycleCallbackProxy implements + InterfaceRttControllerLifecycleCallback { + private InterfaceRttControllerLifecycleCallback mCallback; + private Handler mHandler; + + InterfaceRttControllerLifecycleCallbackProxy( + InterfaceRttControllerLifecycleCallback callback, Handler handler) { + mCallback = callback; + mHandler = handler; + } + + // override equals & hash to make sure that the container HashSet is unique with respect to + // the contained listener + @Override + public boolean equals(Object obj) { + return mCallback == ((InterfaceRttControllerLifecycleCallbackProxy) obj).mCallback; + } + + @Override + public int hashCode() { + return mCallback.hashCode(); + } + + @Override + public void onNewRttController(IWifiRttController controller) { + mHandler.post(() -> mCallback.onNewRttController(controller)); + } + + @Override + public void onRttControllerDestroyed() { + mHandler.post(() -> mCallback.onRttControllerDestroyed()); + } + } + + private void dispatchRttControllerLifecycleOnNew() { + if (VDBG) { + Log.v(TAG, "dispatchRttControllerLifecycleOnNew: # cbs=" + + mRttControllerLifecycleCallbacks.size()); + } + for (InterfaceRttControllerLifecycleCallbackProxy cbp : mRttControllerLifecycleCallbacks) { + cbp.onNewRttController(mIWifiRttController); + } + } + + private void dispatchRttControllerLifecycleOnDestroyed() { + for (InterfaceRttControllerLifecycleCallbackProxy cbp : mRttControllerLifecycleCallbacks) { + cbp.onRttControllerDestroyed(); + } + } + + + /** + * Updates the RttController when the chip mode is changed: + * - Handles callbacks to registered listeners + * - Handles creation of new RttController + */ + private void updateRttControllerOnModeChange() { + synchronized (mLock) { + boolean controllerDestroyed = mIWifiRttController != null; + mIWifiRttController = null; + if (mRttControllerLifecycleCallbacks.size() == 0) { + Log.d(TAG, "updateRttController: no one is interested in RTT controllers"); + return; + } + + IWifiRttController newRttController = createRttControllerIfPossible(); + if (newRttController == null) { + if (controllerDestroyed) { + dispatchRttControllerLifecycleOnDestroyed(); + } + } else { + mIWifiRttController = newRttController; + dispatchRttControllerLifecycleOnNew(); + } + } + } + + /** + * Try to create a new RttController. + * + * @return The new RttController - or null on failure. + */ + private IWifiRttController createRttControllerIfPossible() { + synchronized (mLock) { + if (!isWifiStarted()) { + Log.d(TAG, "createRttControllerIfPossible: Wifi is not started"); + return null; + } + + WifiChipInfo[] chipInfos = getAllChipInfo(); + if (chipInfos == null) { + Log.d(TAG, "createRttControllerIfPossible: no chip info found - most likely chip " + + "not up yet"); + return null; + } + + for (WifiChipInfo chipInfo : chipInfos) { + if (!chipInfo.currentModeIdValid) { + if (VDBG) { + Log.d(TAG, "createRttControllerIfPossible: chip not configured yet: " + + chipInfo); + } + continue; + } + + Mutable<IWifiRttController> rttResp = new Mutable<>(); + try { + chipInfo.chip.createRttController(null, + (WifiStatus status, IWifiRttController rtt) -> { + if (status.code == WifiStatusCode.SUCCESS) { + rttResp.value = rtt; + } else { + Log.e(TAG, "IWifiChip.createRttController failed: " + + statusString(status)); + } + }); + } catch (RemoteException e) { + Log.e(TAG, "IWifiChip.createRttController exception: " + e); + } + if (rttResp.value != null) { + return rttResp.value; + } + } + } + + Log.w(TAG, "createRttControllerIfPossible: not available from any of the chips"); + return null; + } + // general utilities private static String statusString(WifiStatus status) { diff --git a/service/java/com/android/server/wifi/WifiNative.java b/service/java/com/android/server/wifi/WifiNative.java index 7351b720a..29b38aed7 100644 --- a/service/java/com/android/server/wifi/WifiNative.java +++ b/service/java/com/android/server/wifi/WifiNative.java @@ -18,13 +18,10 @@ package com.android.server.wifi; import android.annotation.IntDef; import android.annotation.NonNull; -import android.annotation.Nullable; import android.net.InterfaceConfiguration; import android.net.MacAddress; import android.net.TrafficStats; import android.net.apf.ApfCapabilities; -import android.net.wifi.RttManager; -import android.net.wifi.RttManager.ResponderConfig; import android.net.wifi.ScanResult; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiScanner; @@ -2303,51 +2300,6 @@ public class WifiNative { return mWifiVendorHal.getSupportedFeatureSet(ifaceName); } - public static interface RttEventHandler { - void onRttResults(RttManager.RttResult[] result); - } - - /** - * Starts a new rtt request - * - * @param params RTT request params. Refer to {@link RttManager#RttParams}. - * @param handler Callback to be invoked to notify any results. - * @return true if the request was successful, false otherwise. - */ - public boolean requestRtt( - RttManager.RttParams[] params, RttEventHandler handler) { - return mWifiVendorHal.requestRtt(params, handler); - } - - /** - * Cancels an outstanding rtt request - * - * @param params RTT request params. Refer to {@link RttManager#RttParams} - * @return true if there was an outstanding request and it was successfully cancelled - */ - public boolean cancelRtt(RttManager.RttParams[] params) { - return mWifiVendorHal.cancelRtt(params); - } - - /** - * Enable RTT responder role on the device. Returns {@link ResponderConfig} if the responder - * role is successfully enabled, {@code null} otherwise. - * - * @param timeoutSeconds timeout to use for the responder. - */ - @Nullable - public ResponderConfig enableRttResponder(int timeoutSeconds) { - return mWifiVendorHal.enableRttResponder(timeoutSeconds); - } - - /** - * Disable RTT responder role. Returns {@code true} if responder role is successfully disabled, - * {@code false} otherwise. - */ - public boolean disableRttResponder() { - return mWifiVendorHal.disableRttResponder(); - } - /** * Set the MAC OUI during scanning. * An OUI {Organizationally Unique Identifier} is a 24-bit number that @@ -2362,13 +2314,6 @@ public class WifiNative { } /** - * RTT (Round Trip Time) measurement capabilities of the device. - */ - public RttManager.RttCapabilities getRttCapabilities() { - return mWifiVendorHal.getRttCapabilities(); - } - - /** * Get the APF (Android Packet Filter) capabilities of the device * @param ifaceName Name of the interface. */ diff --git a/service/java/com/android/server/wifi/WifiVendorHal.java b/service/java/com/android/server/wifi/WifiVendorHal.java index 5666dd386..77da7667f 100644 --- a/service/java/com/android/server/wifi/WifiVendorHal.java +++ b/service/java/com/android/server/wifi/WifiVendorHal.java @@ -20,18 +20,9 @@ import android.hardware.wifi.V1_0.IWifiApIface; import android.hardware.wifi.V1_0.IWifiChip; import android.hardware.wifi.V1_0.IWifiChipEventCallback; import android.hardware.wifi.V1_0.IWifiIface; -import android.hardware.wifi.V1_0.IWifiRttController; -import android.hardware.wifi.V1_0.IWifiRttControllerEventCallback; import android.hardware.wifi.V1_0.IWifiStaIface; import android.hardware.wifi.V1_0.IWifiStaIfaceEventCallback; import android.hardware.wifi.V1_0.IfaceType; -import android.hardware.wifi.V1_0.RttBw; -import android.hardware.wifi.V1_0.RttConfig; -import android.hardware.wifi.V1_0.RttPeerType; -import android.hardware.wifi.V1_0.RttPreamble; -import android.hardware.wifi.V1_0.RttResponder; -import android.hardware.wifi.V1_0.RttResult; -import android.hardware.wifi.V1_0.RttType; import android.hardware.wifi.V1_0.StaBackgroundScanBucketEventReportSchemeMask; import android.hardware.wifi.V1_0.StaBackgroundScanBucketParameters; import android.hardware.wifi.V1_0.StaBackgroundScanParameters; @@ -44,7 +35,6 @@ import android.hardware.wifi.V1_0.StaScanData; import android.hardware.wifi.V1_0.StaScanDataFlagMask; import android.hardware.wifi.V1_0.StaScanResult; import android.hardware.wifi.V1_0.WifiBand; -import android.hardware.wifi.V1_0.WifiChannelWidthInMhz; import android.hardware.wifi.V1_0.WifiDebugHostWakeReasonStats; import android.hardware.wifi.V1_0.WifiDebugPacketFateFrameType; import android.hardware.wifi.V1_0.WifiDebugRingBufferFlags; @@ -58,8 +48,6 @@ import android.hardware.wifi.V1_0.WifiStatus; import android.hardware.wifi.V1_0.WifiStatusCode; import android.net.MacAddress; import android.net.apf.ApfCapabilities; -import android.net.wifi.RttManager; -import android.net.wifi.RttManager.ResponderConfig; import android.net.wifi.ScanResult; import android.net.wifi.WifiManager; import android.net.wifi.WifiScanner; @@ -247,7 +235,6 @@ public class WifiVendorHal { // Vendor HAL HIDL interface objects. private IWifiChip mIWifiChip; - private IWifiRttController mIWifiRttController; private HashMap<String, IWifiStaIface> mIWifiStaIfaces = new HashMap<>(); private HashMap<String, IWifiApIface> mIWifiApIfaces = new HashMap<>(); private final HalDeviceManager mHalDeviceManager; @@ -255,7 +242,6 @@ public class WifiVendorHal { private final IWifiStaIfaceEventCallback mIWifiStaIfaceEventCallback; private final ChipEventCallback mIWifiChipEventCallback; private final ChipEventCallbackV12 mIWifiChipEventCallbackV12; - private final RttEventCallback mRttEventCallback; // Plumbing for event handling. // @@ -274,7 +260,6 @@ public class WifiVendorHal { mIWifiStaIfaceEventCallback = new StaIfaceEventCallback(); mIWifiChipEventCallback = new ChipEventCallback(); mIWifiChipEventCallbackV12 = new ChipEventCallbackV12(); - mRttEventCallback = new RttEventCallback(); } public static final Object sLock = new Object(); @@ -427,15 +412,6 @@ public class WifiVendorHal { mLog.err("Failed to register STA iface callback").flush(); return stringResult(null); } - mIWifiRttController = mHalDeviceManager.createRttController(); - if (mIWifiRttController == null) { - mLog.err("Failed to create RTT controller").flush(); - return stringResult(null); - } - if (!registerRttEventCallback()) { - mLog.err("Failed to register RTT controller callback").flush(); - return stringResult(null); - } if (!retrieveWifiChip((IWifiIface) iface)) { mLog.err("Failed to get wifi chip").flush(); return stringResult(null); @@ -601,23 +577,6 @@ public class WifiVendorHal { } /** - * Registers RTT event callback. Returns whether the registration is successful. - */ - private boolean registerRttEventCallback() { - synchronized (sLock) { - if (mIWifiRttController == null) return boolResult(false); - if (mRttEventCallback == null) return boolResult(false); - try { - WifiStatus status = mIWifiRttController.registerEventCallback(mRttEventCallback); - return ok(status); - } catch (RemoteException e) { - handleRemoteException(e); - return false; - } - } - } - - /** * Stops the HAL */ public void stopVendorHal() { @@ -637,7 +596,6 @@ public class WifiVendorHal { mIWifiChip = null; mIWifiStaIfaces.clear(); mIWifiApIfaces.clear(); - mIWifiRttController = null; mDriverDescription = null; mFirmwareDescription = null; } @@ -1247,510 +1205,6 @@ public class WifiVendorHal { return featureSet; } - /* RTT related commands/events */ - - /** - * RTT (Round Trip Time) measurement capabilities of the device. - */ - public RttManager.RttCapabilities getRttCapabilities() { - class AnswerBox { - public RttManager.RttCapabilities value = null; - } - synchronized (sLock) { - if (mIWifiRttController == null) return null; - try { - AnswerBox box = new AnswerBox(); - mIWifiRttController.getCapabilities((status, capabilities) -> { - if (!ok(status)) return; - mVerboseLog.info("rtt capabilites %").c(capabilities.toString()).flush(); - RttManager.RttCapabilities ans = new RttManager.RttCapabilities(); - ans.oneSidedRttSupported = capabilities.rttOneSidedSupported; - ans.twoSided11McRttSupported = capabilities.rttFtmSupported; - ans.lciSupported = capabilities.lciSupported; - ans.lcrSupported = capabilities.lcrSupported; - ans.preambleSupported = frameworkPreambleFromHalPreamble( - capabilities.preambleSupport); - ans.bwSupported = frameworkBwFromHalBw(capabilities.bwSupport); - ans.responderSupported = capabilities.responderSupported; - ans.secureRttSupported = false; - ans.mcVersion = ((int) capabilities.mcVersion) & 0xff; - box.value = ans; - }); - return box.value; - } catch (RemoteException e) { - handleRemoteException(e); - return null; - } - } - } - - private int mRttCmdIdNext = 1; // used to generate new command ids - private int mRttCmdId; // id of currently active request - // Event handler for current active RTT request. - private WifiNative.RttEventHandler mRttEventHandler; - - /** - * Receives a callback from the Hal and passes it along to our client using RttEventHandler - */ - private class RttEventCallback extends IWifiRttControllerEventCallback.Stub { - - @Override - public void onResults(int cmdId, java.util.ArrayList<RttResult> results) { - WifiNative.RttEventHandler eventHandler; - synchronized (sLock) { - if (cmdId != mRttCmdId || mRttEventHandler == null) return; - eventHandler = mRttEventHandler; - // Reset the command id for RTT operations in WifiVendorHal. - WifiVendorHal.this.mRttCmdId = 0; - } - RttManager.RttResult[] rtt = new RttManager.RttResult[results.size()]; - for (int i = 0; i < rtt.length; i++) { - rtt[i] = frameworkRttResultFromHalRttResult(results.get(i)); - } - eventHandler.onRttResults(rtt); - } - } - - /** - * Converts a Hal RttResult to a RttManager.RttResult - */ - @VisibleForTesting - static RttManager.RttResult frameworkRttResultFromHalRttResult(RttResult result) { - RttManager.RttResult ans = new RttManager.RttResult(); - ans.bssid = NativeUtil.macAddressFromByteArray(result.addr); - ans.burstNumber = result.burstNum; - ans.measurementFrameNumber = result.measurementNumber; - ans.successMeasurementFrameNumber = result.successNumber; - ans.frameNumberPerBurstPeer = result.numberPerBurstPeer; - ans.status = result.status; //TODO(b/35138520) - don't assume identity translation - ans.retryAfterDuration = result.retryAfterDuration; - ans.measurementType = result.type; - ans.rssi = result.rssi; - ans.rssiSpread = result.rssiSpread; - //TODO(b/35138520) Fix HAL and framework to use the same units - ans.txRate = result.txRate.bitRateInKbps; - ans.rxRate = result.rxRate.bitRateInKbps; - ans.rtt = result.rtt; - ans.rttStandardDeviation = result.rttSd; - ans.rttSpread = result.rttSpread; - //TODO(b/35138520) These divide-by-10s were in the legacy Hal - ans.distance = result.distanceInMm / 10; // Convert cm to mm - ans.distanceStandardDeviation = result.distanceSdInMm / 10; // Convert cm to mm - ans.distanceSpread = result.distanceSpreadInMm / 10; - - ans.ts = result.timeStampInUs; - ans.burstDuration = result.burstDurationInMs; - ans.negotiatedBurstNum = result.negotiatedBurstNum; - ans.LCI = ieFromHal(result.lci); - ans.LCR = ieFromHal(result.lcr); - ans.secure = false; // Not present in HIDL HAL - return ans; - } - - /** - * Convert a Hal WifiInformationElement to its RttManager equivalent - */ - @VisibleForTesting - static RttManager.WifiInformationElement ieFromHal( - android.hardware.wifi.V1_0.WifiInformationElement ie) { - if (ie == null) return null; - RttManager.WifiInformationElement ans = new RttManager.WifiInformationElement(); - ans.id = ie.id; - ans.data = NativeUtil.byteArrayFromArrayList(ie.data); - return ans; - } - - @VisibleForTesting - static RttConfig halRttConfigFromFrameworkRttParams(RttManager.RttParams params) { - RttConfig rttConfig = new RttConfig(); - if (params.bssid != null) { - byte[] addr = NativeUtil.macAddressToByteArray(params.bssid); - for (int i = 0; i < rttConfig.addr.length; i++) { - rttConfig.addr[i] = addr[i]; - } - } - rttConfig.type = halRttTypeFromFrameworkRttType(params.requestType); - rttConfig.peer = halPeerFromFrameworkPeer(params.deviceType); - rttConfig.channel.width = halChannelWidthFromFrameworkChannelWidth(params.channelWidth); - rttConfig.channel.centerFreq = params.frequency; - rttConfig.channel.centerFreq0 = params.centerFreq0; - rttConfig.channel.centerFreq1 = params.centerFreq1; - rttConfig.burstPeriod = params.interval; // In 100ms units, 0 means no specific - rttConfig.numBurst = params.numberBurst; - rttConfig.numFramesPerBurst = params.numSamplesPerBurst; - rttConfig.numRetriesPerRttFrame = params.numRetriesPerMeasurementFrame; - rttConfig.numRetriesPerFtmr = params.numRetriesPerFTMR; - rttConfig.mustRequestLci = params.LCIRequest; - rttConfig.mustRequestLcr = params.LCRRequest; - rttConfig.burstDuration = params.burstTimeout; - rttConfig.preamble = halPreambleFromFrameworkPreamble(params.preamble); - rttConfig.bw = halBwFromFrameworkBw(params.bandwidth); - return rttConfig; - } - - @VisibleForTesting - static int halRttTypeFromFrameworkRttType(int frameworkRttType) { - switch (frameworkRttType) { - case RttManager.RTT_TYPE_ONE_SIDED: - return RttType.ONE_SIDED; - case RttManager.RTT_TYPE_TWO_SIDED: - return RttType.TWO_SIDED; - default: - throw new IllegalArgumentException("bad " + frameworkRttType); - } - } - - @VisibleForTesting - static int frameworkRttTypeFromHalRttType(int halType) { - switch (halType) { - case RttType.ONE_SIDED: - return RttManager.RTT_TYPE_ONE_SIDED; - case RttType.TWO_SIDED: - return RttManager.RTT_TYPE_TWO_SIDED; - default: - throw new IllegalArgumentException("bad " + halType); - } - } - - @VisibleForTesting - static int halPeerFromFrameworkPeer(int frameworkPeer) { - switch (frameworkPeer) { - case RttManager.RTT_PEER_TYPE_AP: - return RttPeerType.AP; - case RttManager.RTT_PEER_TYPE_STA: - return RttPeerType.STA; - case RttManager.RTT_PEER_P2P_GO: - return RttPeerType.P2P_GO; - case RttManager.RTT_PEER_P2P_CLIENT: - return RttPeerType.P2P_CLIENT; - case RttManager.RTT_PEER_NAN: - return RttPeerType.NAN; - default: - throw new IllegalArgumentException("bad " + frameworkPeer); - } - } - - @VisibleForTesting - static int frameworkPeerFromHalPeer(int halPeer) { - switch (halPeer) { - case RttPeerType.AP: - return RttManager.RTT_PEER_TYPE_AP; - case RttPeerType.STA: - return RttManager.RTT_PEER_TYPE_STA; - case RttPeerType.P2P_GO: - return RttManager.RTT_PEER_P2P_GO; - case RttPeerType.P2P_CLIENT: - return RttManager.RTT_PEER_P2P_CLIENT; - case RttPeerType.NAN: - return RttManager.RTT_PEER_NAN; - default: - throw new IllegalArgumentException("bad " + halPeer); - - } - } - - @VisibleForTesting - static int halChannelWidthFromFrameworkChannelWidth(int frameworkChannelWidth) { - switch (frameworkChannelWidth) { - case ScanResult.CHANNEL_WIDTH_20MHZ: - return WifiChannelWidthInMhz.WIDTH_20; - case ScanResult.CHANNEL_WIDTH_40MHZ: - return WifiChannelWidthInMhz.WIDTH_40; - case ScanResult.CHANNEL_WIDTH_80MHZ: - return WifiChannelWidthInMhz.WIDTH_80; - case ScanResult.CHANNEL_WIDTH_160MHZ: - return WifiChannelWidthInMhz.WIDTH_160; - case ScanResult.CHANNEL_WIDTH_80MHZ_PLUS_MHZ: - return WifiChannelWidthInMhz.WIDTH_80P80; - default: - throw new IllegalArgumentException("bad " + frameworkChannelWidth); - } - } - - @VisibleForTesting - static int frameworkChannelWidthFromHalChannelWidth(int halChannelWidth) { - switch (halChannelWidth) { - case WifiChannelWidthInMhz.WIDTH_20: - return ScanResult.CHANNEL_WIDTH_20MHZ; - case WifiChannelWidthInMhz.WIDTH_40: - return ScanResult.CHANNEL_WIDTH_40MHZ; - case WifiChannelWidthInMhz.WIDTH_80: - return ScanResult.CHANNEL_WIDTH_80MHZ; - case WifiChannelWidthInMhz.WIDTH_160: - return ScanResult.CHANNEL_WIDTH_160MHZ; - case WifiChannelWidthInMhz.WIDTH_80P80: - return ScanResult.CHANNEL_WIDTH_80MHZ_PLUS_MHZ; - default: - throw new IllegalArgumentException("bad " + halChannelWidth); - } - } - - @VisibleForTesting - static int halPreambleFromFrameworkPreamble(int rttManagerPreamble) { - BitMask checkoff = new BitMask(rttManagerPreamble); - int flags = 0; - if (checkoff.testAndClear(RttManager.PREAMBLE_LEGACY)) { - flags |= RttPreamble.LEGACY; - } - if (checkoff.testAndClear(RttManager.PREAMBLE_HT)) { - flags |= RttPreamble.HT; - } - if (checkoff.testAndClear(RttManager.PREAMBLE_VHT)) { - flags |= RttPreamble.VHT; - } - if (checkoff.value != 0) { - throw new IllegalArgumentException("bad " + rttManagerPreamble); - } - return flags; - } - - @VisibleForTesting - static int frameworkPreambleFromHalPreamble(int halPreamble) { - BitMask checkoff = new BitMask(halPreamble); - int flags = 0; - if (checkoff.testAndClear(RttPreamble.LEGACY)) { - flags |= RttManager.PREAMBLE_LEGACY; - } - if (checkoff.testAndClear(RttPreamble.HT)) { - flags |= RttManager.PREAMBLE_HT; - } - if (checkoff.testAndClear(RttPreamble.VHT)) { - flags |= RttManager.PREAMBLE_VHT; - } - if (checkoff.value != 0) { - throw new IllegalArgumentException("bad " + halPreamble); - } - return flags; - } - - @VisibleForTesting - static int halBwFromFrameworkBw(int rttManagerBandwidth) { - BitMask checkoff = new BitMask(rttManagerBandwidth); - int flags = 0; - if (checkoff.testAndClear(RttManager.RTT_BW_5_SUPPORT)) { - flags |= RttBw.BW_5MHZ; - } - if (checkoff.testAndClear(RttManager.RTT_BW_10_SUPPORT)) { - flags |= RttBw.BW_10MHZ; - } - if (checkoff.testAndClear(RttManager.RTT_BW_20_SUPPORT)) { - flags |= RttBw.BW_20MHZ; - } - if (checkoff.testAndClear(RttManager.RTT_BW_40_SUPPORT)) { - flags |= RttBw.BW_40MHZ; - } - if (checkoff.testAndClear(RttManager.RTT_BW_80_SUPPORT)) { - flags |= RttBw.BW_80MHZ; - } - if (checkoff.testAndClear(RttManager.RTT_BW_160_SUPPORT)) { - flags |= RttBw.BW_160MHZ; - } - if (checkoff.value != 0) { - throw new IllegalArgumentException("bad " + rttManagerBandwidth); - } - return flags; - } - - @VisibleForTesting - static int frameworkBwFromHalBw(int rttBw) { - BitMask checkoff = new BitMask(rttBw); - int flags = 0; - if (checkoff.testAndClear(RttBw.BW_5MHZ)) { - flags |= RttManager.RTT_BW_5_SUPPORT; - } - if (checkoff.testAndClear(RttBw.BW_10MHZ)) { - flags |= RttManager.RTT_BW_10_SUPPORT; - } - if (checkoff.testAndClear(RttBw.BW_20MHZ)) { - flags |= RttManager.RTT_BW_20_SUPPORT; - } - if (checkoff.testAndClear(RttBw.BW_40MHZ)) { - flags |= RttManager.RTT_BW_40_SUPPORT; - } - if (checkoff.testAndClear(RttBw.BW_80MHZ)) { - flags |= RttManager.RTT_BW_80_SUPPORT; - } - if (checkoff.testAndClear(RttBw.BW_160MHZ)) { - flags |= RttManager.RTT_BW_160_SUPPORT; - } - if (checkoff.value != 0) { - throw new IllegalArgumentException("bad " + rttBw); - } - return flags; - } - - @VisibleForTesting - static ArrayList<RttConfig> halRttConfigArrayFromFrameworkRttParamsArray( - RttManager.RttParams[] params) { - final int length = params.length; - ArrayList<RttConfig> configs = new ArrayList<RttConfig>(length); - for (int i = 0; i < length; i++) { - RttConfig config = halRttConfigFromFrameworkRttParams(params[i]); - if (config != null) { - configs.add(config); - } - } - return configs; - } - - /** - * Starts a new rtt request - * - * @param params - * @param handler - * @return success indication - */ - public boolean requestRtt(RttManager.RttParams[] params, WifiNative.RttEventHandler handler) { - ArrayList<RttConfig> rttConfigs; - try { - rttConfigs = halRttConfigArrayFromFrameworkRttParamsArray(params); - } catch (IllegalArgumentException e) { - mLog.err("Illegal argument for RTT request").c(e.toString()).flush(); - return false; - } - synchronized (sLock) { - if (mIWifiRttController == null) return boolResult(false); - if (mRttCmdId != 0) return boolResult(false); - mRttCmdId = mRttCmdIdNext++; - mRttEventHandler = handler; - if (mRttCmdIdNext <= 0) mRttCmdIdNext = 1; - try { - WifiStatus status = mIWifiRttController.rangeRequest(mRttCmdId, rttConfigs); - if (ok(status)) return true; - mRttCmdId = 0; - return false; - } catch (RemoteException e) { - handleRemoteException(e); - return false; - } - } - } - - /** - * Cancels an outstanding rtt request - * - * @param params - * @return true if there was an outstanding request and it was successfully cancelled - */ - public boolean cancelRtt(RttManager.RttParams[] params) { - ArrayList<RttConfig> rttConfigs = halRttConfigArrayFromFrameworkRttParamsArray(params); - synchronized (sLock) { - if (mIWifiRttController == null) return boolResult(false); - if (mRttCmdId == 0) return boolResult(false); - ArrayList<byte[/* 6 */]> addrs = new ArrayList<byte[]>(rttConfigs.size()); - for (RttConfig x : rttConfigs) addrs.add(x.addr); - try { - WifiStatus status = mIWifiRttController.rangeCancel(mRttCmdId, addrs); - mRttCmdId = 0; - if (!ok(status)) return false; - return true; - } catch (RemoteException e) { - handleRemoteException(e); - return false; - } - } - } - - private int mRttResponderCmdId = 0; - - /** - * Get RTT responder information e.g. WiFi channel to enable responder on. - * - * @return info Instance of |RttResponder|, or null for error. - */ - private RttResponder getRttResponder() { - class AnswerBox { - public RttResponder value = null; - } - synchronized (sLock) { - if (mIWifiRttController == null) return null; - AnswerBox answer = new AnswerBox(); - try { - mIWifiRttController.getResponderInfo((status, info) -> { - if (!ok(status)) return; - answer.value = info; - }); - return answer.value; - } catch (RemoteException e) { - handleRemoteException(e); - return null; - } - } - } - - /** - * Convert Hal RttResponder to a framework ResponderConfig - * - * @param info Instance of |RttResponder| - * @return framework version of same - */ - private ResponderConfig frameworkResponderConfigFromHalRttResponder(RttResponder info) { - ResponderConfig config = new ResponderConfig(); - config.frequency = info.channel.centerFreq; - config.centerFreq0 = info.channel.centerFreq0; - config.centerFreq1 = info.channel.centerFreq1; - config.channelWidth = frameworkChannelWidthFromHalChannelWidth(info.channel.width); - config.preamble = frameworkPreambleFromHalPreamble(info.preamble); - return config; - } - - /** - * Enables RTT responder role on the device. - * - * @return {@link ResponderConfig} if the responder role is successfully enabled, - * {@code null} otherwise. - */ - public ResponderConfig enableRttResponder(int timeoutSeconds) { - RttResponder info = getRttResponder(); - synchronized (sLock) { - if (mIWifiRttController == null) return null; - if (mRttResponderCmdId != 0) { - mLog.err("responder mode already enabled - this shouldn't happen").flush(); - return null; - } - ResponderConfig config = null; - int id = mRttCmdIdNext++; - if (mRttCmdIdNext <= 0) mRttCmdIdNext = 1; - try { - WifiStatus status = mIWifiRttController.enableResponder( - /* cmdId */id, - /* WifiChannelInfo channelHint */null, - timeoutSeconds, info); - if (ok(status)) { - mRttResponderCmdId = id; - config = frameworkResponderConfigFromHalRttResponder(info); - mVerboseLog.i("enabling rtt " + mRttResponderCmdId); - } - return config; - } catch (RemoteException e) { - handleRemoteException(e); - return null; - } - } - } - - /** - * Disables RTT responder role. - * - * @return {@code true} if responder role is successfully disabled, - * {@code false} otherwise. - */ - public boolean disableRttResponder() { - synchronized (sLock) { - if (mIWifiRttController == null) return boolResult(false); - if (mRttResponderCmdId == 0) return boolResult(false); - try { - WifiStatus status = mIWifiRttController.disableResponder(mRttResponderCmdId); - mRttResponderCmdId = 0; - if (!ok(status)) return false; - return true; - } catch (RemoteException e) { - handleRemoteException(e); - return false; - } - } - } - /** * Set the MAC OUI during scanning. * <p> diff --git a/service/java/com/android/server/wifi/rtt/RttNative.java b/service/java/com/android/server/wifi/rtt/RttNative.java index accd1a2f8..29b0a139f 100644 --- a/service/java/com/android/server/wifi/rtt/RttNative.java +++ b/service/java/com/android/server/wifi/rtt/RttNative.java @@ -57,6 +57,40 @@ public class RttNative extends IWifiRttControllerEventCallback.Stub { private volatile IWifiRttController mIWifiRttController; private volatile RttCapabilities mRttCapabilities; + private final HalDeviceManager.InterfaceRttControllerLifecycleCallback mRttLifecycleCb = + new HalDeviceManager.InterfaceRttControllerLifecycleCallback() { + @Override + public void onNewRttController(IWifiRttController controller) { + if (mDbg) Log.d(TAG, "onNewRttController: controller=" + controller); + synchronized (mLock) { + try { + controller.registerEventCallback(RttNative.this); + } catch (RemoteException e) { + Log.e(TAG, "onNewRttController: exception registering callback: " + e); + if (mIWifiRttController != null) { + mIWifiRttController = null; + mRttService.disable(); + } + return; + } + + mIWifiRttController = controller; + mRttService.enableIfPossible(); + updateRttCapabilities(); + } + } + + @Override + public void onRttControllerDestroyed() { + if (mDbg) Log.d(TAG, "onRttControllerDestroyed"); + synchronized (mLock) { + mIWifiRttController = null; + mRttCapabilities = null; + mRttService.disable(); + } + } + }; + public RttNative(RttServiceImpl rttService, HalDeviceManager halDeviceManager) { mRttService = rttService; mHalDeviceManager = halDeviceManager; @@ -70,9 +104,14 @@ public class RttNative extends IWifiRttControllerEventCallback.Stub { mHalDeviceManager.initialize(); mHalDeviceManager.registerStatusListener(() -> { if (VDBG) Log.d(TAG, "hdm.onStatusChanged"); - updateController(); + if (mHalDeviceManager.isStarted()) { + mHalDeviceManager.registerRttControllerLifecycleCallback(mRttLifecycleCb, + handler); + } }, handler); - updateController(); + if (mHalDeviceManager.isStarted()) { + mHalDeviceManager.registerRttControllerLifecycleCallback(mRttLifecycleCb, handler); + } } } @@ -83,67 +122,36 @@ public class RttNative extends IWifiRttControllerEventCallback.Stub { return mIWifiRttController != null; } - private void updateController() { - if (mDbg) Log.v(TAG, "updateController: mIWifiRttController=" + mIWifiRttController); - - // only care about isStarted (Wi-Fi started) not isReady - since if not - // ready then Wi-Fi will also be down. - synchronized (mLock) { - IWifiRttController localWifiRttController = mIWifiRttController; - if (mHalDeviceManager.isStarted()) { - if (localWifiRttController == null) { - localWifiRttController = mHalDeviceManager.createRttController(); - if (localWifiRttController == null) { - Log.e(TAG, "updateController: Failed creating RTT controller - but Wifi is " - + "started!"); - } else { - try { - localWifiRttController.registerEventCallback(this); - } catch (RemoteException e) { - Log.e(TAG, "updateController: exception registering callback: " + e); - localWifiRttController = null; - } - } - } - } else { - localWifiRttController = null; - } - mIWifiRttController = localWifiRttController; - - if (mIWifiRttController == null) { - mRttService.disable(); - } else { - mRttService.enableIfPossible(); - updateRttCapabilities(); - } - } - } - /** * Updates the RTT capabilities. */ void updateRttCapabilities() { + if (mIWifiRttController == null) { + Log.e(TAG, "updateRttCapabilities: but a RTT controll is NULL!?"); + return; + } if (mRttCapabilities != null) { return; } + if (mDbg) Log.v(TAG, "updateRttCapabilities"); synchronized (mLock) { try { mIWifiRttController.getCapabilities( (status, capabilities) -> { if (status.code != WifiStatusCode.SUCCESS) { - Log.e(TAG, - "updateController: error requesting capabilities -- code=" - + status.code); + Log.e(TAG, "updateRttCapabilities: error requesting capabilities " + + "-- code=" + status.code); return; } if (mDbg) { - Log.v(TAG, "updateController: RTT capabilities=" + capabilities); + Log.v(TAG, "updateRttCapabilities: RTT capabilities=" + + capabilities); } mRttCapabilities = capabilities; }); } catch (RemoteException e) { - Log.e(TAG, "updateController: exception requesting capabilities: " + e); + Log.e(TAG, "updateRttCapabilities: exception requesting capabilities: " + e); } if (mRttCapabilities != null && !mRttCapabilities.rttFtmSupported) { @@ -171,12 +179,12 @@ public class RttNative extends IWifiRttControllerEventCallback.Stub { "rangeRequest: cmdId=" + cmdId + ", # of requests=" + request.mRttPeers.size()); } if (VDBG) Log.v(TAG, "rangeRequest: request=" + request); - updateRttCapabilities(); synchronized (mLock) { if (!isReady()) { Log.e(TAG, "rangeRequest: RttController is null"); return false; } + updateRttCapabilities(); ArrayList<RttConfig> rttConfig = convertRangingRequestToRttConfigs(request, isCalledFromPrivilegedContext, mRttCapabilities); diff --git a/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java b/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java index 823a28d13..e5391f16b 100644 --- a/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java +++ b/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java @@ -45,6 +45,7 @@ import android.hardware.wifi.V1_0.IWifiEventCallback; import android.hardware.wifi.V1_0.IWifiIface; import android.hardware.wifi.V1_0.IWifiNanIface; import android.hardware.wifi.V1_0.IWifiP2pIface; +import android.hardware.wifi.V1_0.IWifiRttController; import android.hardware.wifi.V1_0.IWifiStaIface; import android.hardware.wifi.V1_0.IfaceType; import android.hardware.wifi.V1_0.WifiStatus; @@ -86,6 +87,7 @@ public class HalDeviceManagerTest { private HalDeviceManager mDut; @Mock IServiceManager mServiceManagerMock; @Mock IWifi mWifiMock; + @Mock IWifiRttController mRttControllerMock; @Mock HalDeviceManager.ManagerStatusListener mManagerStatusListenerMock; @Mock private Clock mClock; private TestLooper mTestLooper; @@ -140,6 +142,7 @@ public class HalDeviceManagerTest { when(mWifiMock.registerEventCallback(any(IWifiEventCallback.class))).thenReturn(mStatusOk); when(mWifiMock.start()).thenReturn(mStatusOk); when(mWifiMock.stop()).thenReturn(mStatusOk); + when(mWifiMock.isStarted()).thenReturn(true); mDut = new HalDeviceManagerSpy(); } @@ -519,6 +522,196 @@ public class HalDeviceManagerTest { assertFalse(mDut.isSupported()); } + /** + * Validate RTT configuration when the callback is registered first and the chip is + * configured later - i.e. RTT isn't available immediately. + */ + @Test + public void testAndTriggerRttLifecycleCallbacksRegBeforeChipConfig() throws Exception { + HalDeviceManager.InterfaceRttControllerLifecycleCallback cb = mock( + HalDeviceManager.InterfaceRttControllerLifecycleCallback.class); + + InOrder io = inOrder(cb); + + // initialize a test chip (V1 is fine since we're not testing any specifics of + // concurrency in this test). + ChipMockBase chipMock = new TestChipV1(); + chipMock.initialize(); + mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip, + mManagerStatusListenerMock); + executeAndValidateInitializationSequence(); + executeAndValidateStartupSequence(); + + // register initial cb: don't expect RTT since chip isn't configured + mDut.registerRttControllerLifecycleCallback(cb, mHandler); + mTestLooper.dispatchAll(); + io.verify(cb, times(0)).onNewRttController(any()); + + // create a STA - that will get the chip configured and get us an RTT controller + validateInterfaceSequence(chipMock, + false, // chipModeValid + -1000, // chipModeId (only used if chipModeValid is true) + IfaceType.STA, + "wlan0", + TestChipV1.STA_CHIP_MODE_ID, + false, // high priority + null, // tearDownList + null, // destroyedListener + null // availableListener + ); + verify(chipMock.chip).createRttController(any(), any()); + io.verify(cb).onNewRttController(any()); + + verifyNoMoreInteractions(cb); + } + + /** + * Validate the RTT Controller lifecycle using a multi-mode chip (i.e. a chip which can + * switch modes, during which RTT is destroyed). + * + * 1. Validate that an RTT is created as soon as the callback is registered - if the chip + * is already configured (i.e. it is possible to create the RTT controller). + * + * 2. Validate that only the registered callback is triggered, not previously registered ones + * and not duplicate ones. + * + * 3. Validate that onDestroy callbacks are triggered on mode change. + */ + @Test + public void testAndTriggerRttLifecycleCallbacksMultiModeChip() throws Exception { + HalDeviceManager.InterfaceRttControllerLifecycleCallback cb1 = mock( + HalDeviceManager.InterfaceRttControllerLifecycleCallback.class); + HalDeviceManager.InterfaceRttControllerLifecycleCallback cb2 = mock( + HalDeviceManager.InterfaceRttControllerLifecycleCallback.class); + + InOrder io1 = inOrder(cb1); + InOrder io2 = inOrder(cb2); + + // initialize a test chip (V1 is a must since we're testing a multi-mode chip) & create a + // STA (which will configure the chip). + ChipMockBase chipMock = new TestChipV1(); + chipMock.initialize(); + mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip, + mManagerStatusListenerMock); + executeAndValidateInitializationSequence(); + executeAndValidateStartupSequence(); + validateInterfaceSequence(chipMock, + false, // chipModeValid + -1000, // chipModeId (only used if chipModeValid is true) + IfaceType.STA, + "wlan0", + TestChipV1.STA_CHIP_MODE_ID, + false, // high priority + null, // tearDownList + null, // destroyedListener + null // availableListener + ); + mInOrder.verify(chipMock.chip, times(0)).createRttController(any(), any()); + + // register initial cb - expect the cb right away + mDut.registerRttControllerLifecycleCallback(cb1, mHandler); + mTestLooper.dispatchAll(); + verify(chipMock.chip).createRttController(any(), any()); + io1.verify(cb1).onNewRttController(mRttControllerMock); + + // register a second callback and the first one again + mDut.registerRttControllerLifecycleCallback(cb2, mHandler); + mDut.registerRttControllerLifecycleCallback(cb1, mHandler); + mTestLooper.dispatchAll(); + io2.verify(cb2).onNewRttController(mRttControllerMock); + + // change to AP mode (which for TestChipV1 doesn't allow RTT): trigger onDestroyed for all + validateInterfaceSequence(chipMock, + true, // chipModeValid + TestChipV1.STA_CHIP_MODE_ID, // chipModeId (only used if chipModeValid is true) + IfaceType.AP, + "wlan0", + TestChipV1.AP_CHIP_MODE_ID, + false, // high priority + null, // tearDownList + null, // destroyedListener + null // availableListener + ); + mTestLooper.dispatchAll(); + verify(chipMock.chip, times(2)).createRttController(any(), any()); // but returns a null! + io1.verify(cb1).onRttControllerDestroyed(); + io2.verify(cb2).onRttControllerDestroyed(); + + // change back to STA mode (which for TestChipV1 will re-allow RTT): trigger onNew for all + validateInterfaceSequence(chipMock, + true, // chipModeValid + TestChipV1.AP_CHIP_MODE_ID, // chipModeId (only used if chipModeValid is true) + IfaceType.STA, + "wlan0", + TestChipV1.STA_CHIP_MODE_ID, + false, // high priority + null, // tearDownList + null, // destroyedListener + null // availableListener + ); + mTestLooper.dispatchAll(); + verify(chipMock.chip, times(3)).createRttController(any(), any()); + io1.verify(cb1).onNewRttController(mRttControllerMock); + io2.verify(cb2).onNewRttController(mRttControllerMock); + + verifyNoMoreInteractions(cb1, cb2); + } + + /** + * Validate the RTT Controller lifecycle using a single-mode chip. Specifically validate + * that RTT isn't impacted during STA -> AP change. + */ + @Test + public void testAndTriggerRttLifecycleCallbacksSingleModeChip() throws Exception { + HalDeviceManager.InterfaceRttControllerLifecycleCallback cb = mock( + HalDeviceManager.InterfaceRttControllerLifecycleCallback.class); + + InOrder io = inOrder(cb); + + // initialize a test chip (V2 is a must since we need a single mode chip) + // & create a STA (which will configure the chip). + ChipMockBase chipMock = new TestChipV2(); + chipMock.initialize(); + mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip, + mManagerStatusListenerMock); + executeAndValidateInitializationSequence(); + executeAndValidateStartupSequence(); + validateInterfaceSequence(chipMock, + false, // chipModeValid + -1000, // chipModeId (only used if chipModeValid is true) + IfaceType.STA, + "wlan0", + TestChipV2.CHIP_MODE_ID, + false, // high priority + null, // tearDownList + null, // destroyedListener + null // availableListener + ); + mInOrder.verify(chipMock.chip, times(0)).createRttController(any(), any()); + + // register initial cb - expect the cb right away + mDut.registerRttControllerLifecycleCallback(cb, mHandler); + mTestLooper.dispatchAll(); + verify(chipMock.chip).createRttController(any(), any()); + io.verify(cb).onNewRttController(mRttControllerMock); + + // create an AP: no mode change for TestChipV2 -> expect no impact on RTT + validateInterfaceSequence(chipMock, + true, // chipModeValid + TestChipV2.CHIP_MODE_ID, // chipModeId (only used if chipModeValid is true) + IfaceType.AP, + "wlan0", + TestChipV2.CHIP_MODE_ID, + false, // high priority + null, // tearDownList + null, // destroyedListener + null // availableListener + ); + mTestLooper.dispatchAll(); + + verifyNoMoreInteractions(cb); + } + ////////////////////////////////////////////////////////////////////////////////////// // Chip Specific Tests - but should work on all chips! // (i.e. add copies for each test chip) @@ -2198,6 +2391,7 @@ public class HalDeviceManagerTest { /////////////////////////////////////////////////////////////////////////////////////// // utilities /////////////////////////////////////////////////////////////////////////////////////// + private void dumpDut(String prefix) { StringWriter sw = new StringWriter(); mDut.dump(null, new PrintWriter(sw), null); @@ -2234,7 +2428,7 @@ public class HalDeviceManagerTest { } } - private void executeAndValidateStartupSequence()throws Exception { + private void executeAndValidateStartupSequence() throws Exception { executeAndValidateStartupSequence(1, true); } @@ -2684,6 +2878,7 @@ public class HalDeviceManagerTest { } public WifiStatus answer(int chipMode) { + mChipMockBase.chipModeValid = true; mChipMockBase.chipModeId = chipMode; return mStatusOk; } @@ -2784,6 +2979,24 @@ public class HalDeviceManagerTest { } } + private class CreateRttControllerAnswer extends MockAnswerUtil.AnswerWithArguments { + private final ChipMockBase mChipMockBase; + private final IWifiRttController mRttController; + + CreateRttControllerAnswer(ChipMockBase chipMockBase, IWifiRttController rttController) { + mChipMockBase = chipMockBase; + mRttController = rttController; + } + + public void answer(IWifiIface boundIface, IWifiChip.createRttControllerCallback cb) { + if (mChipMockBase.chipModeIdValidForRtt == mChipMockBase.chipModeId) { + cb.onValues(mStatusOk, mRttController); + } else { + cb.onValues(mStatusFail, null); + } + } + } + private class RemoveXxxIfaceAnswer extends MockAnswerUtil.AnswerWithArguments { private ChipMockBase mChipMockBase; private int mType; @@ -2850,6 +3063,7 @@ public class HalDeviceManagerTest { public int chipId; public boolean chipModeValid = false; public int chipModeId = -1000; + public int chipModeIdValidForRtt = -1; // single chip mode ID where RTT can be created public Map<Integer, ArrayList<String>> interfaceNames = new HashMap<>(); public Map<Integer, Map<String, IWifiIface>> interfacesByName = new HashMap<>(); @@ -2900,6 +3114,9 @@ public class HalDeviceManagerTest { anyString()); doAnswer(new RemoveXxxIfaceAnswer(this, IfaceType.NAN)).when(chip).removeNanIface( anyString()); + + doAnswer(new CreateRttControllerAnswer(this, mRttControllerMock)).when( + chip).createRttController(any(), any()); } } @@ -2962,6 +3179,8 @@ public class HalDeviceManagerTest { cm.availableCombinations.add(cic); availableModes.add(cm); + chipModeIdValidForRtt = STA_CHIP_MODE_ID; + doAnswer(new GetAvailableModesAnswer(this)).when(chip) .getAvailableModes(any(IWifiChip.getAvailableModesCallback.class)); } @@ -3020,6 +3239,8 @@ public class HalDeviceManagerTest { cm.availableCombinations.add(cic); availableModes.add(cm); + chipModeIdValidForRtt = CHIP_MODE_ID; + doAnswer(new GetAvailableModesAnswer(this)).when(chip) .getAvailableModes(any(IWifiChip.getAvailableModesCallback.class)); } @@ -3090,6 +3311,8 @@ public class HalDeviceManagerTest { cm.availableCombinations.add(cic); availableModes.add(cm); + chipModeIdValidForRtt = CHIP_MODE_ID; + doAnswer(new GetAvailableModesAnswer(this)).when(chip) .getAvailableModes(any(IWifiChip.getAvailableModesCallback.class)); } @@ -3159,6 +3382,8 @@ public class HalDeviceManagerTest { cm.availableCombinations.add(cic); availableModes.add(cm); + chipModeIdValidForRtt = CHIP_MODE_ID; + doAnswer(new GetAvailableModesAnswer(this)).when(chip) .getAvailableModes(any(IWifiChip.getAvailableModesCallback.class)); } diff --git a/tests/wifitests/src/com/android/server/wifi/WifiVendorHalTest.java b/tests/wifitests/src/com/android/server/wifi/WifiVendorHalTest.java index d5259c710..9ca722164 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiVendorHalTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiVendorHalTest.java @@ -48,15 +48,9 @@ import android.hardware.wifi.V1_0.IWifiApIface; import android.hardware.wifi.V1_0.IWifiChip; import android.hardware.wifi.V1_0.IWifiChipEventCallback; import android.hardware.wifi.V1_0.IWifiIface; -import android.hardware.wifi.V1_0.IWifiRttController; -import android.hardware.wifi.V1_0.IWifiRttControllerEventCallback; import android.hardware.wifi.V1_0.IWifiStaIface; import android.hardware.wifi.V1_0.IWifiStaIfaceEventCallback; import android.hardware.wifi.V1_0.IfaceType; -import android.hardware.wifi.V1_0.RttBw; -import android.hardware.wifi.V1_0.RttCapabilities; -import android.hardware.wifi.V1_0.RttConfig; -import android.hardware.wifi.V1_0.RttPreamble; import android.hardware.wifi.V1_0.StaApfPacketFilterCapabilities; import android.hardware.wifi.V1_0.StaBackgroundScanCapabilities; import android.hardware.wifi.V1_0.StaBackgroundScanParameters; @@ -86,7 +80,6 @@ import android.hardware.wifi.V1_2.IWifiChipEventCallback.RadioModeInfo; import android.net.KeepalivePacketData; import android.net.MacAddress; import android.net.apf.ApfCapabilities; -import android.net.wifi.RttManager; import android.net.wifi.ScanResult; import android.net.wifi.WifiManager; import android.net.wifi.WifiScanner; @@ -154,8 +147,6 @@ public class WifiVendorHalTest { private android.hardware.wifi.V1_2.IWifiStaIface mIWifiStaIfaceV12; @Mock private android.hardware.wifi.V1_3.IWifiStaIface mIWifiStaIfaceV13; - @Mock - private IWifiRttController mIWifiRttController; private IWifiStaIfaceEventCallback mIWifiStaIfaceEventCallback; private IWifiChipEventCallback mIWifiChipEventCallback; private android.hardware.wifi.V1_2.IWifiChipEventCallback mIWifiChipEventCallbackV12; @@ -310,7 +301,6 @@ public class WifiVendorHalTest { when(mHalDeviceManager.removeIface(any())).thenReturn(true); when(mHalDeviceManager.getChip(any(IWifiIface.class))) .thenReturn(mIWifiChip); - when(mHalDeviceManager.createRttController()).thenReturn(mIWifiRttController); when(mIWifiChip.registerEventCallback(any(IWifiChipEventCallback.class))) .thenReturn(mWifiStatusSuccess); mIWifiStaIfaceEventCallback = null; @@ -335,9 +325,6 @@ public class WifiVendorHalTest { return (mWifiStatusSuccess); })); - when(mIWifiRttController.registerEventCallback(any(IWifiRttControllerEventCallback.class))) - .thenReturn(mWifiStatusSuccess); - doAnswer(new AnswerWithArguments() { public void answer(IWifiIface.getNameCallback cb) throws RemoteException { @@ -375,7 +362,6 @@ public class WifiVendorHalTest { verify(mHalDeviceManager).start(); verify(mHalDeviceManager).createStaIface(eq(false), any(), eq(null)); verify(mHalDeviceManager).getChip(eq(mIWifiStaIface)); - verify(mHalDeviceManager).createRttController(); verify(mHalDeviceManager).isReady(); verify(mHalDeviceManager).isStarted(); verify(mIWifiStaIface).registerEventCallback(any(IWifiStaIfaceEventCallback.class)); @@ -400,7 +386,6 @@ public class WifiVendorHalTest { verify(mHalDeviceManager).isStarted(); verify(mHalDeviceManager, never()).createStaIface(anyBoolean(), any(), eq(null)); - verify(mHalDeviceManager, never()).createRttController(); } /** @@ -424,7 +409,6 @@ public class WifiVendorHalTest { verify(mHalDeviceManager, never()).createStaIface(anyBoolean(), any(), eq(null)); verify(mHalDeviceManager, never()).createApIface(any(), eq(null)); verify(mHalDeviceManager, never()).getChip(any(IWifiIface.class)); - verify(mHalDeviceManager, never()).createRttController(); verify(mIWifiStaIface, never()) .registerEventCallback(any(IWifiStaIfaceEventCallback.class)); } @@ -445,7 +429,6 @@ public class WifiVendorHalTest { verify(mHalDeviceManager, never()).createApIface(any(), eq(null)); verify(mHalDeviceManager, never()).getChip(any(IWifiIface.class)); - verify(mHalDeviceManager, never()).createRttController(); verify(mIWifiStaIface, never()) .registerEventCallback(any(IWifiStaIfaceEventCallback.class)); } @@ -455,26 +438,6 @@ public class WifiVendorHalTest { * {@link WifiVendorHal#startVendorHalSta()}. */ @Test - public void testStartHalFailureInRttControllerCreationInStaMode() throws Exception { - when(mHalDeviceManager.createRttController()).thenReturn(null); - assertFalse(mWifiVendorHal.startVendorHalSta()); - assertFalse(mWifiVendorHal.isHalStarted()); - - verify(mHalDeviceManager).start(); - verify(mHalDeviceManager).createStaIface(eq(false), any(), eq(null)); - verify(mHalDeviceManager).createRttController(); - verify(mHalDeviceManager).stop(); - verify(mIWifiStaIface).registerEventCallback(any(IWifiStaIfaceEventCallback.class)); - - verify(mHalDeviceManager, never()).createApIface(any(), eq(null)); - verify(mHalDeviceManager, never()).getChip(any(IWifiIface.class)); - } - - /** - * Tests the failure to start HAL in STA mode using - * {@link WifiVendorHal#startVendorHalSta()}. - */ - @Test public void testStartHalFailureInChipGetInStaMode() throws Exception { when(mHalDeviceManager.getChip(any(IWifiIface.class))).thenReturn(null); assertFalse(mWifiVendorHal.startVendorHalSta()); @@ -482,7 +445,6 @@ public class WifiVendorHalTest { verify(mHalDeviceManager).start(); verify(mHalDeviceManager).createStaIface(eq(false), any(), eq(null)); - verify(mHalDeviceManager).createRttController(); verify(mHalDeviceManager).getChip(any(IWifiIface.class)); verify(mHalDeviceManager).stop(); verify(mIWifiStaIface).registerEventCallback(any(IWifiStaIfaceEventCallback.class)); @@ -506,7 +468,6 @@ public class WifiVendorHalTest { verify(mHalDeviceManager).stop(); verify(mIWifiStaIface).registerEventCallback(any(IWifiStaIfaceEventCallback.class)); - verify(mHalDeviceManager, never()).createRttController(); verify(mHalDeviceManager, never()).getChip(any(IWifiIface.class)); verify(mHalDeviceManager, never()).createApIface(any(), eq(null)); } @@ -524,7 +485,6 @@ public class WifiVendorHalTest { verify(mHalDeviceManager).start(); verify(mHalDeviceManager).createStaIface(eq(false), any(), eq(null)); - verify(mHalDeviceManager).createRttController(); verify(mHalDeviceManager).getChip(any(IWifiIface.class)); verify(mHalDeviceManager).stop(); verify(mIWifiStaIface).registerEventCallback(any(IWifiStaIfaceEventCallback.class)); @@ -549,7 +509,6 @@ public class WifiVendorHalTest { verify(mHalDeviceManager, never()).createStaIface(anyBoolean(), any(), eq(null)); verify(mHalDeviceManager, never()).getChip(any(IWifiIface.class)); - verify(mHalDeviceManager, never()).createRttController(); } /** @@ -568,7 +527,6 @@ public class WifiVendorHalTest { verify(mHalDeviceManager).stop(); verify(mHalDeviceManager).createStaIface(eq(false), any(), eq(null)); verify(mHalDeviceManager).getChip(eq(mIWifiStaIface)); - verify(mHalDeviceManager).createRttController(); verify(mHalDeviceManager, times(2)).isReady(); verify(mHalDeviceManager, times(2)).isStarted(); @@ -595,7 +553,6 @@ public class WifiVendorHalTest { verify(mHalDeviceManager, times(2)).isStarted(); verify(mHalDeviceManager, never()).createStaIface(anyBoolean(), any(), eq(null)); - verify(mHalDeviceManager, never()).createRttController(); } /** @@ -615,7 +572,6 @@ public class WifiVendorHalTest { verify(mHalDeviceManager).createStaIface(eq(false), internalListenerCaptor.capture(), eq(null)); verify(mHalDeviceManager).getChip(eq(mIWifiStaIface)); - verify(mHalDeviceManager).createRttController(); verify(mHalDeviceManager).isReady(); verify(mHalDeviceManager).isStarted(); verify(mIWifiStaIface).registerEventCallback(any(IWifiStaIfaceEventCallback.class)); @@ -1103,137 +1059,6 @@ public class WifiVendorHalTest { assertEquals(2, ex); } - - /** - * Test translations of RTT type - */ - @Test - public void testRttTypeTranslation() throws Exception { - checkRoundTripIntTranslation( - (y) -> WifiVendorHal.halRttTypeFromFrameworkRttType(y), - (x) -> WifiVendorHal.frameworkRttTypeFromHalRttType(x), - 1, 3); - } - - /** - * Test translations of peer type - */ - @Test - public void testPeerTranslation() throws Exception { - checkRoundTripIntTranslation( - (y) -> WifiVendorHal.halPeerFromFrameworkPeer(y), - (x) -> WifiVendorHal.frameworkPeerFromHalPeer(x), - 1, 6); - } - - /** - * Test translations of channel width - */ - @Test - public void testChannelWidth() throws Exception { - checkRoundTripIntTranslation( - (y) -> WifiVendorHal.halChannelWidthFromFrameworkChannelWidth(y), - (x) -> WifiVendorHal.frameworkChannelWidthFromHalChannelWidth(x), - 0, 5); - } - - /** - * Test translations of preamble type mask - */ - @Test - public void testPreambleTranslation() throws Exception { - checkRoundTripIntTranslation( - (y) -> WifiVendorHal.halPreambleFromFrameworkPreamble(y), - (x) -> WifiVendorHal.frameworkPreambleFromHalPreamble(x), - 0, 8); - } - - /** - * Test translations of bandwidth mask - */ - @Test - public void testBandwidthTranslations() throws Exception { - checkRoundTripIntTranslation( - (y) -> WifiVendorHal.halBwFromFrameworkBw(y), - (x) -> WifiVendorHal.frameworkBwFromHalBw(x), - 0, 64); - } - - /** - * Test translation of framwork RttParams to hal RttConfig - */ - @Test - public void testGetRttStuff() throws Exception { - RttManager.RttParams params = new RttManager.RttParams(); - params.bssid = "03:01:04:01:05:09"; - params.frequency = 2420; - params.channelWidth = ScanResult.CHANNEL_WIDTH_40MHZ; - params.centerFreq0 = 2440; - params.centerFreq1 = 1; - params.num_samples = 2; - params.num_retries = 3; - params.numberBurst = 4; - params.interval = 5; - params.numSamplesPerBurst = 8; - params.numRetriesPerMeasurementFrame = 6; - params.numRetriesPerFTMR = 7; - params.LCIRequest = false; - params.LCRRequest = false; - params.burstTimeout = 15; - String frameish = params.toString(); - assertFalse(frameish.contains("=0,")); // make sure all fields are initialized - RttConfig config = WifiVendorHal.halRttConfigFromFrameworkRttParams(params); - String halish = config.toString(); - StringBuffer expect = new StringBuffer(200); - expect.append("{.addr = [3, 1, 4, 1, 5, 9], .type = ONE_SIDED, .peer = AP, "); - expect.append(".channel = {.width = WIDTH_40, .centerFreq = 2420, "); - expect.append(".centerFreq0 = 2440, .centerFreq1 = 1}, "); - expect.append(".burstPeriod = 5, .numBurst = 4, .numFramesPerBurst = 8, "); - expect.append(".numRetriesPerRttFrame = 6, .numRetriesPerFtmr = 7, "); - expect.append(".mustRequestLci = false, .mustRequestLcr = false, .burstDuration = 15, "); - expect.append(".preamble = HT, .bw = BW_20MHZ}"); - assertEquals(expect.toString(), halish); - } - - /** - * Test that RTT capabilities are plumbed through - */ - @Test - public void testGetRttCapabilities() throws Exception { - RttCapabilities capabilities = new RttCapabilities(); - capabilities.lcrSupported = true; - capabilities.preambleSupport = RttPreamble.LEGACY | RttPreamble.VHT; - capabilities.bwSupport = RttBw.BW_5MHZ | RttBw.BW_20MHZ; - capabilities.mcVersion = 43; - doAnswer(new AnswerWithArguments() { - public void answer(IWifiRttController.getCapabilitiesCallback cb) - throws RemoteException { - cb.onValues(mWifiStatusSuccess, capabilities); - } - }).when(mIWifiRttController).getCapabilities(any( - IWifiRttController.getCapabilitiesCallback.class)); - - assertNull(mWifiVendorHal.getRttCapabilities()); - - assertTrue(mWifiVendorHal.startVendorHalSta()); - - RttManager.RttCapabilities actual = mWifiVendorHal.getRttCapabilities(); - assertTrue(actual.lcrSupported); - assertEquals(RttManager.PREAMBLE_LEGACY | RttManager.PREAMBLE_VHT, - actual.preambleSupported); - assertEquals(RttManager.RTT_BW_5_SUPPORT | RttManager.RTT_BW_20_SUPPORT, - actual.bwSupported); - assertEquals(43, (int) capabilities.mcVersion); - } - - /** - * Negative test of disableRttResponder - */ - @Test - public void testDisableOfUnstartedRtt() throws Exception { - assertFalse(mWifiVendorHal.disableRttResponder()); - } - /** * Test that setScanningMacOui is hooked up to the HAL correctly */ diff --git a/tests/wifitests/src/com/android/server/wifi/rtt/RttNativeTest.java b/tests/wifitests/src/com/android/server/wifi/rtt/RttNativeTest.java index d55d3ba9e..59ef71666 100644 --- a/tests/wifitests/src/com/android/server/wifi/rtt/RttNativeTest.java +++ b/tests/wifitests/src/com/android/server/wifi/rtt/RttNativeTest.java @@ -23,6 +23,7 @@ import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; @@ -69,6 +70,9 @@ public class RttNativeTest { private ArgumentCaptor<List> mRttResultCaptor = ArgumentCaptor.forClass(List.class); private ArgumentCaptor<HalDeviceManager.ManagerStatusListener> mHdmStatusListener = ArgumentCaptor.forClass(HalDeviceManager.ManagerStatusListener.class); + private ArgumentCaptor<HalDeviceManager.InterfaceRttControllerLifecycleCallback> + mRttLifecycleCbCaptor = ArgumentCaptor.forClass( + HalDeviceManager.InterfaceRttControllerLifecycleCallback.class); private ArgumentCaptor<IWifiRttController.getCapabilitiesCallback> mGetCapCbCatpr = ArgumentCaptor.forClass(IWifiRttController.getCapabilitiesCallback.class); @@ -89,7 +93,6 @@ public class RttNativeTest { MockitoAnnotations.initMocks(this); when(mockHalDeviceManager.isStarted()).thenReturn(true); - when(mockHalDeviceManager.createRttController()).thenReturn(mockRttController); mStatusSuccess = new WifiStatus(); mStatusSuccess.code = WifiStatusCode.SUCCESS; @@ -101,7 +104,10 @@ public class RttNativeTest { mDut = new RttNative(mockRttServiceImpl, mockHalDeviceManager); mDut.start(null); - verify(mockHalDeviceManager).registerStatusListener(mHdmStatusListener.capture(), any()); + verify(mockHalDeviceManager).initialize(); + verify(mockHalDeviceManager).registerRttControllerLifecycleCallback( + mRttLifecycleCbCaptor.capture(), any()); + mRttLifecycleCbCaptor.getValue().onNewRttController(mockRttController); verify(mockRttController).registerEventCallback(any()); verify(mockRttServiceImpl).enableIfPossible(); verify(mockRttController).getCapabilities(mGetCapCbCatpr.capture()); @@ -326,9 +332,8 @@ public class RttNativeTest { int cmdId = 55; RangingRequest request = RttTestUtils.getDummyRangingRequest((byte) 0); - // (1) configure Wi-Fi down and send a status change indication - when(mockHalDeviceManager.isStarted()).thenReturn(false); - mHdmStatusListener.getValue().onStatusChanged(); + // (1) simulate Wi-Fi down and send a status change indication + mRttLifecycleCbCaptor.getValue().onRttControllerDestroyed(); verify(mockRttServiceImpl).disable(); assertFalse(mDut.isReady()); @@ -339,6 +344,27 @@ public class RttNativeTest { } /** + * Validate that we react correctly (i.e. enable/disable global RTT availability) when + * notified that the RTT controller has disappear and appeared. + */ + @Test + public void testRttControllerLifecycle() throws Exception { + // RTT controller disappears + mRttLifecycleCbCaptor.getValue().onRttControllerDestroyed(); + verify(mockRttServiceImpl).disable(); + assertFalse(mDut.isReady()); + + // RTT controller re-appears (verification is x2 since 1st time is in setup()) + mRttLifecycleCbCaptor.getValue().onNewRttController(mockRttController); + verify(mockRttController, times(2)).registerEventCallback(any()); + verify(mockRttServiceImpl, times(2)).enableIfPossible(); + verify(mockRttController, times(2)).getCapabilities(mGetCapCbCatpr.capture()); + assertTrue(mDut.isReady()); + + verifyNoMoreInteractions(mockRttServiceImpl, mockRttController); + } + + /** * Validate ranging cancel flow. */ @Test |