1/* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.server.wifi.rtt; 18 19import android.hardware.wifi.V1_0.IWifiRttController; 20import android.hardware.wifi.V1_0.IWifiRttControllerEventCallback; 21import android.hardware.wifi.V1_0.RttBw; 22import android.hardware.wifi.V1_0.RttCapabilities; 23import android.hardware.wifi.V1_0.RttConfig; 24import android.hardware.wifi.V1_0.RttPeerType; 25import android.hardware.wifi.V1_0.RttPreamble; 26import android.hardware.wifi.V1_0.RttResult; 27import android.hardware.wifi.V1_0.RttType; 28import android.hardware.wifi.V1_0.WifiChannelWidthInMhz; 29import android.hardware.wifi.V1_0.WifiStatus; 30import android.hardware.wifi.V1_0.WifiStatusCode; 31import android.net.wifi.rtt.RangingRequest; 32import android.net.wifi.rtt.ResponderConfig; 33import android.os.Handler; 34import android.os.RemoteException; 35import android.util.Log; 36 37import com.android.server.wifi.HalDeviceManager; 38 39import java.io.FileDescriptor; 40import java.io.PrintWriter; 41import java.util.ArrayList; 42import java.util.ListIterator; 43 44/** 45 * TBD 46 */ 47public class RttNative extends IWifiRttControllerEventCallback.Stub { 48 private static final String TAG = "RttNative"; 49 private static final boolean VDBG = false; // STOPSHIP if true 50 /* package */ boolean mDbg = false; 51 52 private final RttServiceImpl mRttService; 53 private final HalDeviceManager mHalDeviceManager; 54 55 private Object mLock = new Object(); 56 57 private volatile IWifiRttController mIWifiRttController; 58 private volatile RttCapabilities mRttCapabilities; 59 60 public RttNative(RttServiceImpl rttService, HalDeviceManager halDeviceManager) { 61 mRttService = rttService; 62 mHalDeviceManager = halDeviceManager; 63 } 64 65 /** 66 * Initialize the object - registering with the HAL device manager. 67 */ 68 public void start(Handler handler) { 69 synchronized (mLock) { 70 mHalDeviceManager.initialize(); 71 mHalDeviceManager.registerStatusListener(() -> { 72 if (VDBG) Log.d(TAG, "hdm.onStatusChanged"); 73 updateController(); 74 }, handler); 75 updateController(); 76 } 77 } 78 79 /** 80 * Returns true if Wi-Fi is ready for RTT requests, false otherwise. 81 */ 82 public boolean isReady() { 83 return mIWifiRttController != null; 84 } 85 86 private void updateController() { 87 if (mDbg) Log.v(TAG, "updateController: mIWifiRttController=" + mIWifiRttController); 88 89 // only care about isStarted (Wi-Fi started) not isReady - since if not 90 // ready then Wi-Fi will also be down. 91 synchronized (mLock) { 92 IWifiRttController localWifiRttController = mIWifiRttController; 93 if (mHalDeviceManager.isStarted()) { 94 if (localWifiRttController == null) { 95 localWifiRttController = mHalDeviceManager.createRttController(); 96 if (localWifiRttController == null) { 97 Log.e(TAG, "updateController: Failed creating RTT controller - but Wifi is " 98 + "started!"); 99 } else { 100 try { 101 localWifiRttController.registerEventCallback(this); 102 } catch (RemoteException e) { 103 Log.e(TAG, "updateController: exception registering callback: " + e); 104 localWifiRttController = null; 105 } 106 } 107 } 108 } else { 109 localWifiRttController = null; 110 } 111 mIWifiRttController = localWifiRttController; 112 113 if (mIWifiRttController == null) { 114 mRttService.disable(); 115 } else { 116 mRttService.enableIfPossible(); 117 updateRttCapabilities(); 118 } 119 } 120 } 121 122 /** 123 * Updates the RTT capabilities. 124 */ 125 void updateRttCapabilities() { 126 if (mRttCapabilities != null) { 127 return; 128 } 129 130 synchronized (mLock) { 131 try { 132 mIWifiRttController.getCapabilities( 133 (status, capabilities) -> { 134 if (status.code != WifiStatusCode.SUCCESS) { 135 Log.e(TAG, 136 "updateController: error requesting capabilities -- code=" 137 + status.code); 138 return; 139 } 140 if (mDbg) { 141 Log.v(TAG, "updateController: RTT capabilities=" + capabilities); 142 } 143 mRttCapabilities = capabilities; 144 }); 145 } catch (RemoteException e) { 146 Log.e(TAG, "updateController: exception requesting capabilities: " + e); 147 } 148 149 if (mRttCapabilities != null && !mRttCapabilities.rttFtmSupported) { 150 Log.wtf(TAG, "Firmware indicates RTT is not supported - but device supports RTT - " 151 + "ignored!?"); 152 } 153 } 154 } 155 156 /** 157 * Issue a range request to the HAL. 158 * 159 * @param cmdId Command ID for the request. Will be used in the corresponding 160 * {@link #onResults(int, ArrayList)}. 161 * @param request Range request. 162 * @param isCalledFromPrivilegedContext Indicates whether privileged APIs are permitted, 163 * initially: support for one-sided RTT. 164 * 165 * @return Success status: true for success, false for failure. 166 */ 167 public boolean rangeRequest(int cmdId, RangingRequest request, 168 boolean isCalledFromPrivilegedContext) { 169 if (mDbg) { 170 Log.v(TAG, 171 "rangeRequest: cmdId=" + cmdId + ", # of requests=" + request.mRttPeers.size()); 172 } 173 if (VDBG) Log.v(TAG, "rangeRequest: request=" + request); 174 updateRttCapabilities(); 175 synchronized (mLock) { 176 if (!isReady()) { 177 Log.e(TAG, "rangeRequest: RttController is null"); 178 return false; 179 } 180 181 ArrayList<RttConfig> rttConfig = convertRangingRequestToRttConfigs(request, 182 isCalledFromPrivilegedContext, mRttCapabilities); 183 if (rttConfig == null) { 184 Log.e(TAG, "rangeRequest: invalid request parameters"); 185 return false; 186 } 187 if (rttConfig.size() == 0) { 188 Log.e(TAG, "rangeRequest: all requests invalidated"); 189 mRttService.onRangingResults(cmdId, new ArrayList<>()); 190 return true; 191 } 192 193 try { 194 WifiStatus status = mIWifiRttController.rangeRequest(cmdId, rttConfig); 195 if (status.code != WifiStatusCode.SUCCESS) { 196 Log.e(TAG, "rangeRequest: cannot issue range request -- code=" + status.code); 197 return false; 198 } 199 } catch (RemoteException e) { 200 Log.e(TAG, "rangeRequest: exception issuing range request: " + e); 201 return false; 202 } 203 204 return true; 205 } 206 } 207 208 /** 209 * Cancel an outstanding ranging request: no guarantees of execution - we will ignore any 210 * results which are returned for the canceled request. 211 * 212 * @param cmdId The cmdId issued with the original rangeRequest command. 213 * @param macAddresses A list of MAC addresses for which to cancel the operation. 214 * @return Success status: true for success, false for failure. 215 */ 216 public boolean rangeCancel(int cmdId, ArrayList<byte[]> macAddresses) { 217 if (mDbg) Log.v(TAG, "rangeCancel: cmdId=" + cmdId); 218 synchronized (mLock) { 219 if (!isReady()) { 220 Log.e(TAG, "rangeCancel: RttController is null"); 221 return false; 222 } 223 224 try { 225 WifiStatus status = mIWifiRttController.rangeCancel(cmdId, macAddresses); 226 if (status.code != WifiStatusCode.SUCCESS) { 227 Log.e(TAG, "rangeCancel: cannot issue range cancel -- code=" + status.code); 228 return false; 229 } 230 } catch (RemoteException e) { 231 Log.e(TAG, "rangeCancel: exception issuing range cancel: " + e); 232 return false; 233 } 234 235 return true; 236 } 237 } 238 239 /** 240 * Callback from HAL with range results. 241 * 242 * @param cmdId Command ID specified in the original request 243 * {@link #rangeRequest(int, RangingRequest, boolean)}. 244 * @param halResults A list of range results. 245 */ 246 @Override 247 public void onResults(int cmdId, ArrayList<RttResult> halResults) { 248 if (mDbg) Log.v(TAG, "onResults: cmdId=" + cmdId + ", # of results=" + halResults.size()); 249 250 // sanitize HAL results 251 if (halResults == null) { 252 halResults = new ArrayList<>(); 253 } 254 ListIterator<RttResult> lit = halResults.listIterator(); 255 while (lit.hasNext()) { 256 if (lit.next() == null) { 257 lit.remove(); 258 } 259 } 260 mRttService.onRangingResults(cmdId, halResults); 261 } 262 263 private static ArrayList<RttConfig> convertRangingRequestToRttConfigs(RangingRequest request, 264 boolean isCalledFromPrivilegedContext, RttCapabilities cap) { 265 ArrayList<RttConfig> rttConfigs = new ArrayList<>(request.mRttPeers.size()); 266 267 // Skipping any configurations which have an error (printing out a message). 268 // The caller will only get results for valid configurations. 269 for (ResponderConfig responder: request.mRttPeers) { 270 if (!isCalledFromPrivilegedContext) { 271 if (!responder.supports80211mc) { 272 Log.e(TAG, "Invalid responder: does not support 802.11mc"); 273 continue; 274 } 275 } 276 277 RttConfig config = new RttConfig(); 278 279 System.arraycopy(responder.macAddress.toByteArray(), 0, config.addr, 0, 280 config.addr.length); 281 282 try { 283 config.type = responder.supports80211mc ? RttType.TWO_SIDED : RttType.ONE_SIDED; 284 if (config.type == RttType.ONE_SIDED && cap != null && !cap.rttOneSidedSupported) { 285 Log.w(TAG, "Device does not support one-sided RTT"); 286 continue; 287 } 288 289 config.peer = halRttPeerTypeFromResponderType(responder.responderType); 290 config.channel.width = halChannelWidthFromResponderChannelWidth( 291 responder.channelWidth); 292 config.channel.centerFreq = responder.frequency; 293 config.channel.centerFreq0 = responder.centerFreq0; 294 config.channel.centerFreq1 = responder.centerFreq1; 295 config.bw = halRttChannelBandwidthFromResponderChannelWidth(responder.channelWidth); 296 config.preamble = halRttPreambleFromResponderPreamble(responder.preamble); 297 298 if (config.peer == RttPeerType.NAN) { 299 config.mustRequestLci = false; 300 config.mustRequestLcr = false; 301 config.burstPeriod = 0; 302 config.numBurst = 0; 303 config.numFramesPerBurst = 5; 304 config.numRetriesPerRttFrame = 0; // irrelevant for 2-sided RTT 305 config.numRetriesPerFtmr = 3; 306 config.burstDuration = 9; 307 } else { // AP + all non-NAN requests 308 config.mustRequestLci = isCalledFromPrivilegedContext; 309 config.mustRequestLcr = isCalledFromPrivilegedContext; 310 config.burstPeriod = 0; 311 config.numBurst = 0; 312 config.numFramesPerBurst = 8; 313 config.numRetriesPerRttFrame = (config.type == RttType.TWO_SIDED ? 0 : 3); 314 config.numRetriesPerFtmr = 3; 315 config.burstDuration = 9; 316 317 if (cap != null) { // constrain parameters per device capabilities 318 config.mustRequestLci = config.mustRequestLci && cap.lciSupported; 319 config.mustRequestLcr = config.mustRequestLcr && cap.lcrSupported; 320 config.bw = halRttChannelBandwidthCapabilityLimiter(config.bw, cap); 321 config.preamble = halRttPreambleCapabilityLimiter(config.preamble, cap); 322 } 323 } 324 } catch (IllegalArgumentException e) { 325 Log.e(TAG, "Invalid configuration: " + e.getMessage()); 326 continue; 327 } 328 329 rttConfigs.add(config); 330 } 331 332 return rttConfigs; 333 } 334 335 private static int halRttPeerTypeFromResponderType(int responderType) { 336 switch (responderType) { 337 case ResponderConfig.RESPONDER_AP: 338 return RttPeerType.AP; 339 case ResponderConfig.RESPONDER_STA: 340 return RttPeerType.STA; 341 case ResponderConfig.RESPONDER_P2P_GO: 342 return RttPeerType.P2P_GO; 343 case ResponderConfig.RESPONDER_P2P_CLIENT: 344 return RttPeerType.P2P_CLIENT; 345 case ResponderConfig.RESPONDER_AWARE: 346 return RttPeerType.NAN; 347 default: 348 throw new IllegalArgumentException( 349 "halRttPeerTypeFromResponderType: bad " + responderType); 350 } 351 } 352 353 private static int halChannelWidthFromResponderChannelWidth(int responderChannelWidth) { 354 switch (responderChannelWidth) { 355 case ResponderConfig.CHANNEL_WIDTH_20MHZ: 356 return WifiChannelWidthInMhz.WIDTH_20; 357 case ResponderConfig.CHANNEL_WIDTH_40MHZ: 358 return WifiChannelWidthInMhz.WIDTH_40; 359 case ResponderConfig.CHANNEL_WIDTH_80MHZ: 360 return WifiChannelWidthInMhz.WIDTH_80; 361 case ResponderConfig.CHANNEL_WIDTH_160MHZ: 362 return WifiChannelWidthInMhz.WIDTH_160; 363 case ResponderConfig.CHANNEL_WIDTH_80MHZ_PLUS_MHZ: 364 return WifiChannelWidthInMhz.WIDTH_80P80; 365 default: 366 throw new IllegalArgumentException( 367 "halChannelWidthFromResponderChannelWidth: bad " + responderChannelWidth); 368 } 369 } 370 371 private static int halRttChannelBandwidthFromResponderChannelWidth(int responderChannelWidth) { 372 switch (responderChannelWidth) { 373 case ResponderConfig.CHANNEL_WIDTH_20MHZ: 374 return RttBw.BW_20MHZ; 375 case ResponderConfig.CHANNEL_WIDTH_40MHZ: 376 return RttBw.BW_40MHZ; 377 case ResponderConfig.CHANNEL_WIDTH_80MHZ: 378 return RttBw.BW_80MHZ; 379 case ResponderConfig.CHANNEL_WIDTH_160MHZ: 380 return RttBw.BW_160MHZ; 381 case ResponderConfig.CHANNEL_WIDTH_80MHZ_PLUS_MHZ: 382 return RttBw.BW_160MHZ; 383 default: 384 throw new IllegalArgumentException( 385 "halRttChannelBandwidthFromHalBandwidth: bad " + responderChannelWidth); 386 } 387 } 388 389 private static int halRttPreambleFromResponderPreamble(int responderPreamble) { 390 switch (responderPreamble) { 391 case ResponderConfig.PREAMBLE_LEGACY: 392 return RttPreamble.LEGACY; 393 case ResponderConfig.PREAMBLE_HT: 394 return RttPreamble.HT; 395 case ResponderConfig.PREAMBLE_VHT: 396 return RttPreamble.VHT; 397 default: 398 throw new IllegalArgumentException( 399 "halRttPreambleFromResponderPreamble: bad " + responderPreamble); 400 } 401 } 402 403 /** 404 * Check to see whether the selected RTT channel bandwidth is supported by the device. 405 * If not supported: return the next lower bandwidth which is supported 406 * If none: throw an IllegalArgumentException. 407 * 408 * Note: the halRttChannelBandwidth is a single bit flag of the ones used in cap.bwSupport (HAL 409 * specifications). 410 */ 411 private static int halRttChannelBandwidthCapabilityLimiter(int halRttChannelBandwidth, 412 RttCapabilities cap) { 413 while ((halRttChannelBandwidth != 0) && ((halRttChannelBandwidth & cap.bwSupport) == 0)) { 414 halRttChannelBandwidth >>= 1; 415 } 416 417 if (halRttChannelBandwidth != 0) { 418 return halRttChannelBandwidth; 419 } 420 421 throw new IllegalArgumentException( 422 "RTT BW=" + halRttChannelBandwidth + ", not supported by device capabilities=" + cap 423 + " - and no supported alternative"); 424 } 425 426 /** 427 * Check to see whether the selected RTT preamble is supported by the device. 428 * If not supported: return the next "lower" preamble which is supported 429 * If none: throw an IllegalArgumentException. 430 * 431 * Note: the halRttPreamble is a single bit flag of the ones used in cap.preambleSupport (HAL 432 * specifications). 433 */ 434 private static int halRttPreambleCapabilityLimiter(int halRttPreamble, RttCapabilities cap) { 435 while ((halRttPreamble != 0) && ((halRttPreamble & cap.preambleSupport) == 0)) { 436 halRttPreamble >>= 1; 437 } 438 439 if (halRttPreamble != 0) { 440 return halRttPreamble; 441 } 442 443 throw new IllegalArgumentException( 444 "RTT Preamble=" + halRttPreamble + ", not supported by device capabilities=" + cap 445 + " - and no supported alternative"); 446 } 447 448 449 /** 450 * Dump the internal state of the class. 451 */ 452 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 453 pw.println("RttNative:"); 454 pw.println(" mHalDeviceManager: " + mHalDeviceManager); 455 pw.println(" mIWifiRttController: " + mIWifiRttController); 456 pw.println(" mRttCapabilities: " + mRttCapabilities); 457 } 458} 459