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 17 package com.android.server.wifi.rtt; 18 19 import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE; 20 import static android.net.wifi.rtt.WifiRttManager.CHARACTERISTICS_KEY_BOOLEAN_LCI; 21 import static android.net.wifi.rtt.WifiRttManager.CHARACTERISTICS_KEY_BOOLEAN_LCR; 22 import static android.net.wifi.rtt.WifiRttManager.CHARACTERISTICS_KEY_BOOLEAN_NTB_INITIATOR; 23 import static android.net.wifi.rtt.WifiRttManager.CHARACTERISTICS_KEY_BOOLEAN_ONE_SIDED_RTT; 24 import static android.net.wifi.rtt.WifiRttManager.CHARACTERISTICS_KEY_BOOLEAN_STA_RESPONDER; 25 26 import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_VERBOSE_LOGGING_ENABLED; 27 28 import android.annotation.NonNull; 29 import android.app.ActivityManager; 30 import android.content.AttributionSource; 31 import android.content.BroadcastReceiver; 32 import android.content.Context; 33 import android.content.Intent; 34 import android.content.IntentFilter; 35 import android.content.pm.PackageManager; 36 import android.location.LocationManager; 37 import android.net.MacAddress; 38 import android.net.wifi.WifiManager; 39 import android.net.wifi.aware.IWifiAwareMacAddressProvider; 40 import android.net.wifi.aware.MacAddrMapping; 41 import android.net.wifi.aware.WifiAwareManager; 42 import android.net.wifi.rtt.IRttCallback; 43 import android.net.wifi.rtt.IWifiRttManager; 44 import android.net.wifi.rtt.RangingRequest; 45 import android.net.wifi.rtt.RangingResult; 46 import android.net.wifi.rtt.RangingResultCallback; 47 import android.net.wifi.rtt.ResponderConfig; 48 import android.net.wifi.rtt.ResponderLocation; 49 import android.net.wifi.rtt.WifiRttManager; 50 import android.os.Binder; 51 import android.os.Bundle; 52 import android.os.Handler; 53 import android.os.IBinder; 54 import android.os.Looper; 55 import android.os.ParcelFileDescriptor; 56 import android.os.PowerManager; 57 import android.os.RemoteException; 58 import android.os.UserHandle; 59 import android.os.WorkSource; 60 import android.os.WorkSource.WorkChain; 61 import android.text.TextUtils; 62 import android.util.Log; 63 import android.util.SparseIntArray; 64 65 import com.android.internal.annotations.VisibleForTesting; 66 import com.android.internal.util.WakeupMessage; 67 import com.android.modules.utils.BasicShellCommandHandler; 68 import com.android.modules.utils.build.SdkLevel; 69 import com.android.server.wifi.BuildProperties; 70 import com.android.server.wifi.Clock; 71 import com.android.server.wifi.FrameworkFacade; 72 import com.android.server.wifi.HalDeviceManager; 73 import com.android.server.wifi.SystemBuildProperties; 74 import com.android.server.wifi.WifiSettingsConfigStore; 75 import com.android.server.wifi.hal.WifiRttController; 76 import com.android.server.wifi.proto.nano.WifiMetricsProto; 77 import com.android.server.wifi.util.WifiPermissionsUtil; 78 import com.android.wifi.resources.R; 79 80 import org.json.JSONException; 81 import org.json.JSONObject; 82 83 import java.io.FileDescriptor; 84 import java.io.PrintWriter; 85 import java.util.ArrayList; 86 import java.util.Arrays; 87 import java.util.HashMap; 88 import java.util.LinkedList; 89 import java.util.List; 90 import java.util.ListIterator; 91 import java.util.Map; 92 93 /** 94 * Implementation of the IWifiRttManager AIDL interface and of the RttService state manager. 95 */ 96 public class RttServiceImpl extends IWifiRttManager.Stub { 97 private static final String TAG = "RttServiceImpl"; 98 private static final boolean VDBG = false; // STOPSHIP if true 99 private boolean mVerboseLoggingEnabled = false; 100 private boolean mVerboseHalLoggingEnabled = false; 101 102 private final Context mContext; 103 private final RttShellCommand mShellCommand; 104 private Clock mClock; 105 private WifiAwareManager mAwareManager; 106 private WifiRttController mWifiRttController; 107 private HalDeviceManager mHalDeviceManager; 108 private RttMetrics mRttMetrics; 109 private WifiPermissionsUtil mWifiPermissionsUtil; 110 private ActivityManager mActivityManager; 111 private PowerManager mPowerManager; 112 private long mLastRequestTimestamp; 113 private final BuildProperties mBuildProperties; 114 private FrameworkFacade mFrameworkFacade; 115 private WifiRttController.Capabilities mCapabilities; 116 117 private RttServiceSynchronized mRttServiceSynchronized; 118 119 /* package */ static final String HAL_RANGING_TIMEOUT_TAG = TAG + " HAL Ranging Timeout"; 120 121 @VisibleForTesting 122 public static final long HAL_RANGING_TIMEOUT_MS = 5_000; // 5 sec 123 @VisibleForTesting 124 public static final long HAL_AWARE_RANGING_TIMEOUT_MS = 10_000; // 10 sec 125 126 // arbitrary, larger than anything reasonable 127 /* package */ static final int MAX_QUEUED_PER_UID = 20; 128 129 private final WifiRttController.RttControllerRangingResultsCallback mRangingResultsCallback = 130 new WifiRttController.RttControllerRangingResultsCallback() { 131 @Override 132 public void onRangingResults(int cmdId, List<RangingResult> rangingResults) { 133 if (mVerboseLoggingEnabled) Log.d(TAG, "onRangingResults: cmdId=" + cmdId); 134 mRttServiceSynchronized.mHandler.post(() -> { 135 mRttServiceSynchronized.onRangingResults(cmdId, rangingResults); 136 }); 137 } 138 }; 139 140 private final HalDeviceManager.InterfaceRttControllerLifecycleCallback mRttLifecycleCb = 141 new HalDeviceManager.InterfaceRttControllerLifecycleCallback() { 142 @Override 143 public void onNewRttController(WifiRttController controller) { 144 if (mVerboseLoggingEnabled) { 145 Log.d(TAG, "onNewRttController: controller=" + controller); 146 } 147 boolean changed = mWifiRttController == null; 148 mWifiRttController = controller; 149 mWifiRttController.registerRangingResultsCallback(mRangingResultsCallback); 150 if (changed) { 151 enableIfPossible(); 152 } 153 } 154 155 @Override 156 public void onRttControllerDestroyed() { 157 if (mVerboseLoggingEnabled) Log.d(TAG, "onRttControllerDestroyed"); 158 mWifiRttController = null; 159 disable(); 160 } 161 }; 162 RttServiceImpl(Context context)163 public RttServiceImpl(Context context) { 164 mContext = context; 165 mBuildProperties = new SystemBuildProperties(); 166 mFrameworkFacade = new FrameworkFacade(); 167 mShellCommand = new RttShellCommand(); 168 mShellCommand.reset(); 169 } 170 updateVerboseLoggingEnabled()171 private void updateVerboseLoggingEnabled() { 172 final int verboseAlwaysOnLevel = mContext.getResources().getInteger( 173 R.integer.config_wifiVerboseLoggingAlwaysOnLevel); 174 mVerboseLoggingEnabled = mFrameworkFacade.isVerboseLoggingAlwaysOn(verboseAlwaysOnLevel, 175 mBuildProperties) || mVerboseHalLoggingEnabled; 176 } 177 178 /* 179 * Shell command: adb shell cmd wifirtt ... 180 */ 181 182 // If set to 0: normal behavior, if set to 1: do not allow any caller (including system 183 // callers) privileged API access 184 private static final String CONTROL_PARAM_OVERRIDE_ASSUME_NO_PRIVILEGE_NAME = 185 "override_assume_no_privilege"; 186 private static final int CONTROL_PARAM_OVERRIDE_ASSUME_NO_PRIVILEGE_DEFAULT = 0; 187 188 private class RttShellCommand extends BasicShellCommandHandler { 189 private Map<String, Integer> mControlParams = new HashMap<>(); 190 191 @Override onCommand(String cmd)192 public int onCommand(String cmd) { 193 final int uid = Binder.getCallingUid(); 194 if (uid != 0) { 195 throw new SecurityException( 196 "Uid " + uid + " does not have access to wifirtt commands"); 197 } 198 199 final PrintWriter pw = getErrPrintWriter(); 200 try { 201 if ("reset".equals(cmd)) { 202 reset(); 203 return 0; 204 } else if ("get".equals(cmd)) { 205 String name = getNextArgRequired(); 206 if (!mControlParams.containsKey(name)) { 207 pw.println("Unknown parameter name -- '" + name + "'"); 208 return -1; 209 } 210 getOutPrintWriter().println(mControlParams.get(name)); 211 return 0; 212 } else if ("set".equals(cmd)) { 213 String name = getNextArgRequired(); 214 String valueStr = getNextArgRequired(); 215 216 if (!mControlParams.containsKey(name)) { 217 pw.println("Unknown parameter name -- '" + name + "'"); 218 return -1; 219 } 220 221 try { 222 mControlParams.put(name, Integer.valueOf(valueStr)); 223 return 0; 224 } catch (NumberFormatException e) { 225 pw.println("Can't convert value to integer -- '" + valueStr + "'"); 226 return -1; 227 } 228 } else if ("get_capabilities".equals(cmd)) { 229 if (mCapabilities == null && mWifiRttController != null) { 230 mCapabilities = mWifiRttController.getRttCapabilities(); 231 } 232 JSONObject j = new JSONObject(); 233 if (mCapabilities != null) { 234 try { 235 j.put("rttOneSidedSupported", mCapabilities.oneSidedRttSupported); 236 j.put("rttFtmSupported", mCapabilities.rttFtmSupported); 237 j.put("lciSupported", mCapabilities.lciSupported); 238 j.put("lcrSupported", mCapabilities.lcrSupported); 239 j.put("responderSupported", mCapabilities.responderSupported); 240 j.put("mcVersion", mCapabilities.mcVersion); 241 j.put("ntbInitiatorSupported", mCapabilities.ntbInitiatorSupported); 242 j.put("ntbResponderSupported", mCapabilities.ntbResponderSupported); 243 } catch (JSONException e) { 244 Log.e(TAG, "onCommand: get_capabilities e=" + e); 245 } 246 } 247 getOutPrintWriter().println(j.toString()); 248 return 0; 249 } else { 250 handleDefaultCommands(cmd); 251 } 252 } catch (Exception e) { 253 pw.println("Exception: " + e); 254 } 255 return -1; 256 } 257 258 @Override onHelp()259 public void onHelp() { 260 final PrintWriter pw = getOutPrintWriter(); 261 262 pw.println("Wi-Fi RTT (wifirt) commands:"); 263 pw.println(" help"); 264 pw.println(" Print this help text."); 265 pw.println(" reset"); 266 pw.println(" Reset parameters to default values."); 267 pw.println(" get_capabilities: prints out the RTT capabilities as a JSON string"); 268 pw.println(" get <name>"); 269 pw.println(" Get the value of the control parameter."); 270 pw.println(" set <name> <value>"); 271 pw.println(" Set the value of the control parameter."); 272 pw.println(" Control parameters:"); 273 for (String name : mControlParams.keySet()) { 274 pw.println(" " + name); 275 } 276 pw.println(); 277 } 278 getControlParam(String name)279 public int getControlParam(String name) { 280 if (mControlParams.containsKey(name)) { 281 return mControlParams.get(name); 282 } 283 284 Log.wtf(TAG, "getControlParam for unknown variable: " + name); 285 return 0; 286 } 287 reset()288 public void reset() { 289 mControlParams.put(CONTROL_PARAM_OVERRIDE_ASSUME_NO_PRIVILEGE_NAME, 290 CONTROL_PARAM_OVERRIDE_ASSUME_NO_PRIVILEGE_DEFAULT); 291 } 292 } 293 294 /* 295 * INITIALIZATION 296 */ 297 298 /** 299 * Initializes the RTT service (usually with objects from an injector). 300 * 301 * @param looper The looper on which to synchronize operations. 302 * @param clock A mockable clock. 303 * @param awareManager The Wi-Fi Aware service (binder) if supported on the system. 304 * @param rttMetrics The Wi-Fi RTT metrics object. 305 * @param wifiPermissionsUtil Utility for permission checks. 306 * @param settingsConfigStore Used for retrieving verbose logging level. 307 * @param halDeviceManager The HAL device manager object. 308 */ start(Looper looper, Clock clock, WifiAwareManager awareManager, RttMetrics rttMetrics, WifiPermissionsUtil wifiPermissionsUtil, WifiSettingsConfigStore settingsConfigStore, HalDeviceManager halDeviceManager)309 public void start(Looper looper, Clock clock, WifiAwareManager awareManager, 310 RttMetrics rttMetrics, WifiPermissionsUtil wifiPermissionsUtil, 311 WifiSettingsConfigStore settingsConfigStore, HalDeviceManager halDeviceManager) { 312 mClock = clock; 313 mAwareManager = awareManager; 314 mHalDeviceManager = halDeviceManager; 315 mRttMetrics = rttMetrics; 316 mWifiPermissionsUtil = wifiPermissionsUtil; 317 mRttServiceSynchronized = new RttServiceSynchronized(looper); 318 mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); 319 mPowerManager = mContext.getSystemService(PowerManager.class); 320 321 mRttServiceSynchronized.mHandler.post(() -> { 322 IntentFilter intentFilter = new IntentFilter(); 323 intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED); 324 mContext.registerReceiver(new BroadcastReceiver() { 325 @Override 326 public void onReceive(Context context, Intent intent) { 327 String action = intent.getAction(); 328 if (mVerboseLoggingEnabled) { 329 Log.v(TAG, "BroadcastReceiver: action=" + action); 330 } 331 if (PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)) { 332 if (mPowerManager.isDeviceIdleMode()) { 333 disable(); 334 } else { 335 enableIfPossible(); 336 } 337 } 338 } 339 }, intentFilter); 340 341 settingsConfigStore.registerChangeListener( 342 WIFI_VERBOSE_LOGGING_ENABLED, 343 (key, newValue) -> enableVerboseLogging(newValue), 344 mRttServiceSynchronized.mHandler); 345 enableVerboseLogging(settingsConfigStore.get(WIFI_VERBOSE_LOGGING_ENABLED)); 346 347 intentFilter = new IntentFilter(); 348 intentFilter.addAction(LocationManager.MODE_CHANGED_ACTION); 349 mContext.registerReceiver(new BroadcastReceiver() { 350 @Override 351 public void onReceive(Context context, Intent intent) { 352 if (mVerboseLoggingEnabled) { 353 Log.v(TAG, "onReceive: MODE_CHANGED_ACTION: intent=" + intent); 354 } 355 if (mWifiPermissionsUtil.isLocationModeEnabled()) { 356 enableIfPossible(); 357 } else { 358 disable(); 359 } 360 } 361 }, intentFilter); 362 363 mHalDeviceManager.initialize(); 364 mHalDeviceManager.registerStatusListener(() -> { 365 if (VDBG) Log.d(TAG, "hdm.onStatusChanged"); 366 if (mHalDeviceManager.isStarted()) { 367 mHalDeviceManager.registerRttControllerLifecycleCallback(mRttLifecycleCb, 368 mRttServiceSynchronized.mHandler); 369 } 370 }, mRttServiceSynchronized.mHandler); 371 if (mHalDeviceManager.isStarted()) { 372 mHalDeviceManager.registerRttControllerLifecycleCallback( 373 mRttLifecycleCb, mRttServiceSynchronized.mHandler); 374 } 375 }); 376 } 377 enableVerboseLogging(boolean verboseEnabled)378 private void enableVerboseLogging(boolean verboseEnabled) { 379 mVerboseHalLoggingEnabled = verboseEnabled || VDBG; 380 updateVerboseLoggingEnabled(); 381 mRttMetrics.enableVerboseLogging(mVerboseLoggingEnabled); 382 if (mWifiRttController != null) { 383 mWifiRttController.enableVerboseLogging(mVerboseLoggingEnabled); 384 } 385 } 386 387 /** 388 * Handles the transition to boot completed phase 389 */ handleBootCompleted()390 public void handleBootCompleted() { 391 updateVerboseLoggingEnabled(); 392 } 393 394 /* 395 * ASYNCHRONOUS DOMAIN - can be called from different threads! 396 */ 397 398 /** 399 * Proxy for the final native call of the parent class. Enables mocking of 400 * the function. 401 */ getMockableCallingUid()402 public int getMockableCallingUid() { 403 return getCallingUid(); 404 } 405 406 /** 407 * Enable the API if possible: broadcast notification & start launching any queued requests 408 * 409 * If possible: 410 * - RTT HAL is available 411 * - Not in Idle mode 412 * - Location Mode allows Wi-Fi based locationing 413 */ enableIfPossible()414 public void enableIfPossible() { 415 boolean isAvailable = isAvailable(); 416 if (VDBG) Log.v(TAG, "enableIfPossible: isAvailable=" + isAvailable); 417 if (!isAvailable) { 418 return; 419 } 420 sendRttStateChangedBroadcast(true); 421 mRttServiceSynchronized.mHandler.post(() -> { 422 // queue should be empty at this point (but this call allows validation) 423 mRttServiceSynchronized.executeNextRangingRequestIfPossible(false); 424 }); 425 } 426 427 /** 428 * Disable the API: 429 * - Clean-up (fail) pending requests 430 * - Broadcast notification 431 */ disable()432 public void disable() { 433 if (VDBG) Log.v(TAG, "disable"); 434 sendRttStateChangedBroadcast(false); 435 mRttServiceSynchronized.mHandler.post(() -> { 436 mRttServiceSynchronized.cleanUpOnDisable(); 437 }); 438 } 439 440 @Override handleShellCommand(@onNull ParcelFileDescriptor in, @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err, @NonNull String[] args)441 public int handleShellCommand(@NonNull ParcelFileDescriptor in, 442 @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err, 443 @NonNull String[] args) { 444 return mShellCommand.exec( 445 this, in.getFileDescriptor(), out.getFileDescriptor(), err.getFileDescriptor(), 446 args); 447 } 448 449 /** 450 * Binder interface API to indicate whether the API is currently available. This requires an 451 * immediate asynchronous response. 452 */ 453 @Override isAvailable()454 public boolean isAvailable() { 455 long ident = Binder.clearCallingIdentity(); 456 try { 457 return mWifiRttController != null && !mPowerManager.isDeviceIdleMode() 458 && mWifiPermissionsUtil.isLocationModeEnabled(); 459 } finally { 460 Binder.restoreCallingIdentity(ident); 461 } 462 } 463 464 @Override getRttCharacteristics()465 public Bundle getRttCharacteristics() { 466 enforceAccessPermission(); 467 if (mCapabilities == null && mWifiRttController != null) { 468 mCapabilities = mWifiRttController.getRttCapabilities(); 469 } 470 return covertCapabilitiesToBundle(mCapabilities); 471 } 472 covertCapabilitiesToBundle(WifiRttController.Capabilities capabilities)473 private Bundle covertCapabilitiesToBundle(WifiRttController.Capabilities capabilities) { 474 Bundle characteristics = new Bundle(); 475 if (capabilities == null) { 476 return characteristics; 477 } 478 characteristics.putBoolean(CHARACTERISTICS_KEY_BOOLEAN_ONE_SIDED_RTT, 479 capabilities.oneSidedRttSupported); 480 characteristics.putBoolean(CHARACTERISTICS_KEY_BOOLEAN_LCI, capabilities.lciSupported); 481 characteristics.putBoolean(CHARACTERISTICS_KEY_BOOLEAN_LCR, capabilities.lcrSupported); 482 characteristics.putBoolean(CHARACTERISTICS_KEY_BOOLEAN_STA_RESPONDER, 483 capabilities.responderSupported); 484 characteristics.putBoolean(CHARACTERISTICS_KEY_BOOLEAN_NTB_INITIATOR, 485 capabilities.ntbInitiatorSupported); 486 return characteristics; 487 } 488 489 /** 490 * Override IEEE 802.11az parameters with overlay values. 491 */ override11azOverlays(RangingRequest rangingRequest)492 private void override11azOverlays(RangingRequest rangingRequest) { 493 int minNtbTime = mContext.getResources().getInteger( 494 R.integer.config_wifi80211azMinTimeBetweenNtbMeasurementsMicros); 495 int maxNtbTime = mContext.getResources().getInteger( 496 R.integer.config_wifi80211azMaxTimeBetweenNtbMeasurementsMicros); 497 if (minNtbTime > 0 || maxNtbTime > 0) { 498 for (ResponderConfig peer : rangingRequest.mRttPeers) { 499 if (peer.is80211azNtbSupported()) { 500 if (maxNtbTime > 0) peer.setNtbMaxTimeBetweenMeasurementsMicros(maxNtbTime); 501 if (minNtbTime > 0) peer.setNtbMinTimeBetweenMeasurementsMicros(minNtbTime); 502 } 503 } 504 } 505 } 506 507 /** 508 * Binder interface API to start a ranging operation. Called on binder thread, operations needs 509 * to be posted to handler thread. 510 */ 511 @Override startRanging(IBinder binder, String callingPackage, String callingFeatureId, WorkSource workSource, RangingRequest request, IRttCallback callback, Bundle extras)512 public void startRanging(IBinder binder, String callingPackage, String callingFeatureId, 513 WorkSource workSource, RangingRequest request, IRttCallback callback, Bundle extras) 514 throws RemoteException { 515 if (VDBG) { 516 Log.v(TAG, "startRanging: binder=" + binder + ", callingPackage=" + callingPackage 517 + ", workSource=" + workSource + ", request=" + request + ", callback=" 518 + callback); 519 } 520 // verify arguments 521 if (binder == null) { 522 throw new IllegalArgumentException("Binder must not be null"); 523 } 524 if (request == null || request.mRttPeers == null || request.mRttPeers.size() == 0) { 525 throw new IllegalArgumentException("Request must not be null or empty"); 526 } 527 for (ResponderConfig responder : request.mRttPeers) { 528 if (responder == null) { 529 throw new IllegalArgumentException("Request must not contain null Responders"); 530 } 531 } 532 if (callback == null) { 533 throw new IllegalArgumentException("Callback must not be null"); 534 } 535 request.enforceValidity(mAwareManager != null); 536 537 if (!isAvailable()) { 538 try { 539 mRttMetrics.recordOverallStatus( 540 WifiMetricsProto.WifiRttLog.OVERALL_RTT_NOT_AVAILABLE); 541 callback.onRangingFailure(RangingResultCallback.STATUS_CODE_FAIL_RTT_NOT_AVAILABLE); 542 } catch (RemoteException e) { 543 Log.e(TAG, "startRanging: disabled, callback failed -- " + e); 544 } 545 return; 546 } 547 548 final int uid = getMockableCallingUid(); 549 550 // permission checks 551 enforceAccessPermission(); 552 enforceChangePermission(); 553 mWifiPermissionsUtil.checkPackage(uid, callingPackage); 554 // check if only Aware APs are ranged. 555 boolean onlyAwareApRanged = request.mRttPeers.stream().allMatch( 556 config -> config.responderType == ResponderConfig.RESPONDER_AWARE); 557 final Object attributionSource; 558 if (onlyAwareApRanged && SdkLevel.isAtLeastT()) { 559 // Special case: if only aware APs are ranged, then allow this request if the caller 560 // has nearby permission. 561 attributionSource = extras.getParcelable( 562 WifiManager.EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE); 563 if (!mWifiPermissionsUtil.checkNearbyDevicesPermission( 564 (AttributionSource) attributionSource, true, 565 "wifi aware ranging")) { 566 // No nearby permission. Still check for location permission. 567 mWifiPermissionsUtil.enforceFineLocationPermission( 568 callingPackage, callingFeatureId, uid); 569 } 570 } else { 571 attributionSource = null; 572 mWifiPermissionsUtil.enforceFineLocationPermission( 573 callingPackage, callingFeatureId, uid); 574 } 575 576 final WorkSource ws; 577 if (workSource != null) { 578 enforceLocationHardware(); 579 // We only care about UIDs in the incoming worksources and not their associated 580 // tags. Clear names so that other operations involving wakesources become simpler. 581 ws = workSource.withoutNames(); 582 } else { 583 ws = null; 584 } 585 586 boolean isCalledFromPrivilegedContext = 587 checkLocationHardware() && mShellCommand.getControlParam( 588 CONTROL_PARAM_OVERRIDE_ASSUME_NO_PRIVILEGE_NAME) == 0; 589 590 // register for binder death 591 IBinder.DeathRecipient dr = new IBinder.DeathRecipient() { 592 @Override 593 public void binderDied() { 594 if (mVerboseLoggingEnabled) Log.v(TAG, "binderDied: uid=" + uid); 595 binder.unlinkToDeath(this, 0); 596 597 mRttServiceSynchronized.mHandler.post(() -> { 598 mRttServiceSynchronized.cleanUpClientRequests(uid, null); 599 }); 600 } 601 }; 602 603 try { 604 binder.linkToDeath(dr, 0); 605 } catch (RemoteException e) { 606 Log.e(TAG, "Error on linkToDeath - " + e); 607 return; 608 } 609 610 override11azOverlays(request); 611 612 mRttServiceSynchronized.mHandler.post(() -> { 613 WorkSource sourceToUse = ws; 614 if (ws == null || ws.isEmpty()) { 615 sourceToUse = new WorkSource(uid); 616 } 617 mRttServiceSynchronized.queueRangingRequest(uid, sourceToUse, binder, dr, 618 callingPackage, callingFeatureId, request, callback, 619 isCalledFromPrivilegedContext, attributionSource); 620 }); 621 } 622 623 @Override cancelRanging(WorkSource workSource)624 public void cancelRanging(WorkSource workSource) throws RemoteException { 625 if (VDBG) Log.v(TAG, "cancelRanging: workSource=" + workSource); 626 enforceLocationHardware(); 627 // We only care about UIDs in the incoming worksources and not their associated 628 // tags. Clear names so that other operations involving wakesources become simpler. 629 final WorkSource ws = (workSource != null) ? workSource.withoutNames() : null; 630 631 if (ws == null || ws.isEmpty()) { 632 Log.e(TAG, "cancelRanging: invalid work-source -- " + ws); 633 return; 634 } 635 636 mRttServiceSynchronized.mHandler.post(() -> { 637 mRttServiceSynchronized.cleanUpClientRequests(0, ws); 638 }); 639 } 640 enforceAccessPermission()641 private void enforceAccessPermission() { 642 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE, TAG); 643 } 644 enforceChangePermission()645 private void enforceChangePermission() { 646 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE, TAG); 647 } 648 enforceLocationHardware()649 private void enforceLocationHardware() { 650 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.LOCATION_HARDWARE, 651 TAG); 652 } 653 checkLocationHardware()654 private boolean checkLocationHardware() { 655 return mContext.checkCallingOrSelfPermission(android.Manifest.permission.LOCATION_HARDWARE) 656 == PackageManager.PERMISSION_GRANTED; 657 } 658 sendRttStateChangedBroadcast(boolean enabled)659 private void sendRttStateChangedBroadcast(boolean enabled) { 660 if (VDBG) Log.v(TAG, "sendRttStateChangedBroadcast: enabled=" + enabled); 661 final Intent intent = new Intent(WifiRttManager.ACTION_WIFI_RTT_STATE_CHANGED); 662 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); 663 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 664 } 665 666 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)667 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 668 if (mContext.checkCallingOrSelfPermission( 669 android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) { 670 pw.println("Permission Denial: can't dump RttService from pid=" 671 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()); 672 return; 673 } 674 pw.println("Wi-Fi RTT Service"); 675 mRttServiceSynchronized.dump(fd, pw, args); 676 pw.println(" mWifiRttController: " + mWifiRttController); 677 if (mWifiRttController != null) { 678 mWifiRttController.dump(pw); 679 } 680 } 681 682 /* 683 * SYNCHRONIZED DOMAIN 684 */ 685 686 /** 687 * RTT service implementation - synchronized on a single thread. All commands should be posted 688 * to the exposed handler. 689 */ 690 private class RttServiceSynchronized { 691 public Handler mHandler; 692 693 private int mNextCommandId = 1000; 694 private Map<Integer, RttRequesterInfo> mRttRequesterInfo = new HashMap<>(); 695 private List<RttRequestInfo> mRttRequestQueue = new LinkedList<>(); 696 private WakeupMessage mRangingTimeoutMessage = null; 697 RttServiceSynchronized(Looper looper)698 RttServiceSynchronized(Looper looper) { 699 mHandler = new Handler(looper); 700 mRangingTimeoutMessage = new WakeupMessage(mContext, mHandler, 701 HAL_RANGING_TIMEOUT_TAG, () -> { 702 timeoutRangingRequest(); 703 }); 704 } 705 cancelRanging(RttRequestInfo rri)706 private void cancelRanging(RttRequestInfo rri) { 707 ArrayList<MacAddress> macAddresses = new ArrayList<>(); 708 for (ResponderConfig peer : rri.request.mRttPeers) { 709 macAddresses.add(peer.macAddress); 710 } 711 712 if (mWifiRttController != null) { 713 mWifiRttController.rangeCancel(rri.cmdId, macAddresses); 714 } else { 715 Log.e(TAG, "Could not call cancelRanging, rttControllerHal is null"); 716 } 717 } 718 cleanUpOnDisable()719 private void cleanUpOnDisable() { 720 if (VDBG) Log.v(TAG, "RttServiceSynchronized.cleanUpOnDisable"); 721 for (RttRequestInfo rri : mRttRequestQueue) { 722 try { 723 if (rri.dispatchedToNative) { 724 // may not be necessary in some cases (e.g. Wi-Fi disable may already clear 725 // up active RTT), but in other cases will be needed (doze disabling RTT 726 // but Wi-Fi still up). Doesn't hurt - worst case will fail. 727 cancelRanging(rri); 728 } 729 mRttMetrics.recordOverallStatus( 730 WifiMetricsProto.WifiRttLog.OVERALL_RTT_NOT_AVAILABLE); 731 rri.callback.onRangingFailure( 732 RangingResultCallback.STATUS_CODE_FAIL_RTT_NOT_AVAILABLE); 733 } catch (RemoteException e) { 734 Log.e(TAG, "RttServiceSynchronized.startRanging: disabled, callback failed -- " 735 + e); 736 } 737 rri.binder.unlinkToDeath(rri.dr, 0); 738 } 739 mRttRequestQueue.clear(); 740 mRangingTimeoutMessage.cancel(); 741 } 742 743 /** 744 * Remove entries related to the specified client and cancel any dispatched to HAL 745 * requests. Expected to provide either the UID or the WorkSource (the other will be 0 or 746 * null respectively). 747 * 748 * A workSource specification will be cleared from the requested workSource and the request 749 * cancelled only if there are no remaining uids in the work-source. 750 */ cleanUpClientRequests(int uid, WorkSource workSource)751 private void cleanUpClientRequests(int uid, WorkSource workSource) { 752 if (VDBG) { 753 Log.v(TAG, "RttServiceSynchronized.cleanUpOnClientDeath: uid=" + uid 754 + ", workSource=" + workSource + ", mRttRequestQueue=" + mRttRequestQueue); 755 } 756 boolean dispatchedRequestAborted = false; 757 ListIterator<RttRequestInfo> it = mRttRequestQueue.listIterator(); 758 while (it.hasNext()) { 759 RttRequestInfo rri = it.next(); 760 761 boolean match = rri.uid == uid; // original UID will never be 0 762 if (rri.workSource != null && workSource != null) { 763 rri.workSource.remove(workSource); 764 if (rri.workSource.isEmpty()) { 765 match = true; 766 } 767 } 768 769 if (match) { 770 if (!rri.dispatchedToNative) { 771 it.remove(); 772 rri.binder.unlinkToDeath(rri.dr, 0); 773 } else { 774 dispatchedRequestAborted = true; 775 Log.d(TAG, "Client death - cancelling RTT operation in progress: cmdId=" 776 + rri.cmdId); 777 mRangingTimeoutMessage.cancel(); 778 cancelRanging(rri); 779 } 780 } 781 } 782 783 if (VDBG) { 784 Log.v(TAG, "RttServiceSynchronized.cleanUpOnClientDeath: uid=" + uid 785 + ", dispatchedRequestAborted=" + dispatchedRequestAborted 786 + ", after cleanup - mRttRequestQueue=" + mRttRequestQueue); 787 } 788 789 if (dispatchedRequestAborted) { 790 executeNextRangingRequestIfPossible(true); 791 } 792 } 793 timeoutRangingRequest()794 private void timeoutRangingRequest() { 795 if (VDBG) { 796 Log.v(TAG, "RttServiceSynchronized.timeoutRangingRequest mRttRequestQueue=" 797 + mRttRequestQueue); 798 } 799 if (mRttRequestQueue.size() == 0) { 800 Log.w(TAG, "RttServiceSynchronized.timeoutRangingRequest: but nothing in queue!?"); 801 return; 802 } 803 RttRequestInfo rri = mRttRequestQueue.get(0); 804 if (!rri.dispatchedToNative) { 805 Log.w(TAG, "RttServiceSynchronized.timeoutRangingRequest: command not dispatched " 806 + "to native!?"); 807 return; 808 } 809 cancelRanging(rri); 810 try { 811 mRttMetrics.recordOverallStatus(WifiMetricsProto.WifiRttLog.OVERALL_TIMEOUT); 812 rri.callback.onRangingFailure(RangingResultCallback.STATUS_CODE_FAIL); 813 } catch (RemoteException e) { 814 Log.e(TAG, "RttServiceSynchronized.timeoutRangingRequest: callback failed: " + e); 815 } 816 executeNextRangingRequestIfPossible(true); 817 } 818 queueRangingRequest(int uid, WorkSource workSource, IBinder binder, IBinder.DeathRecipient dr, String callingPackage, String callingFeatureId, RangingRequest request, IRttCallback callback, boolean isCalledFromPrivilegedContext, Object attributionSource)819 private void queueRangingRequest(int uid, WorkSource workSource, IBinder binder, 820 IBinder.DeathRecipient dr, String callingPackage, String callingFeatureId, 821 RangingRequest request, IRttCallback callback, 822 boolean isCalledFromPrivilegedContext, Object attributionSource) { 823 mRttMetrics.recordRequest(workSource, request); 824 825 if (isRequestorSpamming(workSource)) { 826 Log.w(TAG, 827 "Work source " + workSource + " is spamming, dropping request: " + request); 828 binder.unlinkToDeath(dr, 0); 829 try { 830 mRttMetrics.recordOverallStatus(WifiMetricsProto.WifiRttLog.OVERALL_THROTTLE); 831 callback.onRangingFailure(RangingResultCallback.STATUS_CODE_FAIL); 832 } catch (RemoteException e) { 833 Log.e(TAG, "RttServiceSynchronized.queueRangingRequest: spamming, callback " 834 + "failed -- " + e); 835 } 836 return; 837 } 838 839 RttRequestInfo newRequest = new RttRequestInfo(); 840 newRequest.uid = uid; 841 newRequest.workSource = workSource; 842 newRequest.binder = binder; 843 newRequest.dr = dr; 844 newRequest.callingPackage = callingPackage; 845 newRequest.callingFeatureId = callingFeatureId; 846 newRequest.request = request; 847 newRequest.callback = callback; 848 newRequest.isCalledFromPrivilegedContext = isCalledFromPrivilegedContext; 849 newRequest.attributionSource = attributionSource; 850 mRttRequestQueue.add(newRequest); 851 852 if (VDBG) { 853 Log.v(TAG, "RttServiceSynchronized.queueRangingRequest: newRequest=" + newRequest); 854 } 855 856 executeNextRangingRequestIfPossible(false); 857 } 858 isRequestorSpamming(WorkSource ws)859 private boolean isRequestorSpamming(WorkSource ws) { 860 if (VDBG) Log.v(TAG, "isRequestorSpamming: ws" + ws); 861 862 SparseIntArray counts = new SparseIntArray(); 863 864 for (RttRequestInfo rri : mRttRequestQueue) { 865 for (int i = 0; i < rri.workSource.size(); ++i) { 866 int uid = rri.workSource.getUid(i); 867 counts.put(uid, counts.get(uid) + 1); 868 } 869 870 final List<WorkChain> workChains = rri.workSource.getWorkChains(); 871 if (workChains != null) { 872 for (int i = 0; i < workChains.size(); ++i) { 873 final int uid = workChains.get(i).getAttributionUid(); 874 counts.put(uid, counts.get(uid) + 1); 875 } 876 } 877 } 878 879 for (int i = 0; i < ws.size(); ++i) { 880 if (counts.get(ws.getUid(i)) < MAX_QUEUED_PER_UID) { 881 return false; 882 } 883 } 884 885 final List<WorkChain> workChains = ws.getWorkChains(); 886 if (workChains != null) { 887 for (int i = 0; i < workChains.size(); ++i) { 888 final int uid = workChains.get(i).getAttributionUid(); 889 if (counts.get(uid) < MAX_QUEUED_PER_UID) { 890 return false; 891 } 892 } 893 } 894 895 if (mVerboseLoggingEnabled) { 896 Log.v(TAG, "isRequestorSpamming: ws=" + ws + ", someone is spamming: " + counts); 897 } 898 return true; 899 } 900 executeNextRangingRequestIfPossible(boolean popFirst)901 private void executeNextRangingRequestIfPossible(boolean popFirst) { 902 if (VDBG) Log.v(TAG, "executeNextRangingRequestIfPossible: popFirst=" + popFirst); 903 904 if (popFirst) { 905 if (mRttRequestQueue.size() == 0) { 906 Log.w(TAG, "executeNextRangingRequestIfPossible: pop requested - but empty " 907 + "queue!? Ignoring pop."); 908 } else { 909 RttRequestInfo topOfQueueRequest = mRttRequestQueue.remove(0); 910 topOfQueueRequest.binder.unlinkToDeath(topOfQueueRequest.dr, 0); 911 } 912 } 913 914 if (mRttRequestQueue.size() == 0) { 915 if (VDBG) Log.v(TAG, "executeNextRangingRequestIfPossible: no requests pending"); 916 return; 917 } 918 919 // if top of list is in progress then do nothing 920 RttRequestInfo nextRequest = mRttRequestQueue.get(0); 921 if (nextRequest.peerHandlesTranslated || nextRequest.dispatchedToNative) { 922 if (VDBG) { 923 Log.v(TAG, "executeNextRangingRequestIfPossible: called but a command is " 924 + "executing. topOfQueue=" + nextRequest); 925 } 926 return; 927 } 928 929 startRanging(nextRequest); 930 } 931 startRanging(RttRequestInfo nextRequest)932 private void startRanging(RttRequestInfo nextRequest) { 933 if (VDBG) { 934 Log.v(TAG, "RttServiceSynchronized.startRanging: nextRequest=" + nextRequest); 935 } 936 937 if (!isAvailable()) { 938 Log.d(TAG, "RttServiceSynchronized.startRanging: disabled"); 939 try { 940 mRttMetrics.recordOverallStatus( 941 WifiMetricsProto.WifiRttLog.OVERALL_RTT_NOT_AVAILABLE); 942 nextRequest.callback.onRangingFailure( 943 RangingResultCallback.STATUS_CODE_FAIL_RTT_NOT_AVAILABLE); 944 } catch (RemoteException e) { 945 Log.e(TAG, "RttServiceSynchronized.startRanging: disabled, callback failed -- " 946 + e); 947 executeNextRangingRequestIfPossible(true); 948 return; 949 } 950 } 951 952 if (processAwarePeerHandles(nextRequest)) { 953 if (VDBG) { 954 Log.v(TAG, "RttServiceSynchronized.startRanging: deferring due to PeerHandle " 955 + "Aware requests"); 956 } 957 return; 958 } 959 960 if (!preExecThrottleCheck(nextRequest.workSource, nextRequest.callingPackage)) { 961 Log.w(TAG, "RttServiceSynchronized.startRanging: execution throttled - nextRequest=" 962 + nextRequest + ", mRttRequesterInfo=" + mRttRequesterInfo); 963 try { 964 mRttMetrics.recordOverallStatus(WifiMetricsProto.WifiRttLog.OVERALL_THROTTLE); 965 nextRequest.callback.onRangingFailure(RangingResultCallback.STATUS_CODE_FAIL); 966 } catch (RemoteException e) { 967 Log.e(TAG, "RttServiceSynchronized.startRanging: throttled, callback failed -- " 968 + e); 969 } 970 executeNextRangingRequestIfPossible(true); 971 return; 972 } 973 974 nextRequest.cmdId = mNextCommandId++; 975 mLastRequestTimestamp = mClock.getWallClockMillis(); 976 if (mWifiRttController != null 977 && mWifiRttController.rangeRequest(nextRequest.cmdId, nextRequest.request)) { 978 long timeout = HAL_RANGING_TIMEOUT_MS; 979 for (ResponderConfig responderConfig : nextRequest.request.mRttPeers) { 980 if (responderConfig.responderType == ResponderConfig.RESPONDER_AWARE) { 981 timeout = HAL_AWARE_RANGING_TIMEOUT_MS; 982 break; 983 } 984 } 985 mRangingTimeoutMessage.schedule(mClock.getElapsedSinceBootMillis() + timeout); 986 } else { 987 Log.w(TAG, "RttServiceSynchronized.startRanging: native rangeRequest call failed"); 988 if (mWifiRttController == null) { 989 Log.e(TAG, "mWifiRttController is null"); 990 } 991 try { 992 mRttMetrics.recordOverallStatus( 993 WifiMetricsProto.WifiRttLog.OVERALL_HAL_FAILURE); 994 nextRequest.callback.onRangingFailure(RangingResultCallback.STATUS_CODE_FAIL); 995 } catch (RemoteException e) { 996 Log.e(TAG, "RttServiceSynchronized.startRanging: HAL request failed, callback " 997 + "failed -- " + e); 998 } 999 executeNextRangingRequestIfPossible(true); 1000 } 1001 nextRequest.dispatchedToNative = true; 1002 } 1003 1004 /** 1005 * Perform pre-execution throttling checks: 1006 * - If all uids in ws are in background then check last execution and block if request is 1007 * more frequent than permitted 1008 * - If executing (i.e. permitted) then update execution time 1009 * 1010 * Returns true to permit execution, false to abort it. 1011 */ preExecThrottleCheck(WorkSource ws, String callingPackage)1012 private boolean preExecThrottleCheck(WorkSource ws, String callingPackage) { 1013 if (VDBG) Log.v(TAG, "preExecThrottleCheck: ws=" + ws); 1014 1015 // are all UIDs running in the background or is at least 1 in the foreground? 1016 boolean allUidsInBackground = true; 1017 for (int i = 0; i < ws.size(); ++i) { 1018 int uidImportance = mActivityManager.getUidImportance(ws.getUid(i)); 1019 if (VDBG) { 1020 Log.v(TAG, "preExecThrottleCheck: uid=" + ws.getUid(i) + " -> importance=" 1021 + uidImportance); 1022 } 1023 if (uidImportance <= IMPORTANCE_FOREGROUND_SERVICE) { 1024 allUidsInBackground = false; 1025 break; 1026 } 1027 } 1028 1029 final List<WorkChain> workChains = ws.getWorkChains(); 1030 if (allUidsInBackground && workChains != null) { 1031 for (int i = 0; i < workChains.size(); ++i) { 1032 final WorkChain wc = workChains.get(i); 1033 int uidImportance = mActivityManager.getUidImportance(wc.getAttributionUid()); 1034 if (VDBG) { 1035 Log.v(TAG, "preExecThrottleCheck: workChain=" + wc + " -> importance=" 1036 + uidImportance); 1037 } 1038 1039 if (uidImportance <= IMPORTANCE_FOREGROUND_SERVICE) { 1040 allUidsInBackground = false; 1041 break; 1042 } 1043 } 1044 } 1045 if (allUidsInBackground) { 1046 String[] exceptionList = mContext.getResources().getStringArray( 1047 R.array.config_wifiBackgroundRttThrottleExceptionList); 1048 for (String packageName : exceptionList) { 1049 if (TextUtils.equals(packageName, callingPackage)) { 1050 allUidsInBackground = false; 1051 break; 1052 } 1053 } 1054 } 1055 1056 // if all UIDs are in background then check timestamp since last execution and see if 1057 // any is permitted (infrequent enough) 1058 boolean allowExecution = false; 1059 int backgroundProcessExecGapMs = mContext.getResources().getInteger( 1060 R.integer.config_wifiRttBackgroundExecGapMs); 1061 long mostRecentExecutionPermitted = 1062 mClock.getElapsedSinceBootMillis() - backgroundProcessExecGapMs; 1063 if (allUidsInBackground) { 1064 for (int i = 0; i < ws.size(); ++i) { 1065 RttRequesterInfo info = mRttRequesterInfo.get(ws.getUid(i)); 1066 if (info == null || info.lastRangingExecuted < mostRecentExecutionPermitted) { 1067 allowExecution = true; 1068 break; 1069 } 1070 } 1071 1072 if (workChains != null & !allowExecution) { 1073 for (int i = 0; i < workChains.size(); ++i) { 1074 final WorkChain wc = workChains.get(i); 1075 RttRequesterInfo info = mRttRequesterInfo.get(wc.getAttributionUid()); 1076 if (info == null 1077 || info.lastRangingExecuted < mostRecentExecutionPermitted) { 1078 allowExecution = true; 1079 break; 1080 } 1081 } 1082 } 1083 } else { 1084 allowExecution = true; 1085 } 1086 1087 // update exec time 1088 if (allowExecution) { 1089 for (int i = 0; i < ws.size(); ++i) { 1090 RttRequesterInfo info = mRttRequesterInfo.get(ws.getUid(i)); 1091 if (info == null) { 1092 info = new RttRequesterInfo(); 1093 mRttRequesterInfo.put(ws.getUid(i), info); 1094 } 1095 info.lastRangingExecuted = mClock.getElapsedSinceBootMillis(); 1096 } 1097 1098 if (workChains != null) { 1099 for (int i = 0; i < workChains.size(); ++i) { 1100 final WorkChain wc = workChains.get(i); 1101 RttRequesterInfo info = mRttRequesterInfo.get(wc.getAttributionUid()); 1102 if (info == null) { 1103 info = new RttRequesterInfo(); 1104 mRttRequesterInfo.put(wc.getAttributionUid(), info); 1105 } 1106 info.lastRangingExecuted = mClock.getElapsedSinceBootMillis(); 1107 } 1108 } 1109 } 1110 1111 return allowExecution; 1112 } 1113 1114 /** 1115 * Check request for any PeerHandle Aware requests. If there are any: issue requests to 1116 * translate the peer ID to a MAC address and abort current execution of the range request. 1117 * The request will be re-attempted when response is received. 1118 * 1119 * In cases of failure: pop the current request and execute the next one. Failures: 1120 * - Not able to connect to remote service (unlikely) 1121 * - Request already processed: but we're missing information 1122 * 1123 * @return true if need to abort execution, false otherwise. 1124 */ processAwarePeerHandles(RttRequestInfo request)1125 private boolean processAwarePeerHandles(RttRequestInfo request) { 1126 List<Integer> peerIdsNeedingTranslation = new ArrayList<>(); 1127 for (ResponderConfig rttPeer : request.request.mRttPeers) { 1128 if (rttPeer.peerHandle != null && rttPeer.macAddress == null) { 1129 peerIdsNeedingTranslation.add(rttPeer.peerHandle.peerId); 1130 } 1131 } 1132 1133 if (peerIdsNeedingTranslation.size() == 0) { 1134 return false; 1135 } 1136 1137 if (request.peerHandlesTranslated) { 1138 Log.w(TAG, "processAwarePeerHandles: request=" + request 1139 + ": PeerHandles translated - but information still missing!?"); 1140 try { 1141 mRttMetrics.recordOverallStatus( 1142 WifiMetricsProto.WifiRttLog.OVERALL_AWARE_TRANSLATION_FAILURE); 1143 request.callback.onRangingFailure(RangingResultCallback.STATUS_CODE_FAIL); 1144 } catch (RemoteException e) { 1145 Log.e(TAG, "processAwarePeerHandles: onRangingResults failure -- " + e); 1146 } 1147 executeNextRangingRequestIfPossible(true); 1148 return true; // an abort because we removed request and are executing next one 1149 } 1150 1151 request.peerHandlesTranslated = true; 1152 int[] peerIdsArray = peerIdsNeedingTranslation.stream().mapToInt(i -> i).toArray(); 1153 mAwareManager.requestMacAddresses(request.uid, peerIdsArray, 1154 new IWifiAwareMacAddressProvider.Stub() { 1155 @Override 1156 public void macAddress(MacAddrMapping[] peerIdToMacList) { 1157 // ASYNC DOMAIN 1158 mHandler.post(() -> { 1159 // BACK TO SYNC DOMAIN 1160 processReceivedAwarePeerMacAddresses(request, peerIdToMacList); 1161 }); 1162 } 1163 }); 1164 return true; // a deferral 1165 } 1166 processReceivedAwarePeerMacAddresses(RttRequestInfo request, MacAddrMapping[] peerIdToMacList)1167 private void processReceivedAwarePeerMacAddresses(RttRequestInfo request, 1168 MacAddrMapping[] peerIdToMacList) { 1169 if (VDBG) { 1170 Log.v(TAG, "processReceivedAwarePeerMacAddresses: request=" + request); 1171 Log.v(TAG, "processReceivedAwarePeerMacAddresses: peerIdToMacList begin"); 1172 for (MacAddrMapping mapping : peerIdToMacList) { 1173 Log.v(TAG, " " + mapping.peerId + ": " 1174 + MacAddress.fromBytes(mapping.macAddress)); 1175 } 1176 Log.v(TAG, "processReceivedAwarePeerMacAddresses: peerIdToMacList end"); 1177 } 1178 1179 RangingRequest.Builder newRequestBuilder = new RangingRequest.Builder(); 1180 for (ResponderConfig rttPeer : request.request.mRttPeers) { 1181 if (rttPeer.peerHandle != null && rttPeer.macAddress == null) { 1182 byte[] mac = null; 1183 for (MacAddrMapping mapping : peerIdToMacList) { 1184 if (mapping.peerId == rttPeer.peerHandle.peerId) { 1185 mac = mapping.macAddress; 1186 break; 1187 } 1188 } 1189 if (mac == null || mac.length != 6) { 1190 Log.e(TAG, "processReceivedAwarePeerMacAddresses: received an invalid MAC " 1191 + "address for peerId=" + rttPeer.peerHandle.peerId); 1192 continue; 1193 } 1194 // To create a ResponderConfig object with both a MAC address and peer 1195 // handler, we're bypassing the standard Builder pattern and directly using 1196 // the constructor. This is because the SDK's Builder.build() method has a 1197 // built-in restriction that prevents setting both properties simultaneously. 1198 // To avoid triggering this exception, we're directly invoking the 1199 // constructor to accommodate both values. 1200 ResponderConfig.Builder responderConfigBuilder = new ResponderConfig.Builder() 1201 .setMacAddress(MacAddress.fromBytes(mac)) 1202 .setPeerHandle(rttPeer.peerHandle) 1203 .setResponderType(rttPeer.getResponderType()) 1204 .set80211mcSupported(rttPeer.is80211mcSupported()) 1205 .set80211azNtbSupported(rttPeer.is80211azNtbSupported()) 1206 .setChannelWidth(rttPeer.getChannelWidth()) 1207 .setFrequencyMhz(rttPeer.getFrequencyMhz()) 1208 .setCenterFreq1Mhz(rttPeer.getCenterFreq1Mhz()) 1209 .setCenterFreq0Mhz(rttPeer.getCenterFreq0Mhz()) 1210 .setPreamble(rttPeer.getPreamble()); 1211 newRequestBuilder.addResponder(new ResponderConfig(responderConfigBuilder)); 1212 } else { 1213 newRequestBuilder.addResponder(rttPeer); 1214 } 1215 } 1216 newRequestBuilder.setRttBurstSize(request.request.getRttBurstSize()); 1217 request.request = newRequestBuilder.build(); 1218 1219 // run request again 1220 startRanging(request); 1221 } 1222 onRangingResults(int cmdId, List<RangingResult> results)1223 private void onRangingResults(int cmdId, List<RangingResult> results) { 1224 if (mRttRequestQueue.size() == 0) { 1225 Log.e(TAG, "RttServiceSynchronized.onRangingResults: no current RTT request " 1226 + "pending!?"); 1227 return; 1228 } 1229 mRangingTimeoutMessage.cancel(); 1230 RttRequestInfo topOfQueueRequest = mRttRequestQueue.get(0); 1231 1232 if (VDBG) { 1233 Log.v(TAG, "RttServiceSynchronized.onRangingResults: cmdId=" + cmdId 1234 + ", topOfQueueRequest=" + topOfQueueRequest + ", results=" 1235 + Arrays.toString(results.toArray())); 1236 } 1237 1238 if (topOfQueueRequest.cmdId != cmdId) { 1239 Log.e(TAG, "RttServiceSynchronized.onRangingResults: cmdId=" + cmdId 1240 + ", does not match pending RTT request cmdId=" + topOfQueueRequest.cmdId); 1241 return; 1242 } 1243 1244 boolean onlyAwareApRanged = topOfQueueRequest.request.mRttPeers.stream().allMatch( 1245 config -> config.responderType == ResponderConfig.RESPONDER_AWARE); 1246 boolean permissionGranted = false; 1247 if (onlyAwareApRanged && SdkLevel.isAtLeastT()) { 1248 // Special case: if only aware APs are ranged, then allow this request if the caller 1249 // has nearby permission. 1250 permissionGranted = mWifiPermissionsUtil.checkNearbyDevicesPermission( 1251 (AttributionSource) topOfQueueRequest.attributionSource, true, 1252 "wifi aware on ranging result"); 1253 } 1254 if (!permissionGranted) { 1255 permissionGranted = 1256 mWifiPermissionsUtil.checkCallersLocationPermission( 1257 topOfQueueRequest.callingPackage, 1258 topOfQueueRequest.callingFeatureId, 1259 topOfQueueRequest.uid, /* coarseForTargetSdkLessThanQ */ false, 1260 null) && mWifiPermissionsUtil.isLocationModeEnabled(); 1261 } 1262 try { 1263 if (permissionGranted) { 1264 List<RangingResult> finalResults = postProcessResults(topOfQueueRequest.request, 1265 results, topOfQueueRequest.isCalledFromPrivilegedContext); 1266 mRttMetrics.recordOverallStatus(WifiMetricsProto.WifiRttLog.OVERALL_SUCCESS); 1267 mRttMetrics.recordResult(topOfQueueRequest.request, results, 1268 (int) (mClock.getWallClockMillis() - mLastRequestTimestamp)); 1269 if (VDBG) { 1270 Log.v(TAG, "RttServiceSynchronized.onRangingResults: finalResults=" 1271 + finalResults); 1272 } 1273 topOfQueueRequest.callback.onRangingResults(finalResults); 1274 } else { 1275 Log.w(TAG, "RttServiceSynchronized.onRangingResults: location permission " 1276 + "revoked - not forwarding results"); 1277 mRttMetrics.recordOverallStatus( 1278 WifiMetricsProto.WifiRttLog.OVERALL_LOCATION_PERMISSION_MISSING); 1279 topOfQueueRequest.callback.onRangingFailure( 1280 RangingResultCallback.STATUS_CODE_FAIL); 1281 } 1282 } catch (RemoteException e) { 1283 Log.e(TAG, 1284 "RttServiceSynchronized.onRangingResults: callback exception -- " + e); 1285 } 1286 1287 executeNextRangingRequestIfPossible(true); 1288 } 1289 1290 /* 1291 * Post process the results: 1292 * - For requests without results: add FAILED results 1293 * - For Aware requests using PeerHandle: replace MAC address with PeerHandle 1294 * - Effectively: throws away results which don't match requests 1295 */ postProcessResults(RangingRequest request, List<RangingResult> results, boolean isCalledFromPrivilegedContext)1296 private List<RangingResult> postProcessResults(RangingRequest request, 1297 List<RangingResult> results, boolean isCalledFromPrivilegedContext) { 1298 Map<MacAddress, RangingResult> resultEntries = new HashMap<>(); 1299 for (RangingResult result : results) { 1300 resultEntries.put(result.getMacAddress(), result); 1301 } 1302 1303 List<RangingResult> finalResults = new ArrayList<>(request.mRttPeers.size()); 1304 1305 for (ResponderConfig peer : request.mRttPeers) { 1306 RangingResult resultForRequest = resultEntries.get(peer.macAddress); 1307 if (resultForRequest == null || resultForRequest.getStatus() 1308 != WifiRttController.FRAMEWORK_RTT_STATUS_SUCCESS) { 1309 if (mVerboseLoggingEnabled) { 1310 Log.v(TAG, "postProcessResults: missing=" + peer.macAddress); 1311 } 1312 RangingResult.Builder builder = new RangingResult.Builder() 1313 .setStatus(RangingResult.STATUS_FAIL); 1314 if (peer.peerHandle == null) { 1315 builder.setMacAddress(peer.getMacAddress()); 1316 } else { 1317 builder.setPeerHandle(peer.peerHandle); 1318 } 1319 finalResults.add(builder.build()); 1320 } else { 1321 1322 // Clear LCI and LCR data if the location data should not be retransmitted, 1323 // has a retention expiration time, contains no useful data, or did not parse, 1324 // or the caller is not in a privileged context. 1325 byte[] lci = resultForRequest.getLci(); 1326 byte[] lcr = resultForRequest.getLcr(); 1327 ResponderLocation responderLocation = 1328 resultForRequest.getUnverifiedResponderLocation(); 1329 if (responderLocation == null || !isCalledFromPrivilegedContext) { 1330 lci = null; 1331 lcr = null; 1332 } 1333 RangingResult.Builder builder = new RangingResult.Builder(); 1334 builder.setStatus(RangingResult.STATUS_SUCCESS) 1335 .setDistanceMm(resultForRequest.getDistanceMm()) 1336 .setDistanceStdDevMm(resultForRequest.getDistanceStdDevMm()) 1337 .setRssi(resultForRequest.getRssi()) 1338 .setNumAttemptedMeasurements( 1339 resultForRequest.getNumAttemptedMeasurements()) 1340 .setNumSuccessfulMeasurements( 1341 resultForRequest.getNumSuccessfulMeasurements()) 1342 .setLci(lci) 1343 .setLcr(lcr) 1344 .setUnverifiedResponderLocation(responderLocation) 1345 .setRangingTimestampMillis(resultForRequest.getRangingTimestampMillis()) 1346 .set80211mcMeasurement(resultForRequest.is80211mcMeasurement()) 1347 .setMeasurementChannelFrequencyMHz( 1348 resultForRequest.getMeasurementChannelFrequencyMHz()) 1349 .setMeasurementBandwidth(resultForRequest.getMeasurementBandwidth()) 1350 .set80211azNtbMeasurement(resultForRequest.is80211azNtbMeasurement()) 1351 .setMinTimeBetweenNtbMeasurementsMicros( 1352 resultForRequest.getMinTimeBetweenNtbMeasurementsMicros()) 1353 .setMaxTimeBetweenNtbMeasurementsMicros( 1354 resultForRequest.getMaxTimeBetweenNtbMeasurementsMicros()) 1355 .set80211azInitiatorTxLtfRepetitionsCount( 1356 resultForRequest.get80211azInitiatorTxLtfRepetitionsCount()) 1357 .set80211azResponderTxLtfRepetitionsCount( 1358 resultForRequest.get80211azResponderTxLtfRepetitionsCount()) 1359 .set80211azNumberOfTxSpatialStreams( 1360 resultForRequest.get80211azNumberOfTxSpatialStreams()) 1361 .set80211azNumberOfRxSpatialStreams( 1362 resultForRequest.get80211azNumberOfRxSpatialStreams()); 1363 if (peer.peerHandle == null) { 1364 builder.setMacAddress(peer.getMacAddress()); 1365 } else { 1366 builder.setPeerHandle(peer.peerHandle); 1367 } 1368 if (SdkLevel.isAtLeastV() && resultForRequest.getVendorData() != null 1369 && !resultForRequest.getVendorData().isEmpty()) { 1370 builder.setVendorData(resultForRequest.getVendorData()); 1371 } 1372 finalResults.add(builder.build()); 1373 } 1374 } 1375 return finalResults; 1376 } 1377 1378 // dump call (asynchronous most likely) dump(FileDescriptor fd, PrintWriter pw, String[] args)1379 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1380 pw.println(" mNextCommandId: " + mNextCommandId); 1381 pw.println(" mRttRequesterInfo: " + mRttRequesterInfo); 1382 pw.println(" mRttRequestQueue: " + mRttRequestQueue); 1383 pw.println(" mRangingTimeoutMessage: " + mRangingTimeoutMessage); 1384 pw.println(" mWifiRttController: " + mWifiRttController); 1385 pw.println(" mHalDeviceManager: " + mHalDeviceManager); 1386 mRttMetrics.dump(fd, pw, args); 1387 } 1388 } 1389 1390 private static class RttRequestInfo { 1391 public int uid; 1392 public WorkSource workSource; 1393 public IBinder binder; 1394 public IBinder.DeathRecipient dr; 1395 public String callingPackage; 1396 public String callingFeatureId; 1397 public RangingRequest request; 1398 public IRttCallback callback; 1399 public boolean isCalledFromPrivilegedContext; 1400 // This should be of Class AttributionSource, not is declared as Object for mainline 1401 // backward compatibility. 1402 public Object attributionSource; 1403 1404 public int cmdId = 0; // uninitialized cmdId value 1405 public boolean dispatchedToNative = false; 1406 public boolean peerHandlesTranslated = false; 1407 1408 @Override toString()1409 public String toString() { 1410 return new StringBuilder("RttRequestInfo: uid=").append(uid).append( 1411 ", workSource=").append(workSource).append(", binder=").append(binder).append( 1412 ", dr=").append(dr).append(", callingPackage=").append(callingPackage).append( 1413 ", callingFeatureId=").append(callingFeatureId).append(", request=").append( 1414 request.toString()).append(", callback=").append(callback).append( 1415 ", cmdId=").append(cmdId).append(", peerHandlesTranslated=").append( 1416 peerHandlesTranslated).append(", isCalledFromPrivilegedContext=").append( 1417 isCalledFromPrivilegedContext).toString(); 1418 } 1419 } 1420 1421 private static class RttRequesterInfo { 1422 public long lastRangingExecuted; 1423 1424 @Override toString()1425 public String toString() { 1426 return new StringBuilder("RttRequesterInfo: lastRangingExecuted=").append( 1427 lastRangingExecuted).toString(); 1428 } 1429 } 1430 } 1431