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