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