blob: 3c0541b60a3ec49370bc7f4ed35f0ab3f5370ae8 [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.wifi.rtt;
import android.annotation.IntDef;
import android.annotation.Nullable;
import android.hardware.wifi.V1_0.IWifiRttController;
import android.hardware.wifi.V1_0.IWifiRttControllerEventCallback;
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.RttPeerType;
import android.hardware.wifi.V1_0.RttPreamble;
import android.hardware.wifi.V1_0.RttResult;
import android.hardware.wifi.V1_0.RttStatus;
import android.hardware.wifi.V1_0.RttType;
import android.hardware.wifi.V1_0.WifiChannelWidthInMhz;
import android.hardware.wifi.V1_0.WifiStatus;
import android.hardware.wifi.V1_0.WifiStatusCode;
import android.net.MacAddress;
import android.net.wifi.rtt.RangingRequest;
import android.net.wifi.rtt.RangingResult;
import android.net.wifi.rtt.ResponderConfig;
import android.net.wifi.rtt.ResponderLocation;
import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
import com.android.server.wifi.HalDeviceManager;
import com.android.server.wifi.util.NativeUtil;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Objects;
/**
* TBD
*/
public class RttNative {
private static final String TAG = "RttNative";
private static final boolean VDBG = false; // STOPSHIP if true
/* package */ boolean mDbg = false;
/** Unknown status */
public static final int FRAMEWORK_RTT_STATUS_UNKNOWN = -1;
/** Success */
public static final int FRAMEWORK_RTT_STATUS_SUCCESS = 0;
/** General failure status */
public static final int FRAMEWORK_RTT_STATUS_FAILURE = 1;
/** Target STA does not respond to request */
public static final int FRAMEWORK_RTT_STATUS_FAIL_NO_RSP = 2;
/** Request rejected. Applies to 2-sided RTT only */
public static final int FRAMEWORK_RTT_STATUS_FAIL_REJECTED = 3;
public static final int FRAMEWORK_RTT_STATUS_FAIL_NOT_SCHEDULED_YET = 4;
/** Timing measurement times out */
public static final int FRAMEWORK_RTT_STATUS_FAIL_TM_TIMEOUT = 5;
/** Target on different channel, cannot range */
public static final int FRAMEWORK_RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL = 6;
/** Ranging not supported */
public static final int FRAMEWORK_RTT_STATUS_FAIL_NO_CAPABILITY = 7;
/** Request aborted for unknown reason */
public static final int FRAMEWORK_RTT_STATUS_ABORTED = 8;
/** Invalid T1-T4 timestamp */
public static final int FRAMEWORK_RTT_STATUS_FAIL_INVALID_TS = 9;
/** 11mc protocol failed */
public static final int FRAMEWORK_RTT_STATUS_FAIL_PROTOCOL = 10;
/** Request could not be scheduled */
public static final int FRAMEWORK_RTT_STATUS_FAIL_SCHEDULE = 11;
/** Responder cannot collaborate at time of request */
public static final int FRAMEWORK_RTT_STATUS_FAIL_BUSY_TRY_LATER = 12;
/** Bad request args */
public static final int FRAMEWORK_RTT_STATUS_INVALID_REQ = 13;
/** WiFi not enabled. */
public static final int FRAMEWORK_RTT_STATUS_NO_WIFI = 14;
/** Responder overrides param info, cannot range with new params */
public static final int FRAMEWORK_RTT_STATUS_FAIL_FTM_PARAM_OVERRIDE = 15;
/** @hide */
@IntDef(prefix = "FRAMEWORK_RTT_STATUS_", value = {FRAMEWORK_RTT_STATUS_UNKNOWN,
FRAMEWORK_RTT_STATUS_SUCCESS, FRAMEWORK_RTT_STATUS_FAILURE,
FRAMEWORK_RTT_STATUS_FAIL_NO_RSP, FRAMEWORK_RTT_STATUS_FAIL_REJECTED,
FRAMEWORK_RTT_STATUS_FAIL_NOT_SCHEDULED_YET, FRAMEWORK_RTT_STATUS_FAIL_TM_TIMEOUT,
FRAMEWORK_RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL, FRAMEWORK_RTT_STATUS_FAIL_NO_CAPABILITY,
FRAMEWORK_RTT_STATUS_ABORTED, FRAMEWORK_RTT_STATUS_FAIL_INVALID_TS,
FRAMEWORK_RTT_STATUS_FAIL_PROTOCOL, FRAMEWORK_RTT_STATUS_FAIL_SCHEDULE,
FRAMEWORK_RTT_STATUS_FAIL_BUSY_TRY_LATER, FRAMEWORK_RTT_STATUS_INVALID_REQ,
FRAMEWORK_RTT_STATUS_NO_WIFI, FRAMEWORK_RTT_STATUS_FAIL_FTM_PARAM_OVERRIDE})
@Retention(RetentionPolicy.SOURCE)
public @interface FrameworkRttStatus {}
private final RttServiceImpl mRttService;
private final HalDeviceManager mHalDeviceManager;
private Object mLock = new Object();
private volatile IWifiRttController mIWifiRttController;
private volatile Capabilities mRttCapabilities;
private final WifiRttControllerEventCallback mWifiRttControllerEventCallback;
private volatile android.hardware.wifi.V1_4.IWifiRttController mIWifiRttController14;
private final WifiRttControllerEventCallback14 mWifiRttControllerEventCallback14;
private static final int CONVERSION_US_TO_MS = 1_000;
private final HalDeviceManager.InterfaceRttControllerLifecycleCallback mRttLifecycleCb =
new HalDeviceManager.InterfaceRttControllerLifecycleCallback() {
@Override
public void onNewRttController(IWifiRttController controller) {
if (mDbg) Log.d(TAG, "onNewRttController: controller=" + controller);
synchronized (mLock) {
mIWifiRttController = controller;
mIWifiRttController14 = getWifiRttControllerV1_4();
try {
if (mIWifiRttController14 != null) {
mIWifiRttController14.registerEventCallback_1_4(
mWifiRttControllerEventCallback14);
} else {
mIWifiRttController.registerEventCallback(
mWifiRttControllerEventCallback);
}
} catch (RemoteException e) {
Log.e(TAG, "onNewRttController: exception registering callback: " + e);
if (mIWifiRttController != null) {
mIWifiRttController = null;
mIWifiRttController14 = null;
mRttService.disable();
}
return;
}
mRttService.enableIfPossible();
updateRttCapabilities();
}
}
@Override
public void onRttControllerDestroyed() {
if (mDbg) Log.d(TAG, "onRttControllerDestroyed");
synchronized (mLock) {
mIWifiRttController = null;
mIWifiRttController14 = null;
mRttCapabilities = null;
mRttService.disable();
}
}
};
public RttNative(RttServiceImpl rttService, HalDeviceManager halDeviceManager) {
mRttService = rttService;
mHalDeviceManager = halDeviceManager;
mWifiRttControllerEventCallback = new WifiRttControllerEventCallback();
mWifiRttControllerEventCallback14 = new WifiRttControllerEventCallback14();
}
/**
* Initialize the object - registering with the HAL device manager.
*/
public void start(Handler handler) {
synchronized (mLock) {
mHalDeviceManager.initialize();
mHalDeviceManager.registerStatusListener(() -> {
if (VDBG) Log.d(TAG, "hdm.onStatusChanged");
if (mHalDeviceManager.isStarted()) {
mHalDeviceManager.registerRttControllerLifecycleCallback(mRttLifecycleCb,
handler);
}
}, handler);
if (mHalDeviceManager.isStarted()) {
mHalDeviceManager.registerRttControllerLifecycleCallback(mRttLifecycleCb, handler);
}
}
}
/**
* Returns true if Wi-Fi is ready for RTT requests, false otherwise.
*/
public boolean isReady() {
return mIWifiRttController != null;
}
/**
* Returns the RTT capabilities. Will only be null when disabled (e.g. no STA interface
* available - not necessarily up).
*/
public @Nullable Capabilities getRttCapabilities() {
return mRttCapabilities;
}
/**
* Updates the RTT capabilities.
*/
void updateRttCapabilities() {
if (mIWifiRttController == null) {
Log.e(TAG, "updateRttCapabilities: but a RTT controller is NULL!?");
return;
}
if (mRttCapabilities != null) {
return;
}
if (mDbg) Log.v(TAG, "updateRttCapabilities");
synchronized (mLock) {
try {
if (mIWifiRttController14 != null) {
mIWifiRttController14.getCapabilities_1_4(
(status, capabilities14) -> {
if (status.code != WifiStatusCode.SUCCESS) {
Log.e(TAG, "updateRttCapabilities:"
+ " error requesting capabilities "
+ "-- code=" + status.code);
return;
}
if (mDbg) {
Log.v(TAG, "updateRttCapabilities: RTT capabilities="
+ capabilities14);
}
mRttCapabilities = new Capabilities(capabilities14);
});
} else {
mIWifiRttController.getCapabilities(
(status, capabilities) -> {
if (status.code != WifiStatusCode.SUCCESS) {
Log.e(TAG, "updateRttCapabilities:"
+ " error requesting capabilities "
+ "-- code=" + status.code);
return;
}
if (mDbg) {
Log.v(TAG, "updateRttCapabilities: RTT capabilities="
+ capabilities);
}
mRttCapabilities = new Capabilities(capabilities);
});
}
} catch (RemoteException e) {
Log.e(TAG, "updateRttCapabilities: exception requesting capabilities: " + e);
}
if (mRttCapabilities != null && !mRttCapabilities.rttFtmSupported) {
Log.wtf(TAG, "Firmware indicates RTT is not supported - but device supports RTT - "
+ "ignored!?");
}
}
}
/**
* Issue a range request to the HAL.
*
* @param cmdId Command ID for the request. Will be used in the corresponding
* {@link WifiRttControllerEventCallback#onResults(int, ArrayList)}.
* @param request Range request.
* @param isCalledFromPrivilegedContext Indicates whether privileged APIs are permitted,
* initially: support for one-sided RTT.
*
* @return Success status: true for success, false for failure.
*/
public boolean rangeRequest(int cmdId, RangingRequest request,
boolean isCalledFromPrivilegedContext) {
if (mDbg) {
Log.v(TAG,
"rangeRequest: cmdId=" + cmdId + ", # of requests=" + request.mRttPeers.size());
}
if (VDBG) Log.v(TAG, "rangeRequest: request=" + request);
synchronized (mLock) {
if (!isReady()) {
Log.e(TAG, "rangeRequest: RttController is null");
return false;
}
updateRttCapabilities();
if (mIWifiRttController14 != null) {
return sendRangeRequest14(cmdId, request, isCalledFromPrivilegedContext);
} else {
return sendRangeRequest(cmdId, request, isCalledFromPrivilegedContext);
}
}
}
private boolean sendRangeRequest(int cmdId, RangingRequest request,
boolean isCalledFromPrivilegedContext) {
ArrayList<RttConfig> rttConfig = convertRangingRequestToRttConfigs(request,
isCalledFromPrivilegedContext, mRttCapabilities);
if (rttConfig == null) {
Log.e(TAG, "sendRangeRequest: invalid request parameters");
return false;
}
if (rttConfig.size() == 0) {
Log.e(TAG, "sendRangeRequest: all requests invalidated");
mRttService.onRangingResults(cmdId, new ArrayList<>());
return true;
}
try {
WifiStatus status = mIWifiRttController.rangeRequest(cmdId, rttConfig);
if (status.code != WifiStatusCode.SUCCESS) {
Log.e(TAG, "sendRangeRequest: cannot issue range request -- code=" + status.code);
return false;
}
} catch (RemoteException e) {
Log.e(TAG, "sendRangeRequest: exception issuing range request: " + e);
return false;
}
return true;
}
private boolean sendRangeRequest14(int cmdId, RangingRequest request,
boolean isCalledFromPrivilegedContext) {
ArrayList<android.hardware.wifi.V1_4.RttConfig> rttConfig =
convertRangingRequestToRttConfigs14(request,
isCalledFromPrivilegedContext, mRttCapabilities);
if (rttConfig == null) {
Log.e(TAG, "sendRangeRequest14: invalid request parameters");
return false;
}
if (rttConfig.size() == 0) {
Log.e(TAG, "sendRangeRequest14: all requests invalidated");
mRttService.onRangingResults(cmdId, new ArrayList<>());
return true;
}
try {
WifiStatus status = mIWifiRttController14.rangeRequest_1_4(cmdId, rttConfig);
if (status.code != WifiStatusCode.SUCCESS) {
Log.e(TAG, "sendRangeRequest14: cannot issue range request -- code="
+ status.code);
return false;
}
} catch (RemoteException e) {
Log.e(TAG, "sendRangeRequest14: exception issuing range request: " + e);
return false;
}
return true;
}
/**
* Cancel an outstanding ranging request: no guarantees of execution - we will ignore any
* results which are returned for the canceled request.
*
* @param cmdId The cmdId issued with the original rangeRequest command.
* @param macAddresses A list of MAC addresses for which to cancel the operation.
* @return Success status: true for success, false for failure.
*/
public boolean rangeCancel(int cmdId, ArrayList<byte[]> macAddresses) {
if (mDbg) Log.v(TAG, "rangeCancel: cmdId=" + cmdId);
synchronized (mLock) {
if (!isReady()) {
Log.e(TAG, "rangeCancel: RttController is null");
return false;
}
try {
WifiStatus status = mIWifiRttController.rangeCancel(cmdId, macAddresses);
if (status.code != WifiStatusCode.SUCCESS) {
Log.e(TAG, "rangeCancel: cannot issue range cancel -- code=" + status.code);
return false;
}
} catch (RemoteException e) {
Log.e(TAG, "rangeCancel: exception issuing range cancel: " + e);
return false;
}
return true;
}
}
private static ArrayList<RttConfig> convertRangingRequestToRttConfigs(RangingRequest request,
boolean isCalledFromPrivilegedContext, Capabilities cap) {
ArrayList<RttConfig> rttConfigs = new ArrayList<>(request.mRttPeers.size());
// Skipping any configurations which have an error (printing out a message).
// The caller will only get results for valid configurations.
for (ResponderConfig responder: request.mRttPeers) {
RttConfig config = new RttConfig();
System.arraycopy(responder.macAddress.toByteArray(), 0, config.addr, 0,
config.addr.length);
try {
config.type = responder.supports80211mc ? RttType.TWO_SIDED : RttType.ONE_SIDED;
if (config.type == RttType.ONE_SIDED && cap != null && !cap.oneSidedRttSupported) {
Log.w(TAG, "Device does not support one-sided RTT");
continue;
}
config.peer = halRttPeerTypeFromResponderType(responder.responderType);
config.channel.width = halChannelWidthFromResponderChannelWidth(
responder.channelWidth);
config.channel.centerFreq = responder.frequency;
config.channel.centerFreq0 = responder.centerFreq0;
config.channel.centerFreq1 = responder.centerFreq1;
config.bw = halRttChannelBandwidthFromResponderChannelWidth(responder.channelWidth);
config.preamble = halRttPreambleFromResponderPreamble(responder.preamble);
validateBwAndPreambleCombination(config.bw, config.preamble);
if (config.peer == RttPeerType.NAN) {
config.mustRequestLci = false;
config.mustRequestLcr = false;
config.burstPeriod = 0;
config.numBurst = 0;
config.numFramesPerBurst = request.mRttBurstSize;
config.numRetriesPerRttFrame = 0; // irrelevant for 2-sided RTT
config.numRetriesPerFtmr = 3;
config.burstDuration = 9;
} else { // AP + all non-NAN requests
config.mustRequestLci = true;
config.mustRequestLcr = true;
config.burstPeriod = 0;
config.numBurst = 0;
config.numFramesPerBurst = request.mRttBurstSize;
config.numRetriesPerRttFrame = (config.type == RttType.TWO_SIDED ? 0 : 3);
config.numRetriesPerFtmr = 3;
config.burstDuration = 9;
if (cap != null) { // constrain parameters per device capabilities
config.mustRequestLci = config.mustRequestLci && cap.lciSupported;
config.mustRequestLcr = config.mustRequestLcr && cap.lcrSupported;
config.bw = halRttChannelBandwidthCapabilityLimiter(config.bw, cap);
config.preamble = halRttPreambleCapabilityLimiter(config.preamble, cap);
}
}
} catch (IllegalArgumentException e) {
Log.e(TAG, "Invalid configuration: " + e.getMessage());
continue;
}
rttConfigs.add(config);
}
return rttConfigs;
}
private static void validateBwAndPreambleCombination(int bw, int preamble) {
if (bw <= RttBw.BW_20MHZ) {
return;
}
if (bw == RttBw.BW_40MHZ && preamble >= RttPreamble.HT) {
return;
}
if (bw >= RttBw.BW_80MHZ && preamble >= RttPreamble.VHT) {
return;
}
throw new IllegalArgumentException(
"bw and preamble combination is invalid, bw: " + bw + " preamble: " + preamble);
}
private static ArrayList<android.hardware.wifi.V1_4.RttConfig>
convertRangingRequestToRttConfigs14(
RangingRequest request, boolean isCalledFromPrivilegedContext, Capabilities cap) {
ArrayList<android.hardware.wifi.V1_4.RttConfig> rttConfigs =
new ArrayList<>(request.mRttPeers.size());
// Skipping any configurations which have an error (printing out a message).
// The caller will only get results for valid configurations.
for (ResponderConfig responder: request.mRttPeers) {
android.hardware.wifi.V1_4.RttConfig config =
new android.hardware.wifi.V1_4.RttConfig();
System.arraycopy(responder.macAddress.toByteArray(), 0, config.addr, 0,
config.addr.length);
try {
config.type = responder.supports80211mc ? RttType.TWO_SIDED : RttType.ONE_SIDED;
if (config.type == RttType.ONE_SIDED && cap != null && !cap.oneSidedRttSupported) {
Log.w(TAG, "Device does not support one-sided RTT");
continue;
}
config.peer = halRttPeerTypeFromResponderType(responder.responderType);
config.channel.width = halChannelWidthFromResponderChannelWidth(
responder.channelWidth);
config.channel.centerFreq = responder.frequency;
config.channel.centerFreq0 = responder.centerFreq0;
config.channel.centerFreq1 = responder.centerFreq1;
config.bw = halRttChannelBandwidthFromResponderChannelWidth(responder.channelWidth);
config.preamble = halRttPreamble14FromResponderPreamble(responder.preamble);
if (config.peer == RttPeerType.NAN) {
config.mustRequestLci = false;
config.mustRequestLcr = false;
config.burstPeriod = 0;
config.numBurst = 0;
config.numFramesPerBurst = request.mRttBurstSize;
config.numRetriesPerRttFrame = 0; // irrelevant for 2-sided RTT
config.numRetriesPerFtmr = 3;
config.burstDuration = 9;
} else { // AP + all non-NAN requests
config.mustRequestLci = true;
config.mustRequestLcr = true;
config.burstPeriod = 0;
config.numBurst = 0;
config.numFramesPerBurst = request.mRttBurstSize;
config.numRetriesPerRttFrame = (config.type == RttType.TWO_SIDED ? 0 : 3);
config.numRetriesPerFtmr = 3;
config.burstDuration = 9;
if (cap != null) { // constrain parameters per device capabilities
config.mustRequestLci = config.mustRequestLci && cap.lciSupported;
config.mustRequestLcr = config.mustRequestLcr && cap.lcrSupported;
config.bw = halRttChannelBandwidthCapabilityLimiter(config.bw, cap);
config.preamble = halRttPreambleCapabilityLimiter(config.preamble, cap);
}
}
} catch (IllegalArgumentException e) {
Log.e(TAG, "Invalid configuration: " + e.getMessage());
continue;
}
rttConfigs.add(config);
}
return rttConfigs;
}
private static int halRttPeerTypeFromResponderType(int responderType) {
switch (responderType) {
case ResponderConfig.RESPONDER_AP:
return RttPeerType.AP;
case ResponderConfig.RESPONDER_STA:
return RttPeerType.STA;
case ResponderConfig.RESPONDER_P2P_GO:
return RttPeerType.P2P_GO;
case ResponderConfig.RESPONDER_P2P_CLIENT:
return RttPeerType.P2P_CLIENT;
case ResponderConfig.RESPONDER_AWARE:
return RttPeerType.NAN;
default:
throw new IllegalArgumentException(
"halRttPeerTypeFromResponderType: bad " + responderType);
}
}
private static int halChannelWidthFromResponderChannelWidth(int responderChannelWidth) {
switch (responderChannelWidth) {
case ResponderConfig.CHANNEL_WIDTH_20MHZ:
return WifiChannelWidthInMhz.WIDTH_20;
case ResponderConfig.CHANNEL_WIDTH_40MHZ:
return WifiChannelWidthInMhz.WIDTH_40;
case ResponderConfig.CHANNEL_WIDTH_80MHZ:
return WifiChannelWidthInMhz.WIDTH_80;
case ResponderConfig.CHANNEL_WIDTH_160MHZ:
return WifiChannelWidthInMhz.WIDTH_160;
case ResponderConfig.CHANNEL_WIDTH_80MHZ_PLUS_MHZ:
return WifiChannelWidthInMhz.WIDTH_80P80;
default:
throw new IllegalArgumentException(
"halChannelWidthFromResponderChannelWidth: bad " + responderChannelWidth);
}
}
private static int halRttChannelBandwidthFromResponderChannelWidth(int responderChannelWidth) {
switch (responderChannelWidth) {
case ResponderConfig.CHANNEL_WIDTH_20MHZ:
return RttBw.BW_20MHZ;
case ResponderConfig.CHANNEL_WIDTH_40MHZ:
return RttBw.BW_40MHZ;
case ResponderConfig.CHANNEL_WIDTH_80MHZ:
return RttBw.BW_80MHZ;
case ResponderConfig.CHANNEL_WIDTH_160MHZ:
case ResponderConfig.CHANNEL_WIDTH_80MHZ_PLUS_MHZ:
return RttBw.BW_160MHZ;
default:
throw new IllegalArgumentException(
"halRttChannelBandwidthFromHalBandwidth: bad " + responderChannelWidth);
}
}
private static int halRttPreambleFromResponderPreamble(int responderPreamble) {
switch (responderPreamble) {
case ResponderConfig.PREAMBLE_LEGACY:
return RttPreamble.LEGACY;
case ResponderConfig.PREAMBLE_HT:
return RttPreamble.HT;
case ResponderConfig.PREAMBLE_VHT:
return RttPreamble.VHT;
default:
throw new IllegalArgumentException(
"halRttPreambleFromResponderPreamble: bad " + responderPreamble);
}
}
private static int halRttPreamble14FromResponderPreamble(int responderPreamble) {
switch (responderPreamble) {
case ResponderConfig.PREAMBLE_LEGACY:
return RttPreamble.LEGACY;
case ResponderConfig.PREAMBLE_HT:
return RttPreamble.HT;
case ResponderConfig.PREAMBLE_VHT:
return RttPreamble.VHT;
case ResponderConfig.PREAMBLE_HE:
return android.hardware.wifi.V1_4.RttPreamble.HE;
default:
throw new IllegalArgumentException(
"halRttPreamble14FromResponderPreamble: bad " + responderPreamble);
}
}
/**
* Check to see whether the selected RTT channel bandwidth is supported by the device.
* If not supported: return the next lower bandwidth which is supported
* If none: throw an IllegalArgumentException.
*
* Note: the halRttChannelBandwidth is a single bit flag of the ones used in cap.bwSupport (HAL
* specifications).
*/
private static int halRttChannelBandwidthCapabilityLimiter(int halRttChannelBandwidth,
Capabilities cap) {
while ((halRttChannelBandwidth != 0) && ((halRttChannelBandwidth & cap.bwSupported) == 0)) {
halRttChannelBandwidth >>= 1;
}
if (halRttChannelBandwidth != 0) {
return halRttChannelBandwidth;
}
throw new IllegalArgumentException(
"RTT BW=" + halRttChannelBandwidth + ", not supported by device capabilities=" + cap
+ " - and no supported alternative");
}
/**
* Check to see whether the selected RTT preamble is supported by the device.
* If not supported: return the next "lower" preamble which is supported
* If none: throw an IllegalArgumentException.
*
* Note: the halRttPreamble is a single bit flag of the ones used in cap.preambleSupport (HAL
* specifications).
*/
private static int halRttPreambleCapabilityLimiter(int halRttPreamble, Capabilities cap) {
while ((halRttPreamble != 0) && ((halRttPreamble & cap.preambleSupported) == 0)) {
halRttPreamble >>= 1;
}
if (halRttPreamble != 0) {
return halRttPreamble;
}
throw new IllegalArgumentException(
"RTT Preamble=" + halRttPreamble + ", not supported by device capabilities=" + cap
+ " - and no supported alternative");
}
/**
* Check if HAL Interface 1.4 is running
*
* @return 1.4 IWifiRttController object if the device is running the 1.4 hal service, null
* otherwise
*/
private android.hardware.wifi.V1_4.IWifiRttController getWifiRttControllerV1_4() {
if (mIWifiRttController == null) {
return null;
}
return android.hardware.wifi.V1_4.IWifiRttController.castFrom(mIWifiRttController);
}
/**
* Dump the internal state of the class.
*/
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("RttNative:");
pw.println(" mHalDeviceManager: " + mHalDeviceManager);
pw.println(" mIWifiRttController: " + mIWifiRttController);
pw.println(" mRttCapabilities: " + mRttCapabilities);
}
/**
* Callback for events on 1.0 WifiRttController
*/
private class WifiRttControllerEventCallback extends IWifiRttControllerEventCallback.Stub {
/**
* Callback from HAL with range results.
*
* @param cmdId Command ID specified in the original request
* {@link #rangeRequest(int, RangingRequest, boolean)}.
* @param halResults A list of range results.
*/
@Override
public void onResults(int cmdId, ArrayList<RttResult> halResults) {
// sanitize HAL results
if (halResults == null) {
halResults = new ArrayList<>();
}
halResults.removeIf(Objects::isNull);
if (mDbg) {
Log.v(TAG, "onResults: cmdId=" + cmdId + ", # of results=" + halResults.size());
}
ArrayList<RangingResult> rangingResults = convertHalResultsRangingResults(halResults);
mRttService.onRangingResults(cmdId, rangingResults);
}
}
/**
* Callback for events on 1.4 WifiRttController
*/
private class WifiRttControllerEventCallback14 extends
android.hardware.wifi.V1_4.IWifiRttControllerEventCallback.Stub {
@Override
public void onResults(int cmdId, ArrayList<RttResult> halResults) {
// This callback is not supported on this version of the interface
return;
}
@Override
public void onResults_1_4(int cmdId,
ArrayList<android.hardware.wifi.V1_4.RttResult> halResults) {
if (mDbg) {
Log.v(TAG,
"onResults_1_4: cmdId=" + cmdId + ", # of results=" + halResults.size());
}
// sanitize HAL results
if (halResults == null) {
halResults = new ArrayList<>();
}
halResults.removeIf(Objects::isNull);
ArrayList<RangingResult> rangingResults = convertHalResultsRangingResults14(halResults);
mRttService.onRangingResults(cmdId, rangingResults);
}
}
private ArrayList<RangingResult> convertHalResultsRangingResults(
ArrayList<RttResult> halResults) {
ArrayList<RangingResult> rangingResults = new ArrayList<>();
for (RttResult rttResult : halResults) {
byte[] lci = NativeUtil.byteArrayFromArrayList(rttResult.lci.data);
byte[] lcr = NativeUtil.byteArrayFromArrayList(rttResult.lcr.data);
ResponderLocation responderLocation;
try {
responderLocation = new ResponderLocation(lci, lcr);
if (!responderLocation.isValid()) {
responderLocation = null;
}
} catch (Exception e) {
responderLocation = null;
Log.e(TAG,
"ResponderLocation: lci/lcr parser failed exception -- " + e);
}
if (rttResult.successNumber <= 1
&& rttResult.distanceSdInMm != 0) {
if (mDbg) {
Log.w(TAG, "postProcessResults: non-zero distance stdev with 0||1 num "
+ "samples!? result=" + rttResult);
}
rttResult.distanceSdInMm = 0;
}
rangingResults.add(new RangingResult(
convertHalStatusToFrameworkStatus(rttResult.status),
MacAddress.fromBytes(rttResult.addr),
rttResult.distanceInMm, rttResult.distanceSdInMm,
rttResult.rssi / -2, rttResult.numberPerBurstPeer,
rttResult.successNumber, lci, lcr, responderLocation,
rttResult.timeStampInUs / CONVERSION_US_TO_MS,
rttResult.type == RttType.TWO_SIDED));
}
return rangingResults;
}
private ArrayList<RangingResult> convertHalResultsRangingResults14(
ArrayList<android.hardware.wifi.V1_4.RttResult> halResults) {
ArrayList<RangingResult> rangingResults = new ArrayList<>();
for (android.hardware.wifi.V1_4.RttResult rttResult : halResults) {
byte[] lci = NativeUtil.byteArrayFromArrayList(rttResult.lci.data);
byte[] lcr = NativeUtil.byteArrayFromArrayList(rttResult.lcr.data);
ResponderLocation responderLocation;
try {
responderLocation = new ResponderLocation(lci, lcr);
if (!responderLocation.isValid()) {
responderLocation = null;
}
} catch (Exception e) {
responderLocation = null;
Log.e(TAG,
"ResponderLocation: lci/lcr parser failed exception -- " + e);
}
if (rttResult.successNumber <= 1
&& rttResult.distanceSdInMm != 0) {
if (mDbg) {
Log.w(TAG, "postProcessResults: non-zero distance stdev with 0||1 num "
+ "samples!? result=" + rttResult);
}
rttResult.distanceSdInMm = 0;
}
rangingResults.add(new RangingResult(
convertHalStatusToFrameworkStatus(rttResult.status),
MacAddress.fromBytes(rttResult.addr),
rttResult.distanceInMm, rttResult.distanceSdInMm,
rttResult.rssi / -2, rttResult.numberPerBurstPeer,
rttResult.successNumber, lci, lcr, responderLocation,
rttResult.timeStampInUs / CONVERSION_US_TO_MS,
rttResult.type == RttType.TWO_SIDED));
}
return rangingResults;
}
private @FrameworkRttStatus int convertHalStatusToFrameworkStatus(int halStatus) {
switch (halStatus) {
case RttStatus.SUCCESS:
return FRAMEWORK_RTT_STATUS_SUCCESS;
case RttStatus.FAILURE:
return FRAMEWORK_RTT_STATUS_FAILURE;
case RttStatus.FAIL_NO_RSP:
return FRAMEWORK_RTT_STATUS_FAIL_NO_RSP;
case RttStatus.FAIL_REJECTED:
return FRAMEWORK_RTT_STATUS_FAIL_REJECTED;
case RttStatus.FAIL_NOT_SCHEDULED_YET:
return FRAMEWORK_RTT_STATUS_FAIL_NOT_SCHEDULED_YET;
case RttStatus.FAIL_TM_TIMEOUT:
return FRAMEWORK_RTT_STATUS_FAIL_TM_TIMEOUT;
case RttStatus.FAIL_AP_ON_DIFF_CHANNEL:
return FRAMEWORK_RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL;
case RttStatus.FAIL_NO_CAPABILITY:
return FRAMEWORK_RTT_STATUS_FAIL_NO_CAPABILITY;
case RttStatus.ABORTED:
return FRAMEWORK_RTT_STATUS_ABORTED;
case RttStatus.FAIL_INVALID_TS:
return FRAMEWORK_RTT_STATUS_FAIL_INVALID_TS;
case RttStatus.FAIL_PROTOCOL:
return FRAMEWORK_RTT_STATUS_FAIL_PROTOCOL;
case RttStatus.FAIL_SCHEDULE:
return FRAMEWORK_RTT_STATUS_FAIL_SCHEDULE;
case RttStatus.FAIL_BUSY_TRY_LATER:
return FRAMEWORK_RTT_STATUS_FAIL_BUSY_TRY_LATER;
case RttStatus.INVALID_REQ:
return FRAMEWORK_RTT_STATUS_INVALID_REQ;
case RttStatus.NO_WIFI:
return FRAMEWORK_RTT_STATUS_NO_WIFI;
case RttStatus.FAIL_FTM_PARAM_OVERRIDE:
return FRAMEWORK_RTT_STATUS_FAIL_FTM_PARAM_OVERRIDE;
default:
Log.e(TAG, "Unrecognized RttStatus: " + halStatus);
return FRAMEWORK_RTT_STATUS_UNKNOWN;
}
}
/**
* Rtt capabilities inside framework
*/
public class Capabilities {
//1-sided rtt measurement is supported
public boolean oneSidedRttSupported;
//location configuration information supported
public boolean lciSupported;
//location civic records supported
public boolean lcrSupported;
//preamble supported, see bit mask definition above
public int preambleSupported;
//RTT bandwidth supported
public int bwSupported;
// Whether STA responder role is supported.
public boolean responderSupported;
//Draft 11mc version supported, including major and minor version. e.g, draft 4.3 is 43.
public byte mcVersion;
//if ftm rtt data collection is supported.
public boolean rttFtmSupported;
public Capabilities(RttCapabilities rttHalCapabilities) {
oneSidedRttSupported = rttHalCapabilities.rttOneSidedSupported;
lciSupported = rttHalCapabilities.lciSupported;
lcrSupported = rttHalCapabilities.lcrSupported;
responderSupported = rttHalCapabilities.responderSupported;
preambleSupported = rttHalCapabilities.preambleSupport;
mcVersion = rttHalCapabilities.mcVersion;
bwSupported = rttHalCapabilities.bwSupport;
rttFtmSupported = rttHalCapabilities.rttFtmSupported;
}
public Capabilities(android.hardware.wifi.V1_4.RttCapabilities rttHalCapabilities) {
oneSidedRttSupported = rttHalCapabilities.rttOneSidedSupported;
lciSupported = rttHalCapabilities.lciSupported;
lcrSupported = rttHalCapabilities.lcrSupported;
responderSupported = rttHalCapabilities.responderSupported;
preambleSupported = rttHalCapabilities.preambleSupport;
mcVersion = rttHalCapabilities.mcVersion;
bwSupported = rttHalCapabilities.bwSupport;
rttFtmSupported = rttHalCapabilities.rttFtmSupported;
}
}
}