• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 package com.android.server.uwb;
17 
18 import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
19 
20 import static com.android.server.uwb.data.UwbUciConstants.MAC_ADDRESSING_MODE_EXTENDED;
21 import static com.android.server.uwb.data.UwbUciConstants.MAC_ADDRESSING_MODE_SHORT;
22 import static com.android.server.uwb.data.UwbUciConstants.RANGING_DEVICE_ROLE_OBSERVER;
23 import static com.android.server.uwb.data.UwbUciConstants.REASON_STATE_CHANGE_WITH_SESSION_MANAGEMENT_COMMANDS;
24 import static com.android.server.uwb.data.UwbUciConstants.ROUND_USAGE_OWR_AOA_MEASUREMENT;
25 import static com.android.server.uwb.data.UwbUciConstants.STATUS_CODE_OK;
26 import static com.android.server.uwb.data.UwbUciConstants.UWB_DEVICE_EXT_MAC_ADDRESS_LEN;
27 import static com.android.server.uwb.data.UwbUciConstants.UWB_DEVICE_SHORT_MAC_ADDRESS_LEN;
28 import static com.android.server.uwb.data.UwbUciConstants.UWB_SESSION_STATE_ACTIVE;
29 import static com.android.server.uwb.util.DataTypeConversionUtil.macAddressByteArrayToLong;
30 
31 import static com.google.uwb.support.fira.FiraParams.FILTER_TYPE_APPLICATION;
32 import static com.google.uwb.support.fira.FiraParams.FILTER_TYPE_DEFAULT;
33 import static com.google.uwb.support.fira.FiraParams.FILTER_TYPE_NONE;
34 import static com.google.uwb.support.fira.FiraParams.MULTICAST_LIST_UPDATE_ACTION_ADD;
35 import static com.google.uwb.support.fira.FiraParams.MULTICAST_LIST_UPDATE_ACTION_DELETE;
36 import static com.google.uwb.support.fira.FiraParams.PROTOCOL_NAME;
37 import static com.google.uwb.support.fira.FiraParams.P_STS_MULTICAST_LIST_UPDATE_ACTION_ADD_16_BYTE;
38 import static com.google.uwb.support.fira.FiraParams.P_STS_MULTICAST_LIST_UPDATE_ACTION_ADD_32_BYTE;
39 import static com.google.uwb.support.fira.FiraParams.RangeDataNtfConfigCapabilityFlag.HAS_RANGE_DATA_NTF_CONFIG_DISABLE;
40 import static com.google.uwb.support.fira.FiraParams.RangeDataNtfConfigCapabilityFlag.HAS_RANGE_DATA_NTF_CONFIG_ENABLE;
41 
42 import android.annotation.NonNull;
43 import android.annotation.Nullable;
44 import android.app.ActivityManager;
45 import android.app.AlarmManager;
46 import android.content.AttributionSource;
47 import android.os.Binder;
48 import android.os.Handler;
49 import android.os.IBinder;
50 import android.os.Looper;
51 import android.os.Message;
52 import android.os.PersistableBundle;
53 import android.os.RemoteException;
54 import android.os.Trace;
55 import android.util.Log;
56 import android.util.Pair;
57 import android.uwb.IUwbAdapter;
58 import android.uwb.IUwbRangingCallbacks;
59 import android.uwb.RangingChangeReason;
60 import android.uwb.SessionHandle;
61 import android.uwb.UwbAddress;
62 
63 import androidx.annotation.VisibleForTesting;
64 
65 import com.android.modules.utils.build.SdkLevel;
66 import com.android.server.uwb.advertisement.UwbAdvertiseManager;
67 import com.android.server.uwb.correction.UwbFilterEngine;
68 import com.android.server.uwb.correction.pose.ApplicationPoseSource;
69 import com.android.server.uwb.correction.pose.IPoseSource;
70 import com.android.server.uwb.data.DtTagUpdateRangingRoundsStatus;
71 import com.android.server.uwb.data.UwbMulticastListUpdateStatus;
72 import com.android.server.uwb.data.UwbOwrAoaMeasurement;
73 import com.android.server.uwb.data.UwbRangingData;
74 import com.android.server.uwb.data.UwbTwoWayMeasurement;
75 import com.android.server.uwb.data.UwbUciConstants;
76 import com.android.server.uwb.jni.INativeUwbManager;
77 import com.android.server.uwb.jni.NativeUwbManager;
78 import com.android.server.uwb.params.TlvUtil;
79 import com.android.server.uwb.proto.UwbStatsLog;
80 import com.android.server.uwb.util.ArrayUtils;
81 import com.android.server.uwb.util.DataTypeConversionUtil;
82 import com.android.server.uwb.util.LruList;
83 import com.android.server.uwb.util.UwbUtil;
84 
85 import com.google.uwb.support.base.Params;
86 import com.google.uwb.support.ccc.CccOpenRangingParams;
87 import com.google.uwb.support.ccc.CccParams;
88 import com.google.uwb.support.ccc.CccRangingStartedParams;
89 import com.google.uwb.support.ccc.CccSpecificationParams;
90 import com.google.uwb.support.ccc.CccStartRangingParams;
91 import com.google.uwb.support.dltdoa.DlTDoARangingRoundsUpdate;
92 import com.google.uwb.support.dltdoa.DlTDoARangingRoundsUpdateStatus;
93 import com.google.uwb.support.fira.FiraOpenSessionParams;
94 import com.google.uwb.support.fira.FiraParams;
95 import com.google.uwb.support.fira.FiraPoseUpdateParams;
96 import com.google.uwb.support.fira.FiraRangingReconfigureParams;
97 import com.google.uwb.support.fira.FiraSpecificationParams;
98 import com.google.uwb.support.generic.GenericSpecificationParams;
99 import com.google.uwb.support.oemextension.AdvertisePointedTarget;
100 import com.google.uwb.support.oemextension.SessionStatus;
101 
102 import java.io.Closeable;
103 import java.io.FileDescriptor;
104 import java.io.PrintWriter;
105 import java.util.ArrayList;
106 import java.util.Collection;
107 import java.util.Collections;
108 import java.util.Comparator;
109 import java.util.EnumSet;
110 import java.util.List;
111 import java.util.Optional;
112 import java.util.Set;
113 import java.util.SortedMap;
114 import java.util.TreeMap;
115 import java.util.concurrent.Callable;
116 import java.util.concurrent.ConcurrentHashMap;
117 import java.util.concurrent.ExecutionException;
118 import java.util.concurrent.ExecutorService;
119 import java.util.concurrent.Executors;
120 import java.util.concurrent.FutureTask;
121 import java.util.concurrent.TimeUnit;
122 import java.util.concurrent.TimeoutException;
123 import java.util.stream.Collectors;
124 
125 public class UwbSessionManager implements INativeUwbManager.SessionNotification,
126         ActivityManager.OnUidImportanceListener {
127 
128     private static final String TAG = "UwbSessionManager";
129     private static final byte OPERATION_TYPE_INIT_SESSION = 0;
130 
131     @VisibleForTesting
132     public static final int SESSION_OPEN_RANGING = 1;
133     @VisibleForTesting
134     public static final int SESSION_START_RANGING = 2;
135     @VisibleForTesting
136     public static final int SESSION_STOP_RANGING = 3;
137     @VisibleForTesting
138     public static final int SESSION_RECONFIG_RANGING = 4;
139     @VisibleForTesting
140     public static final int SESSION_DEINIT = 5;
141     @VisibleForTesting
142     public static final int SESSION_ON_DEINIT = 6;
143     @VisibleForTesting
144     public static final int SESSION_SEND_DATA = 7;
145     @VisibleForTesting
146     public static final int SESSION_UPDATE_DT_TAG_RANGING_ROUNDS = 8;
147 
148     // TODO: don't expose the internal field for testing.
149     @VisibleForTesting
150     final ConcurrentHashMap<SessionHandle, UwbSession> mSessionTable = new ConcurrentHashMap();
151     // Used for storing recently closed sessions for debugging purposes.
152     final LruList<UwbSession> mDbgRecentlyClosedSessions = new LruList<>(5);
153     final ConcurrentHashMap<Integer, List<UwbSession>> mNonPrivilegedUidToFiraSessionsTable =
154             new ConcurrentHashMap();
155     final ConcurrentHashMap<Integer, Integer> mSessionTokenMap = new ConcurrentHashMap<>();
156     private final ActivityManager mActivityManager;
157     private final NativeUwbManager mNativeUwbManager;
158     private final UwbMetrics mUwbMetrics;
159     private final UwbConfigurationManager mConfigurationManager;
160     private final UwbSessionNotificationManager mSessionNotificationManager;
161     private final UwbAdvertiseManager mAdvertiseManager;
162     private final UwbInjector mUwbInjector;
163     private final AlarmManager mAlarmManager;
164     private final Looper mLooper;
165     private final EventTask mEventTask;
166 
167     private Boolean mIsRangeDataNtfConfigEnableDisableSupported;
168 
UwbSessionManager( UwbConfigurationManager uwbConfigurationManager, NativeUwbManager nativeUwbManager, UwbMetrics uwbMetrics, UwbAdvertiseManager uwbAdvertiseManager, UwbSessionNotificationManager uwbSessionNotificationManager, UwbInjector uwbInjector, AlarmManager alarmManager, ActivityManager activityManager, Looper serviceLooper)169     public UwbSessionManager(
170             UwbConfigurationManager uwbConfigurationManager,
171             NativeUwbManager nativeUwbManager, UwbMetrics uwbMetrics,
172             UwbAdvertiseManager uwbAdvertiseManager,
173             UwbSessionNotificationManager uwbSessionNotificationManager,
174             UwbInjector uwbInjector, AlarmManager alarmManager, ActivityManager activityManager,
175             Looper serviceLooper) {
176         mNativeUwbManager = nativeUwbManager;
177         mNativeUwbManager.setSessionListener(this);
178         mUwbMetrics = uwbMetrics;
179         mAdvertiseManager = uwbAdvertiseManager;
180         mConfigurationManager = uwbConfigurationManager;
181         mSessionNotificationManager = uwbSessionNotificationManager;
182         mUwbInjector = uwbInjector;
183         mAlarmManager = alarmManager;
184         mActivityManager = activityManager;
185         mLooper = serviceLooper;
186         mEventTask = new EventTask(serviceLooper);
187         registerUidImportanceTransitions();
188     }
189 
isRangeDataNtfConfigEnableDisableSupported()190     private boolean isRangeDataNtfConfigEnableDisableSupported() {
191         if (mIsRangeDataNtfConfigEnableDisableSupported == null) {
192             String defaultChipId = mUwbInjector.getMultichipData().getDefaultChipId();
193             GenericSpecificationParams specificationParams =
194                     mUwbInjector.getUwbServiceCore().getCachedSpecificationParams(defaultChipId);
195             if (specificationParams == null) return false;
196             EnumSet<FiraParams.RangeDataNtfConfigCapabilityFlag> supportedRangeDataNtfConfigs =
197                     specificationParams.getFiraSpecificationParams()
198                             .getRangeDataNtfConfigCapabilities();
199             mIsRangeDataNtfConfigEnableDisableSupported =
200                     supportedRangeDataNtfConfigs.containsAll(EnumSet.of(
201                             HAS_RANGE_DATA_NTF_CONFIG_DISABLE,
202                             HAS_RANGE_DATA_NTF_CONFIG_ENABLE));
203         }
204         return mIsRangeDataNtfConfigEnableDisableSupported;
205     }
206 
207     @Override
onUidImportance(final int uid, final int importance)208     public void onUidImportance(final int uid, final int importance) {
209         Handler handler = new Handler(mLooper);
210         handler.post(() -> {
211             List<UwbSession> uwbSessions = mNonPrivilegedUidToFiraSessionsTable.get(uid);
212             // Not a uid in the watch list
213             if (uwbSessions == null) return;
214             boolean newModeHasNonPrivilegedFgApp =
215                     UwbInjector.isForegroundAppOrServiceImportance(importance);
216             for (UwbSession uwbSession : uwbSessions) {
217                 // already at correct state.
218                 if (newModeHasNonPrivilegedFgApp == uwbSession.hasNonPrivilegedFgApp()) {
219                     continue;
220                 }
221                 uwbSession.setHasNonPrivilegedFgApp(newModeHasNonPrivilegedFgApp);
222                 int sessionId = uwbSession.getSessionId();
223                 Log.i(TAG, "App state change for session " + sessionId + ". IsFg: "
224                         + newModeHasNonPrivilegedFgApp);
225                 // Reconfigure the session based on the new fg/bg state if
226                 // NtfConfigEnableDisable is supported.
227                 if (isRangeDataNtfConfigEnableDisableSupported()) {
228                     Log.i(TAG, "Session " + sessionId
229                             + " reconfiguring ntf control due to app state change");
230                     uwbSession.reconfigureFiraSessionOnFgStateChange();
231                 }
232                 // Recalculate session priority based on the new fg/bg state.
233                 if (!uwbSession.mSessionPriorityOverride) {
234                     int newSessionPriority = uwbSession.calculateSessionPriority();
235                     Log.i(TAG, "Session " + sessionId
236                             + " recalculating session priority, new priority: "
237                             + newSessionPriority);
238                     uwbSession.setStackSessionPriority(newSessionPriority);
239                 }
240             }
241         });
242     }
243 
244     // Detect UIDs going foreground/background
registerUidImportanceTransitions()245     private void registerUidImportanceTransitions() {
246         mActivityManager.addOnUidImportanceListener(
247                 UwbSessionManager.this, IMPORTANCE_FOREGROUND_SERVICE);
248     }
249 
hasAllRangingResultError(@onNull UwbRangingData rangingData)250     private static boolean hasAllRangingResultError(@NonNull UwbRangingData rangingData) {
251         if (rangingData.getRangingMeasuresType()
252                 == UwbUciConstants.RANGING_MEASUREMENT_TYPE_TWO_WAY) {
253             for (UwbTwoWayMeasurement measure : rangingData.getRangingTwoWayMeasures()) {
254                 if (measure.isStatusCodeOk()) {
255                     return false;
256                 }
257             }
258         } else if (rangingData.getRangingMeasuresType()
259                 == UwbUciConstants.RANGING_MEASUREMENT_TYPE_OWR_AOA) {
260             UwbOwrAoaMeasurement measure = rangingData.getRangingOwrAoaMeasure();
261             if (measure.getRangingStatus() == UwbUciConstants.STATUS_CODE_OK) {
262                 return false;
263             }
264         }
265         return true;
266     }
267 
268     @Override
onRangeDataNotificationReceived(UwbRangingData rangingData)269     public void onRangeDataNotificationReceived(UwbRangingData rangingData) {
270         Trace.beginSection("UWB#onRangeDataNotificationReceived");
271         long sessionId = rangingData.getSessionId();
272         UwbSession uwbSession = getUwbSession((int) sessionId);
273         if (uwbSession != null) {
274             // TODO: b/268065070 Include UWB logs for both filtered and unfiltered data.
275             mSessionNotificationManager.onRangingResult(uwbSession, rangingData);
276             processRangeData(rangingData, uwbSession);
277             if (mUwbInjector.getDeviceConfigFacade().isRangingErrorStreakTimerEnabled()
278                     && uwbSession.mRangingErrorStreakTimeoutMs
279                     != UwbSession.RANGING_RESULT_ERROR_NO_TIMEOUT) {
280                 if (hasAllRangingResultError(rangingData)) {
281                     uwbSession.startRangingResultErrorStreakTimerIfNotSet();
282                 } else {
283                     uwbSession.stopRangingResultErrorStreakTimerIfSet();
284                 }
285             }
286         } else {
287             Log.i(TAG, "Session is not initialized or Ranging Data is Null");
288         }
289         Trace.endSection();
290     }
291 
292     /* Notification of received data over UWB to Application*/
293     @Override
onDataReceived( long sessionId, int status, long sequenceNum, byte[] address, int sourceEndPoint, int destEndPoint, byte[] data)294     public void onDataReceived(
295             long sessionId, int status, long sequenceNum,
296             byte[] address, int sourceEndPoint, int destEndPoint, byte[] data) {
297         Log.d(TAG, "onDataReceived(): Received data packet - "
298                 + "Address: " + UwbUtil.toHexString(address)
299                 + ", Data: " + UwbUtil.toHexString(data)
300                 + ", sessionId: " + sessionId
301                 + ", status: " + status
302                 + ", sequenceNum: " + sequenceNum);
303 
304         UwbSession uwbSession = getUwbSession((int) sessionId);
305         if (uwbSession == null) {
306             Log.e(TAG, "onDataReceived(): Received data for unknown sessionId = " + sessionId);
307             return;
308         }
309 
310         // Size of address in the UCI Packet for DATA_MESSAGE_RCV is always expected to be 8
311         // (EXTENDED_ADDRESS_BYTE_LENGTH). It can contain the MacAddress in short format however
312         // (2 LSB with MacAddress, 6 MSB zeroed out).
313         if (address.length != UWB_DEVICE_EXT_MAC_ADDRESS_LEN) {
314             Log.e(TAG, "onDataReceived(): Received data for sessionId = " + sessionId
315                     + ", with unexpected MacAddress length = " + address.length);
316             return;
317         }
318         mUwbMetrics.logDataRx(uwbSession, status);
319 
320         Long longAddress = macAddressByteArrayToLong(address);
321         UwbAddress uwbAddress = UwbAddress.fromBytes(address);
322 
323         // When the data packet is received on a non OWR-for-AoA ranging session, send it to the
324         // higher layer. For the OWR-for-AoA ranging session, the data packet is only sent when the
325         // received SESSION_INFO_NTF indicate this Observer device is pointing to an Advertiser.
326         if (uwbSession.getRangingRoundUsage() != ROUND_USAGE_OWR_AOA_MEASUREMENT) {
327             mSessionNotificationManager.onDataReceived(
328                     uwbSession, uwbAddress, new PersistableBundle(), data);
329             return;
330         }
331 
332         ReceivedDataInfo info = new ReceivedDataInfo();
333         info.sessionId = sessionId;
334         info.status = status;
335         info.sequenceNum = sequenceNum;
336         info.address = longAddress;
337         info.sourceEndPoint = sourceEndPoint;
338         info.destEndPoint = destEndPoint;
339         info.payload = data;
340 
341         uwbSession.addReceivedDataInfo(info);
342     }
343 
344     /* Notification of data send status */
345     @Override
onDataSendStatus( long sessionId, int dataTransferStatus, long sequenceNum)346     public void onDataSendStatus(
347             long sessionId, int dataTransferStatus, long sequenceNum) {
348         Log.d(TAG, "onDataSendStatus(): Received data send status - "
349                 + ", sessionId: " + sessionId
350                 + ", status: " + dataTransferStatus
351                 + ", sequenceNum: " + sequenceNum);
352 
353         UwbSession uwbSession = getUwbSession((int) sessionId);
354         if (uwbSession == null) {
355             Log.e(TAG, "onDataSendStatus(): Received data send status for unknown sessionId = "
356                     + sessionId);
357             return;
358         }
359 
360         SendDataInfo sendDataInfo = uwbSession.getSendDataInfo(sequenceNum);
361         if (sendDataInfo == null) {
362             Log.e(TAG, "onDataSendStatus(): No SendDataInfo found for data packet (sessionId = "
363                     + sessionId + ", sequenceNum = " + sequenceNum + ")");
364             return;
365         }
366 
367         // A note on status - earlier spec versions had the same status value (0x1) as an error,
368         // the code is written as per recent spec versions (v2.0.0_0.0.9r0).
369         if (dataTransferStatus == UwbUciConstants.STATUS_CODE_DATA_TRANSFER_REPETITION_OK
370                 || dataTransferStatus == UwbUciConstants.STATUS_CODE_DATA_TRANSFER_OK) {
371             mSessionNotificationManager.onDataSent(
372                     uwbSession, sendDataInfo.remoteDeviceAddress, sendDataInfo.params);
373         } else {
374             mSessionNotificationManager.onDataSendFailed(
375                     uwbSession, sendDataInfo.remoteDeviceAddress, dataTransferStatus,
376                     sendDataInfo.params);
377         }
378         // TODO(b/274711916): When Data Repetition during Data Packet Tx flow is implemented
379         // change here to remove the sendDataInfo only after all the copies of the packet have
380         // been sent.
381         uwbSession.removeSendDataInfo(sequenceNum);
382     }
383 
384     /** Updates pose information if the session is using an ApplicationPoseSource */
updatePose(SessionHandle sessionHandle, PersistableBundle params)385     public void updatePose(SessionHandle sessionHandle, PersistableBundle params) {
386         int sessionId = getSessionId(sessionHandle);
387         UwbSession uwbSession = getUwbSession(sessionId);
388 
389         if (uwbSession == null) {
390             // Session doesn't exist yet/anymore.
391             return;
392         }
393 
394         uwbSession.updatePose(FiraPoseUpdateParams.fromBundle(params));
395     }
396 
397     @VisibleForTesting
398     static final class ReceivedDataInfo {
399         public long sessionId;
400         public int status;
401         public long sequenceNum;
402         public long address;
403         public int sourceEndPoint;
404         public int destEndPoint;
405         public byte[] payload;
406     }
407 
408     @Override
onMulticastListUpdateNotificationReceived( UwbMulticastListUpdateStatus multicastListUpdateStatus)409     public void onMulticastListUpdateNotificationReceived(
410             UwbMulticastListUpdateStatus multicastListUpdateStatus) {
411         Log.d(TAG, "onMulticastListUpdateNotificationReceived");
412         UwbSession uwbSession = getUwbSession((int) multicastListUpdateStatus.getSessionId());
413         if (uwbSession == null) {
414             Log.d(TAG, "onMulticastListUpdateNotificationReceived - invalid session");
415             return;
416         }
417         uwbSession.setMulticastListUpdateStatus(multicastListUpdateStatus);
418         synchronized (uwbSession.getWaitObj()) {
419             uwbSession.getWaitObj().blockingNotify();
420         }
421     }
422 
423     @Override
onSessionStatusNotificationReceived(long sessionId, int state, int reasonCode)424     public void onSessionStatusNotificationReceived(long sessionId, int state, int reasonCode) {
425         Log.i(TAG, "onSessionStatusNotificationReceived - Session ID : " + sessionId + ", state : "
426                 + UwbSessionNotificationHelper.getSessionStateString(state)
427                 + ", reasonCode:" + reasonCode);
428         UwbSession uwbSession = getUwbSession((int) sessionId);
429 
430         if (uwbSession == null) {
431             Log.d(TAG, "onSessionStatusNotificationReceived - invalid session");
432             return;
433         }
434         if (mUwbInjector.getUwbServiceCore().isOemExtensionCbRegistered()) {
435             PersistableBundle sessionStatusBundle = new SessionStatus.Builder()
436                     .setSessionId(sessionId)
437                     .setState(state)
438                     .setReasonCode(reasonCode)
439                     .setAppPackageName(uwbSession.getAttributionSource().getPackageName())
440                     .setSessiontoken(mSessionTokenMap.getOrDefault(uwbSession.getSessionId(), 0))
441                     .build()
442                     .toBundle();
443             try {
444                 mUwbInjector.getUwbServiceCore().getOemExtensionCallback()
445                         .onSessionStatusNotificationReceived(sessionStatusBundle);
446             } catch (RemoteException e) {
447                 Log.e(TAG, "Failed to send vendor notification", e);
448             }
449         }
450         int prevState = uwbSession.getSessionState();
451         setCurrentSessionState((int) sessionId, state);
452 
453         if ((uwbSession.getOperationType() == SESSION_ON_DEINIT
454                 && state == UwbUciConstants.UWB_SESSION_STATE_IDLE)
455                 || (uwbSession.getOperationType() == SESSION_STOP_RANGING
456                 && state == UwbUciConstants.UWB_SESSION_STATE_IDLE
457                 && reasonCode != REASON_STATE_CHANGE_WITH_SESSION_MANAGEMENT_COMMANDS)) {
458             Log.d(TAG, "Session status NTF is received due to in-band session state change");
459         } else {
460             synchronized (uwbSession.getWaitObj()) {
461                 uwbSession.getWaitObj().blockingNotify();
462             }
463         }
464 
465         //TODO : process only error handling in this switch function, b/218921154
466         switch (state) {
467             case UwbUciConstants.UWB_SESSION_STATE_IDLE:
468                 if (prevState == UwbUciConstants.UWB_SESSION_STATE_ACTIVE) {
469                     // If session was stopped explicitly, then the onStopped() is sent from
470                     // stopRanging method.
471                     if (reasonCode != REASON_STATE_CHANGE_WITH_SESSION_MANAGEMENT_COMMANDS) {
472                         mSessionNotificationManager.onRangingStoppedWithUciReasonCode(
473                                 uwbSession, reasonCode);
474                         mUwbMetrics.longRangingStopEvent(uwbSession);
475                     }
476                 } else if (prevState == UwbUciConstants.UWB_SESSION_STATE_IDLE) {
477                     //mSessionNotificationManager.onRangingReconfigureFailed(
478                     //      uwbSession, reasonCode);
479                 }
480                 break;
481             case UwbUciConstants.UWB_SESSION_STATE_DEINIT:
482                 mEventTask.execute(SESSION_ON_DEINIT, uwbSession);
483                 break;
484             default:
485                 break;
486         }
487     }
488 
setAppConfigurations(UwbSession uwbSession)489     private int setAppConfigurations(UwbSession uwbSession) {
490         int status = mConfigurationManager.setAppConfigurations(uwbSession.getSessionId(),
491                 uwbSession.getParams(), uwbSession.getChipId());
492         if (status == UwbUciConstants.STATUS_CODE_OK
493                 && mUwbInjector.getUwbServiceCore().isOemExtensionCbRegistered()) {
494             try {
495                 status = mUwbInjector.getUwbServiceCore().getOemExtensionCallback()
496                         .onSessionConfigurationReceived(uwbSession.getParams().toBundle());
497             } catch (RemoteException e) {
498                 Log.e(TAG, "Failed to send vendor notification", e);
499             }
500         }
501         return status;
502     }
503 
initSession(AttributionSource attributionSource, SessionHandle sessionHandle, int sessionId, byte sessionType, String protocolName, Params params, IUwbRangingCallbacks rangingCallbacks, String chipId)504     public synchronized void initSession(AttributionSource attributionSource,
505             SessionHandle sessionHandle, int sessionId, byte sessionType, String protocolName,
506             Params params, IUwbRangingCallbacks rangingCallbacks, String chipId)
507             throws RemoteException {
508         Log.i(TAG, "initSession() - sessionId: " + sessionId + ", sessionHandle: " + sessionHandle
509                 + ", sessionType: " + sessionType);
510         UwbSession uwbSession =  createUwbSession(attributionSource, sessionHandle, sessionId,
511                 sessionType, protocolName, params, rangingCallbacks, chipId);
512         // Check the attribution source chain to ensure that there are no 3p apps which are not in
513         // fg which can receive the ranging results.
514         AttributionSource nonPrivilegedAppAttrSource =
515                 uwbSession.getAnyNonPrivilegedAppInAttributionSource();
516         if (nonPrivilegedAppAttrSource != null) {
517             Log.d(TAG, "Found a 3p app/service in the attribution source of request: "
518                     + nonPrivilegedAppAttrSource);
519             // TODO(b/211445008): Move this operation to uwb thread.
520             long identity = Binder.clearCallingIdentity();
521             boolean hasNonPrivilegedFgApp = mUwbInjector.isForegroundAppOrService(
522                     nonPrivilegedAppAttrSource.getUid(),
523                     nonPrivilegedAppAttrSource.getPackageName());
524             Binder.restoreCallingIdentity(identity);
525             uwbSession.setHasNonPrivilegedFgApp(hasNonPrivilegedFgApp);
526             if (!hasNonPrivilegedFgApp) {
527                 if (!mUwbInjector.getDeviceConfigFacade().isBackgroundRangingEnabled()) {
528                     Log.e(TAG, "openRanging - System policy disallows for non fg 3p apps");
529                     rangingCallbacks.onRangingOpenFailed(sessionHandle,
530                             RangingChangeReason.SYSTEM_POLICY, new PersistableBundle());
531                     return;
532                 } else {
533                     Log.d(TAG, "openRanging - System policy allows for non fg 3p apps");
534                 }
535             }
536         }
537         if (isExistedSession(sessionHandle) || isExistedSession(sessionId)) {
538             Log.i(TAG, "Duplicated session. SessionHandle: " + sessionHandle + ", SessionId: "
539                     + sessionId);
540             rangingCallbacks.onRangingOpenFailed(sessionHandle, RangingChangeReason.BAD_PARAMETERS,
541                     UwbSessionNotificationHelper.convertUciStatusToParam(protocolName,
542                             UwbUciConstants.STATUS_CODE_ERROR_SESSION_DUPLICATE));
543             mUwbMetrics.logRangingInitEvent(uwbSession,
544                     UwbUciConstants.STATUS_CODE_ERROR_SESSION_DUPLICATE);
545             return;
546         }
547 
548         boolean maxSessionsExceeded = false;
549         // TODO: getCccSessionCount and getFiraSessionCount should be chip specific
550         if (protocolName.equals(CccParams.PROTOCOL_NAME)
551                 && getCccSessionCount() >= getMaxCccSessionsNumber(chipId)) {
552             Log.i(TAG, "Max CCC Sessions Exceeded");
553             // All CCC sessions have the same priority so there's no point in trying to make space
554             // if max sessions are already reached.
555             maxSessionsExceeded = true;
556         } else if (protocolName.equals(FiraParams.PROTOCOL_NAME)
557                 && getFiraSessionCount() >= getMaxFiraSessionsNumber(chipId)) {
558             Log.i(TAG, "Max Fira Sessions Exceeded");
559             maxSessionsExceeded = !tryMakeSpaceForFiraSession(
560                     uwbSession.getStackSessionPriority());
561         }
562         if (maxSessionsExceeded) {
563             rangingCallbacks.onRangingOpenFailed(sessionHandle,
564                     RangingChangeReason.MAX_SESSIONS_REACHED,
565                     UwbSessionNotificationHelper.convertUciStatusToParam(protocolName,
566                             UwbUciConstants.STATUS_CODE_ERROR_MAX_SESSIONS_EXCEEDED));
567             mUwbMetrics.logRangingInitEvent(uwbSession,
568                     UwbUciConstants.STATUS_CODE_ERROR_MAX_SESSIONS_EXCEEDED);
569             return;
570         }
571 
572         try {
573             uwbSession.getBinder().linkToDeath(uwbSession, 0);
574         } catch (RemoteException e) {
575             uwbSession.binderDied();
576             Log.e(TAG, "linkToDeath fail - sessionID : " + uwbSession.getSessionId());
577             rangingCallbacks.onRangingOpenFailed(sessionHandle, RangingChangeReason.UNKNOWN,
578                     UwbSessionNotificationHelper.convertUciStatusToParam(protocolName,
579                             UwbUciConstants.STATUS_CODE_FAILED));
580             mUwbMetrics.logRangingInitEvent(uwbSession,
581                     UwbUciConstants.STATUS_CODE_FAILED);
582             removeSession(uwbSession);
583             return;
584         }
585 
586         mSessionTable.put(sessionHandle, uwbSession);
587         addToNonPrivilegedUidToFiraSessionTableIfNecessary(uwbSession);
588         mEventTask.execute(SESSION_OPEN_RANGING, uwbSession);
589         return;
590     }
591 
tryMakeSpaceForFiraSession(int priorityThreshold)592     private boolean tryMakeSpaceForFiraSession(int priorityThreshold) {
593         Optional<UwbSession> lowestPrioritySession = getSessionWithLowestPriorityByProtocol(
594                 FiraParams.PROTOCOL_NAME);
595         if (!lowestPrioritySession.isPresent()) {
596             Log.w(TAG,
597                     "New session blocked by max sessions exceeded, but list of sessions is "
598                             + "empty");
599             return false;
600         }
601         if (lowestPrioritySession.get().getStackSessionPriority() < priorityThreshold) {
602             return deInitDueToLowPriority(lowestPrioritySession.get().getSessionHandle());
603         }
604         return false;
605     }
606 
607     // TODO: use UwbInjector.
608     @VisibleForTesting
createUwbSession(AttributionSource attributionSource, SessionHandle sessionHandle, int sessionId, byte sessionType, String protocolName, Params params, IUwbRangingCallbacks iUwbRangingCallbacks, String chipId)609     UwbSession createUwbSession(AttributionSource attributionSource, SessionHandle sessionHandle,
610             int sessionId, byte sessionType, String protocolName, Params params,
611             IUwbRangingCallbacks iUwbRangingCallbacks, String chipId) {
612         return new UwbSession(attributionSource, sessionHandle, sessionId, sessionType,
613                 protocolName, params, iUwbRangingCallbacks, chipId);
614     }
615 
deInitSession(SessionHandle sessionHandle)616     public synchronized void deInitSession(SessionHandle sessionHandle) {
617         if (!isExistedSession(sessionHandle)) {
618             Log.i(TAG, "Not initialized session ID");
619             return;
620         }
621 
622         int sessionId = getSessionId(sessionHandle);
623         Log.i(TAG, "deinitSession() - sessionId: " + sessionId
624                 + ", sessionHandle: " + sessionHandle);
625         UwbSession uwbSession = getUwbSession(sessionId);
626         mEventTask.execute(SESSION_DEINIT, uwbSession, STATUS_CODE_OK);
627         return;
628     }
629 
630     /**
631      * Logs and executes session de-init task with low priority being sent as the reason in
632      * ranging closed callback.
633      */
deInitDueToLowPriority(SessionHandle sessionHandle)634     private synchronized boolean deInitDueToLowPriority(SessionHandle sessionHandle) {
635         int sessionId = getSessionId(sessionHandle);
636         if (!isExistedSession(sessionHandle)) {
637             Log.w(TAG, "Session " + sessionId + " expected to exist but not found. "
638                     + "Failed to de-initialize low priority session.");
639             return false;
640         }
641 
642         Log.i(TAG, "deInitDueToLowPriority() - sessionId: " + sessionId
643                 + ", sessionHandle: " + sessionHandle);
644         UwbSession uwbSession = getUwbSession(sessionId);
645         mEventTask.execute(SESSION_DEINIT, uwbSession,
646                 UwbUciConstants.STATUS_CODE_ERROR_MAX_SESSIONS_EXCEEDED);
647         return true;
648     }
649 
startRanging(SessionHandle sessionHandle, @Nullable Params params)650     public synchronized void startRanging(SessionHandle sessionHandle, @Nullable Params params) {
651         if (!isExistedSession(sessionHandle)) {
652             Log.i(TAG, "Not initialized session ID");
653             return;
654         }
655 
656         int sessionId = getSessionId(sessionHandle);
657         Log.i(TAG, "startRanging() - sessionId: " + sessionId
658                 + ", sessionHandle: " + sessionHandle);
659 
660         UwbSession uwbSession = getUwbSession(sessionId);
661 
662         int currentSessionState = getCurrentSessionState(sessionId);
663         if (currentSessionState == UwbUciConstants.UWB_SESSION_STATE_IDLE) {
664             if (uwbSession.getProtocolName().equals(CccParams.PROTOCOL_NAME)
665                     && params instanceof CccStartRangingParams) {
666                 CccStartRangingParams rangingStartParams = (CccStartRangingParams) params;
667                 Log.i(TAG, "startRanging() - update RAN multiplier: "
668                         + rangingStartParams.getRanMultiplier());
669                 // Need to update the RAN multiplier from the CccStartRangingParams for CCC session.
670                 uwbSession.updateCccParamsOnStart(rangingStartParams);
671             }
672             if (uwbSession.getProtocolName().equals(FiraParams.PROTOCOL_NAME)) {
673                 // Need to update session priority if it changed.
674                 uwbSession.updateFiraParamsOnStartIfChanged();
675             }
676             mEventTask.execute(SESSION_START_RANGING, uwbSession);
677         } else if (currentSessionState == UwbUciConstants.UWB_SESSION_STATE_ACTIVE) {
678             Log.i(TAG, "session is already ranging");
679             mSessionNotificationManager.onRangingStartFailed(
680                     uwbSession, UwbUciConstants.STATUS_CODE_REJECTED);
681         } else {
682             Log.i(TAG, "session can't start ranging");
683             mSessionNotificationManager.onRangingStartFailed(
684                     uwbSession, UwbUciConstants.STATUS_CODE_FAILED);
685             mUwbMetrics.longRangingStartEvent(uwbSession, UwbUciConstants.STATUS_CODE_FAILED);
686         }
687     }
688 
stopRangingInternal(SessionHandle sessionHandle, boolean triggeredBySystemPolicy)689     private synchronized void stopRangingInternal(SessionHandle sessionHandle,
690             boolean triggeredBySystemPolicy) {
691         if (!isExistedSession(sessionHandle)) {
692             Log.i(TAG, "Not initialized session ID");
693             return;
694         }
695 
696         int sessionId = getSessionId(sessionHandle);
697         Log.i(TAG, "stopRanging() - sessionId: " + sessionId
698                 + ", sessionHandle: " + sessionHandle);
699 
700         UwbSession uwbSession = getUwbSession(sessionId);
701         int currentSessionState = getCurrentSessionState(sessionId);
702         if (currentSessionState == UwbUciConstants.UWB_SESSION_STATE_ACTIVE) {
703             mEventTask.execute(SESSION_STOP_RANGING, uwbSession, triggeredBySystemPolicy ? 1 : 0);
704         } else if (currentSessionState == UwbUciConstants.UWB_SESSION_STATE_IDLE) {
705             Log.i(TAG, "session is already idle state");
706             mSessionNotificationManager.onRangingStopped(uwbSession,
707                     UwbUciConstants.STATUS_CODE_OK);
708             mUwbMetrics.longRangingStopEvent(uwbSession);
709         } else {
710             mSessionNotificationManager.onRangingStopFailed(uwbSession,
711                     UwbUciConstants.STATUS_CODE_REJECTED);
712             Log.i(TAG, "Not active session ID");
713         }
714     }
715 
stopRanging(SessionHandle sessionHandle)716     public synchronized void stopRanging(SessionHandle sessionHandle) {
717         stopRangingInternal(sessionHandle, false /* triggeredBySystemPolicy */);
718     }
719 
720     /**
721      * Get the UwbSession corresponding to the given UWB Session ID. This API returns {@code null}
722      * when the UWB session is not found.
723      */
724     @Nullable
getUwbSession(int sessionId)725     public UwbSession getUwbSession(int sessionId) {
726         return mSessionTable.values()
727                 .stream()
728                 .filter(v -> v.getSessionId() == sessionId)
729                 .findAny()
730                 .orElse(null);
731     }
732 
733     /**
734      * Get the Uwb Session ID corresponding to the given UWB Session Handle. This API returns
735      * {@code null} when the UWB session ID is not found.
736      */
737     @Nullable
getSessionId(SessionHandle sessionHandle)738     public Integer getSessionId(SessionHandle sessionHandle) {
739         UwbSession session = mSessionTable.get(sessionHandle);
740         if (session == null) return null;
741         return session.getSessionId();
742     }
743 
getActiveSessionCount()744     private int getActiveSessionCount() {
745         return Math.toIntExact(
746                 mSessionTable.values()
747                         .stream()
748                         .filter(v -> v.getSessionState() == UwbUciConstants.DEVICE_STATE_ACTIVE)
749                         .count()
750         );
751     }
752 
processRangeData(UwbRangingData rangingData, UwbSession uwbSession)753     private void processRangeData(UwbRangingData rangingData, UwbSession uwbSession) {
754         if (rangingData.getRangingMeasuresType()
755                 != UwbUciConstants.RANGING_MEASUREMENT_TYPE_OWR_AOA) {
756             return;
757         }
758 
759         if (!isValidUwbSessionForOwrAoaRanging(uwbSession)) {
760             return;
761         }
762 
763         // Record the OWR Aoa Measurement from the RANGE_DATA_NTF.
764         UwbOwrAoaMeasurement uwbOwrAoaMeasurement = rangingData.getRangingOwrAoaMeasure();
765         mAdvertiseManager.updateAdvertiseTarget(uwbOwrAoaMeasurement);
766 
767         byte[] macAddressBytes = getValidMacAddressFromOwrAoaMeasurement(
768                 rangingData, uwbOwrAoaMeasurement);
769         if (macAddressBytes == null)  {
770             Log.i(TAG, "OwR Aoa UwbSession: Invalid MacAddress for remote device");
771             return;
772         }
773 
774         boolean advertisePointingResult = mAdvertiseManager.isPointedTarget(macAddressBytes);
775         if (mUwbInjector.getUwbServiceCore().isOemExtensionCbRegistered()) {
776             try {
777                 PersistableBundle pointedTargetBundle = new AdvertisePointedTarget.Builder()
778                         .setMacAddress(macAddressBytes)
779                         .setAdvertisePointingResult(advertisePointingResult)
780                         .build()
781                         .toBundle();
782 
783                 advertisePointingResult = mUwbInjector
784                         .getUwbServiceCore()
785                         .getOemExtensionCallback()
786                         .onCheckPointedTarget(pointedTargetBundle);
787             } catch (RemoteException e) {
788                 e.printStackTrace();
789             }
790         }
791 
792         if (advertisePointingResult) {
793             // Use a loop to notify all the received application data payload(s) (in sequence number
794             // order) for this OWR AOA ranging session.
795             long macAddress = macAddressByteArrayToLong(macAddressBytes);
796             UwbAddress uwbAddress = UwbAddress.fromBytes(macAddressBytes);
797 
798             List<ReceivedDataInfo> receivedDataInfoList = uwbSession.getAllReceivedDataInfo(
799                     macAddress);
800             if (receivedDataInfoList.isEmpty()) {
801                 Log.i(TAG, "OwR Aoa UwbSession: Application Payload data not found for"
802                         + " MacAddress = " + UwbUtil.toHexString(macAddress));
803                 return;
804             }
805 
806             receivedDataInfoList.stream().forEach(r ->
807                     mSessionNotificationManager.onDataReceived(
808                             uwbSession, uwbAddress, new PersistableBundle(), r.payload));
809             mUwbMetrics.logDataToUpperLayer(uwbSession, receivedDataInfoList.size());
810             mAdvertiseManager.removeAdvertiseTarget(macAddress);
811         }
812     }
813 
814     @Nullable
getValidMacAddressFromOwrAoaMeasurement(UwbRangingData rangingData, UwbOwrAoaMeasurement uwbOwrAoaMeasurement)815     private byte[] getValidMacAddressFromOwrAoaMeasurement(UwbRangingData rangingData,
816             UwbOwrAoaMeasurement uwbOwrAoaMeasurement) {
817         byte[] macAddress = uwbOwrAoaMeasurement.getMacAddress();
818         if (rangingData.getMacAddressMode() == MAC_ADDRESSING_MODE_SHORT) {
819             return (macAddress.length == UWB_DEVICE_SHORT_MAC_ADDRESS_LEN) ? macAddress : null;
820         } else if (rangingData.getMacAddressMode() == MAC_ADDRESSING_MODE_EXTENDED) {
821             return (macAddress.length == UWB_DEVICE_EXT_MAC_ADDRESS_LEN) ? macAddress : null;
822         }
823         return null;
824     }
825 
isExistedSession(SessionHandle sessionHandle)826     public boolean isExistedSession(SessionHandle sessionHandle) {
827         return (getSessionId(sessionHandle) != null);
828     }
829 
isExistedSession(int sessionId)830     public boolean isExistedSession(int sessionId) {
831         return getUwbSession(sessionId) != null;
832     }
833 
stopAllRanging()834     public void stopAllRanging() {
835         Log.d(TAG, "stopAllRanging()");
836         for (UwbSession uwbSession : mSessionTable.values()) {
837             int status = mNativeUwbManager.stopRanging(uwbSession.getSessionId(),
838                     uwbSession.getChipId());
839 
840             if (status != UwbUciConstants.STATUS_CODE_OK) {
841                 Log.i(TAG, "stopAllRanging() - Session " + uwbSession.getSessionId()
842                         + " is failed to stop ranging");
843             } else {
844                 mUwbMetrics.longRangingStopEvent(uwbSession);
845                 uwbSession.setSessionState(UwbUciConstants.UWB_SESSION_STATE_IDLE);
846             }
847         }
848     }
849 
deinitAllSession()850     public synchronized void deinitAllSession() {
851         Log.d(TAG, "deinitAllSession()");
852         for (UwbSession uwbSession : mSessionTable.values()) {
853             handleOnDeInit(uwbSession);
854         }
855 
856         // Not resetting chip on UWB toggle off.
857         // mNativeUwbManager.deviceReset(UwbUciConstants.UWBS_RESET);
858     }
859 
handleOnDeInit(UwbSession uwbSession)860     public synchronized void handleOnDeInit(UwbSession uwbSession) {
861         if (!isExistedSession(uwbSession.getSessionHandle())) {
862             Log.i(TAG, "onDeinit - Ignoring already deleted session "
863                     + uwbSession.getSessionId());
864             return;
865         }
866         Log.d(TAG, "onDeinit: " + uwbSession.getSessionId());
867         mSessionNotificationManager.onRangingClosedWithApiReasonCode(uwbSession,
868                 RangingChangeReason.SYSTEM_POLICY);
869         mUwbMetrics.logRangingCloseEvent(uwbSession, UwbUciConstants.STATUS_CODE_OK);
870 
871         // Reset all UWB session timers when the session is de-init.
872         uwbSession.stopTimers();
873         removeSession(uwbSession);
874     }
875 
setCurrentSessionState(int sessionId, int state)876     public void setCurrentSessionState(int sessionId, int state) {
877         UwbSession uwbSession = getUwbSession(sessionId);
878         if (uwbSession != null) {
879             uwbSession.setSessionState(state);
880         }
881     }
882 
getCurrentSessionState(int sessionId)883     public int getCurrentSessionState(int sessionId) {
884         UwbSession uwbSession = getUwbSession(sessionId);
885         if (uwbSession != null) {
886             return uwbSession.getSessionState();
887         }
888         return UwbUciConstants.UWB_SESSION_STATE_ERROR;
889     }
890 
getSessionCount()891     public int getSessionCount() {
892         return mSessionTable.size();
893     }
894 
getCccSessionCount()895     public long getCccSessionCount() {
896         return mSessionTable.values().stream().filter(
897                 s -> s.mProtocolName.equals(CccParams.PROTOCOL_NAME)).count();
898     }
899 
getFiraSessionCount()900     public long getFiraSessionCount() {
901         return mSessionTable.values().stream().filter(
902                 s -> s.mProtocolName.equals(FiraParams.PROTOCOL_NAME)).count();
903     }
904 
905     /** Returns max number of CCC sessions possible on given chip  */
getMaxCccSessionsNumber(String chipId)906     public long getMaxCccSessionsNumber(String chipId) {
907         GenericSpecificationParams params =
908                 mUwbInjector.getUwbServiceCore().getCachedSpecificationParams(chipId);
909         if (params != null && params.getCccSpecificationParams() != null) {
910             return params.getCccSpecificationParams().getMaxRangingSessionNumber();
911         } else {
912             // specification params are empty, return the default CCC max sessions value
913             return CccSpecificationParams.DEFAULT_MAX_RANGING_SESSIONS_NUMBER;
914         }
915     }
916 
917     /** Returns max number of Fira sessions possible on given chip  */
getMaxFiraSessionsNumber(String chipId)918     public long getMaxFiraSessionsNumber(String chipId) {
919         GenericSpecificationParams params =
920                 mUwbInjector.getUwbServiceCore().getCachedSpecificationParams(chipId);
921         if (params != null && params.getFiraSpecificationParams() != null) {
922             return params.getFiraSpecificationParams().getMaxRangingSessionNumber();
923         } else {
924             // specification params are empty, return the default Fira max sessions value
925             return FiraSpecificationParams.DEFAULT_MAX_RANGING_SESSIONS_NUMBER;
926         }
927     }
928 
929     /** Gets the session with the lowest session priority among all sessions with given protocol. */
getSessionWithLowestPriorityByProtocol(String protocolName)930     public Optional<UwbSession> getSessionWithLowestPriorityByProtocol(String protocolName) {
931         return mSessionTable.values().stream().filter(
932                 s -> s.mProtocolName.equals(protocolName)).min(
933                 Comparator.comparingInt(UwbSession::getStackSessionPriority));
934     }
935 
getSessionIdSet()936     public Set<Integer> getSessionIdSet() {
937         return mSessionTable.values()
938                 .stream()
939                 .map(v -> v.getSessionId())
940                 .collect(Collectors.toSet());
941     }
942 
reconfigureInternal(SessionHandle sessionHandle, @Nullable Params params, boolean triggeredByFgStateChange)943     private synchronized int reconfigureInternal(SessionHandle sessionHandle,
944             @Nullable Params params, boolean triggeredByFgStateChange) {
945         int status = UwbUciConstants.STATUS_CODE_ERROR_SESSION_NOT_EXIST;
946         if (!isExistedSession(sessionHandle)) {
947             Log.i(TAG, "Not initialized session ID");
948             return status;
949         }
950         int sessionId = getSessionId(sessionHandle);
951         Log.i(TAG, "reconfigure() - Session ID : " + sessionId);
952         UwbSession uwbSession = getUwbSession(sessionId);
953         if (uwbSession.getProtocolName().equals(FiraParams.PROTOCOL_NAME)
954                 && params instanceof FiraRangingReconfigureParams) {
955             FiraRangingReconfigureParams rangingReconfigureParams =
956                     (FiraRangingReconfigureParams) params;
957             Log.i(TAG, "reconfigure() - update reconfigure params: "
958                     + rangingReconfigureParams);
959             // Do not update mParams if this was triggered by framework.
960             if (!triggeredByFgStateChange) {
961                 uwbSession.updateFiraParamsOnReconfigure(rangingReconfigureParams);
962             }
963         }
964         mEventTask.execute(SESSION_RECONFIG_RANGING,
965                 new ReconfigureEventParams(uwbSession, params, triggeredByFgStateChange));
966         return 0;
967     }
968 
reconfigure(SessionHandle sessionHandle, @Nullable Params params)969     public synchronized int reconfigure(SessionHandle sessionHandle, @Nullable Params params) {
970         return reconfigureInternal(sessionHandle, params, false /* triggeredByFgStateChange */);
971     }
972 
973     /** Send the payload data to a remote device in the UWB session */
sendData(SessionHandle sessionHandle, UwbAddress remoteDeviceAddress, PersistableBundle params, byte[] data)974     public synchronized void sendData(SessionHandle sessionHandle, UwbAddress remoteDeviceAddress,
975             PersistableBundle params, byte[] data) {
976         SendDataInfo info = new SendDataInfo();
977         info.sessionHandle = sessionHandle;
978         info.remoteDeviceAddress = remoteDeviceAddress;
979         info.params = params;
980         info.data = data;
981 
982         mEventTask.execute(SESSION_SEND_DATA, info);
983     }
984 
985     private static final class SendDataInfo {
986         public SessionHandle sessionHandle;
987         public UwbAddress remoteDeviceAddress;
988         public PersistableBundle params;
989         public byte[] data;
990     }
991 
992     private static final class RangingRoundsUpdateDtTagInfo {
993         public SessionHandle sessionHandle;
994         public PersistableBundle params;
995     }
996 
997     /** DT Tag ranging round update */
rangingRoundsUpdateDtTag(SessionHandle sessionHandle, PersistableBundle bundle)998     public void rangingRoundsUpdateDtTag(SessionHandle sessionHandle,
999             PersistableBundle bundle) {
1000         RangingRoundsUpdateDtTagInfo info = new RangingRoundsUpdateDtTagInfo();
1001         info.sessionHandle = sessionHandle;
1002         info.params = bundle;
1003 
1004         mEventTask.execute(SESSION_UPDATE_DT_TAG_RANGING_ROUNDS, info);
1005     }
1006 
1007     /** Query Max Application data size for the given UWB Session */
queryMaxDataSizeBytes(SessionHandle sessionHandle)1008     public synchronized int queryMaxDataSizeBytes(SessionHandle sessionHandle) {
1009         if (!isExistedSession(sessionHandle)) {
1010             throw new IllegalStateException("Not initialized session ID");
1011         }
1012 
1013         int sessionId = getSessionId(sessionHandle);
1014         UwbSession uwbSession = getUwbSession(sessionId);
1015         if (uwbSession == null) {
1016             throw new IllegalStateException("UwbSession not found");
1017         }
1018 
1019         synchronized (uwbSession.getWaitObj()) {
1020             return mNativeUwbManager.queryMaxDataSizeBytes(uwbSession.getSessionId(),
1021                     uwbSession.getChipId());
1022         }
1023     }
1024 
1025     /** Handle ranging rounds update for DT Tag */
handleRangingRoundsUpdateDtTag(RangingRoundsUpdateDtTagInfo info)1026     public void handleRangingRoundsUpdateDtTag(RangingRoundsUpdateDtTagInfo info) {
1027         SessionHandle sessionHandle = info.sessionHandle;
1028         Integer sessionId = getSessionId(sessionHandle);
1029         if (sessionId == null) {
1030             Log.i(TAG, "UwbSessionId not found");
1031             return;
1032         }
1033         UwbSession uwbSession = getUwbSession(sessionId);
1034         if (uwbSession == null) {
1035             Log.i(TAG, "UwbSession not found");
1036             return;
1037         }
1038         DlTDoARangingRoundsUpdate dlTDoARangingRoundsUpdate = DlTDoARangingRoundsUpdate
1039                 .fromBundle(info.params);
1040 
1041         if (dlTDoARangingRoundsUpdate.getSessionId() != getSessionId(sessionHandle)) {
1042             throw new IllegalArgumentException("Wrong session ID");
1043         }
1044 
1045         FutureTask<DtTagUpdateRangingRoundsStatus> rangingRoundsUpdateTask = new FutureTask<>(
1046                 () -> {
1047                     synchronized (uwbSession.getWaitObj()) {
1048                         return mNativeUwbManager.sessionUpdateDtTagRangingRounds(
1049                                 (int) dlTDoARangingRoundsUpdate.getSessionId(),
1050                                 dlTDoARangingRoundsUpdate.getNoOfRangingRounds(),
1051                                 dlTDoARangingRoundsUpdate.getRangingRoundIndexes(),
1052                                 uwbSession.getChipId());
1053                     }
1054                 }
1055         );
1056 
1057         DtTagUpdateRangingRoundsStatus status = null;
1058         ExecutorService executor = Executors.newSingleThreadExecutor();
1059         executor.submit(rangingRoundsUpdateTask);
1060         try {
1061             status = rangingRoundsUpdateTask.get(IUwbAdapter
1062                     .RANGING_ROUNDS_UPDATE_DT_TAG_THRESHOLD_MS, TimeUnit.MILLISECONDS);
1063         } catch (TimeoutException e) {
1064             Log.i(TAG, "Failed to update ranging rounds for Dt tag - status : TIMEOUT");
1065             executor.shutdownNow();
1066         } catch (InterruptedException | ExecutionException e) {
1067             e.printStackTrace();
1068         }
1069         // Native stack returns null if unsuccessful
1070         if (status == null) {
1071             status = new DtTagUpdateRangingRoundsStatus(
1072                     UwbUciConstants.STATUS_CODE_ERROR_ROUND_INDEX_NOT_ACTIVATED,
1073                     0,
1074                     new byte[]{});
1075         }
1076         PersistableBundle params = new DlTDoARangingRoundsUpdateStatus.Builder()
1077                 .setStatus(status.getStatus())
1078                 .setNoOfRangingRounds(status.getNoOfRangingRounds())
1079                 .setRangingRoundIndexes(status.getRangingRoundIndexes())
1080                 .build()
1081                 .toBundle();
1082         mSessionNotificationManager.onRangingRoundsUpdateStatus(uwbSession, params);
1083     }
1084 
removeSession(UwbSession uwbSession)1085     void removeSession(UwbSession uwbSession) {
1086         if (uwbSession != null) {
1087             uwbSession.getBinder().unlinkToDeath(uwbSession, 0);
1088             removeAdvertiserData(uwbSession);
1089             uwbSession.close();
1090             removeFromNonPrivilegedUidToFiraSessionTableIfNecessary(uwbSession);
1091             mSessionTokenMap.remove(uwbSession.getSessionId());
1092             mSessionTable.remove(uwbSession.getSessionHandle());
1093             mDbgRecentlyClosedSessions.add(uwbSession);
1094         }
1095     }
1096 
removeAdvertiserData(UwbSession uwbSession)1097     private void removeAdvertiserData(UwbSession uwbSession) {
1098         for (long remoteMacAddress : uwbSession.getRemoteMacAddressList()) {
1099             mAdvertiseManager.removeAdvertiseTarget(remoteMacAddress);
1100         }
1101     }
1102 
addToNonPrivilegedUidToFiraSessionTableIfNecessary(@onNull UwbSession uwbSession)1103     void addToNonPrivilegedUidToFiraSessionTableIfNecessary(@NonNull UwbSession uwbSession) {
1104         if (uwbSession.getSessionType() == UwbUciConstants.SESSION_TYPE_RANGING) {
1105             AttributionSource nonPrivilegedAppAttrSource =
1106                     uwbSession.getAnyNonPrivilegedAppInAttributionSource();
1107             if (nonPrivilegedAppAttrSource != null) {
1108                 Log.d(TAG, "Detected start of non privileged FIRA session from "
1109                         + nonPrivilegedAppAttrSource);
1110                 List<UwbSession> sessions = mNonPrivilegedUidToFiraSessionsTable.computeIfAbsent(
1111                         nonPrivilegedAppAttrSource.getUid(), v -> new ArrayList<>());
1112                 sessions.add(uwbSession);
1113             }
1114         }
1115     }
1116 
removeFromNonPrivilegedUidToFiraSessionTableIfNecessary(@onNull UwbSession uwbSession)1117     void removeFromNonPrivilegedUidToFiraSessionTableIfNecessary(@NonNull UwbSession uwbSession) {
1118         if (uwbSession.getSessionType() == UwbUciConstants.SESSION_TYPE_RANGING) {
1119             AttributionSource nonPrivilegedAppAttrSource =
1120                     uwbSession.getAnyNonPrivilegedAppInAttributionSource();
1121             if (nonPrivilegedAppAttrSource != null) {
1122                 Log.d(TAG, "Detected end of non privileged FIRA session from "
1123                         + nonPrivilegedAppAttrSource);
1124                 List<UwbSession> sessions = mNonPrivilegedUidToFiraSessionsTable.get(
1125                         nonPrivilegedAppAttrSource.getUid());
1126                 if (sessions == null) {
1127                     Log.wtf(TAG, "No sessions found for uid: "
1128                             + nonPrivilegedAppAttrSource.getUid());
1129                     return;
1130                 }
1131                 sessions.remove(uwbSession);
1132                 if (sessions.isEmpty()) {
1133                     mNonPrivilegedUidToFiraSessionsTable.remove(
1134                             nonPrivilegedAppAttrSource.getUid());
1135                 }
1136             }
1137         }
1138     }
1139 
1140     private static class ReconfigureEventParams {
1141         public final UwbSession uwbSession;
1142         public final Params params;
1143         public final boolean triggeredByFgStateChange;
1144 
ReconfigureEventParams(UwbSession uwbSession, Params params, boolean triggeredByFgStateChange)1145         ReconfigureEventParams(UwbSession uwbSession, Params params,
1146                 boolean triggeredByFgStateChange) {
1147             this.uwbSession = uwbSession;
1148             this.params = params;
1149             this.triggeredByFgStateChange = triggeredByFgStateChange;
1150         }
1151     }
1152 
1153     private class EventTask extends Handler {
1154 
EventTask(Looper looper)1155         EventTask(Looper looper) {
1156             super(looper);
1157         }
1158 
1159         @Override
handleMessage(Message msg)1160         public void handleMessage(Message msg) {
1161             int type = msg.what;
1162             switch (type) {
1163                 case SESSION_OPEN_RANGING: {
1164                     UwbSession uwbSession = (UwbSession) msg.obj;
1165                     handleOpenRanging(uwbSession);
1166                     break;
1167                 }
1168 
1169                 case SESSION_START_RANGING: {
1170                     UwbSession uwbSession = (UwbSession) msg.obj;
1171                     handleStartRanging(uwbSession);
1172                     break;
1173                 }
1174 
1175                 case SESSION_STOP_RANGING: {
1176                     UwbSession uwbSession = (UwbSession) msg.obj;
1177                     boolean triggeredBySystemPolicy = msg.arg1 == 1;
1178                     handleStopRanging(uwbSession, triggeredBySystemPolicy);
1179                     break;
1180                 }
1181 
1182                 case SESSION_RECONFIG_RANGING: {
1183                     Log.d(TAG, "SESSION_RECONFIG_RANGING");
1184                     ReconfigureEventParams params = (ReconfigureEventParams) msg.obj;
1185                     handleReconfigure(
1186                             params.uwbSession, params.params, params.triggeredByFgStateChange);
1187                     break;
1188                 }
1189 
1190                 case SESSION_DEINIT: {
1191                     UwbSession uwbSession = (UwbSession) msg.obj;
1192                     int reason = msg.arg1;
1193                     handleDeInitWithReason(uwbSession, reason);
1194                     break;
1195                 }
1196 
1197                 case SESSION_ON_DEINIT: {
1198                     UwbSession uwbSession = (UwbSession) msg.obj;
1199                     handleOnDeInit(uwbSession);
1200                     break;
1201                 }
1202 
1203                 case SESSION_SEND_DATA: {
1204                     Log.d(TAG, "SESSION_SEND_DATA");
1205                     SendDataInfo info = (SendDataInfo) msg.obj;
1206                     handleSendData(info);
1207                     break;
1208                 }
1209 
1210                 case SESSION_UPDATE_DT_TAG_RANGING_ROUNDS: {
1211                     Log.d(TAG, "SESSION_UPDATE_DT_TAG_RANGING_ROUNDS");
1212                     RangingRoundsUpdateDtTagInfo info = (RangingRoundsUpdateDtTagInfo) msg.obj;
1213                     handleRangingRoundsUpdateDtTag(info);
1214                     break;
1215                 }
1216 
1217                 default: {
1218                     Log.d(TAG, "EventTask : Undefined Task");
1219                     break;
1220                 }
1221             }
1222         }
1223 
execute(int task, Object obj)1224         public void execute(int task, Object obj) {
1225             Message msg = mEventTask.obtainMessage();
1226             msg.what = task;
1227             msg.obj = obj;
1228             this.sendMessage(msg);
1229         }
1230 
execute(int task, Object obj, int arg1)1231         public void execute(int task, Object obj, int arg1) {
1232             Message msg = mEventTask.obtainMessage();
1233             msg.what = task;
1234             msg.obj = obj;
1235             msg.arg1 = arg1;
1236             this.sendMessage(msg);
1237         }
1238 
handleOpenRanging(UwbSession uwbSession)1239         private void handleOpenRanging(UwbSession uwbSession) {
1240             Trace.beginSection("UWB#handleOpenRanging");
1241             // TODO(b/211445008): Consolidate to a single uwb thread.
1242             FutureTask<Integer> initSessionTask = new FutureTask<>(
1243                     () -> {
1244                         int status = UwbUciConstants.STATUS_CODE_FAILED;
1245                         synchronized (uwbSession.getWaitObj()) {
1246                             uwbSession.setOperationType(OPERATION_TYPE_INIT_SESSION);
1247                             status = mNativeUwbManager.initSession(
1248                                     uwbSession.getSessionId(),
1249                                     uwbSession.getSessionType(),
1250                                     uwbSession.getChipId());
1251                             if (status != UwbUciConstants.STATUS_CODE_OK) {
1252                                 return status;
1253                             }
1254                             mSessionTokenMap.put(uwbSession.getSessionId(), mNativeUwbManager
1255                                     .getSessionToken(uwbSession.getSessionId(),
1256                                             uwbSession.getChipId()));
1257                             uwbSession.getWaitObj().blockingWait();
1258                             status = UwbUciConstants.STATUS_CODE_FAILED;
1259                             if (uwbSession.getSessionState()
1260                                     == UwbUciConstants.UWB_SESSION_STATE_INIT) {
1261                                 status = UwbSessionManager.this.setAppConfigurations(uwbSession);
1262                                 if (status != UwbUciConstants.STATUS_CODE_OK) {
1263                                     return status;
1264                                 }
1265 
1266                                 uwbSession.getWaitObj().blockingWait();
1267                                 status = UwbUciConstants.STATUS_CODE_FAILED;
1268                                 if (uwbSession.getSessionState()
1269                                         == UwbUciConstants.UWB_SESSION_STATE_IDLE) {
1270                                     mSessionNotificationManager.onRangingOpened(uwbSession);
1271                                     status = UwbUciConstants.STATUS_CODE_OK;
1272                                 } else {
1273                                     status = UwbUciConstants.STATUS_CODE_FAILED;
1274                                 }
1275                                 return status;
1276                             }
1277                             return status;
1278                         }
1279                     });
1280 
1281             int status = UwbUciConstants.STATUS_CODE_FAILED;
1282             try {
1283                 status = mUwbInjector.runTaskOnSingleThreadExecutor(initSessionTask,
1284                         IUwbAdapter.RANGING_SESSION_OPEN_THRESHOLD_MS);
1285             } catch (TimeoutException e) {
1286                 Log.i(TAG, "Failed to initialize session - status : TIMEOUT");
1287             } catch (InterruptedException e) {
1288                 e.printStackTrace();
1289             } catch (ExecutionException e) {
1290                 e.printStackTrace();
1291             }
1292 
1293             mUwbMetrics.logRangingInitEvent(uwbSession, status);
1294             if (status != UwbUciConstants.STATUS_CODE_OK) {
1295                 Log.i(TAG, "Failed to initialize session - status : " + status);
1296                 mSessionNotificationManager.onRangingOpenFailed(uwbSession, status);
1297                 uwbSession.setOperationType(SESSION_ON_DEINIT);
1298                 mNativeUwbManager.deInitSession(uwbSession.getSessionId(), uwbSession.getChipId());
1299                 removeSession(uwbSession);
1300             }
1301             Log.i(TAG, "sessionInit() : finish - sessionId : " + uwbSession.getSessionId());
1302             Trace.endSection();
1303         }
1304 
handleStartRanging(UwbSession uwbSession)1305         private void handleStartRanging(UwbSession uwbSession) {
1306             Trace.beginSection("UWB#handleStartRanging");
1307             // TODO(b/211445008): Consolidate to a single uwb thread.
1308             FutureTask<Integer> startRangingTask = new FutureTask<>(
1309                     () -> {
1310                         int status = UwbUciConstants.STATUS_CODE_FAILED;
1311                         synchronized (uwbSession.getWaitObj()) {
1312                             if (uwbSession.getNeedsAppConfigUpdate()) {
1313                                 uwbSession.resetNeedsAppConfigUpdate();
1314                                 status = mConfigurationManager.setAppConfigurations(
1315                                         uwbSession.getSessionId(),
1316                                         uwbSession.getParams(), uwbSession.getChipId());
1317                                 if (status != UwbUciConstants.STATUS_CODE_OK) {
1318                                     mSessionNotificationManager.onRangingStartFailed(
1319                                             uwbSession, status);
1320                                     return status;
1321                                 }
1322                             }
1323 
1324                             uwbSession.setOperationType(SESSION_START_RANGING);
1325                             status = mNativeUwbManager.startRanging(uwbSession.getSessionId(),
1326                                     uwbSession.getChipId());
1327                             if (status != UwbUciConstants.STATUS_CODE_OK) {
1328                                 mSessionNotificationManager.onRangingStartFailed(
1329                                         uwbSession, status);
1330                                 return status;
1331                             }
1332                             uwbSession.getWaitObj().blockingWait();
1333                             if (uwbSession.getSessionState()
1334                                     == UwbUciConstants.UWB_SESSION_STATE_ACTIVE) {
1335                                 // TODO: Ensure |rangingStartedParams| is valid for FIRA sessions
1336                                 // as well.
1337                                 Params rangingStartedParams = uwbSession.getParams();
1338                                 // For CCC sessions, retrieve the app configs
1339                                 if (uwbSession.getProtocolName().equals(CccParams.PROTOCOL_NAME)) {
1340                                     Pair<Integer, CccRangingStartedParams> statusAndParams  =
1341                                             mConfigurationManager.getAppConfigurations(
1342                                                     uwbSession.getSessionId(),
1343                                                     CccParams.PROTOCOL_NAME,
1344                                                     new byte[0],
1345                                                     CccRangingStartedParams.class,
1346                                                     uwbSession.getChipId());
1347                                     if (statusAndParams.first != UwbUciConstants.STATUS_CODE_OK) {
1348                                         Log.e(TAG, "Failed to get CCC ranging started params");
1349                                     }
1350                                     rangingStartedParams = statusAndParams.second;
1351                                 }
1352                                 mSessionNotificationManager.onRangingStarted(
1353                                         uwbSession, rangingStartedParams);
1354                             } else {
1355                                 status = UwbUciConstants.STATUS_CODE_FAILED;
1356                                 mSessionNotificationManager.onRangingStartFailed(uwbSession,
1357                                         status);
1358                             }
1359                         }
1360                         return status;
1361                     });
1362             int status = UwbUciConstants.STATUS_CODE_FAILED;
1363             try {
1364                 status = mUwbInjector.runTaskOnSingleThreadExecutor(startRangingTask,
1365                         IUwbAdapter.RANGING_SESSION_START_THRESHOLD_MS);
1366             } catch (TimeoutException e) {
1367                 Log.i(TAG, "Failed to Start Ranging - status : TIMEOUT");
1368                 mSessionNotificationManager.onRangingStartFailed(
1369                         uwbSession, UwbUciConstants.STATUS_CODE_FAILED);
1370             } catch (InterruptedException e) {
1371                 e.printStackTrace();
1372             } catch (ExecutionException e) {
1373                 e.printStackTrace();
1374             }
1375             mUwbMetrics.longRangingStartEvent(uwbSession, status);
1376             Trace.endSection();
1377         }
1378 
handleStopRanging(UwbSession uwbSession, boolean triggeredBySystemPolicy)1379         private void handleStopRanging(UwbSession uwbSession, boolean triggeredBySystemPolicy) {
1380             Trace.beginSection("UWB#handleStopRanging");
1381             // TODO(b/211445008): Consolidate to a single uwb thread.
1382             FutureTask<Integer> stopRangingTask = new FutureTask<>(
1383                     () -> {
1384                         int status = UwbUciConstants.STATUS_CODE_FAILED;
1385                         synchronized (uwbSession.getWaitObj()) {
1386                             uwbSession.setOperationType(SESSION_STOP_RANGING);
1387                             status = mNativeUwbManager.stopRanging(uwbSession.getSessionId(),
1388                                     uwbSession.getChipId());
1389                             if (status != UwbUciConstants.STATUS_CODE_OK) {
1390                                 mSessionNotificationManager.onRangingStopFailed(uwbSession, status);
1391                                 return status;
1392                             }
1393                             uwbSession.getWaitObj().blockingWait();
1394                             if (uwbSession.getSessionState()
1395                                     == UwbUciConstants.UWB_SESSION_STATE_IDLE) {
1396                                 int apiReasonCode = triggeredBySystemPolicy
1397                                         ? RangingChangeReason.SYSTEM_POLICY
1398                                         : RangingChangeReason.LOCAL_API;
1399                                 mSessionNotificationManager.onRangingStoppedWithApiReasonCode(
1400                                         uwbSession, apiReasonCode);
1401                             } else {
1402                                 status = UwbUciConstants.STATUS_CODE_FAILED;
1403                                 mSessionNotificationManager.onRangingStopFailed(uwbSession,
1404                                         status);
1405                             }
1406                         }
1407                         return status;
1408                     });
1409 
1410 
1411             int status = UwbUciConstants.STATUS_CODE_FAILED;
1412             int timeoutMs = IUwbAdapter.RANGING_SESSION_START_THRESHOLD_MS;
1413             if (uwbSession.getProtocolName().equals(PROTOCOL_NAME)) {
1414                 int minTimeoutNecessary = uwbSession.getCurrentFiraRangingIntervalMs() * 4;
1415                 timeoutMs = timeoutMs > minTimeoutNecessary ? timeoutMs : minTimeoutNecessary;
1416             }
1417             Log.v(TAG, "Stop timeout: " + timeoutMs);
1418             try {
1419                 status = mUwbInjector.runTaskOnSingleThreadExecutor(stopRangingTask, timeoutMs);
1420             } catch (TimeoutException e) {
1421                 Log.i(TAG, "Failed to Stop Ranging - status : TIMEOUT");
1422                 mSessionNotificationManager.onRangingStopFailed(
1423                         uwbSession, UwbUciConstants.STATUS_CODE_FAILED);
1424             } catch (InterruptedException e) {
1425                 e.printStackTrace();
1426             } catch (ExecutionException e) {
1427                 e.printStackTrace();
1428             }
1429             if (status != UwbUciConstants.STATUS_CODE_FAILED) {
1430                 mUwbMetrics.longRangingStopEvent(uwbSession);
1431             }
1432             // Reset all UWB session timers when the session is stopped.
1433             uwbSession.stopTimers();
1434             removeAdvertiserData(uwbSession);
1435             Trace.endSection();
1436         }
1437 
handleReconfigure(UwbSession uwbSession, @Nullable Params param, boolean triggeredByFgStateChange)1438         private void handleReconfigure(UwbSession uwbSession, @Nullable Params param,
1439                 boolean triggeredByFgStateChange) {
1440             if (!(param instanceof FiraRangingReconfigureParams)) {
1441                 Log.e(TAG, "Invalid reconfigure params: " + param);
1442                 mSessionNotificationManager.onRangingReconfigureFailed(
1443                         uwbSession, UwbUciConstants.STATUS_CODE_INVALID_PARAM);
1444                 return;
1445             }
1446             Trace.beginSection("UWB#handleReconfigure");
1447             FiraRangingReconfigureParams rangingReconfigureParams =
1448                     (FiraRangingReconfigureParams) param;
1449             // TODO(b/211445008): Consolidate to a single uwb thread.
1450             FutureTask<Integer> cmdTask = new FutureTask<>(
1451                     () -> {
1452                         int status = UwbUciConstants.STATUS_CODE_FAILED;
1453                         synchronized (uwbSession.getWaitObj()) {
1454                             // Handle SESSION_UPDATE_CONTROLLER_MULTICAST_LIST_CMD
1455                             UwbAddress[] addrList = rangingReconfigureParams.getAddressList();
1456                             Integer action = rangingReconfigureParams.getAction();
1457                             // Action will indicate if this is a controlee add/remove.
1458                             //  if null, it's a session configuration change.
1459                             if (action != null) {
1460                                 if (addrList == null) {
1461                                     Log.e(TAG,
1462                                             "Multicast update missing the address list.");
1463                                     return status;
1464                                 }
1465                                 int dstAddressListSize = addrList.length;
1466                                 List<byte[]> dstAddressList = new ArrayList<>();
1467                                 for (UwbAddress address : addrList) {
1468                                     dstAddressList.add(getComputedMacAddress(address));
1469                                 }
1470                                 int[] subSessionIdList;
1471                                 if (!ArrayUtils.isEmpty(
1472                                         rangingReconfigureParams.getSubSessionIdList())) {
1473                                     subSessionIdList =
1474                                         rangingReconfigureParams.getSubSessionIdList();
1475                                 } else {
1476                                     // Set to 0's for the UCI stack.
1477                                     subSessionIdList = new int[dstAddressListSize];
1478                                 }
1479                                 boolean isV2 = action
1480                                         == P_STS_MULTICAST_LIST_UPDATE_ACTION_ADD_16_BYTE
1481                                         || action
1482                                         == P_STS_MULTICAST_LIST_UPDATE_ACTION_ADD_32_BYTE;
1483                                 status = mNativeUwbManager.controllerMulticastListUpdate(
1484                                         uwbSession.getSessionId(),
1485                                         action,
1486                                         subSessionIdList.length,
1487                                         ArrayUtils.toPrimitive(dstAddressList),
1488                                         subSessionIdList,
1489                                         isV2 ? rangingReconfigureParams
1490                                                 .getSubSessionKeyList() : null,
1491                                         uwbSession.getChipId());
1492                                 if (status != UwbUciConstants.STATUS_CODE_OK) {
1493                                     Log.e(TAG, "Unable to update controller multicast list.");
1494                                     if (isMulticastActionAdd(action)) {
1495                                         mSessionNotificationManager.onControleeAddFailed(
1496                                                 uwbSession, status);
1497                                     } else if (action == MULTICAST_LIST_UPDATE_ACTION_DELETE) {
1498                                         mSessionNotificationManager.onControleeRemoveFailed(
1499                                                 uwbSession, status);
1500                                     }
1501                                     return status;
1502                                 }
1503 
1504                                 uwbSession.getWaitObj().blockingWait();
1505 
1506                                 UwbMulticastListUpdateStatus multicastList =
1507                                         uwbSession.getMulticastListUpdateStatus();
1508 
1509                                 if (multicastList == null) {
1510                                     Log.e(TAG, "Confirmed controller multicast list is empty!");
1511                                     return status;
1512                                 }
1513 
1514                                 for (int i = 0; i < multicastList.getNumOfControlee(); i++) {
1515                                     int actionStatus = multicastList.getStatus()[i];
1516                                     if (actionStatus == UwbUciConstants.STATUS_CODE_OK) {
1517                                         if (isMulticastActionAdd(action)) {
1518                                             uwbSession.addControlee(
1519                                                     multicastList.getControleeUwbAddresses()[i]);
1520                                             mSessionNotificationManager.onControleeAdded(
1521                                                     uwbSession);
1522                                         } else if (action == MULTICAST_LIST_UPDATE_ACTION_DELETE) {
1523                                             uwbSession.removeControlee(
1524                                                     multicastList.getControleeUwbAddresses()[i]);
1525                                             mSessionNotificationManager.onControleeRemoved(
1526                                                     uwbSession);
1527                                         }
1528                                     }
1529                                     else {
1530                                         status = actionStatus;
1531                                         if (isMulticastActionAdd(action)) {
1532                                             mSessionNotificationManager.onControleeAddFailed(
1533                                                     uwbSession, actionStatus);
1534                                         } else if (action == MULTICAST_LIST_UPDATE_ACTION_DELETE) {
1535                                             mSessionNotificationManager.onControleeRemoveFailed(
1536                                                     uwbSession, actionStatus);
1537                                         }
1538                                     }
1539                                 }
1540                             } else {
1541                                 // setAppConfigurations only applies to config changes,
1542                                 //  not controlee list changes
1543                                 status = mConfigurationManager.setAppConfigurations(
1544                                         uwbSession.getSessionId(), param, uwbSession.getChipId());
1545                             }
1546                             if (status == UwbUciConstants.STATUS_CODE_OK) {
1547                                 // only call this if all controlees succeeded otherwise the
1548                                 //  fail status cause a onRangingReconfigureFailed later.
1549                                 if (!triggeredByFgStateChange) {
1550                                     mSessionNotificationManager.onRangingReconfigured(uwbSession);
1551                                 }
1552                             }
1553                             Log.d(TAG, "Multicast update status: " + status);
1554                             return status;
1555                         }
1556                     });
1557             int status = UwbUciConstants.STATUS_CODE_FAILED;
1558             try {
1559                 status = mUwbInjector.runTaskOnSingleThreadExecutor(cmdTask,
1560                         IUwbAdapter.RANGING_SESSION_OPEN_THRESHOLD_MS);
1561             } catch (TimeoutException e) {
1562                 Log.i(TAG, "Failed to Reconfigure - status : TIMEOUT");
1563             } catch (InterruptedException e) {
1564                 e.printStackTrace();
1565             } catch (ExecutionException e) {
1566                 e.printStackTrace();
1567             }
1568             if (status != UwbUciConstants.STATUS_CODE_OK) {
1569                 Log.i(TAG, "Failed to Reconfigure : " + status);
1570                 if (!triggeredByFgStateChange) {
1571                     mSessionNotificationManager.onRangingReconfigureFailed(uwbSession, status);
1572                 }
1573             }
1574             Trace.endSection();
1575         }
1576 
isMulticastActionAdd(Integer action)1577         private boolean isMulticastActionAdd(Integer action) {
1578             return action == MULTICAST_LIST_UPDATE_ACTION_ADD
1579                     || action == P_STS_MULTICAST_LIST_UPDATE_ACTION_ADD_16_BYTE
1580                     || action == P_STS_MULTICAST_LIST_UPDATE_ACTION_ADD_32_BYTE;
1581         }
1582 
handleDeInitWithReason(UwbSession uwbSession, int reason)1583         private void handleDeInitWithReason(UwbSession uwbSession, int reason) {
1584             Trace.beginSection("UWB#handleDeInitWithReason");
1585             // TODO(b/211445008): Consolidate to a single uwb thread.
1586             FutureTask<Integer> deInitTask = new FutureTask<>(
1587                     (Callable<Integer>) () -> {
1588                         int status = UwbUciConstants.STATUS_CODE_FAILED;
1589                         synchronized (uwbSession.getWaitObj()) {
1590                             status = mNativeUwbManager.deInitSession(uwbSession.getSessionId(),
1591                                     uwbSession.getChipId());
1592                             if (status != UwbUciConstants.STATUS_CODE_OK) {
1593                                 mSessionNotificationManager.onRangingClosed(uwbSession, status);
1594                                 return status;
1595                             }
1596                             uwbSession.getWaitObj().blockingWait();
1597                             Log.i(TAG, "onRangingClosed - status : " + status);
1598                             mSessionNotificationManager.onRangingClosed(uwbSession,
1599                                     reason);
1600                         }
1601                         return status;
1602                     });
1603 
1604             int status = UwbUciConstants.STATUS_CODE_FAILED;
1605             try {
1606                 status = mUwbInjector.runTaskOnSingleThreadExecutor(deInitTask,
1607                         IUwbAdapter.RANGING_SESSION_CLOSE_THRESHOLD_MS);
1608             } catch (TimeoutException e) {
1609                 Log.i(TAG, "Failed to Stop Ranging - status : TIMEOUT");
1610                 mSessionNotificationManager.onRangingClosed(uwbSession, status);
1611             } catch (InterruptedException | ExecutionException e) {
1612                 e.printStackTrace();
1613             }
1614             mUwbMetrics.logRangingCloseEvent(uwbSession, status);
1615 
1616             // Reset all UWB session timers when the session is de-initialized (ie, closed).
1617             uwbSession.stopTimers();
1618             removeSession(uwbSession);
1619             Log.i(TAG, "deinit finish : status :" + status);
1620             Trace.endSection();
1621         }
1622 
handleSendData(SendDataInfo sendDataInfo)1623         private void handleSendData(SendDataInfo sendDataInfo) {
1624             int status = UwbUciConstants.STATUS_CODE_ERROR_SESSION_NOT_EXIST;
1625             SessionHandle sessionHandle = sendDataInfo.sessionHandle;
1626             if (sessionHandle == null) {
1627                 Log.i(TAG, "Not present sessionHandle");
1628                 mSessionNotificationManager.onDataSendFailed(
1629                         null, sendDataInfo.remoteDeviceAddress, status, sendDataInfo.params);
1630                 return;
1631             }
1632 
1633             Integer sessionId = getSessionId(sessionHandle);
1634             if (sessionId == null) {
1635                 Log.i(TAG, "UwbSessionId not found");
1636                 mSessionNotificationManager.onDataSendFailed(
1637                         null, sendDataInfo.remoteDeviceAddress, status, sendDataInfo.params);
1638                 return;
1639             }
1640 
1641             // TODO(b/256675656): Check if there is race condition between uwbSession being
1642             // retrieved here and used below (and similar for uwbSession being stored in the
1643             //  mLooper message and being used during processing for all other message types).
1644             UwbSession uwbSession = getUwbSession(sessionId);
1645             if (uwbSession == null) {
1646                 Log.i(TAG, "UwbSession not found");
1647                 mSessionNotificationManager.onDataSendFailed(
1648                         null, sendDataInfo.remoteDeviceAddress, status, sendDataInfo.params);
1649                 return;
1650             }
1651 
1652             // TODO(b/211445008): Consolidate to a single uwb thread.
1653             FutureTask<Integer> sendDataTask = new FutureTask<>((Callable<Integer>) () -> {
1654                 int sendDataStatus = UwbUciConstants.STATUS_CODE_FAILED;
1655                 synchronized (uwbSession.getWaitObj()) {
1656                     if (!isValidUwbSessionForApplicationDataTransfer(uwbSession)) {
1657                         sendDataStatus = UwbUciConstants.STATUS_CODE_FAILED;
1658                         Log.i(TAG, "UwbSession not in active state");
1659                         mSessionNotificationManager.onDataSendFailed(
1660                                 uwbSession, sendDataInfo.remoteDeviceAddress, sendDataStatus,
1661                                 sendDataInfo.params);
1662                         return sendDataStatus;
1663                     }
1664                     if (!isValidSendDataInfo(sendDataInfo)) {
1665                         sendDataStatus = UwbUciConstants.STATUS_CODE_INVALID_PARAM;
1666                         mSessionNotificationManager.onDataSendFailed(
1667                                 uwbSession, sendDataInfo.remoteDeviceAddress, sendDataStatus,
1668                                 sendDataInfo.params);
1669                         return sendDataStatus;
1670                     }
1671 
1672                     // Get the UCI sequence number for this data packet, and store it.
1673                     byte sequenceNum = uwbSession.getAndIncrementDataSndSequenceNumber();
1674                     uwbSession.addSendDataInfo(sequenceNum, sendDataInfo);
1675 
1676                     sendDataStatus = mNativeUwbManager.sendData(
1677                             uwbSession.getSessionId(),
1678                             DataTypeConversionUtil.convertShortMacAddressBytesToExtended(
1679                                     sendDataInfo.remoteDeviceAddress.toBytes()),
1680                             UwbUciConstants.UWB_DESTINATION_END_POINT_HOST, sequenceNum,
1681                             sendDataInfo.data, uwbSession.getChipId());
1682                     mUwbMetrics.logDataTx(uwbSession, sendDataStatus);
1683                     if (sendDataStatus != STATUS_CODE_OK) {
1684                         Log.e(TAG, "MSG_SESSION_SEND_DATA error status: " + sendDataStatus
1685                                 + " for data packet sessionId: " + sessionId
1686                                 + ", sequence number: " + sequenceNum);
1687                         mSessionNotificationManager.onDataSendFailed(
1688                                 uwbSession, sendDataInfo.remoteDeviceAddress, sendDataStatus,
1689                                 sendDataInfo.params);
1690                         uwbSession.removeSendDataInfo(sequenceNum);
1691                     }
1692                     return sendDataStatus;
1693                 }
1694             });
1695 
1696             status = UwbUciConstants.STATUS_CODE_FAILED;
1697             try {
1698                 status = mUwbInjector.runTaskOnSingleThreadExecutor(sendDataTask,
1699                         IUwbAdapter.RANGING_SESSION_OPEN_THRESHOLD_MS);
1700             } catch (TimeoutException e) {
1701                 Log.i(TAG, "Failed to Send data - status : TIMEOUT");
1702                 mSessionNotificationManager.onDataSendFailed(uwbSession,
1703                         sendDataInfo.remoteDeviceAddress, status, sendDataInfo.params);
1704             } catch (InterruptedException | ExecutionException e) {
1705                 e.printStackTrace();
1706             }
1707         }
1708     }
1709 
isValidUwbSessionForOwrAoaRanging(UwbSession uwbSession)1710     private boolean isValidUwbSessionForOwrAoaRanging(UwbSession uwbSession) {
1711         Params params = uwbSession.getParams();
1712         if (params instanceof FiraOpenSessionParams) {
1713             FiraOpenSessionParams firaParams = (FiraOpenSessionParams) params;
1714             if (firaParams.getRangingRoundUsage() != ROUND_USAGE_OWR_AOA_MEASUREMENT) {
1715                 Log.i(TAG, "OwR Aoa UwbSession: Invalid ranging round usage value = "
1716                         + firaParams.getRangingRoundUsage());
1717                 return false;
1718             }
1719             if (firaParams.getDeviceRole() != RANGING_DEVICE_ROLE_OBSERVER) {
1720                 Log.i(TAG, "OwR Aoa UwbSession: Invalid device role value = "
1721                         + firaParams.getDeviceRole());
1722                 return false;
1723             }
1724             return true;
1725         }
1726         return false;
1727     }
1728 
isValidUwbSessionForApplicationDataTransfer(UwbSession uwbSession)1729     private boolean isValidUwbSessionForApplicationDataTransfer(UwbSession uwbSession) {
1730         // The session state must be SESSION_STATE_ACTIVE, as that's required to transmit or receive
1731         // application data.
1732         return uwbSession != null && uwbSession.getSessionState() == UWB_SESSION_STATE_ACTIVE;
1733     }
1734 
isValidSendDataInfo(SendDataInfo sendDataInfo)1735     private boolean isValidSendDataInfo(SendDataInfo sendDataInfo) {
1736         if (sendDataInfo.data == null) {
1737             return false;
1738         }
1739 
1740         if (sendDataInfo.remoteDeviceAddress == null) {
1741             return false;
1742         }
1743 
1744         if (sendDataInfo.remoteDeviceAddress.size()
1745                 > UwbUciConstants.UWB_DEVICE_EXT_MAC_ADDRESS_LEN) {
1746             return false;
1747         }
1748         return true;
1749     }
1750 
1751     /** Represents a UWB session */
1752     public class UwbSession implements IBinder.DeathRecipient, Closeable {
1753         @VisibleForTesting
1754         public static final long RANGING_RESULT_ERROR_NO_TIMEOUT = 0;
1755         private static final String RANGING_RESULT_ERROR_STREAK_TIMER_TAG =
1756                 "UwbSessionRangingResultError";
1757         private static final long NON_PRIVILEGED_BG_APP_TIMEOUT_MS = 120_000;
1758         @VisibleForTesting
1759         public static final String NON_PRIVILEGED_BG_APP_TIMER_TAG =
1760                 "UwbSessionNonPrivilegedBgAppError";
1761         @VisibleForTesting
1762         static final int CCC_SESSION_PRIORITY = 80;
1763         @VisibleForTesting
1764         static final int SYSTEM_APP_SESSION_PRIORITY = 70;
1765         @VisibleForTesting
1766         static final int FG_SESSION_PRIORITY = 60;
1767         // Default session priority value needs to be different from other session priority buckets,
1768         // so we can detect overrides from the shell or System API.
1769         @VisibleForTesting
1770         static final int DEFAULT_SESSION_PRIORITY = 50;
1771         @VisibleForTesting
1772         static final int BG_SESSION_PRIORITY = 40;
1773 
1774         private final AttributionSource mAttributionSource;
1775         private final SessionHandle mSessionHandle;
1776         private final int mSessionId;
1777         private final byte mSessionType;
1778         private final int mRangingRoundUsage;
1779         private final IUwbRangingCallbacks mIUwbRangingCallbacks;
1780         private final String mProtocolName;
1781         private final IBinder mIBinder;
1782         private final WaitObj mWaitObj;
1783         private boolean mAcquiredDefaultPose = false;
1784         private Params mParams;
1785         private int mSessionState;
1786         // Session priority as tracked by the UWB stack that changes based on the requesting
1787         // app/service bg/fg state changes. Note, it will differ from the Fira SESSION_PRIORITY
1788         // param given to UWBS if the state changed after the session became active.
1789         private int mStackSessionPriority;
1790         private boolean mSessionPriorityOverride = false;
1791         private boolean mNeedsAppConfigUpdate = false;
1792         private UwbMulticastListUpdateStatus mMulticastListUpdateStatus;
1793         private final int mProfileType;
1794         private AlarmManager.OnAlarmListener mRangingResultErrorStreakTimerListener;
1795         private AlarmManager.OnAlarmListener mNonPrivilegedBgAppTimerListener;
1796         private int mOperationType = OPERATION_TYPE_INIT_SESSION;
1797         private final String mChipId;
1798         private boolean mHasNonPrivilegedFgApp = false;
1799         private long mRangingErrorStreakTimeoutMs = RANGING_RESULT_ERROR_NO_TIMEOUT;
1800         // Use a Map<RemoteMacAddress, SortedMap<SequenceNumber, ReceivedDataInfo>> to store all
1801         // the Application payload data packets received in this (active) UWB Session.
1802         // - The outer key (RemoteMacAddress) is used to identify the Advertiser device that sends
1803         //   the data (there can be multiple advertisers in the same UWB session).
1804         // - The inner key (SequenceNumber) is used to ensure we don't store duplicate packets,
1805         //   and notify them to the higher layers in-order.
1806         // TODO(b/270068278): Change the type of SequenceNumber from Long to Integer everywhere.
1807         private final ConcurrentHashMap<Long, SortedMap<Long, ReceivedDataInfo>>
1808                 mReceivedDataInfoMap;
1809         private IPoseSource mPoseSource;
1810 
1811         // Store the UCI sequence number for the next Data packet (to be sent to UWBS).
1812         private byte mDataSndSequenceNumber;
1813         // Store a Map<SequenceNumber, SendDataInfo>, for every Data packet (sent to UWBS). It's
1814         // used when the corresponding DataTransferStatusNtf is received (from UWBS).
1815         private final ConcurrentHashMap<Long, SendDataInfo> mSendDataInfoMap;
1816 
1817         @VisibleForTesting
1818         public List<UwbControlee> mControleeList;
1819 
UwbSession(AttributionSource attributionSource, SessionHandle sessionHandle, int sessionId, byte sessionType, String protocolName, Params params, IUwbRangingCallbacks iUwbRangingCallbacks, String chipId)1820         UwbSession(AttributionSource attributionSource, SessionHandle sessionHandle, int sessionId,
1821                 byte sessionType, String protocolName, Params params,
1822                 IUwbRangingCallbacks iUwbRangingCallbacks, String chipId) {
1823             this.mAttributionSource = attributionSource;
1824             this.mSessionHandle = sessionHandle;
1825             this.mSessionId = sessionId;
1826             this.mSessionType = sessionType;
1827             this.mProtocolName = protocolName;
1828             this.mIUwbRangingCallbacks = iUwbRangingCallbacks;
1829             this.mIBinder = iUwbRangingCallbacks.asBinder();
1830             this.mSessionState = UwbUciConstants.UWB_SESSION_STATE_DEINIT;
1831             this.mStackSessionPriority = calculateSessionPriority();
1832             this.mParams = params;
1833             this.mWaitObj = new WaitObj();
1834             this.mProfileType = convertProtolNameToProfileType(protocolName);
1835             this.mChipId = chipId;
1836 
1837             if (params instanceof FiraOpenSessionParams) {
1838                 FiraOpenSessionParams firaParams = (FiraOpenSessionParams) params;
1839 
1840                 this.mRangingRoundUsage = firaParams.getRangingRoundUsage();
1841 
1842                 // Set up pose sources before we start creating UwbControlees.
1843                 switch (firaParams.getFilterType()) {
1844                     case FILTER_TYPE_DEFAULT:
1845                         this.mPoseSource = mUwbInjector.acquirePoseSource();
1846                         this.mAcquiredDefaultPose = true;
1847                         break;
1848                     case FILTER_TYPE_APPLICATION:
1849                         this.mPoseSource = new ApplicationPoseSource();
1850                         break;
1851                 }
1852 
1853                 if (firaParams.getDestAddressList() != null) {
1854                     // Set up list of all controlees involved.
1855                     mControleeList = firaParams.getDestAddressList().stream()
1856                             .map(addr -> new UwbControlee(addr, createFilterEngine(), mUwbInjector))
1857                             .collect(Collectors.toList());
1858                 }
1859                 mRangingErrorStreakTimeoutMs = firaParams
1860                         .getRangingErrorStreakTimeoutMs();
1861 
1862                 // Add stack calculated session priority to Fira open session params. The stack
1863                 // session priority might change later based on fg/bg state changes, but the
1864                 // SESSION_PRIORITY given to the UWBS on open session will stay the same since
1865                 // UWBS doesn't support reconfiguring session priority while the session is active.
1866                 // In case the session stops being active, session priority will update on next
1867                 // start ranging call.
1868                 if (firaParams.getSessionPriority() != DEFAULT_SESSION_PRIORITY) {
1869                     mSessionPriorityOverride = true;
1870                     mStackSessionPriority = firaParams.getSessionPriority();
1871                 } else {
1872                     mParams = firaParams.toBuilder().setSessionPriority(
1873                             mStackSessionPriority).build();
1874                 }
1875             } else {
1876                 this.mRangingRoundUsage = -1;
1877             }
1878 
1879             this.mReceivedDataInfoMap = new ConcurrentHashMap<>();
1880             this.mDataSndSequenceNumber = 0;
1881             this.mSendDataInfoMap = new ConcurrentHashMap<>();
1882         }
1883 
1884         /**
1885          * Calculates the priority of the session based on the protocol type and the originating
1886          * app/service requesting the session.
1887          *
1888          * Session priority ranking order (from highest to lowest priority):
1889          *  1. Any CCC session
1890          *  2. Any System app/service
1891          *  3. Other apps/services running in Foreground
1892          *  4. Other apps/services running in Background
1893          */
calculateSessionPriority()1894         public int calculateSessionPriority() {
1895             if (mProtocolName.equals(CccParams.PROTOCOL_NAME)) {
1896                 return CCC_SESSION_PRIORITY;
1897             }
1898             AttributionSource nonPrivilegedAppAttrSource =
1899                     this.getAnyNonPrivilegedAppInAttributionSource();
1900             if (nonPrivilegedAppAttrSource == null) {
1901                 return SYSTEM_APP_SESSION_PRIORITY;
1902             }
1903             long identity = Binder.clearCallingIdentity();
1904             boolean isFgAppOrService = mUwbInjector.isForegroundAppOrService(
1905                     nonPrivilegedAppAttrSource.getUid(),
1906                     nonPrivilegedAppAttrSource.getPackageName());
1907             Binder.restoreCallingIdentity(identity);
1908             if (isFgAppOrService) {
1909                 return FG_SESSION_PRIORITY;
1910             }
1911             return BG_SESSION_PRIORITY;
1912         }
1913 
isPrivilegedApp(int uid, String packageName)1914         private boolean isPrivilegedApp(int uid, String packageName) {
1915             return mUwbInjector.isSystemApp(uid, packageName)
1916                     || mUwbInjector.isAppSignedWithPlatformKey(uid);
1917         }
1918 
1919         /**
1920          * Check the attribution source chain to check if there are any 3p apps.
1921          * @return AttributionSource of first non-system app found in the chain, null otherwise.
1922          */
1923         @Nullable
getAnyNonPrivilegedAppInAttributionSource()1924         public AttributionSource getAnyNonPrivilegedAppInAttributionSource() {
1925             // Iterate attribution source chain to ensure that there is no non-fg 3p app in the
1926             // request.
1927             AttributionSource attributionSource = mAttributionSource;
1928             while (attributionSource != null) {
1929                 int uid = attributionSource.getUid();
1930                 String packageName = attributionSource.getPackageName();
1931                 if (!isPrivilegedApp(uid, packageName)) {
1932                     return attributionSource;
1933                 }
1934                 attributionSource = attributionSource.getNext();
1935             }
1936             return null;
1937         }
1938 
1939         /**
1940          * Gets the list of controlees active under this session.
1941          */
getControleeList()1942         public List<UwbControlee> getControleeList() {
1943             return Collections.unmodifiableList(mControleeList);
1944         }
1945 
1946         /**
1947          * Store a ReceivedDataInfo for the UwbSession. If we already have stored data from the
1948          * same advertiser and with the same sequence number, this is a no-op.
1949          */
addReceivedDataInfo(ReceivedDataInfo receivedDataInfo)1950         public void addReceivedDataInfo(ReceivedDataInfo receivedDataInfo) {
1951             SortedMap<Long, ReceivedDataInfo> innerMap = mReceivedDataInfoMap.get(
1952                     receivedDataInfo.address);
1953             if (innerMap == null) {
1954                 innerMap = new TreeMap<>();
1955                 mReceivedDataInfoMap.put(receivedDataInfo.address, innerMap);
1956             }
1957 
1958             // Check if the sorted InnerMap has reached the max number of Rx packets we want to
1959             // store; if so we drop the smallest (sequence number) packet between the new received
1960             // packet and the stored packets.
1961             int maxRxPacketsToStore =
1962                     mUwbInjector.getDeviceConfigFacade().getRxDataMaxPacketsToStore();
1963             if (innerMap.size() < maxRxPacketsToStore) {
1964                 innerMap.putIfAbsent(receivedDataInfo.sequenceNum, receivedDataInfo);
1965             } else if (innerMap.size() == maxRxPacketsToStore) {
1966                 Long smallestStoredSequenceNumber = innerMap.firstKey();
1967                 if (smallestStoredSequenceNumber < receivedDataInfo.sequenceNum
1968                         && !innerMap.containsKey(receivedDataInfo.sequenceNum)) {
1969                     innerMap.remove(smallestStoredSequenceNumber);
1970                     innerMap.putIfAbsent(receivedDataInfo.sequenceNum, receivedDataInfo);
1971                 }
1972             }
1973         }
1974 
1975         /**
1976           * Return all the ReceivedDataInfo from the given remote device, in sequence number order.
1977           * This method also removes the returned packets from the Map, so the same packet will
1978           * not be returned again (in a future call).
1979           */
getAllReceivedDataInfo(long macAddress)1980         public List<ReceivedDataInfo> getAllReceivedDataInfo(long macAddress) {
1981             SortedMap<Long, ReceivedDataInfo> innerMap = mReceivedDataInfoMap.get(macAddress);
1982             if (innerMap == null) {
1983                 // No stored ReceivedDataInfo(s) for the address.
1984                 return List.of();
1985             }
1986 
1987             List<ReceivedDataInfo> receivedDataInfoList = new ArrayList<>(innerMap.values());
1988             innerMap.clear();
1989             return receivedDataInfoList;
1990         }
1991 
clearReceivedDataInfo()1992         private void clearReceivedDataInfo() {
1993             for (long macAddress : getRemoteMacAddressList()) {
1994                 SortedMap<Long, ReceivedDataInfo> innerMap = mReceivedDataInfoMap.get(macAddress);
1995                 innerMap.clear();
1996             }
1997             mReceivedDataInfoMap.clear();
1998         }
1999 
2000         /**
2001          * Get (and increment) the UCI sequence number for the next Data packet to be sent to UWBS.
2002          */
getAndIncrementDataSndSequenceNumber()2003         public byte getAndIncrementDataSndSequenceNumber() {
2004             return mDataSndSequenceNumber++;
2005         }
2006 
2007         /**
2008          * Store a SendDataInfo for a UCI Data packet sent to UWBS.
2009          */
addSendDataInfo(long sequenceNumber, SendDataInfo sendDataInfo)2010         public void addSendDataInfo(long sequenceNumber, SendDataInfo sendDataInfo) {
2011             mSendDataInfoMap.put(sequenceNumber, sendDataInfo);
2012         }
2013 
2014         /**
2015          * Remove the SendDataInfo for a UCI packet from the current UWB Session.
2016          */
removeSendDataInfo(long sequenceNumber)2017         public void removeSendDataInfo(long sequenceNumber) {
2018             mSendDataInfoMap.remove(sequenceNumber);
2019         }
2020 
2021         /**
2022          * Get the SendDataInfo for a UCI packet from the current UWB Session.
2023          */
2024         @Nullable
getSendDataInfo(long sequenceNumber)2025         public SendDataInfo getSendDataInfo(long sequenceNumber) {
2026             return mSendDataInfoMap.get(sequenceNumber);
2027         }
2028 
2029         /**
2030          * Adds a Controlee to the session. This should only be called to reflect
2031          *  the state of the native UWB interface.
2032          * @param address The UWB address of the Controlee to add.
2033          */
addControlee(UwbAddress address)2034         public void addControlee(UwbAddress address) {
2035             if (mControleeList != null
2036                     && mControleeList.stream().noneMatch(e -> e.getUwbAddress().equals(address))) {
2037                 mControleeList.add(new UwbControlee(address, createFilterEngine(), mUwbInjector));
2038             }
2039         }
2040 
2041         /**
2042          * Fetches a {@link UwbControlee} object by {@link UwbAddress}.
2043          * @param address The UWB address of the Controlee to find.
2044          * @return The matching {@link UwbControlee}, or null if not found.
2045          */
getControlee(UwbAddress address)2046         public UwbControlee getControlee(UwbAddress address) {
2047             UwbControlee result = mControleeList
2048                     .stream()
2049                     .filter(e -> e.getUwbAddress().equals(address))
2050                     .findFirst()
2051                     .orElse(null);
2052             if (result == null) {
2053                 Log.d(TAG, "Failure to find controlee " + address);
2054             }
2055             return result;
2056         }
2057 
2058         /**
2059          * Removes a Controlee from the session. This should only be called to reflect
2060          *  the state of the native UWB interface.
2061          * @param address The UWB address of the Controlee to remove.
2062          */
removeControlee(UwbAddress address)2063         public void removeControlee(UwbAddress address) {
2064             if (mControleeList != null) {
2065                 for (UwbControlee controlee : mControleeList) {
2066                     if (controlee.getUwbAddress().equals(address)) {
2067                         controlee.close();
2068                         mControleeList.remove(controlee);
2069                         break;
2070                     }
2071                 }
2072             }
2073         }
2074 
getAttributionSource()2075         public AttributionSource getAttributionSource() {
2076             return this.mAttributionSource;
2077         }
2078 
getSessionId()2079         public int getSessionId() {
2080             return this.mSessionId;
2081         }
2082 
getSessionType()2083         public byte getSessionType() {
2084             return this.mSessionType;
2085         }
2086 
getRangingRoundUsage()2087         public int getRangingRoundUsage() {
2088             return this.mRangingRoundUsage;
2089         }
2090 
getChipId()2091         public String getChipId() {
2092             return this.mChipId;
2093         }
2094 
getSessionHandle()2095         public SessionHandle getSessionHandle() {
2096             return this.mSessionHandle;
2097         }
2098 
getParams()2099         public Params getParams() {
2100             return this.mParams;
2101         }
2102 
updateCccParamsOnStart(CccStartRangingParams rangingStartParams)2103         public void updateCccParamsOnStart(CccStartRangingParams rangingStartParams) {
2104             // Need to update the RAN multiplier and initiation time
2105             // from the CccStartRangingParams for CCC session.
2106             CccOpenRangingParams newParams =
2107                     new CccOpenRangingParams.Builder((CccOpenRangingParams) mParams)
2108                             .setRanMultiplier(rangingStartParams.getRanMultiplier())
2109                             .setInitiationTimeMs(rangingStartParams.getInitiationTimeMs())
2110                             .build();
2111             this.mParams = newParams;
2112             this.mNeedsAppConfigUpdate = true;
2113         }
2114 
2115         /**
2116          * Checks if session priority of the current session changed from the initial value, if so
2117          * updates the session priority param and marks session for needed app config update.
2118          */
updateFiraParamsOnStartIfChanged()2119         public void updateFiraParamsOnStartIfChanged() {
2120             // Need to check if session priority changed and update if it did
2121             FiraOpenSessionParams firaOpenSessionParams = (FiraOpenSessionParams) mParams;
2122             if (mStackSessionPriority != firaOpenSessionParams.getSessionPriority()) {
2123                 this.mParams = ((FiraOpenSessionParams) mParams).toBuilder().setSessionPriority(
2124                         mStackSessionPriority).build();
2125                 this.mNeedsAppConfigUpdate = true;
2126             }
2127         }
2128 
updateFiraParamsOnReconfigure(FiraRangingReconfigureParams reconfigureParams)2129         public void updateFiraParamsOnReconfigure(FiraRangingReconfigureParams reconfigureParams) {
2130             // Need to update the reconfigure params from the FiraRangingReconfigureParams for
2131             // FiRa session.
2132             FiraOpenSessionParams.Builder newParamsBuilder =
2133                     new FiraOpenSessionParams.Builder((FiraOpenSessionParams) mParams);
2134             if (reconfigureParams.getBlockStrideLength() != null) {
2135                 newParamsBuilder.setBlockStrideLength(reconfigureParams.getBlockStrideLength());
2136             }
2137             if (reconfigureParams.getRangeDataNtfConfig() != null) {
2138                 newParamsBuilder.setRangeDataNtfConfig(reconfigureParams.getRangeDataNtfConfig());
2139             }
2140             if (reconfigureParams.getRangeDataProximityNear() != null) {
2141                 newParamsBuilder.setRangeDataNtfProximityNear(
2142                         reconfigureParams.getRangeDataProximityNear());
2143             }
2144             if (reconfigureParams.getRangeDataProximityFar() != null) {
2145                 newParamsBuilder.setRangeDataNtfProximityFar(
2146                         reconfigureParams.getRangeDataProximityFar());
2147             }
2148             if (reconfigureParams.getRangeDataAoaAzimuthLower() != null) {
2149                 newParamsBuilder.setRangeDataNtfAoaAzimuthLower(
2150                         reconfigureParams.getRangeDataAoaAzimuthLower());
2151             }
2152             if (reconfigureParams.getRangeDataAoaAzimuthUpper() != null) {
2153                 newParamsBuilder.setRangeDataNtfAoaAzimuthUpper(
2154                         reconfigureParams.getRangeDataAoaAzimuthUpper());
2155             }
2156             if (reconfigureParams.getRangeDataAoaElevationLower() != null) {
2157                 newParamsBuilder.setRangeDataNtfAoaElevationLower(
2158                         reconfigureParams.getRangeDataAoaElevationLower());
2159             }
2160             if (reconfigureParams.getRangeDataAoaElevationUpper() != null) {
2161                 newParamsBuilder.setRangeDataNtfAoaElevationUpper(
2162                         reconfigureParams.getRangeDataAoaElevationUpper());
2163             }
2164             this.mParams = newParamsBuilder.build();
2165         }
2166 
getCurrentFiraRangingIntervalMs()2167         public int getCurrentFiraRangingIntervalMs() {
2168             FiraOpenSessionParams firaOpenSessionParams = (FiraOpenSessionParams) mParams;
2169             return firaOpenSessionParams.getRangingIntervalMs()
2170                     * (firaOpenSessionParams.getBlockStrideLength() + 1);
2171         }
2172 
getProtocolName()2173         public String getProtocolName() {
2174             return this.mProtocolName;
2175         }
2176 
getIUwbRangingCallbacks()2177         public IUwbRangingCallbacks getIUwbRangingCallbacks() {
2178             return this.mIUwbRangingCallbacks;
2179         }
2180 
getSessionState()2181         public int getSessionState() {
2182             return this.mSessionState;
2183         }
2184 
setSessionState(int state)2185         public void setSessionState(int state) {
2186             this.mSessionState = state;
2187         }
2188 
getStackSessionPriority()2189         public int getStackSessionPriority() {
2190             return this.mStackSessionPriority;
2191         }
2192 
setStackSessionPriority(int priority)2193         public void setStackSessionPriority(int priority) {
2194             this.mStackSessionPriority = priority;
2195         }
2196 
getNeedsAppConfigUpdate()2197         public boolean getNeedsAppConfigUpdate() {
2198             return this.mNeedsAppConfigUpdate;
2199         }
2200 
2201         /** Reset the needsAppConfigUpdate flag to false. */
resetNeedsAppConfigUpdate()2202         public void resetNeedsAppConfigUpdate() {
2203             this.mNeedsAppConfigUpdate = false;
2204         }
2205 
getRemoteMacAddressList()2206         public Set<Long> getRemoteMacAddressList() {
2207             return mReceivedDataInfoMap.keySet();
2208         }
2209 
setMulticastListUpdateStatus( UwbMulticastListUpdateStatus multicastListUpdateStatus)2210         public void setMulticastListUpdateStatus(
2211                 UwbMulticastListUpdateStatus multicastListUpdateStatus) {
2212             mMulticastListUpdateStatus = multicastListUpdateStatus;
2213         }
2214 
getMulticastListUpdateStatus()2215         public UwbMulticastListUpdateStatus getMulticastListUpdateStatus() {
2216             return mMulticastListUpdateStatus;
2217         }
2218 
convertProtolNameToProfileType(String protocolName)2219         private int convertProtolNameToProfileType(String protocolName) {
2220             if (protocolName.equals(FiraParams.PROTOCOL_NAME)) {
2221                 return UwbStatsLog.UWB_SESSION_INITIATED__PROFILE__FIRA;
2222             } else if (protocolName.equals(CccParams.PROTOCOL_NAME)) {
2223                 return UwbStatsLog.UWB_SESSION_INITIATED__PROFILE__CCC;
2224             } else {
2225                 return UwbStatsLog.UWB_SESSION_INITIATED__PROFILE__CUSTOMIZED;
2226             }
2227         }
2228 
getProfileType()2229         public int getProfileType() {
2230             return mProfileType;
2231         }
2232 
getParallelSessionCount()2233         public int getParallelSessionCount() {
2234             if (mSessionTable.containsKey(mSessionHandle)) {
2235                 return getSessionCount() - 1;
2236             }
2237             return getSessionCount();
2238         }
2239 
getBinder()2240         public IBinder getBinder() {
2241             return mIBinder;
2242         }
2243 
getWaitObj()2244         public WaitObj getWaitObj() {
2245             return mWaitObj;
2246         }
2247 
hasNonPrivilegedFgApp()2248         public boolean hasNonPrivilegedFgApp() {
2249             return mHasNonPrivilegedFgApp;
2250         }
2251 
setHasNonPrivilegedFgApp(boolean hasNonPrivilegedFgApp)2252         public void setHasNonPrivilegedFgApp(boolean hasNonPrivilegedFgApp) {
2253             mHasNonPrivilegedFgApp = hasNonPrivilegedFgApp;
2254         }
2255 
2256         /**
2257          * Starts a timer to detect if the error streak is longer than
2258          * {@link UwbSession#mRangingErrorStreakTimeoutMs }.
2259          */
startRangingResultErrorStreakTimerIfNotSet()2260         public void startRangingResultErrorStreakTimerIfNotSet() {
2261             // Start a timer on first failure to detect continuous failures.
2262             if (mRangingResultErrorStreakTimerListener == null) {
2263                 mRangingResultErrorStreakTimerListener = () -> {
2264                     Log.w(TAG, "Continuous errors or no ranging results detected for "
2265                             + mRangingErrorStreakTimeoutMs + " ms."
2266                             + " Stopping session");
2267                     stopRangingInternal(mSessionHandle, true /* triggeredBySystemPolicy */);
2268                 };
2269                 Log.v(TAG, "Starting error timer for "
2270                         + mRangingErrorStreakTimeoutMs + " ms.");
2271                 mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
2272                         mUwbInjector.getElapsedSinceBootMillis()
2273                                 + mRangingErrorStreakTimeoutMs,
2274                         RANGING_RESULT_ERROR_STREAK_TIMER_TAG,
2275                         mRangingResultErrorStreakTimerListener, mEventTask);
2276             }
2277         }
2278 
stopRangingResultErrorStreakTimerIfSet()2279         public void stopRangingResultErrorStreakTimerIfSet() {
2280             // Cancel error streak timer on any success.
2281             if (mRangingResultErrorStreakTimerListener != null) {
2282                 mAlarmManager.cancel(mRangingResultErrorStreakTimerListener);
2283                 mRangingResultErrorStreakTimerListener = null;
2284             }
2285         }
2286 
2287         /**
2288          * Starts a timer to detect if the app that started the UWB session is in the background
2289          * for longer than {@link UwbSession#NON_PRIVILEGED_BG_APP_TIMEOUT_MS}.
2290          */
startNonPrivilegedBgAppTimerIfNotSet()2291         private void startNonPrivilegedBgAppTimerIfNotSet() {
2292             // Start a timer when the non-privileged app goes into the background.
2293             if (mNonPrivilegedBgAppTimerListener == null) {
2294                 mNonPrivilegedBgAppTimerListener = () -> {
2295                     Log.w(TAG, "Non-privileged app in background for longer than timeout - "
2296                             + " Stopping session");
2297                     stopRangingInternal(mSessionHandle, true /* triggeredBySystemPolicy */);
2298                 };
2299                 mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
2300                         mUwbInjector.getElapsedSinceBootMillis()
2301                                 + NON_PRIVILEGED_BG_APP_TIMEOUT_MS,
2302                         NON_PRIVILEGED_BG_APP_TIMER_TAG,
2303                         mNonPrivilegedBgAppTimerListener, mEventTask);
2304             }
2305         }
2306 
stopNonPrivilegedBgAppTimerIfSet()2307         private void stopNonPrivilegedBgAppTimerIfSet() {
2308             // Stop the timer when the non-privileged app goes into the foreground.
2309             if (mNonPrivilegedBgAppTimerListener != null) {
2310                 mAlarmManager.cancel(mNonPrivilegedBgAppTimerListener);
2311                 mNonPrivilegedBgAppTimerListener = null;
2312             }
2313         }
2314 
stopTimers()2315         private void stopTimers() {
2316             // Reset any stored error streak or non-privileged background app timestamps.
2317             stopRangingResultErrorStreakTimerIfSet();
2318             stopNonPrivilegedBgAppTimerIfSet();
2319         }
2320 
reconfigureFiraSessionOnFgStateChange()2321         public void reconfigureFiraSessionOnFgStateChange() {
2322             // Reconfigure the session to change notification control when the app transitions
2323             // from fg to bg and vice versa.
2324             FiraRangingReconfigureParams.Builder builder =
2325                     new FiraRangingReconfigureParams.Builder();
2326             // If app is in fg, use the configured ntf control, else disable.
2327             if (mHasNonPrivilegedFgApp) {
2328                 FiraOpenSessionParams params = (FiraOpenSessionParams) mParams;
2329                 builder.setRangeDataNtfConfig(params.getRangeDataNtfConfig())
2330                         .setRangeDataProximityNear(params.getRangeDataNtfProximityNear())
2331                         .setRangeDataProximityFar(params.getRangeDataNtfProximityFar());
2332             } else {
2333                 builder.setRangeDataNtfConfig(FiraParams.RANGE_DATA_NTF_CONFIG_DISABLE);
2334             }
2335             FiraRangingReconfigureParams reconfigureParams = builder.build();
2336             reconfigureInternal(
2337                     mSessionHandle, reconfigureParams, true /* triggeredByFgStateChange */);
2338 
2339             if (!mUwbInjector.getDeviceConfigFacade().isBackgroundRangingEnabled()) {
2340                 Log.d(TAG, "reconfigureFiraSessionOnFgStateChange - System policy disallows for "
2341                         + "non fg 3p apps");
2342                 // When a non-privileged app goes into the background, start a timer (that will stop
2343                 // the ranging session). If the app goes back into the foreground, the timer will
2344                 // get reset (but any stopped UWB session will not be auto-resumed).
2345                 if (!mHasNonPrivilegedFgApp) {
2346                     startNonPrivilegedBgAppTimerIfNotSet();
2347                 } else {
2348                     stopNonPrivilegedBgAppTimerIfSet();
2349                 }
2350             } else {
2351                 Log.d(TAG, "reconfigureFiraSessionOnFgStateChange - System policy allows for "
2352                         + "non fg 3p apps");
2353             }
2354         }
2355 
getOperationType()2356         public int getOperationType() {
2357             return mOperationType;
2358         }
2359 
setOperationType(int type)2360         public void setOperationType(int type) {
2361             mOperationType = type;
2362         }
2363 
2364         /** Creates a filter engine based on the device configuration. */
createFilterEngine()2365         public UwbFilterEngine createFilterEngine() {
2366             if (mParams instanceof FiraOpenSessionParams) {
2367                 FiraOpenSessionParams firaParams = (FiraOpenSessionParams) mParams;
2368                 if (firaParams.getFilterType() == FILTER_TYPE_NONE) {
2369                     return null; /* Bail early. App requested no engine. */
2370                 }
2371             }
2372 
2373             return mUwbInjector.createFilterEngine(mPoseSource);
2374         }
2375 
2376         /** Updates the pose information if an ApplicationPoseSource is being used. */
updatePose(FiraPoseUpdateParams updateParams)2377         public void updatePose(FiraPoseUpdateParams updateParams) {
2378             if (mPoseSource instanceof ApplicationPoseSource) {
2379                 ApplicationPoseSource aps = (ApplicationPoseSource) mPoseSource;
2380                 aps.applyPose(updateParams.getPoseInfo());
2381             } else {
2382                 throw new IllegalStateException("Session not configured for application poses.");
2383             }
2384         }
2385 
2386         @Override
binderDied()2387         public void binderDied() {
2388             Log.i(TAG, "binderDied : getSessionId is getSessionId() " + getSessionId());
2389 
2390             synchronized (UwbSessionManager.this) {
2391                 int status = mNativeUwbManager.deInitSession(getSessionId(), getChipId());
2392                 mUwbMetrics.logRangingCloseEvent(this, status);
2393                 if (status == UwbUciConstants.STATUS_CODE_OK) {
2394                     removeSession(this);
2395                     Log.i(TAG,
2396                             "binderDied : Fira/CCC Session counts currently are "
2397                                     + getFiraSessionCount()
2398                                     + "/" + getCccSessionCount());
2399                 } else {
2400                     Log.e(TAG,
2401                             "binderDied : sessionDeinit Failure because of NativeSessionDeinit "
2402                                     + "Error");
2403                 }
2404             }
2405         }
2406 
2407         /**
2408          * Cleans up resources held by this object.
2409          */
close()2410         public void close() {
2411             if (this.mAcquiredDefaultPose) {
2412                 if (mControleeList != null) {
2413                     for (UwbControlee controlee : mControleeList) {
2414                         controlee.close();
2415                     }
2416                     mControleeList.clear();
2417                 }
2418 
2419                 this.mAcquiredDefaultPose = false;
2420                 mUwbInjector.releasePoseSource();
2421             }
2422 
2423             mSendDataInfoMap.clear();
2424             clearReceivedDataInfo();
2425         }
2426 
2427         /**
2428          * Gets the pose source for this session. This may be the default pose source provided
2429          * by UwbInjector.java when the session was created, or a specialized pose source later
2430          * requested by the application.
2431          */
getPoseSource()2432         public IPoseSource getPoseSource() {
2433             return mPoseSource;
2434         }
2435 
2436         @Override
toString()2437         public String toString() {
2438             return "UwbSession: { Session Id: " + getSessionId()
2439                     + ", Handle: " + getSessionHandle()
2440                     + ", Protocol: " + getProtocolName()
2441                     + ", State: " + getSessionState()
2442                     + ", Data Send Sequence Number: " + mDataSndSequenceNumber
2443                     + ", Params: " + getParams()
2444                     + ", AttributionSource: " + getAttributionSource()
2445                     + " }";
2446         }
2447     }
2448 
2449     // TODO: refactor the async operation flow.
2450     // Wrapper for unit test.
2451     @VisibleForTesting
2452     static class WaitObj {
WaitObj()2453         WaitObj() {
2454         }
2455 
blockingWait()2456         void blockingWait() throws InterruptedException {
2457             wait();
2458         }
2459 
blockingNotify()2460         void blockingNotify() {
2461             notify();
2462         }
2463     }
2464 
2465     /**
2466      * Dump the UWB session manager debug info
2467      */
dump(FileDescriptor fd, PrintWriter pw, String[] args)2468     public synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2469         pw.println("---- Dump of UwbSessionManager ----");
2470         pw.println("Active sessions: ");
2471         for (UwbSession uwbSession : mSessionTable.values()) {
2472             pw.println(uwbSession);
2473         }
2474         pw.println("Recently closed sessions: ");
2475         for (UwbSession uwbSession: mDbgRecentlyClosedSessions.getEntries()) {
2476             pw.println(uwbSession);
2477         }
2478         List<Integer> nonPrivilegedSessionIds =
2479                 mNonPrivilegedUidToFiraSessionsTable.entrySet()
2480                         .stream()
2481                         .map(e -> e.getValue()
2482                                 .stream()
2483                                 .map(UwbSession::getSessionId)
2484                                 .collect(Collectors.toList()))
2485                         .flatMap(Collection::stream)
2486                         .collect(Collectors.toList());
2487         pw.println("Non Privileged Fira Session Ids: " + nonPrivilegedSessionIds);
2488         pw.println("---- Dump of UwbSessionManager ----");
2489     }
2490 
getComputedMacAddress(UwbAddress address)2491     private static byte[] getComputedMacAddress(UwbAddress address) {
2492         if (!SdkLevel.isAtLeastU()) {
2493             return TlvUtil.getReverseBytes(address.toBytes());
2494         }
2495         return address.toBytes();
2496     }
2497 }
2498